diff --git a/Package@swift-5.10.swift b/Package@swift-5.10.swift index 4cc868d..235a6ce 100644 --- a/Package@swift-5.10.swift +++ b/Package@swift-5.10.swift @@ -2,6 +2,12 @@ import PackageDescription +#if swift(>=5.10) +let settings = [ SwiftSetting.enableExperimentalFeature("StrictConcurrency") ] +#else +let settings = [ SwiftSetting ]() +#endif + var package = Package( name: "Lighter", @@ -28,7 +34,7 @@ var package = Package( // generated models and such. // Note that Lighter isn't that useful w/o code generation (i.e. as a // standalone lib). - .target(name: "Lighter"), + .target(name: "Lighter", swiftSettings: settings), // MARK: - Plugin Support @@ -37,14 +43,15 @@ var package = Package( // Swift source code. .target(name : "LighterCodeGenAST", path : "Plugins/Libraries/LighterCodeGenAST", - exclude : [ "README.md" ]), + exclude : [ "README.md" ], swiftSettings: settings), // This library contains all the code generation, to be used by different // clients. .target(name : "LighterGeneration", dependencies : [ "LighterCodeGenAST", "SQLite3Schema" ], path : "Plugins/Libraries/LighterGeneration", - exclude : [ "README.md", "LighterConfiguration/README.md" ]), + exclude : [ "README.md", "LighterConfiguration/README.md" ], + swiftSettings: settings), // MARK: - Tests diff --git a/Plugins/Libraries/LighterCodeGenAST/Generation/CodeGenerator.swift b/Plugins/Libraries/LighterCodeGenAST/Generation/CodeGenerator.swift index e4b4432..e9359cc 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Generation/CodeGenerator.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Generation/CodeGenerator.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // // Yes, this isn't particularily nice, but does the job. Keep in mind that @@ -14,10 +14,10 @@ public final class CodeGenerator { /// The configuration of the CodeGenerator. - public struct Configuration: Equatable { + public struct Configuration: Equatable, Sendable { /// How comments should be rendered. - public enum CommentStyle: String { + public enum CommentStyle: String, Sendable { case dashes = "//", tripleDashes = "///" case stars = "*", doubleStars = "**" case noComments = "" diff --git a/Plugins/Libraries/LighterCodeGenAST/Generation/GenStructures.swift b/Plugins/Libraries/LighterCodeGenAST/Generation/GenStructures.swift index 7286df7..f854090 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Generation/GenStructures.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Generation/GenStructures.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // public extension CodeGenerator { @@ -12,31 +12,69 @@ public extension CodeGenerator { omitPublic : Bool = false) { assert(value.type != nil || value.value != nil) + + func writeBody() { + if value.public && !omitPublic { append("public ") } + if `static` { append("static ") } + append(value.let ? "let " : "var ") + append(tickedWhenReserved(value.name)) + if let type = value.type { + append(configuration.propertyTypeSeparator) // " : " + append(string(for: type)) + } + if let value = value.value { + append(configuration.propertyValueSeparator) // " = " + append(string(for: value)) + } + appendEOL() + } + + func writePlain() { + if let ( major, minor ) = value.minimumSwiftVersion { + assert(major >= 5) + writeln("#if swift(>=\(major).\(minor))") + } + + writePropertyComment(value.comment) + appendIndent() + writeBody() - if let ( major, minor ) = value.minimumSwiftVersion { - assert(major >= 5) - writeln("#if swift(>=\(major).\(minor))") + if let ( major, minor ) = value.minimumSwiftVersion { + assert(major >= 5) + writeln("#endif // swift(>=\(major).\(minor))") + } } - writePropertyComment(value.comment) - appendIndent() - if value.public && !omitPublic { append("public ") } - if `static` { append("static ") } - append(value.let ? "let " : "var ") - append(tickedWhenReserved(value.name)) - if let type = value.type { - append(configuration.propertyTypeSeparator) // " : " - append(string(for: type)) - } - if let value = value.value { - append(configuration.propertyValueSeparator) // " = " - append(string(for: value)) - } - appendEOL() + if value.nonIsolatedUnsafe { + if let ( major, minor ) = value.minimumSwiftVersion, + (major > 5) || (major >= 5 && minor >= 10) + { + writePlain() + } + else { + writeln("#if swift(>=5.10)") - if let ( major, minor ) = value.minimumSwiftVersion { - assert(major >= 5) - writeln("#endif // swift(>=\(major).\(minor))") + writePropertyComment(value.comment) + appendIndent() + append("nonisolated(unsafe) ") + writeBody() + + if let ( major, minor ) = value.minimumSwiftVersion { + assert(major >= 5) + writeln("#elseif swift(>=\(major).\(minor))") + } + else { + writeln("#else") + } + + writePropertyComment(value.comment) + appendIndent() + writeBody() + writeln("#endif") + } + } + else { + writePlain() } } diff --git a/Plugins/Libraries/LighterCodeGenAST/Nodes/Expression.swift b/Plugins/Libraries/LighterCodeGenAST/Nodes/Expression.swift index ed8ee1f..d40cc24 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Nodes/Expression.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Nodes/Expression.swift @@ -1,15 +1,15 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** * An AST node for various Swift expressions. */ -public indirect enum Expression: Equatable { +public indirect enum Expression: Equatable, Sendable { /// The operators for ``compare(lhs:operator:rhs:)`` expressions. - public enum Operator: String { + public enum Operator: String, Sendable { case equal = "==" case notEqual = "!=" case greaterThanOrEqual = ">=" @@ -82,12 +82,12 @@ public indirect enum Expression: Equatable { * * Used as the value for ``Expression/functionCall(_:)``. */ -public struct FunctionCall: Equatable { +public struct FunctionCall: Equatable, Sendable { /** * A parameter passed as part of the function call. */ - public struct Parameter: Equatable { + public struct Parameter: Equatable, Sendable { /// The keyword/label of the parameter, can be `nil` if it is a wildcard /// (unlabled) parameter. @@ -105,7 +105,7 @@ public struct FunctionCall: Equatable { /** * A trailing closure attached to a function call. */ - public struct TrailingClosure: Equatable { + public struct TrailingClosure: Equatable, Sendable { /// The parameter list of the trailing closure (e.g. `( a, b ) in`). public let parameters: [ String ] diff --git a/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionComment.swift b/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionComment.swift index 0c56296..2e1a151 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionComment.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionComment.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** @@ -8,10 +8,10 @@ * * Has all the function specific things, like parameters and such. */ -public struct FunctionComment: Equatable { +public struct FunctionComment: Equatable, Sendable { /// A comment for a function parameter. - public struct Parameter: Equatable { + public struct Parameter: Equatable, Sendable { /// The name of the function parameter being documented. public var name : String diff --git a/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionDeclaration.swift b/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionDeclaration.swift index 3bdbaac..1d8ffbb 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionDeclaration.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionDeclaration.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** @@ -19,7 +19,7 @@ * where C1: SQLColumn, C2: SQLColumn, T == C1.T, T == C2.T * ``` */ -public struct FunctionDeclaration: Equatable { +public struct FunctionDeclaration: Equatable, Sendable { /// Is the function public? public let `public` : Bool diff --git a/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionDefinition.swift b/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionDefinition.swift index 053e737..48287db 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionDefinition.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionDefinition.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** @@ -9,7 +9,7 @@ * * Plus extra annotations like ``inlinable`` and the ``comment``. */ -public struct FunctionDefinition: Equatable { +public struct FunctionDefinition: Equatable, Sendable { /// Whether the definition is `@inlinable` (included in the module header). public var inlinable : Bool diff --git a/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionParameter.swift b/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionParameter.swift index c7e4426..812e859 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionParameter.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Nodes/FunctionParameter.swift @@ -1,13 +1,13 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // public extension FunctionDeclaration { /// A parameter, like `from table: KeyPath` /// Or: `limit: Int? = nil` - struct Parameter: Equatable { + struct Parameter: Equatable, Sendable { /// The "label" of the parameter, e.g. the `from` in `select(from table:)`. /// Can be `nil` for a wildcard (`_`). diff --git a/Plugins/Libraries/LighterCodeGenAST/Nodes/GenericConstraint.swift b/Plugins/Libraries/LighterCodeGenAST/Nodes/GenericConstraint.swift index 6d083cf..fae3379 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Nodes/GenericConstraint.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Nodes/GenericConstraint.swift @@ -1,13 +1,13 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** * A generic constraint attached to a ``FunctionDeclaration`` generic parameter * or an ``Extension``. */ -public enum GenericConstraint: Equatable { +public enum GenericConstraint: Equatable, Sendable { /// `C1: SQLColumn` case conformance(name: String, type: TypeReference) diff --git a/Plugins/Libraries/LighterCodeGenAST/Nodes/Literal.swift b/Plugins/Libraries/LighterCodeGenAST/Nodes/Literal.swift index 22a8929..00acf7b 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Nodes/Literal.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Nodes/Literal.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** @@ -8,7 +8,7 @@ * * E.g. as used in default values like: `limit: Int? = nil` (the `nil`). */ -public enum Literal: Equatable { +public enum Literal: Equatable, Sendable { /// `nil` case `nil` diff --git a/Plugins/Libraries/LighterCodeGenAST/Nodes/Statement.swift b/Plugins/Libraries/LighterCodeGenAST/Nodes/Statement.swift index a3900c3..be40e9b 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Nodes/Statement.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Nodes/Statement.swift @@ -1,18 +1,18 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** * An AST node for a Swift statement. */ -public enum Statement: Equatable { +public enum Statement: Equatable, Sendable { /** * A pair for an `if`, `else if` statement, consisting of a condition and the * associated ``Statement``s. */ - public struct ConditionStatementPair: Equatable { + public struct ConditionStatementPair: Equatable, Sendable { /// The condition that must be true to have the ``statements`` executed. public var condition : Expression diff --git a/Plugins/Libraries/LighterCodeGenAST/Nodes/Struct.swift b/Plugins/Libraries/LighterCodeGenAST/Nodes/Struct.swift index f6841f7..b07462a 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Nodes/Struct.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Nodes/Struct.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** @@ -11,8 +11,10 @@ public struct Struct { /** * An instance variable of a ``Struct``. */ - public struct InstanceVariable { + public struct InstanceVariable: Sendable { + /// Whether the definition is `nonisolated(unsafe)`, requires Swift 5.10+ + public var nonIsolatedUnsafe : Bool /// Is the property public? public var `public` : Bool /// Is the property readonly. @@ -31,7 +33,9 @@ public struct Struct { public var minimumSwiftVersion : ( major: Int, minor: Int )? /// Initialize a new instance variable node. - public init(public: Bool = true, `let`: Bool = true, _ name: String, + public init(nonIsolatedUnsafe: Bool = false, + public: Bool = true, `let`: Bool = true, + _ name: String, type: TypeReference? = nil, value: Expression? = nil, minimumSwiftVersion : ( major: Int, minor: Int )? = nil, comment: String? = nil) @@ -43,6 +47,7 @@ public struct Struct { self.value = value self.minimumSwiftVersion = minimumSwiftVersion self.comment = comment + self.nonIsolatedUnsafe = nonIsolatedUnsafe } } @@ -159,11 +164,13 @@ public extension Struct.InstanceVariable { } /// Initialize a new instance variable node for a `var`. - static func `var`(public: Bool = true, _ name: String, _ type: TypeReference, + static func `var`(nonIsolatedUnsafe: Bool = false, + public: Bool = true, _ name: String, _ type: TypeReference, comment: String? = nil) -> Self { - .init(public: `public`, let: false, name, type: type, value: nil, + .init(nonIsolatedUnsafe: nonIsolatedUnsafe, public: `public`, + let: false, name, type: type, value: nil, comment: comment) } } diff --git a/Plugins/Libraries/LighterCodeGenAST/Nodes/TypeReference.swift b/Plugins/Libraries/LighterCodeGenAST/Nodes/TypeReference.swift index 7f1932a..994a4b1 100644 --- a/Plugins/Libraries/LighterCodeGenAST/Nodes/TypeReference.swift +++ b/Plugins/Libraries/LighterCodeGenAST/Nodes/TypeReference.swift @@ -1,12 +1,12 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** * A reference to some type, e.g. `Void` or `Person` or `Int`. */ -public indirect enum TypeReference: Equatable { +public indirect enum TypeReference: Equatable, Sendable { /// `Void` case void diff --git a/Plugins/Libraries/LighterGeneration/GenModel/Fancyfier.swift b/Plugins/Libraries/LighterGeneration/GenModel/Fancyfier.swift index c290287..ac54744 100644 --- a/Plugins/Libraries/LighterGeneration/GenModel/Fancyfier.swift +++ b/Plugins/Libraries/LighterGeneration/GenModel/Fancyfier.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import SQLite3Schema @@ -36,7 +36,7 @@ import struct Foundation.CharacterSet */ public final class Fancifier { - public struct Options: Equatable { + public struct Options: Equatable, Sendable { // Detect Keys diff --git a/Plugins/Libraries/LighterGeneration/GenModel/Property.swift b/Plugins/Libraries/LighterGeneration/GenModel/Property.swift index 70878af..4376724 100644 --- a/Plugins/Libraries/LighterGeneration/GenModel/Property.swift +++ b/Plugins/Libraries/LighterGeneration/GenModel/Property.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import SQLite3Schema @@ -10,12 +10,12 @@ public extension EntityInfo { /** * A property represents a column in a SQL table or view. */ - struct Property: Equatable { + struct Property: Equatable, Sendable { /** * The Swift type of the property. */ - public enum PropertyType: Equatable { // `SQLiteValueType` + public enum PropertyType: Equatable, Sendable { // `SQLiteValueType` case integer case double case string diff --git a/Plugins/Libraries/LighterGeneration/LighterAPI.swift b/Plugins/Libraries/LighterGeneration/LighterAPI.swift index 1ba9f13..2e325bb 100644 --- a/Plugins/Libraries/LighterGeneration/LighterAPI.swift +++ b/Plugins/Libraries/LighterGeneration/LighterAPI.swift @@ -1,13 +1,13 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import Foundation /// The settings specific to the API usage of the Lighter lib /// (embedded or not). -public struct LighterAPI: Equatable { +public struct LighterAPI: Equatable, Sendable { /// `SQLRecord` public var recordType = "SQLRecord" diff --git a/Plugins/Libraries/LighterGeneration/LighterConfiguration/EmbeddedLighter.swift b/Plugins/Libraries/LighterGeneration/LighterConfiguration/EmbeddedLighter.swift index bf4c0c2..5ecb6ce 100644 --- a/Plugins/Libraries/LighterGeneration/LighterConfiguration/EmbeddedLighter.swift +++ b/Plugins/Libraries/LighterGeneration/LighterConfiguration/EmbeddedLighter.swift @@ -1,15 +1,15 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // public extension LighterConfiguration { - struct EmbeddedLighter: Equatable { + struct EmbeddedLighter: Equatable, Sendable { - public struct Selects: Equatable { + public struct Selects: Equatable, Sendable { - public struct Config: Equatable { + public struct Config: Equatable, Sendable { public var columns : Int public var sorts : Int @@ -39,7 +39,7 @@ public extension LighterConfiguration { } } - public struct Updates: Equatable { + public struct Updates: Equatable, Sendable { public var keyBased : Int public var predicateBased : Int diff --git a/Plugins/Libraries/LighterGeneration/LighterConfiguration/LighterConfiguration.swift b/Plugins/Libraries/LighterGeneration/LighterConfiguration/LighterConfiguration.swift index 1eda130..0d37887 100644 --- a/Plugins/Libraries/LighterGeneration/LighterConfiguration/LighterConfiguration.swift +++ b/Plugins/Libraries/LighterGeneration/LighterConfiguration/LighterConfiguration.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import LighterCodeGenAST @@ -30,7 +30,7 @@ import LighterCodeGenAST * } * ``` */ -public struct LighterConfiguration: Equatable { +public struct LighterConfiguration: Equatable, Sendable { public static let filename = "Lighter.json" diff --git a/Plugins/Libraries/LighterGeneration/RecordGeneration/EnlighterASTGenerator.swift b/Plugins/Libraries/LighterGeneration/RecordGeneration/EnlighterASTGenerator.swift index a93e69e..8dc5fba 100644 --- a/Plugins/Libraries/LighterGeneration/RecordGeneration/EnlighterASTGenerator.swift +++ b/Plugins/Libraries/LighterGeneration/RecordGeneration/EnlighterASTGenerator.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import LighterCodeGenAST @@ -19,17 +19,17 @@ public final class EnlighterASTGenerator { /// The name of the Swift file that is being generated. public let filename : String - public struct Options: Equatable { + public struct Options: Equatable, Sendable { /// How to bind Date values into the database. - public enum DateStorageStyle: String { + public enum DateStorageStyle: String, Sendable { /// Save as a REAL containing the unix timestamp case timeIntervalSince1970 = "utime" /// Save as text, using a formatter. case formatter } /// How to store UUID columns, as strings or blobs - public enum UUIDStorageStyle: String { + public enum UUIDStorageStyle: String, Sendable { /// Store UUIDs as string, e.g. `81E42B93-3DA3-47BB-8D82-9BDE9E60242F` case text /// Store UUIDs as compact 16-byte BLOBs (efficient) @@ -37,14 +37,14 @@ public final class EnlighterASTGenerator { } /// How the generated code should import Lighter (if enabled) - public enum LighterImport: String { + public enum LighterImport: String, Sendable { case none case `import` case reexport } /// Whether or how to generate low-level SQLite functions. - public enum RawFunctionStyle: Hashable { + public enum RawFunctionStyle: Hashable, Sendable { /// Do not generate low level `sqlite3_record_fetch` style functions. case omit /// Attach the low-level functions to the Record type itself, @@ -55,7 +55,7 @@ public final class EnlighterASTGenerator { case globalFunctions(prefix: String) // default prefix: `sqlite3_` } - public enum RawOperationNames: Equatable { + public enum RawOperationNames: Equatable, Sendable { case lowercaseAndPluralize } @@ -134,8 +134,8 @@ public final class EnlighterASTGenerator { public var markRawStructsAsHashable = true /// Additional protocol conformances that should be attached to the - /// record structures. Defaults to `Codable`. - public var extraRecordConformances = [ "Codable" ] + /// record structures. Defaults to `Codable` and `Sendable`. + public var extraRecordConformances = [ "Codable", "Sendable" ] /// Whether Swift filter matcher should be generated. /// (i.e. the ability to use a Swift closure instead of a SQL where). diff --git a/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateDatabaseStruct.swift b/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateDatabaseStruct.swift index b6c769b..7d70c76 100644 --- a/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateDatabaseStruct.swift +++ b/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateDatabaseStruct.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import LighterCodeGenAST @@ -68,7 +68,7 @@ extension EnlighterASTGenerator { // Schema version - typeVariables.append(.var( + typeVariables.append(.let( public: options.public, "userVersion", is: .integer(database.userVersion), comment: "User version of the database (`PRAGMA user_version`)." @@ -84,7 +84,7 @@ extension EnlighterASTGenerator { // Whether SQLite3 supports returning (the user can override!) - typeVariables.append(.var( + typeVariables.append(.let( public: options.public, "useInsertReturning", is: .cmp( .call(name: "sqlite3_libversion_number"), @@ -104,7 +104,8 @@ extension EnlighterASTGenerator { let comment = "The `DateFormatter` used for parsing string date values." if options.useLighter { typeVariables.append( - .var(public: false, "_\(name)", type, comment: comment) + .var(nonIsolatedUnsafe: true, + public: false, "_\(name)", type, comment: comment) ) computedTypeProperties.append( .var(public: options.public, inlinable: false, @@ -557,7 +558,9 @@ extension EnlighterASTGenerator { { let firstEntity = database.entities.first ?? .init(name: "NoTypes") return Struct( - public: options.public, name: api.recordTypeLookupTarget, + public: options.public, + name: api.recordTypeLookupTarget, + conformances: [ .name("Swift.Sendable") ], variables: database.entities.map { let name = "\($0.name)\(suffix ?? "")" return .let( @@ -600,7 +603,7 @@ extension EnlighterASTGenerator { } } - fileprivate static let defaultSQLiteDateFormatterExpression = + fileprivate static var defaultSQLiteDateFormatterExpression : Expression { Expression.inlineClosureCall([ .let("formatter", is: .call(name: "DateFormatter")), .set(instance: "formatter", "dateFormat", @@ -610,4 +613,5 @@ extension EnlighterASTGenerator { [ ("identifier", .string("en_US_POSIX"))])), .return(.variable("formatter")) ]) + } } diff --git a/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateRawFunctions.swift b/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateRawFunctions.swift index 0a6964d..7723f0b 100644 --- a/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateRawFunctions.swift +++ b/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateRawFunctions.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import LighterCodeGenAST @@ -148,7 +148,7 @@ extension EnlighterASTGenerator { // MARK: - Helpers - fileprivate static let stepAndReturnError : [ Statement ] = [ + fileprivate static var stepAndReturnError : [ Statement ] { [ .let("rc", is: .call(name: "sqlite3_step", .variable("statement"))), .return( .conditional( @@ -157,22 +157,22 @@ extension EnlighterASTGenerator { .variable("SQLITE_OK") ) ) - ] + ] } private func prepareSQL(_ schemaSQLProperty: String, for entity: EntityInfo) - -> [ Statement ] + -> [ Statement ] { [ .let("sql", is: .variablePath([ entity.name, api.recordSchemaName, schemaSQLProperty])) ] + Self.prepareSQL } - static let prepareSQL : [ Statement ] = [ + static var prepareSQL : [ Statement ] { [ // Could use `Self` for record attached funcs .var("handle", type: .name("OpaquePointer?")), .raw("guard sqlite3_prepare_v2(db, sql, -1, &handle, nil) == SQLITE_OK,"), .raw(" let statement = handle else { return sqlite3_errcode(db) }"), .raw("defer { sqlite3_finalize(statement) }") - ] + ] } func functionName(for entity: EntityInfo, operation: String) -> String { switch options.rawFunctions { diff --git a/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateRecordStructure.swift b/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateRecordStructure.swift index 9d2cff4..7772793 100644 --- a/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateRecordStructure.swift +++ b/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateRecordStructure.swift @@ -189,7 +189,7 @@ extension EnlighterASTGenerator { let pkeys = entity.primaryKeyProperties return Struct( public: options.public, name: "ID", - conformances: [ .name("Hashable") ], + conformances: [ .name("Swift.Hashable") ], variables: pkeys.map { property in .let(public: options.public, property.name, type(for: property), comment: nil) diff --git a/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateSchemaStructure.swift b/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateSchemaStructure.swift index 859438f..8f8d681 100644 --- a/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateSchemaStructure.swift +++ b/Plugins/Libraries/LighterGeneration/RecordGeneration/GenerateSchemaStructure.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import LighterCodeGenAST @@ -288,6 +288,12 @@ extension EnlighterASTGenerator { }, computedProperties: computedProps, typeFunctions: typeFunctions, + functions: [ + .init( + declaration: .makeInit(public: options.public), + statements: [] + ) + ], comment: .init( headline: "Static type information for the ``\(entity.name)`` record (`\(entity.externalName)` SQL table).", diff --git a/Plugins/Libraries/LighterGeneration/VariadicGeneration/GenerateSelectFunctions.swift b/Plugins/Libraries/LighterGeneration/VariadicGeneration/GenerateSelectFunctions.swift index 162421d..079f660 100644 --- a/Plugins/Libraries/LighterGeneration/VariadicGeneration/GenerateSelectFunctions.swift +++ b/Plugins/Libraries/LighterGeneration/VariadicGeneration/GenerateSelectFunctions.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import LighterCodeGenAST @@ -358,7 +358,9 @@ public final class SelectFunctionGeneration: FunctionGenerator { if columnParameterNames.count > 1 { return .array(.tuple( names: columnParameterNames, - types: Cs.map { .qualifiedType(baseName: $0, name: api.columnValuePAT) } + types: Cs.map { + .qualifiedType(baseName: $0, name: api.columnValuePAT) + } )) } else { @@ -489,7 +491,7 @@ public final class SelectFunctionGeneration: FunctionGenerator { .call(try: true, name: "fetch", parameters: [ ( nil, .variable("sql") ), - ( nil, .variable(builderVariableName, "bindings" ) ) + ( nil, .variable("bindings" ) ) ], trailing: ( parameters: [ "stmt", "_" ], statements: [ .call(instance: "records", name: "append", parameters: [ ( nil, // could generate the labels @@ -501,6 +503,8 @@ public final class SelectFunctionGeneration: FunctionGenerator { .return(.variable("records")) ] + statements.append(.let("bindings", + is: .variable(builderVariableName, "bindings"))) if asyncFunctions { // try await runOnDatabaseQueue { try fetch(from, limit: limit) } statements.append( diff --git a/Sources/Lighter/ConnectionHandlers/SQLConnectionHandler.swift b/Sources/Lighter/ConnectionHandlers/SQLConnectionHandler.swift index 06624e0..ed39733 100644 --- a/Sources/Lighter/ConnectionHandlers/SQLConnectionHandler.swift +++ b/Sources/Lighter/ConnectionHandlers/SQLConnectionHandler.swift @@ -12,7 +12,7 @@ import SQLite3 * * This can be subclassed by users to implement custom pooling strategies. */ -open class SQLConnectionHandler { +open class SQLConnectionHandler: @unchecked Sendable { /** * Returns a connection handler that will open a new database handle on diff --git a/Sources/Lighter/ConnectionHandlers/SimplePool.swift b/Sources/Lighter/ConnectionHandlers/SimplePool.swift index defdd64..1251c42 100644 --- a/Sources/Lighter/ConnectionHandlers/SimplePool.swift +++ b/Sources/Lighter/ConnectionHandlers/SimplePool.swift @@ -185,7 +185,7 @@ extension SQLConnectionHandler { } } -fileprivate final class AppLifecycleHandler: NSObject { +fileprivate final class AppLifecycleHandler: NSObject, @unchecked Sendable { private weak var owner : SQLConnectionHandler.SimplePool? @@ -224,7 +224,8 @@ fileprivate final class AppLifecycleHandler: NSObject { private static let isAppExtension = Bundle.main.bundleURL.pathExtension == "appex" - private static let fgName : NSNotification.Name = { + @MainActor + private static var fgName : NSNotification.Name = { if !isAppExtension { return UIApplication.willEnterForegroundNotification } @@ -234,7 +235,8 @@ fileprivate final class AppLifecycleHandler: NSObject { return NSExtensionHostWillEnterForegroundNotification #endif }() - private static let bgName : NSNotification.Name = { + @MainActor + private static var bgName : NSNotification.Name = { if !isAppExtension { return UIApplication.didEnterBackgroundNotification } diff --git a/Sources/Lighter/Expression/SQLBuilder.swift b/Sources/Lighter/Expression/SQLBuilder.swift index ca9fe24..b13ab62 100644 --- a/Sources/Lighter/Expression/SQLBuilder.swift +++ b/Sources/Lighter/Expression/SQLBuilder.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022-2023 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // #if canImport(Foundation) @@ -10,7 +10,7 @@ /** * A helper struct to build SQL queries. */ -public struct SQLBuilder { +public struct SQLBuilder: Sendable { // Called `SQLExpression` in ZeeQL/EOF @usableFromInline var sql = "" diff --git a/Sources/Lighter/Expression/SQLInterpolation.swift b/Sources/Lighter/Expression/SQLInterpolation.swift index 026a6f2..c8f3fb4 100644 --- a/Sources/Lighter/Expression/SQLInterpolation.swift +++ b/Sources/Lighter/Expression/SQLInterpolation.swift @@ -1,12 +1,12 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // -public struct SQLInterpolation: StringInterpolationProtocol { +public struct SQLInterpolation: StringInterpolationProtocol, Sendable { @usableFromInline - enum Fragment { + enum Fragment: Sendable { // Would be nice to support columns, but those would make the fragment // generic and non-hashable? case raw (String) diff --git a/Sources/Lighter/Operations/GeneratedVariadicOperations.swift b/Sources/Lighter/Operations/GeneratedVariadicOperations.swift index 9e8afda..28203c9 100644 --- a/Sources/Lighter/Operations/GeneratedVariadicOperations.swift +++ b/Sources/Lighter/Operations/GeneratedVariadicOperations.swift @@ -1,4 +1,4 @@ -// Autocreated by GenerateInternalVariadics at 2022-08-17T15:57:10Z +// Autocreated by GenerateInternalVariadics at 2024-04-07T13:46:27Z public extension SQLDatabaseFetchOperations { @@ -31,8 +31,9 @@ public extension SQLDatabaseFetchOperations { var builder = SQLBuilder() builder.addColumn(column) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -70,8 +71,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column1) builder.addColumn(column2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -121,8 +123,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column2) builder.addColumn(column3) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -177,8 +180,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column3) builder.addColumn(column4) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -238,8 +242,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column4) builder.addColumn(column5) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -297,8 +302,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column5) builder.addColumn(column6) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -341,8 +347,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -393,8 +400,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column2) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -452,8 +460,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column3) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -516,8 +525,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column4) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -585,8 +595,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column5) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -651,8 +662,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column6) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -707,8 +719,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -766,8 +779,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -832,8 +846,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -903,8 +918,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -979,8 +995,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -1052,8 +1069,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -1088,8 +1106,9 @@ public extension SQLDatabaseFetchOperations { var builder = SQLBuilder() builder.addColumn(column) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -1125,8 +1144,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column1) builder.addColumn(column2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -1167,8 +1187,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column2) builder.addColumn(column3) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -1220,8 +1241,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column3) builder.addColumn(column4) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -1278,8 +1300,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column4) builder.addColumn(column5) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -1334,8 +1357,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column5) builder.addColumn(column6) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -1376,8 +1400,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -1419,8 +1444,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column2) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -1475,8 +1501,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column3) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -1536,8 +1563,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column4) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -1602,8 +1630,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column5) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -1665,8 +1694,9 @@ public extension SQLDatabaseFetchOperations { builder.addColumn(column6) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -1712,8 +1742,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -1768,8 +1799,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -1831,8 +1863,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -1899,8 +1932,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -1972,8 +2006,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -2042,8 +2077,9 @@ public extension SQLDatabaseFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -2086,9 +2122,10 @@ public extension SQLDatabaseAsyncFetchOperations { var builder = SQLBuilder() builder.addColumn(column) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -2127,9 +2164,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column1) builder.addColumn(column2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -2180,9 +2218,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column2) builder.addColumn(column3) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -2238,9 +2277,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column3) builder.addColumn(column4) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -2301,9 +2341,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column4) builder.addColumn(column5) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -2362,9 +2403,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column5) builder.addColumn(column6) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -2408,9 +2450,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -2462,9 +2505,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column2) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -2523,9 +2567,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column3) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -2589,9 +2634,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column4) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -2660,9 +2706,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column5) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -2728,9 +2775,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column6) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -2786,9 +2834,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -2847,9 +2896,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -2915,9 +2965,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -2988,9 +3039,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -3066,9 +3118,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -3141,9 +3194,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: predicate(T.schema)) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -3179,9 +3233,10 @@ public extension SQLDatabaseAsyncFetchOperations { var builder = SQLBuilder() builder.addColumn(column) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -3218,9 +3273,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column1) builder.addColumn(column2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -3262,9 +3318,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column2) builder.addColumn(column3) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -3317,9 +3374,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column3) builder.addColumn(column4) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -3377,9 +3435,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column4) builder.addColumn(column5) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -3435,9 +3494,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column5) builder.addColumn(column6) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -3479,9 +3539,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -3524,9 +3585,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column2) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -3582,9 +3644,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column3) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -3645,9 +3708,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column4) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -3713,9 +3777,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column5) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -3778,9 +3843,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addColumn(column6) builder.addSort(sortColumn, direction) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) @@ -3827,9 +3893,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ C.Value ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append(try C.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0)) } return records @@ -3885,9 +3952,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1) ) ) @@ -3950,9 +4018,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2) ) ) @@ -4020,9 +4089,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3) ) ) @@ -4095,9 +4165,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4) ) ) @@ -4167,9 +4238,10 @@ public extension SQLDatabaseAsyncFetchOperations { builder.addSort(sortColumn1, direction1) builder.addSort(sortColumn2, direction2) let sql = builder.generateSelect(limit: limit, predicate: SQLTruePredicate.shared) + let bindings = builder.bindings return try await runOnDatabaseQueue() { var records = [ ( column1: C1.Value, column2: C2.Value, column3: C3.Value, column4: C4.Value, column5: C5.Value, column6: C6.Value ) ]() - try fetch(sql, builder.bindings) { ( stmt, _ ) in + try fetch(sql, bindings) { ( stmt, _ ) in records.append( ( try C1.Value.init(unsafeSQLite3StatementHandle: stmt, column: 0), try C2.Value.init(unsafeSQLite3StatementHandle: stmt, column: 1), try C3.Value.init(unsafeSQLite3StatementHandle: stmt, column: 2), try C4.Value.init(unsafeSQLite3StatementHandle: stmt, column: 3), try C5.Value.init(unsafeSQLite3StatementHandle: stmt, column: 4), try C6.Value.init(unsafeSQLite3StatementHandle: stmt, column: 5) ) ) diff --git a/Sources/Lighter/Operations/SQLDatabaseAsyncChangeOperations.swift b/Sources/Lighter/Operations/SQLDatabaseAsyncChangeOperations.swift index 6843f07..7afd764 100644 --- a/Sources/Lighter/Operations/SQLDatabaseAsyncChangeOperations.swift +++ b/Sources/Lighter/Operations/SQLDatabaseAsyncChangeOperations.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // // Same like `SQLDatabaseChangeOperations`, async/await variant if available. @@ -41,7 +41,9 @@ public extension SQLDatabaseAsyncChangeOperations { async throws where T: SQLDeletableRecord, T.Schema: SQLKeyedTableSchema { - try await runOnDatabaseQueue { try delete(from: table, id: id) } + try await runOnDatabaseQueue { + try delete(from: T.self) { _ in T.Schema.primaryKeyColumn == id } + } } /** @@ -65,8 +67,9 @@ public extension SQLDatabaseAsyncChangeOperations { async throws where C: SQLColumn, T == C.T, T: SQLDeletableRecord { + let ref = T.schema[keyPath: column] try await runOnDatabaseQueue { - try delete(from: table, where: column, is: value) + try delete(from: T.self) { _ in ref == value } } } @@ -87,12 +90,18 @@ public extension SQLDatabaseAsyncChangeOperations { * - predicate: The qualifier selecting the records to delete. */ @inlinable - func delete(from table : KeyPath, - where p : @escaping ( T.Schema ) -> P) + func delete(from table : KeyPath, + where predicate : @escaping ( T.Schema ) -> P) async throws where T: SQLDeletableRecord, P: SQLPredicate { - try await runOnDatabaseQueue { try delete(from: table, where: p) } + var builder = SQLBuilder() + builder.generateDelete(from: T.Schema.externalName, + where: predicate(T.schema)) + let cb = builder + try await runOnDatabaseQueue { + try execute(cb.sql, cb.bindings, readOnly: false) + } } } @@ -192,7 +201,7 @@ public extension SQLDatabaseAsyncChangeOperations { */ @inlinable func delete(_ records: S) async throws - where S: Sequence, + where S: Sequence & Sendable, S.Element: SQLDeletableRecord, S.Element.Schema: SQLKeyedTableSchema { @@ -216,7 +225,7 @@ public extension SQLDatabaseAsyncChangeOperations { */ @inlinable func update(_ records: S) async throws - where S: Sequence, + where S: Sequence & Sendable, S.Element: SQLUpdatableRecord, S.Element.Schema: SQLKeyedTableSchema { @@ -248,7 +257,7 @@ public extension SQLDatabaseAsyncChangeOperations { @inlinable @discardableResult func insert(_ records: S) async throws -> [ S.Element ] - where S: Sequence, S.Element: SQLInsertableRecord + where S: Sequence & Sendable, S.Element: SQLInsertableRecord { try await runOnDatabaseQueue { try insert(records) } } diff --git a/Sources/Lighter/Operations/SQLDatabaseAsyncOperations.swift b/Sources/Lighter/Operations/SQLDatabaseAsyncOperations.swift index a5bba00..652e954 100644 --- a/Sources/Lighter/Operations/SQLDatabaseAsyncOperations.swift +++ b/Sources/Lighter/Operations/SQLDatabaseAsyncOperations.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import Dispatch @@ -15,7 +15,7 @@ import Dispatch * - ``SQLDatabaseFetchOperations`` * - ``SQLDatabaseAsyncChangeOperations`` */ -public protocol SQLDatabaseAsyncOperations: SQLDatabaseOperations { +public protocol SQLDatabaseAsyncOperations: SQLDatabaseOperations, Sendable { /** * The queue that is used to run concurrent async SQL operations. @@ -51,7 +51,7 @@ public extension SQLDatabaseAsyncOperations { */ @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) @inlinable - func runOnDatabaseQueue(block: @escaping () throws -> R) async throws -> R + func runOnDatabaseQueue(block: @Sendable @escaping () throws -> R) async throws -> R { return try await withCheckedThrowingContinuation { continuation in asyncDatabaseQueue.async { diff --git a/Sources/Lighter/Operations/SQLDatabaseChangeOperations.swift b/Sources/Lighter/Operations/SQLDatabaseChangeOperations.swift index d380388..4a16156 100644 --- a/Sources/Lighter/Operations/SQLDatabaseChangeOperations.swift +++ b/Sources/Lighter/Operations/SQLDatabaseChangeOperations.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import SQLite3 @@ -44,7 +44,7 @@ public extension SQLDatabaseChangeOperations { throws where T: SQLDeletableRecord, T.Schema: SQLKeyedTableSchema { - try delete(from: table) {_ in T.Schema.primaryKeyColumn == id } + try delete(from: table) { _ in T.Schema.primaryKeyColumn == id } } /** @@ -83,15 +83,38 @@ public extension SQLDatabaseChangeOperations { * - table: A KeyPath to the table to use, e.g. `\.people`. * - predicate: The qualifier selecting the records to delete. */ + @inlinable func delete(from table : KeyPath, where predicate : ( T.Schema ) -> P) throws where T: SQLDeletableRecord, P: SQLPredicate + { + try delete(from: T.self, where: predicate) + } + + /** + * Delete records from a table that match a certain predicate. + * + * Example: + * ```swift + * try db.delete(from: \.people) { + * $0.isArchived == 1 + * } + * ``` + * + * - Parameters: + * - table: A KeyPath to the table to use, e.g. `\.people`. + * - predicate: The qualifier selecting the records to delete. + */ + func delete(from table : T.Type, + where predicate : ( T.Schema ) -> P) throws + where T: SQLDeletableRecord, P: SQLPredicate { var builder = SQLBuilder() builder.generateDelete(from: T.Schema.externalName, where: predicate(T.schema)) try execute(builder.sql, builder.bindings, readOnly: false) } + } public extension SQLDatabaseChangeOperations { diff --git a/Sources/Lighter/Operations/SQLRecordAsyncFetchOperations.swift b/Sources/Lighter/Operations/SQLRecordAsyncFetchOperations.swift index 7a28060..2156ee8 100644 --- a/Sources/Lighter/Operations/SQLRecordAsyncFetchOperations.swift +++ b/Sources/Lighter/Operations/SQLRecordAsyncFetchOperations.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // // Same like `SQLRecordFetchOperations`, async/await variant if available. @@ -22,7 +22,8 @@ public extension SQLRecordFetchOperations * - Throws: Rethrows any errors the block throws. */ @inlinable - func runOnDatabaseQueue(block: @escaping () throws -> R) async throws -> R + func runOnDatabaseQueue(block: @Sendable @escaping () throws -> R) + async throws -> R { try await operations.runOnDatabaseQueue(block: block) } @@ -62,8 +63,10 @@ public extension SQLRecordFetchOperations async throws -> [ T ] where SC: SQLColumn, SC.T == T { - try await runOnDatabaseQueue { - try fetch(limit: limit, orderBy: column, direction) + let column = T.schema[keyPath: column] + return try await runOnDatabaseQueue { + try fetch(limit: limit, orderBy: column, direction, + where: { _ in SQLTruePredicate.shared }) } } @@ -89,11 +92,12 @@ public extension SQLRecordFetchOperations func fetch(limit : Int? = nil, orderBy column : KeyPath, _ direction : SQLSortOrder = .ascending, - where predicate : @escaping ( T.Schema ) -> P) + where predicate : @Sendable @escaping ( T.Schema ) -> P) async throws -> [ T ] where SC: SQLColumn, SC.T == T, P: SQLPredicate { - try await runOnDatabaseQueue { + let column = T.schema[keyPath: column] + return try await runOnDatabaseQueue { try fetch(limit: limit, orderBy: column, direction, where: predicate) } } @@ -126,12 +130,14 @@ public extension SQLRecordFetchOperations _ direction1 : SQLSortOrder, // can't be optional! _ column2 : KeyPath, _ direction2 : SQLSortOrder = .ascending, - where predicate : @escaping ( T.Schema ) -> P) + where predicate : @Sendable @escaping (T.Schema)->P) async throws -> [ T ] where SC1: SQLColumn, SC1.T == T, SC2: SQLColumn, SC2.T == T, P: SQLPredicate { - try await runOnDatabaseQueue { + let column1 = T.schema[keyPath: column1] + let column2 = T.schema[keyPath: column2] + return try await runOnDatabaseQueue { try fetch(limit: limit, orderBy: column1, direction1, column2, direction2, where: predicate) @@ -154,7 +160,7 @@ public extension SQLRecordFetchOperations */ @inlinable func fetch

(limit : Int? = nil, - where predicate : @escaping ( T.Schema ) -> P) + where predicate : @Sendable @escaping ( T.Schema ) -> P) async throws -> [ T ] where P: SQLPredicate { @@ -182,7 +188,15 @@ public extension SQLRecordFetchOperations async throws -> T? where C: SQLColumn, T == C.T { - try await runOnDatabaseQueue { try find(by: matchColumn, value) } + let matchColumn = T.schema[keyPath: matchColumn] + var builder = SQLBuilder() + builder.generateSelect(limit: 1, predicate: matchColumn == value) + + let cb = builder + return try await runOnDatabaseQueue { + try fetch(verbatim: cb.sql, bindings: cb.bindings, + indices: T.Schema.selectColumnIndices).first + } } /** @@ -237,7 +251,7 @@ public extension SQLRecordFetchOperations * - Returns: The number of records matching the predicate. */ @inlinable - func fetchCount

(where predicate: @escaping ( T.Schema ) -> P) + func fetchCount

(where predicate: @Sendable @escaping ( T.Schema ) -> P) async throws -> Int where P: SQLPredicate { @@ -275,9 +289,10 @@ public extension SQLRecordFetchOperations async throws -> [ FK.Destination : [ T ] ] where FK: SQLForeignKeyColumn, FK.T == T, FK.Value == FK.DestinationColumn.Value, - S: Sequence, S.Element == FK.Destination + S: Sequence & Sendable, S.Element == FK.Destination { - try await runOnDatabaseQueue { + let foreignKey = T.schema[keyPath: foreignKey] + return try await runOnDatabaseQueue { try fetch(for: foreignKey, in: destinationRecords, omitEmpty: omitEmpty, limit: limit) } @@ -307,9 +322,10 @@ public extension SQLRecordFetchOperations async throws -> [ FK.DestinationColumn.Value : [ T ] ] where FK: SQLForeignKeyColumn, FK.T == T, FK.Value == FK.DestinationColumn.Value, - S: Sequence, S.Element == FK.DestinationColumn.Value + S: Sequence & Sendable, S.Element == FK.DestinationColumn.Value { - try await runOnDatabaseQueue { + let foreignKey = T.schema[keyPath: foreignKey] + return try await runOnDatabaseQueue { try fetch(for: foreignKey, in: destinationsColumns, omitEmpty: omitEmpty, limit: limit) } @@ -333,7 +349,8 @@ public extension SQLRecordFetchOperations where FK: SQLForeignKeyColumn, FK.T == T, FK.Value == FK.DestinationColumn.Value { - try await runOnDatabaseQueue { + let foreignKey = T.schema[keyPath: foreignKey] + return try await runOnDatabaseQueue { try fetch(for: foreignKey, in: destinationRecord, limit: limit) } } @@ -353,7 +370,8 @@ public extension SQLRecordFetchOperations where FK: SQLForeignKeyColumn, FK.T == T, FK.Value == FK.DestinationColumn.Value? { - try await runOnDatabaseQueue { + let foreignKey = T.schema[keyPath: foreignKey] + return try await runOnDatabaseQueue { try fetch(for: foreignKey, in: destinationRecord, limit: limit) } } @@ -373,7 +391,8 @@ public extension SQLRecordFetchOperations where FK: SQLForeignKeyColumn, FK.T == T, FK.Value? == FK.DestinationColumn.Value { - try await runOnDatabaseQueue { + let foreignKey = T.schema[keyPath: foreignKey] + return try await runOnDatabaseQueue { try fetch(for: foreignKey, in: destinationRecord, limit: limit) } } @@ -395,7 +414,10 @@ public extension SQLRecordFetchOperations where FK: SQLForeignKeyColumn, FK.T == T, FK.Value == FK.DestinationColumn.Value { - try await runOnDatabaseQueue { try findTarget(for: foreignKey, in: record) } + let foreignKey = T.schema[keyPath: foreignKey] + return try await runOnDatabaseQueue { + try findTarget(for: foreignKey, in: record) + } } /** @@ -412,7 +434,10 @@ public extension SQLRecordFetchOperations where FK: SQLForeignKeyColumn, FK.T == T, FK.Value == Optional { - try await runOnDatabaseQueue { try findTarget(for: foreignKey, in: record) } + let foreignKey = T.schema[keyPath: foreignKey] + return try await runOnDatabaseQueue { + try findTarget(for: foreignKey, in: record) + } } /** @@ -429,7 +454,10 @@ public extension SQLRecordFetchOperations where FK: SQLForeignKeyColumn, FK.T == T, Optional == FK.DestinationColumn.Value { - try await runOnDatabaseQueue { try findTarget(for: foreignKey, in: record) } + let foreignKey = T.schema[keyPath: foreignKey] + return try await runOnDatabaseQueue { + try findTarget(for: foreignKey, in: record) + } } } diff --git a/Sources/Lighter/Operations/SQLRecordFetchOperations.swift b/Sources/Lighter/Operations/SQLRecordFetchOperations.swift index c48b1a9..16c05de 100644 --- a/Sources/Lighter/Operations/SQLRecordFetchOperations.swift +++ b/Sources/Lighter/Operations/SQLRecordFetchOperations.swift @@ -42,6 +42,11 @@ public struct SQLRecordFetchOperations public init(_ operations: Ops) { self.operations = operations } } +#if swift(>=5.5) && canImport(_Concurrency) +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +extension SQLRecordFetchOperations: Sendable + where Ops: SQLDatabaseAsyncOperations {} +#endif public extension SQLDatabaseFetchOperations { // this is what DB/TX conform to @@ -200,6 +205,7 @@ public extension SQLRecordFetchOperations { // sync fetches * schema as the first argument (e.g. `$0.personId == 10`). * - Returns: An array of ``SQLRecord``s matching the type specified. */ + @inlinable func fetch(limit : Int? = nil, orderBy column : KeyPath, _ direction : SQLSortOrder = .ascending, @@ -207,13 +213,41 @@ public extension SQLRecordFetchOperations { // sync fetches throws -> [ T ] where SC: SQLColumn, SC.T == T, P: SQLPredicate { - var builder = SQLBuilder() + try fetch(limit: limit, orderBy: T.schema[keyPath: column], direction, + where: predicate) + } + /** + * Fetch filtered records of a view/table in a sorted manner. + * + * Example: + * ``` + * let people = try db.people.fetch(orderBy: Person.schema.name) { + * $0.name.hasPrefix("Du") + * } + * ``` + * + * - Parameters: + * - limit: An optional fetch limit (defaults to no limit) + * - column: The column to sort the results by. + * - direction: The sort direction (ascending or descending) + * - predicate: A closure returning a filter predicate, receives the record + * schema as the first argument (e.g. `$0.personId == 10`). + * - Returns: An array of ``SQLRecord``s matching the type specified. + */ + func fetch(limit : Int? = nil, + orderBy column : SC, + _ direction : SQLSortOrder = .ascending, + where predicate : ( T.Schema ) -> P) + throws -> [ T ] + where SC: SQLColumn, SC.T == T, P: SQLPredicate + { + var builder = SQLBuilder() builder.addSort(column, direction) builder.generateSelect(limit: limit, predicate: predicate(T.schema)) return try fetch(verbatim: builder.sql, bindings: builder.bindings, indices: T.Schema.selectColumnIndices) } - + /** * Fetch filtered records of a view/table in a sorted manner. * @@ -246,6 +280,45 @@ public extension SQLRecordFetchOperations { // sync fetches throws -> [ T ] where SC1: SQLColumn, SC1.T == T, SC2: SQLColumn, SC2.T == T, P: SQLPredicate + { + try fetch(limit: limit, + orderBy: T.schema[keyPath: column1], direction1, + T.schema[keyPath: column2], direction2, + where: predicate) + } + + /** + * Fetch filtered records of a view/table in a sorted manner. + * + * Example: + * ``` + * let persons = try db.fetch(\.people, orderBy: \.lastname, .ascending, + * \.firstname, .descending) + * { + * $0.name.hasPrefix("Du") + * } + * ``` + * + * - Parameters: + * - from: A KeyPath leading to a ``SQLRecord`` type, e.g. `\.person` + * - limit: An optional fetch limit (defaults to no limit) + * - column1: The first column to sort the results by. + * - direction1: The first sort direction (ascending or descending) + * - column2: The second column to sort the results by. + * - direction2: The second sort direction (ascending or descending) + * - predicate: A closure returning a filter predicate, receives the record + * schema as the first argument (e.g. `$0.personId == 10`). + * - Returns: An array of ``SQLRecord``s matching the type specified. + */ + func fetch(limit : Int? = nil, + orderBy column1 : SC1, + _ direction1 : SQLSortOrder, // can't be optional! + _ column2 : SC2, + _ direction2 : SQLSortOrder = .ascending, + where predicate : ( T.Schema ) -> P) + throws -> [ T ] + where SC1: SQLColumn, SC1.T == T, SC2: SQLColumn, SC2.T == T, + P: SQLPredicate { var builder = SQLBuilder() builder.addSort(column1, direction1) @@ -254,7 +327,7 @@ public extension SQLRecordFetchOperations { // sync fetches return try fetch(verbatim: builder.sql, bindings: builder.bindings, indices: T.Schema.selectColumnIndices) } - + /** * Fetch records of a certain type using a custom query. * @@ -324,10 +397,11 @@ public extension SQLRecordFetchOperations { // sync finds @inlinable func find(by matchColumn : KeyPath, _ value : C.Value) throws -> T? - where C: SQLColumn, T == C.T + where C: SQLColumn, T == C.T { (try fetch(limit: 1) { $0[keyPath: matchColumn] == value }).first } + } diff --git a/Sources/Lighter/Operations/SQLRecordForeignKeyOperations.swift b/Sources/Lighter/Operations/SQLRecordForeignKeyOperations.swift index 36f75d7..6ad9556 100644 --- a/Sources/Lighter/Operations/SQLRecordForeignKeyOperations.swift +++ b/Sources/Lighter/Operations/SQLRecordForeignKeyOperations.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // public extension SQLRecordFetchOperations { @@ -32,8 +32,37 @@ public extension SQLRecordFetchOperations { FK.Value == FK.DestinationColumn.Value, S: Sequence, S.Element == FK.Destination { - let foreignKey = T.schema[keyPath: foreignKey] - + try fetch(for: T.schema[keyPath: foreignKey], in: destinationRecords, + omitEmpty: omitEmpty, limit: limit) + } + + /** + * Fetch the records associated with the foreign key. + * + * ```swift + * let addresses = + * try db.addresses.fetch(for: Person.Schema.personId, in: persons) + * ``` + * + * - Parameters: + * - foreignKey: KeyPath to the ``SQLForeignKeyColumn`` (e.g. `\.personId`) + * - destinationRecords: A sequence of records matching the destination of + * the foreign key (e.g. `[ donald, dagobert ]`. + * - omitEmpty: Whether to omit destination records that have no values + * in the foreign key table. + * - limit: An optional limit on the results. + */ + @_disfavoredOverload + @inlinable + func fetch(for foreignKey: FK, + in destinationRecords: S, + omitEmpty : Bool = false, + limit : Int? = nil) + throws -> [ FK.Destination : [ T ] ] + where FK: SQLForeignKeyColumn, FK.T == T, + FK.Value == FK.DestinationColumn.Value, + S: Sequence, S.Element == FK.Destination + { var destinationKeys = [ FK.DestinationColumn.Value ]() var keyedDestinations = [ FK.DestinationColumn.Value : FK.Destination ]() for record in destinationRecords { @@ -69,6 +98,7 @@ public extension SQLRecordFetchOperations { return resultMap } + /** * Fetch the records associated with the foreign key. * @@ -94,8 +124,35 @@ public extension SQLRecordFetchOperations { FK.Value == FK.DestinationColumn.Value, S: Sequence, S.Element == FK.DestinationColumn.Value { - let foreignKey = T.schema[keyPath: foreignKey] - + try fetch(for: T.schema[keyPath: foreignKey], in: destinationsColumns, + omitEmpty: omitEmpty, limit: limit) + } + + /** + * Fetch the records associated with the foreign key. + * + * ```swift + * let addresses = + * try db.addresses.fetch(for: Address.schema.personId, in: personIDs) + * ``` + * + * - Parameters: + * - foreignKey: KeyPath to the ``SQLForeignKeyColumn`` (e.g. `\.personId`) + * - destinationsColumns: A sequence of records matching the destination of + * the foreign key (e.g. `[ donald, dagobert ]`. + * - omitEmpty: Whether to omit destination records that have no values + * in the foreign key table. + * - limit: An optional limit on the results. + */ + @_disfavoredOverload + @inlinable + func fetch(for foreignKey: FK, in destinationsColumns: S, + omitEmpty: Bool = false, limit: Int? = nil) + throws -> [ FK.DestinationColumn.Value : [ T ] ] + where FK: SQLForeignKeyColumn, FK.T == T, + FK.Value == FK.DestinationColumn.Value, + S: Sequence, S.Element == FK.DestinationColumn.Value + { var builder = SQLBuilder() let predicate = foreignKey.in(destinationsColumns) builder.generateSelect(limit: limit, predicate: predicate) @@ -137,7 +194,25 @@ public extension SQLRecordFetchOperations { where FK: SQLForeignKeyColumn, FK.T == T, FK.Value == FK.DestinationColumn.Value { - let foreignKey = T.schema[keyPath: foreignKey] + try fetch(for: T.schema[keyPath: foreignKey], in: destinationRecord, + limit: limit) + } + + /** + * Fetch the records associated with the foreign key. + * + * ```swift + * let addresses = try db.addresses.fetch(for: \.personId, in: person) + * ``` + */ + @_disfavoredOverload + @inlinable + func fetch(for foreignKey: FK, in destinationRecord: FK.Destination, + limit: Int? = nil) + throws -> [ T ] + where FK: SQLForeignKeyColumn, FK.T == T, + FK.Value == FK.DestinationColumn.Value + { let value = destinationRecord[keyPath: foreignKey.destinationColumn.keyPath] var builder = SQLBuilder() @@ -168,7 +243,27 @@ public extension SQLRecordFetchOperations { where FK: SQLForeignKeyColumn, FK.T == T, FK.Value == FK.DestinationColumn.Value? // source is optional { - let foreignKey = T.schema[keyPath: foreignKey] + try fetch(for: T.schema[keyPath: foreignKey], in: destinationRecord, + limit: limit) + } + + /** + * Fetch the records associated with the foreign key. + * + * ```swift + * let addresses = + * try db.addresses.fetch(for: Address.schema.personId, in: person) + * ``` + */ + @_disfavoredOverload + @inlinable + func fetch(for foreignKey: FK, + in destinationRecord: FK.Destination, + limit: Int? = nil) + throws -> [ T ] + where FK: SQLForeignKeyColumn, FK.T == T, + FK.Value == FK.DestinationColumn.Value? // source is optional + { let value = destinationRecord[keyPath: foreignKey.destinationColumn.keyPath] var builder = SQLBuilder() @@ -199,7 +294,24 @@ public extension SQLRecordFetchOperations { where FK: SQLForeignKeyColumn, FK.T == T, FK.Value? == FK.DestinationColumn.Value // dest is optional { - let foreignKey = T.schema[keyPath: foreignKey] + try fetch(for: T.schema[keyPath: foreignKey], in: destinationRecord, + limit: limit) + } + /** + * Fetch the records associated with the foreign key. + * + * ```swift + * let addresses = try db.addresses.fetch(for: \.personId, in: person) + * ``` + */ + @_disfavoredOverload + @inlinable + func fetch(for foreignKey: FK, in destinationRecord: FK.Destination, + limit: Int? = nil) + throws -> [ T ] + where FK: SQLForeignKeyColumn, FK.T == T, + FK.Value? == FK.DestinationColumn.Value // dest is optional + { let value = destinationRecord[keyPath: foreignKey.destinationColumn.keyPath] var builder = SQLBuilder() @@ -236,11 +348,32 @@ public extension SQLRecordFetchOperations { throws -> FK.Destination? where FK: SQLForeignKeyColumn, FK.T == T, FK.Value == FK.DestinationColumn.Value + { + try findTarget(for: T.schema[keyPath: foreignKey], in: record) + } + /** + * Locate the record connected to a specific foreign key. + * + * Example: + * ```swift + * let person = try db.addresses.findTarget(for: \.personId, in: address) + * ``` + * + * - Parameters: + * - foreignKey: KeyPath to foreign key to match (e.g. `\.personId`). + * - record: The record containing the foreign key. + * - Returns: The destination record, if found. + */ + @_disfavoredOverload + @inlinable + func findTarget(for foreignKey: FK, in record: T) + throws -> FK.Destination? + where FK: SQLForeignKeyColumn, FK.T == T, + FK.Value == FK.DestinationColumn.Value { // This could still be `Int? == Int?`, we might also want a non-optional // variant? (that doesn't return an optional destination, but throws // instead). - let foreignKey = T.schema[keyPath: foreignKey] let value = record[keyPath: foreignKey.keyPath] var builder = SQLBuilder() @@ -275,10 +408,31 @@ public extension SQLRecordFetchOperations { throws -> FK.Destination? where FK: SQLForeignKeyColumn, FK.T == T, FK.Value == Optional // source is optional + { + try findTarget(for: T.schema[keyPath: foreignKey], in: record) + } + /** + * Locate the record connected to a specific (nullable) foreign key. + * + * Example: + * ```swift + * let person = try db.addresses.findTarget(for: \.personId, in: address) + * ``` + * + * - Parameters: + * - foreignKey: KeyPath to foreign key to match (e.g. `\.personId`). + * - record: The record containing the foreign key. + * - Returns: The destination record, if found. + */ + @_disfavoredOverload + @inlinable + func findTarget(for foreignKey: FK, in record: T) + throws -> FK.Destination? + where FK: SQLForeignKeyColumn, FK.T == T, + FK.Value == Optional // source is optional { // This is the variant where an optional foreign-key matches the // non-optional destination column. - let foreignKey = T.schema[keyPath: foreignKey] guard let value = record[keyPath: foreignKey.keyPath] else { return nil } var builder = SQLBuilder() @@ -313,11 +467,33 @@ public extension SQLRecordFetchOperations { throws -> FK.Destination? where FK: SQLForeignKeyColumn, FK.T == T, Optional == FK.DestinationColumn.Value // dest is optional + { + try findTarget(for: T.schema[keyPath: foreignKey], in: record) + } + + /** + * Locate the record connected to a specific (nullable) foreign key. + * + * Example: + * ```swift + * let person = try db.addresses.findTarget(for: \.personId, in: address) + * ``` + * + * - Parameters: + * - foreignKey: KeyPath to foreign key to match (e.g. `\.personId`). + * - record: The record containing the foreign key. + * - Returns: The destination record, if found. + */ + @_disfavoredOverload + @inlinable + func findTarget(for foreignKey: FK, in record: T) + throws -> FK.Destination? + where FK: SQLForeignKeyColumn, FK.T == T, + Optional == FK.DestinationColumn.Value // dest is optional { // This is the variant where an non-optional foreign-key matches an // optional destination column (e.g. the primary can be NULL! Northwind...). - let foreignKey = T.schema[keyPath: foreignKey] - let value = record[keyPath: foreignKey.keyPath] + let value = record[keyPath: foreignKey.keyPath] var builder = SQLBuilder() let predicate = foreignKey.destinationColumn == value diff --git a/Sources/Lighter/Predicates/SQLColumnComparisonPredicate.swift b/Sources/Lighter/Predicates/SQLColumnComparisonPredicate.swift index 6b92c04..5d2e509 100644 --- a/Sources/Lighter/Predicates/SQLColumnComparisonPredicate.swift +++ b/Sources/Lighter/Predicates/SQLColumnComparisonPredicate.swift @@ -20,7 +20,7 @@ public struct SQLColumnComparisonPredicate: SQLPredicate L.Value == R.Value { - public enum ComparisonOperator: String { + public enum ComparisonOperator: String, Sendable { /** * Check whether the ``SQLColumn`` is the same like the other column diff --git a/Sources/Lighter/Predicates/SQLColumnValuePredicate.swift b/Sources/Lighter/Predicates/SQLColumnValuePredicate.swift index 35c1287..4ef5e7c 100644 --- a/Sources/Lighter/Predicates/SQLColumnValuePredicate.swift +++ b/Sources/Lighter/Predicates/SQLColumnValuePredicate.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // #if canImport(Foundation) @@ -20,7 +20,7 @@ import struct Foundation.Data */ public struct SQLColumnValuePredicate: SQLPredicate { - public enum ComparisonOperator: String { + public enum ComparisonOperator: String, Sendable { /** * Check whether the ``SQLColumn`` is the same like the given value. diff --git a/Sources/Lighter/Predicates/SQLCompoundPredicate.swift b/Sources/Lighter/Predicates/SQLCompoundPredicate.swift index f8554ea..f9897b9 100644 --- a/Sources/Lighter/Predicates/SQLCompoundPredicate.swift +++ b/Sources/Lighter/Predicates/SQLCompoundPredicate.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** @@ -21,7 +21,7 @@ public struct SQLCompoundPredicate: SQLPredicate /** * The operator by which the predicates are joined. */ - public enum Operator: String { + public enum Operator: String, Sendable { /// Both predicates must be true for the whole predicate to be true. case and = "AND" /// Either predicate must be true for the whole predicate to be true. diff --git a/Sources/Lighter/Predicates/SQLPredicate.swift b/Sources/Lighter/Predicates/SQLPredicate.swift index edd343f..e2270bb 100644 --- a/Sources/Lighter/Predicates/SQLPredicate.swift +++ b/Sources/Lighter/Predicates/SQLPredicate.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** @@ -24,7 +24,7 @@ * person_id = 10 * ``` */ -public protocol SQLPredicate { +public protocol SQLPredicate: Sendable { /** * Append the SQL representing the predicate to the ``SQLBuilder``. diff --git a/Sources/Lighter/Predicates/SQLSortOrder.swift b/Sources/Lighter/Predicates/SQLSortOrder.swift index 102d30a..d98613d 100644 --- a/Sources/Lighter/Predicates/SQLSortOrder.swift +++ b/Sources/Lighter/Predicates/SQLSortOrder.swift @@ -1,12 +1,12 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** * The sort order that can be applied in select. Ascending or descending. */ -public enum SQLSortOrder: String { +public enum SQLSortOrder: String, Sendable { case ascending = "ASC" case descending = "DESC" } diff --git a/Sources/Lighter/Predicates/SQLTruePredicate.swift b/Sources/Lighter/Predicates/SQLTruePredicate.swift index 540cf2a..ee88d60 100644 --- a/Sources/Lighter/Predicates/SQLTruePredicate.swift +++ b/Sources/Lighter/Predicates/SQLTruePredicate.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** @@ -8,13 +8,16 @@ */ public struct SQLTruePredicate: SQLPredicate { - /// A shared instance of the true predicate. - public static let shared = SQLTruePredicate() - + @inlinable + static var shared : SQLTruePredicate { SQLTruePredicate() } + // MARK: - SQL Generation static let sql = "1 = 1" + @inlinable + public init() {} + public func generateSQL(into builder: inout SQLBuilder) { builder.append(Self.sql) } @@ -22,7 +25,8 @@ public struct SQLTruePredicate: SQLPredicate { extension SQLPredicate where Self == SQLTruePredicate { - static var `true` : SQLTruePredicate { .shared } + @inlinable + static var `true` : SQLTruePredicate { SQLTruePredicate() } } /** @@ -30,11 +34,16 @@ extension SQLPredicate where Self == SQLTruePredicate { */ public struct SQLBoolPredicate: SQLPredicate { - public static let `true` = Self(value: true) - public static let `false` = Self(value: false) + @inlinable + public static var `true` : Self { Self(true) } + @inlinable + public static var `false` : Self { Self(false) } public let value : Bool + @inlinable + public init(_ value: Bool) { self.value = value } + public func generateSQL(into builder: inout SQLBuilder) { builder.append(value ? "1 = 1" : "1 = 0") } diff --git a/Sources/Lighter/Schema/SQLColumn.swift b/Sources/Lighter/Schema/SQLColumn.swift index 00db490..62613c9 100644 --- a/Sources/Lighter/Schema/SQLColumn.swift +++ b/Sources/Lighter/Schema/SQLColumn.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** @@ -16,7 +16,7 @@ * Note that SQLite itself (w/o STRICT mode) allows columns to have arbitrary * types. */ -public protocol SQLColumn: Hashable { +public protocol SQLColumn: Hashable, Sendable { /// The ``SQLTableRecord`` or ``SQLViewRecord`` of the column. associatedtype T : SQLRecord @@ -58,7 +58,8 @@ public protocol SQLColumn: Hashable { * * Checkout the ``SQLColumn`` description for more information. */ -public struct MappedColumn: SQLColumn +public struct MappedColumn: SQLColumn, + @unchecked Sendable // to workaround `KeyPath` Sendability. where T: SQLRecord, Value: SQLiteValueType & Hashable { // the column itself doesn't need to have identity (though it has in SQLite) diff --git a/Sources/Lighter/Schema/SQLEntitySchema.swift b/Sources/Lighter/Schema/SQLEntitySchema.swift index 6e29bfd..7e81aee 100644 --- a/Sources/Lighter/Schema/SQLEntitySchema.swift +++ b/Sources/Lighter/Schema/SQLEntitySchema.swift @@ -1,12 +1,12 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** * The schema information for either a SQLite table or view. */ -public protocol SQLEntitySchema { +public protocol SQLEntitySchema: Sendable { /** * A tuple containing the SQL statement (or parameter) index of each diff --git a/Sources/Lighter/Schema/SQLForeignKeyColumn.swift b/Sources/Lighter/Schema/SQLForeignKeyColumn.swift index 74d2987..442b411 100644 --- a/Sources/Lighter/Schema/SQLForeignKeyColumn.swift +++ b/Sources/Lighter/Schema/SQLForeignKeyColumn.swift @@ -1,13 +1,13 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** * A ``SQLColumn`` that is a (single) foreign key targetting a different column * in another table. */ -public protocol SQLForeignKeyColumn: SQLColumn { +public protocol SQLForeignKeyColumn: SQLColumn, Sendable { /// The type of the ``SQLColumn`` the foreign key is targetting. associatedtype DestinationColumn : SQLColumn @@ -25,7 +25,9 @@ public protocol SQLForeignKeyColumn: SQLColumn { * * Checkout the ``SQLForeignKeyColumn`` description for more information. */ -public struct MappedForeignKey: SQLForeignKeyColumn +public struct MappedForeignKey + : SQLForeignKeyColumn, + @unchecked Sendable // to workaround `KeyPath` Sendability. where T: SQLRecord, Value: SQLiteValueType & Hashable, DestinationColumn: SQLColumn { @@ -43,7 +45,8 @@ public struct MappedForeignKey: SQLForeignKeyColumn @inlinable public init(externalName: String, defaultValue: Value, keyPath: KeyPath, - destinationColumn: @escaping @autoclosure () -> DestinationColumn) + destinationColumn: + @Sendable @escaping @autoclosure () -> DestinationColumn) { self.externalName = externalName self.defaultValue = defaultValue diff --git a/Sources/Lighter/Schema/SQLRecord.swift b/Sources/Lighter/Schema/SQLRecord.swift index 5f0ba88..70bce94 100644 --- a/Sources/Lighter/Schema/SQLRecord.swift +++ b/Sources/Lighter/Schema/SQLRecord.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // /** @@ -19,7 +19,7 @@ * Note that all `SQLRecord`s are always `Hashable`, because all the SQLite base * types are `Hashable`. */ -public protocol SQLRecord: Hashable { +public protocol SQLRecord: Hashable, Sendable { /// The ``SQLEntitySchema`` associated with the record. The schema contains /// the static type information for the SQL schema. diff --git a/Sources/Lighter/Schema/SQLiteValueType.swift b/Sources/Lighter/Schema/SQLiteValueType.swift index 4e8093c..2a3c5e6 100644 --- a/Sources/Lighter/Schema/SQLiteValueType.swift +++ b/Sources/Lighter/Schema/SQLiteValueType.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022-2023 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // import SQLite3 @@ -47,7 +47,7 @@ import struct Foundation.UUID * Note: `SQLiteValueType`s are usually `Hashable`, making record types * Hashable too! */ -public protocol SQLiteValueType { +public protocol SQLiteValueType: Sendable { /** * Initialize a SQLite value from a column in the given SQLite3 prepared @@ -100,7 +100,8 @@ public protocol SQLiteValueType { * An error happened while converting between SQLite types and a * `RawRepresentable`. */ -public enum SQLiteRawConversionError: Swift.Error { +public enum SQLiteRawConversionError: Swift.Error, Sendable +{ /// The raw value initializers returned `nil` for the given raw value. case couldNotConvertRawValue(RawValue) @@ -518,12 +519,17 @@ extension Array: SQLiteValueType where Element == UInt8 { extension Date : SQLiteValueType { - public enum SQLiteDateStorageStyle: Hashable { + public enum SQLiteDateStorageStyle: Hashable, Sendable { case timeIntervalSince1970 case formatter(DateFormatter) } +#if swift(>=5.10) + /// The style is non-isolated and should only be set once on startup. + nonisolated(unsafe) public static var sqlDateStorageStyle = SQLiteDateStorageStyle.timeIntervalSince1970 + /// The style is non-isolated and should only be set once on startup. + nonisolated(unsafe) public static var defaultSQLiteDateFormatter : DateFormatter = { // `SELECT datetime();` gives: `2004-08-19 18:51:06` in UTC let df = DateFormatter() @@ -531,8 +537,19 @@ extension Date : SQLiteValueType { df.locale = Locale(identifier: "en_US_POSIX") return df }() +#else + public static var sqlDateStorageStyle = + SQLiteDateStorageStyle.timeIntervalSince1970 + public static var defaultSQLiteDateFormatter : DateFormatter = { + // `SELECT datetime();` gives: `2004-08-19 18:51:06` in UTC + let df = DateFormatter() + df.dateFormat = "yyyy-MM-dd HH:mm:ss" + df.locale = Locale(identifier: "en_US_POSIX") + return df + }() +#endif - public enum SQLiteDateConversionError: Swift.Error { + public enum SQLiteDateConversionError: Swift.Error, Sendable { case unexpectedNull case couldNotParseDateString(String) } @@ -644,7 +661,7 @@ extension Data: SQLiteValueType { extension URL : SQLiteValueType { - public struct SQLCouldNotParseURL: Swift.Error { + public struct SQLCouldNotParseURL: Swift.Error, Sendable { public let string : String public init(string: String) { self.string = string } } @@ -682,7 +699,7 @@ extension URL : SQLiteValueType { extension Decimal : SQLiteValueType { - public struct SQLCouldNotParseDecimal: Swift.Error { + public struct SQLCouldNotParseDecimal: Swift.Error, Sendable { public let string : String public init(string: String) { self.string = string } } @@ -736,13 +753,19 @@ extension Decimal : SQLiteValueType { extension UUID : SQLiteValueType { - public enum SQLiteUUIDStorageStyle: Hashable { + public enum SQLiteUUIDStorageStyle: Hashable, Sendable { case string case blob } +#if swift(>=5.10) + /// The style is non-isolated and should only be set once on startup. + nonisolated(unsafe) + public static var sqlUUIDStorageStyle = SQLiteUUIDStorageStyle.blob +#else public static var sqlUUIDStorageStyle = SQLiteUUIDStorageStyle.blob +#endif - public enum SQLCouldNotLoadUUID: Swift.Error { + public enum SQLCouldNotLoadUUID: Swift.Error, Sendable { case couldNotParseString(String) case dataWithInvalidLength(Int) } diff --git a/Sources/Lighter/Transactions/SQLTransactionAsync.swift b/Sources/Lighter/Transactions/SQLTransactionAsync.swift index 41e6973..9c1e355 100644 --- a/Sources/Lighter/Transactions/SQLTransactionAsync.swift +++ b/Sources/Lighter/Transactions/SQLTransactionAsync.swift @@ -48,7 +48,7 @@ public extension SQLDatabase where Self: SQLDatabaseAsyncOperations { @discardableResult func transaction( mode : SQLTransactionType = .default, - execute : @escaping ( SQLChangeTransaction ) throws -> R + execute : @Sendable @escaping ( SQLChangeTransaction ) throws -> R ) async throws -> R { try await runOnDatabaseQueue { @@ -83,7 +83,8 @@ public extension SQLDatabase where Self: SQLDatabaseAsyncOperations { */ @inlinable @discardableResult - func readTransaction(execute: @escaping (SQLTransaction) throws -> R) + func readTransaction(execute: @Sendable @escaping + (SQLTransaction) throws -> R) async throws -> R { try await runOnDatabaseQueue { diff --git a/Sources/Lighter/Transactions/SQLTransactionType.swift b/Sources/Lighter/Transactions/SQLTransactionType.swift index 8402b54..81a9ab4 100644 --- a/Sources/Lighter/Transactions/SQLTransactionType.swift +++ b/Sources/Lighter/Transactions/SQLTransactionType.swift @@ -14,7 +14,7 @@ * immediately fail w/ `SQLITE_BUSY` if the database lock is in use. * While an immediate transaction will wait to acquire the lock. */ -public enum SQLTransactionType: String { +public enum SQLTransactionType: String, Sendable { /// Start a read transaction on the first SELECT and upgrade to a write /// transaction on the first modification. @@ -31,5 +31,6 @@ public enum SQLTransactionType: String { /// reads in others. case exclusive = "EXCLUSIVE" - public static let `default` = SQLTransactionType.immediate + @inlinable + public static var `default` : SQLTransactionType { .immediate } } diff --git a/Sources/Lighter/Utilities/LighterError.swift b/Sources/Lighter/Utilities/LighterError.swift index 57bc6f3..8004ce9 100644 --- a/Sources/Lighter/Utilities/LighterError.swift +++ b/Sources/Lighter/Utilities/LighterError.swift @@ -11,23 +11,7 @@ import struct Foundation.URL * This carries a higher level error type as well as the SQLite3 * error code and message. */ -public struct LighterError: Swift.Error { - - /// The kind of the error that happened within Lighter. - public enum ErrorType: Hashable { - - case insertFailed(record: AnyHashable) - case updateFailed(record: AnyHashable) - case deleteFailed(record: AnyHashable) - - case couldNotOpenDatabase(URL) - - case couldNotBeginTransaction - case couldNotRollbackTransaction - case couldNotCommitTransaction - - case couldNotFindRelationshipTarget - } +public struct LighterError: Swift.Error, Sendable { /// The higher level error type. public let type : ErrorType @@ -45,4 +29,70 @@ public struct LighterError: Swift.Error { self.code = code self.message = message.flatMap(String.init(cString:)) } + + /// The kind of the error that happened within Lighter. + public enum ErrorType: Hashable, Sendable { + + // Those are Sendable, they are the record types internally. + case insertFailed(record: any SQLInsertableRecord) + case updateFailed(record: any SQLUpdatableRecord) + case deleteFailed(record: any SQLDeletableRecord) + + case couldNotOpenDatabase(URL) + + case couldNotBeginTransaction + case couldNotRollbackTransaction + case couldNotCommitTransaction + + case couldNotFindRelationshipTarget + + @inlinable + public static func ==(lhs: Self, rhs: Self) -> Bool { + func isEqual(lhs: T, rhs: any Equatable) -> Bool { + guard let rhs = rhs as? T else { return false } + return lhs == rhs + } + + switch ( lhs, rhs ) { + case ( .insertFailed(let lhs), .insertFailed(let rhs)): + return isEqual(lhs: lhs, rhs: rhs) + case ( .updateFailed(let lhs), .updateFailed(let rhs)): + return isEqual(lhs: lhs, rhs: rhs) + case ( .deleteFailed(let lhs), .deleteFailed(let rhs)): + return isEqual(lhs: lhs, rhs: rhs) + + case ( .couldNotOpenDatabase(let lhs), .couldNotOpenDatabase(let rhs)): + return lhs == rhs + + case ( .couldNotBeginTransaction, .couldNotBeginTransaction ): + return true + case ( .couldNotRollbackTransaction, .couldNotRollbackTransaction ): + return true + case ( .couldNotCommitTransaction, .couldNotCommitTransaction ): + return true + case ( .couldNotFindRelationshipTarget, + .couldNotFindRelationshipTarget ): + return true + + default: + return false + } + } + + public func hash(into hasher: inout Hasher) { + switch self { + case .insertFailed(let record) : record.hash(into: &hasher) + case .updateFailed(let record) : record.hash(into: &hasher) + case .deleteFailed(let record) : record.hash(into: &hasher) + + case .couldNotOpenDatabase(let url): url.hash(into: &hasher) + + // TBD: + case .couldNotBeginTransaction : 1.hash(into: &hasher) + case .couldNotRollbackTransaction : 2.hash(into: &hasher) + case .couldNotCommitTransaction : 3.hash(into: &hasher) + case .couldNotFindRelationshipTarget : 4.hash(into: &hasher) + } + } + } } diff --git a/Sources/Lighter/Utilities/SendableKeyPath.swift b/Sources/Lighter/Utilities/SendableKeyPath.swift new file mode 100644 index 0000000..1185a49 --- /dev/null +++ b/Sources/Lighter/Utilities/SendableKeyPath.swift @@ -0,0 +1,8 @@ +// +// Created by Helge Heß. +// Copyright © 2024 ZeeZide GmbH. +// + +// Ugh. But how else? Swift 6 maybe. +extension KeyPath: @unchecked Sendable + where Root: Sendable, Value: Sendable {} diff --git a/Sources/SQLite3Schema/Column.swift b/Sources/SQLite3Schema/Column.swift index 09e5a53..9c0b70c 100644 --- a/Sources/SQLite3Schema/Column.swift +++ b/Sources/SQLite3Schema/Column.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // extension Schema { @@ -10,7 +10,7 @@ extension Schema { * * The information as-is returned by `PRAGMA table_info($table)`. */ - public struct Column: Hashable, Identifiable { + public struct Column: Hashable, Identifiable, Sendable { /** * An enum that represents a default value set for a SQLite column. @@ -18,7 +18,7 @@ extension Schema { * Can be `null`, an `integer`, a `real`, a `text` or a `blob` (the * possible types returned by `sqlite3_column_type`). */ - public enum DefaultValue: Hashable { + public enum DefaultValue: Hashable, Sendable { case null @@ -47,11 +47,24 @@ extension Schema { /// Whether the column is the / part of the primary key of a table. public let isPrimaryKey : Bool - /// Initialize a new `Column` structure. - public init(id: Int64, name: String, type: ColumnType? = .text, - isNotNull: Bool = false, - defaultValue: DefaultValue? = nil, - isPrimaryKey: Bool = false) + /** + * Initialize a new `Column` structure. + * + * - Parameters: + * - id: The id associated w/ the column in the database. + * - name: The name of the column. + * - type: The type of the column, defaults to `.text`. + * - isNotNull: Whether the column has a not-null constraint. + * - defaultValue: The columns default value, if there is one assigned. + * - isPrimaryKey: Whether the column is part, or the, primary key. + */ + @inlinable + public init(id : Int64, + name : String, + type : ColumnType? = .text, + isNotNull : Bool = false, + defaultValue : DefaultValue? = nil, + isPrimaryKey : Bool = false) { self.id = id self.name = name diff --git a/Sources/SQLite3Schema/DataTypes.swift b/Sources/SQLite3Schema/DataTypes.swift index a6e27ae..5063c88 100644 --- a/Sources/SQLite3Schema/DataTypes.swift +++ b/Sources/SQLite3Schema/DataTypes.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) @@ -58,7 +58,7 @@ extension Schema { * To learn more about type affinity: * https://www.sqlite.org/datatype3.html#type_affinity */ - public enum TypeAffinity: String, Hashable { + public enum TypeAffinity: String, Hashable, Sendable { case text = "TEXT" case numeric = "NUMERIC" // either INTEGER or REAL @@ -78,7 +78,7 @@ extension Schema { * For example `VARCHAR(255)` is not a SQLite type, but SQLite detects it * properly and assigns it ``TypeAffinity/text``. */ - public enum ColumnType: Hashable, RawRepresentable { + public enum ColumnType: Hashable, RawRepresentable, Sendable { // strict types case integer // this is really the exact `INTEGER`, not .int diff --git a/Sources/SQLite3Schema/ForeignKey.swift b/Sources/SQLite3Schema/ForeignKey.swift index 865c469..89e25ab 100644 --- a/Sources/SQLite3Schema/ForeignKey.swift +++ b/Sources/SQLite3Schema/ForeignKey.swift @@ -1,6 +1,6 @@ // // Created by Helge Heß. -// Copyright © 2022 ZeeZide GmbH. +// Copyright © 2022-2024 ZeeZide GmbH. // #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) @@ -23,12 +23,12 @@ extension Schema { * Note that to enforce foreign key constraints, the setting must be * esplicitly enabled on a connection, via `PRAGMA foreignkeys = ON;`. */ - public struct ForeignKey: Hashable, Identifiable { + public struct ForeignKey: Hashable, Identifiable, Sendable { /** * The action to take on updates/deletes affecting a constraint. */ - public enum Action: String { + public enum Action: String, Sendable { /// No action is performed, the foreign key might become a "dangling" /// pointer. @@ -54,7 +54,7 @@ extension Schema { /// The foreign key match strategy. /// SQLite can only do `simple`, this has no actual effect (as of today). - public enum Match: String { + public enum Match: String, Sendable { case none = "NONE" case simple = "SIMPLE" @@ -85,12 +85,14 @@ extension Schema { public let match : Match /// Initialize a new `ForeignKey` structure. - public init(id: Int64, seq: Int64 = 0, + public init(id : Int64, + seq : Int64 = 0, sourceColumn : String, destinationTable : String, destinationColumn : String? = nil, updateAction : Action = .noAction, - deleteAction : Action = .noAction, match: Match = .simple) + deleteAction : Action = .noAction, + match : Match = .simple) { self.id = id self.seq = seq diff --git a/Tests/EntityGenTests/ASTDatabaseStructGenerationTests.swift b/Tests/EntityGenTests/ASTDatabaseStructGenerationTests.swift index 97a4976..89c2557 100644 --- a/Tests/EntityGenTests/ASTDatabaseStructGenerationTests.swift +++ b/Tests/EntityGenTests/ASTDatabaseStructGenerationTests.swift @@ -34,7 +34,7 @@ final class ASTDatabaseStructGenerationTests: XCTestCase { XCTAssertTrue(source.contains("SQLDatabase, SQLDatabaseAsyncChangeOperations")) XCTAssertTrue(source.contains("public struct TestDB")) - XCTAssertTrue(source.contains("public struct RecordTypes")) + XCTAssertTrue(source.contains("public struct RecordTypes : Swift.Sendable")) XCTAssertTrue(source.contains("public let people = Person.self")) XCTAssertTrue(source.contains("public static let recordTypes = RecordTypes()")) // has not dates!: @@ -68,7 +68,7 @@ final class ASTDatabaseStructGenerationTests: XCTestCase { XCTAssertTrue(source.contains("SQLDatabase, SQLDatabaseAsyncChangeOperations")) XCTAssertTrue(source.contains("public struct TestDB")) - XCTAssertTrue(source.contains("public struct RecordTypes")) + XCTAssertTrue(source.contains("public struct RecordTypes : Swift.Sendable")) XCTAssertTrue(source.contains("public let people = Person.self")) XCTAssertTrue(source.contains("public static let recordTypes = RecordTypes()")) // has not dates!: @@ -101,7 +101,7 @@ final class ASTDatabaseStructGenerationTests: XCTestCase { XCTAssertFalse(source.contains("SQLDatabase")) XCTAssertFalse(source.contains("SQLDatabaseAsyncChangeOperations")) XCTAssertTrue(source.contains("public struct TestDB")) - XCTAssertFalse(source.contains("public struct RecordTypes")) + XCTAssertFalse(source.contains("public struct RecordTypes : Swift.Sendable")) XCTAssertFalse(source.contains("public let people = Person.self")) XCTAssertFalse(source.contains("public static let recordTypes = RecordTypes()")) // has not dates!: @@ -180,6 +180,10 @@ final class ASTDatabaseStructGenerationTests: XCTestCase { //print("GOT:\n-----\n\(source)\n-----") XCTAssertTrue(source.contains("static var _dateFormatter : DateFormatter?")) + XCTAssertTrue(source.contains( + "nonisolated(unsafe) static var _dateFormatter : DateFormatter?")) + XCTAssertTrue(source.contains("#if swift(>=5.10)")) + XCTAssertTrue(source.contains( "public static var dateFormatter : DateFormatter? {")) XCTAssertTrue(source.contains( diff --git a/Tests/NorthwindTests/NorthwindTests.swift b/Tests/NorthwindTests/NorthwindTests.swift index 5989afc..2296df4 100644 --- a/Tests/NorthwindTests/NorthwindTests.swift +++ b/Tests/NorthwindTests/NorthwindTests.swift @@ -137,7 +137,7 @@ final class NorthwindTests: XCTestCase { }() // print("GOT:\n-----\n\(source)\n-----") - XCTAssertTrue(source.contains("public struct ID : Hashable")) + XCTAssertTrue(source.contains("public struct ID : Swift.Hashable")) XCTAssertTrue(source.contains( "public init(_ customerID: String, _ customerTypeID: String)")) XCTAssertTrue(source.contains(