DataLireCoder swift package

This commit is contained in:
2025-04-27 12:53:43 +03:00
parent 2cca986016
commit 5aec6ea578
60 changed files with 7144 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
import Foundation
import DataLiteCore
final class KeyedContainer<Decoder: RowDecoder & KeyCheckingDecoder, Key: CodingKey>: Container, KeyedDecodingContainerProtocol {
// MARK: - Properties
let decoder: Decoder
let codingPath: [any CodingKey]
let allKeys: [Key]
// MARK: - Inits
init(
decoder: Decoder,
codingPath: [any CodingKey],
allKeys: [Key]
) {
self.decoder = decoder
self.codingPath = codingPath
self.allKeys = allKeys
}
// MARK: - Container Methods
func contains(_ key: Key) -> Bool {
decoder.contains(key)
}
func decodeNil(forKey key: Key) throws -> Bool {
try decoder.decodeNil(for: key)
}
func decode<T: Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
switch type {
case is Date.Type:
try decoder.decodeDate(for: key) as! T
case let type as SQLiteRawRepresentable.Type:
try decoder.decode(type, for: key) as! T
default:
try T(from: decoder.decoder(for: key))
}
}
func nestedContainer<NestedKey: CodingKey>(
keyedBy type: NestedKey.Type,
forKey key: Key
) throws -> KeyedDecodingContainer<NestedKey> {
let info = """
Attempted to decode a nested keyed container for key '\(key.stringValue)',
but the value cannot be represented as a keyed container.
"""
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.typeMismatch(
KeyedDecodingContainer<NestedKey>.self,
context
)
}
func nestedUnkeyedContainer(
forKey key: Key
) throws -> any UnkeyedDecodingContainer {
let info = """
Attempted to decode a nested unkeyed container for key '\(key.stringValue)',
but the value cannot be represented as an unkeyed container.
"""
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.typeMismatch(
UnkeyedDecodingContainer.self,
context
)
}
func superDecoder() throws -> any Swift.Decoder {
let info = """
Attempted to get a superDecoder,
but SQLiteRowDecoder does not support superDecoding.
"""
let context = DecodingError.Context(
codingPath: codingPath,
debugDescription: info
)
throw DecodingError.typeMismatch(Swift.Decoder.self, context)
}
func superDecoder(forKey key: Key) throws -> any Swift.Decoder {
let info = """
Attempted to get a superDecoder for key '\(key.stringValue)',
but SQLiteRowDecoder does not support nested structures.
"""
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.typeMismatch(Swift.Decoder.self, context)
}
}

View File

@@ -0,0 +1,104 @@
import Foundation
import DataLiteCore
public final class MultiRowDecoder: RowDecoder {
// MARK: - Properties
public let dateDecoder: any DateDecoder
public let sqliteData: [SQLiteRow]
public let codingPath: [any CodingKey]
public let userInfo: [CodingUserInfoKey: Any]
public var count: Int? { sqliteData.count }
// MARK: Inits
public init(
dateDecoder: any DateDecoder,
sqliteData: [SQLiteRow],
codingPath: [any CodingKey],
userInfo: [CodingUserInfoKey: Any]
) {
self.dateDecoder = dateDecoder
self.sqliteData = sqliteData
self.codingPath = codingPath
self.userInfo = userInfo
}
// MARK: Methods
public func decodeNil(for key: any CodingKey) throws -> Bool {
let info = "Attempted to decode nil, but it's not supported for an array of rows."
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.dataCorrupted(context)
}
public func decodeDate(for key: any CodingKey) throws -> Date {
return try decode(Date.self, for: key)
}
public func decode<T: SQLiteRawRepresentable>(
_ type: T.Type,
for key: any CodingKey
) throws -> T {
let info = "Expected a type of \(type), but found an array of rows."
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.typeMismatch(type, context)
}
public func decoder(for key: any CodingKey) throws -> any Decoder {
guard let index = key.intValue else {
let info = "Expected an integer key, but found a non-integer key."
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.keyNotFound(key, context)
}
return SingleRowDecoder(
dateDecoder: dateDecoder,
sqliteData: sqliteData[index],
codingPath: codingPath + [key],
userInfo: userInfo
)
}
public func container<Key: CodingKey>(
keyedBy type: Key.Type
) throws -> KeyedDecodingContainer<Key> {
let info = "Expected a keyed container, but found an array of rows."
let context = DecodingError.Context(
codingPath: codingPath,
debugDescription: info
)
throw DecodingError.typeMismatch(
KeyedDecodingContainer<Key>.self,
context
)
}
public func unkeyedContainer() throws -> any UnkeyedDecodingContainer {
UnkeyedContainer(
decoder: self,
codingPath: codingPath
)
}
public func singleValueContainer() throws -> any SingleValueDecodingContainer {
let info = "Expected a single value container, but found an array of rows."
let context = DecodingError.Context(
codingPath: codingPath,
debugDescription: info
)
throw DecodingError.typeMismatch(
SingleValueDecodingContainer.self,
context
)
}
}

View File

@@ -0,0 +1,135 @@
import Foundation
import DataLiteCore
private import DLCCommon
public final class SingleRowDecoder: RowDecoder, KeyCheckingDecoder {
// MARK: - Properties
public let dateDecoder: any DateDecoder
public let sqliteData: SQLiteRow
public let codingPath: [any CodingKey]
public let userInfo: [CodingUserInfoKey: Any]
public var count: Int? { sqliteData.count }
// MARK: Inits
public init(
dateDecoder: any DateDecoder,
sqliteData: SQLiteRow,
codingPath: [any CodingKey],
userInfo: [CodingUserInfoKey: Any]
) {
self.dateDecoder = dateDecoder
self.sqliteData = sqliteData
self.codingPath = codingPath
self.userInfo = userInfo
}
// MARK: - Methods
public func contains(_ key: any CodingKey) -> Bool {
sqliteData.contains(key)
}
public func decodeNil(for key: any CodingKey) throws -> Bool {
guard sqliteData.contains(key) else {
let info = "No value associated with key \(key)."
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.keyNotFound(key, context)
}
return sqliteData[key] == .null
}
public func decodeDate(for key: any CodingKey) throws -> Date {
try dateDecoder.decode(from: self, for: key)
}
public func decode<T: SQLiteRawRepresentable>(
_ type: T.Type,
for key: any CodingKey
) throws -> T {
guard let value = sqliteData[key] else {
let info = "No value associated with key \(key)."
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.keyNotFound(key, context)
}
guard value != .null else {
let info = "Cannot get value of type \(T.self), found null value instead."
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.valueNotFound(type, context)
}
guard let result = T(value) else {
let info = "Expected to decode \(T.self) but found an \(value) instead."
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.typeMismatch(type, context)
}
return result
}
public func decoder(for key: any CodingKey) throws -> any Decoder {
guard let data = sqliteData[key] else {
let info = "No value associated with key \(key)."
let context = DecodingError.Context(
codingPath: codingPath + [key],
debugDescription: info
)
throw DecodingError.keyNotFound(key, context)
}
return SingleValueDecoder(
dateDecoder: dateDecoder,
sqliteData: data,
codingPath: codingPath + [key],
userInfo: userInfo
)
}
public func container<Key: CodingKey>(
keyedBy type: Key.Type
) throws -> KeyedDecodingContainer<Key> {
let allKeys = sqliteData.compactMap { (column, _) in
Key(stringValue: column)
}
let container = KeyedContainer(
decoder: self,
codingPath: codingPath,
allKeys: allKeys
)
return KeyedDecodingContainer(container)
}
public func unkeyedContainer() throws -> any UnkeyedDecodingContainer {
UnkeyedContainer(
decoder: self,
codingPath: codingPath
)
}
public func singleValueContainer() throws -> any SingleValueDecodingContainer {
let info = "Expected a single value container, but found a row value."
let context = DecodingError.Context(
codingPath: codingPath,
debugDescription: info
)
throw DecodingError.typeMismatch(
SingleValueDecodingContainer.self,
context
)
}
}

View File

@@ -0,0 +1,36 @@
import Foundation
import DataLiteCore
final class SingleValueContainer<Decoder: ValueDecoder>: Container, SingleValueDecodingContainer {
// MARK: - Properties
let decoder: Decoder
let codingPath: [any CodingKey]
// MARK: - Inits
init(
decoder: Decoder,
codingPath: [any CodingKey]
) {
self.decoder = decoder
self.codingPath = codingPath
}
// MARK: - Container Methods
func decodeNil() -> Bool {
decoder.decodeNil()
}
func decode<T: Decodable>(_ type: T.Type) throws -> T {
switch type {
case is Date.Type:
try decoder.decodeDate() as! T
case let type as SQLiteRawRepresentable.Type:
try decoder.decode(type) as! T
default:
try T(from: decoder)
}
}
}

View File

@@ -0,0 +1,87 @@
import Foundation
import DataLiteCore
final class SingleValueDecoder: ValueDecoder {
// MARK: - Properties
let dateDecoder: any DateDecoder
let sqliteData: SQLiteRawValue
let codingPath: [any CodingKey]
let userInfo: [CodingUserInfoKey: Any]
// MARK: - Inits
init(
dateDecoder: any DateDecoder,
sqliteData: SQLiteRawValue,
codingPath: [any CodingKey],
userInfo: [CodingUserInfoKey: Any]
) {
self.dateDecoder = dateDecoder
self.sqliteData = sqliteData
self.codingPath = codingPath
self.userInfo = userInfo
}
// MARK: - Methods
func decodeNil() -> Bool {
sqliteData == .null
}
func decodeDate() throws -> Date {
try dateDecoder.decode(from: self)
}
func decode<T: SQLiteRawRepresentable>(_ type: T.Type) throws -> T {
guard sqliteData != .null else {
let info = "Cannot get value of type \(T.self), found null value instead."
let context = DecodingError.Context(
codingPath: codingPath,
debugDescription: info
)
throw DecodingError.valueNotFound(type, context)
}
guard let result = type.init(sqliteData) else {
let info = "Expected to decode \(T.self) but found an \(sqliteData) instead."
let context = DecodingError.Context(
codingPath: codingPath,
debugDescription: info
)
throw DecodingError.typeMismatch(type, context)
}
return result
}
func container<Key: CodingKey>(
keyedBy type: Key.Type
) throws -> KeyedDecodingContainer<Key> {
let info = "Expected a keyed container, but found a single value."
let context = DecodingError.Context(
codingPath: codingPath,
debugDescription: info
)
throw DecodingError.typeMismatch(
KeyedDecodingContainer<Key>.self,
context
)
}
func unkeyedContainer() throws -> any UnkeyedDecodingContainer {
let info = "Expected a unkeyed container, but found a single value."
let context = DecodingError.Context(
codingPath: codingPath,
debugDescription: info
)
throw DecodingError.typeMismatch(
UnkeyedDecodingContainer.self,
context
)
}
func singleValueContainer() throws -> any SingleValueDecodingContainer {
SingleValueContainer(decoder: self, codingPath: codingPath)
}
}

View File

@@ -0,0 +1,121 @@
import Foundation
import DataLiteCore
private import DLCCommon
final class UnkeyedContainer<Decoder: RowDecoder>: Container, UnkeyedDecodingContainer {
// MARK: - Properties
let decoder: Decoder
let codingPath: [any CodingKey]
var count: Int? {
decoder.count
}
var isAtEnd: Bool {
currentIndex >= count ?? 0
}
private(set) var currentIndex: Int = 0
private var currentKey: CodingKey {
RowCodingKey(intValue: currentIndex)
}
// MARK: - Inits
init(
decoder: Decoder,
codingPath: [any CodingKey]
) {
self.decoder = decoder
self.codingPath = codingPath
}
// MARK: - Container Methods
func decodeNil() throws -> Bool {
try checkIsAtEnd(Optional<Any>.self)
if try decoder.decodeNil(for: currentKey) {
currentIndex += 1
return true
} else {
return false
}
}
func decode<T: Decodable>(_ type: T.Type) throws -> T {
try checkIsAtEnd(type)
defer { currentIndex += 1 }
switch type {
case is Date.Type:
return try decoder.decodeDate(for: currentKey) as! T
case let type as SQLiteRawRepresentable.Type:
return try decoder.decode(type, for: currentKey) as! T
default:
return try T(from: decoder.decoder(for: currentKey))
}
}
func nestedContainer<NestedKey: CodingKey>(
keyedBy type: NestedKey.Type
) throws -> KeyedDecodingContainer<NestedKey> {
let info = """
Attempted to decode a nested keyed container,
but the value cannot be represented as a keyed container.
"""
let context = DecodingError.Context(
codingPath: codingPath + [currentKey],
debugDescription: info
)
throw DecodingError.typeMismatch(
KeyedDecodingContainer<NestedKey>.self,
context
)
}
func nestedUnkeyedContainer() throws -> any UnkeyedDecodingContainer {
let info = """
Attempted to decode a nested unkeyed container,
but the value cannot be represented as an unkeyed container.
"""
let context = DecodingError.Context(
codingPath: codingPath + [currentKey],
debugDescription: info
)
throw DecodingError.typeMismatch(
UnkeyedDecodingContainer.self,
context
)
}
func superDecoder() throws -> any Swift.Decoder {
let info = """
Attempted to get a superDecoder,
but SQLiteRowDecoder does not support superDecoding.
"""
let context = DecodingError.Context(
codingPath: codingPath + [currentKey],
debugDescription: info
)
throw DecodingError.typeMismatch(Swift.Decoder.self, context)
}
}
// MARK: - Private Methods
private extension UnkeyedContainer {
@inline(__always)
func checkIsAtEnd<T>(_ type: T.Type) throws {
guard !isAtEnd else {
let info = "Unkeyed container is at end."
let context = DecodingError.Context(
codingPath: codingPath + [currentKey],
debugDescription: info
)
throw DecodingError.valueNotFound(type, context)
}
}
}