From 4f45fc6fa4ebe4e692f6a562095d6e944098f7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20He=C3=9F?= Date: Sat, 7 Dec 2024 16:34:56 +0100 Subject: [PATCH 1/8] Rename `fetchSpecificiationWith(bindings:)` to `resolvingBindings` Was misspelled and using an old Swift style. --- Sources/ZeeQL/Access/AccessDataSource.swift | 26 +++++-------------- .../Access/AccessDataSourceFinders.swift | 11 ++------ .../ZeeQL/Control/FetchSpecification.swift | 25 +++++++----------- 3 files changed, 17 insertions(+), 45 deletions(-) diff --git a/Sources/ZeeQL/Access/AccessDataSource.swift b/Sources/ZeeQL/Access/AccessDataSource.swift index 29b70c0..9206613 100644 --- a/Sources/ZeeQL/Access/AccessDataSource.swift +++ b/Sources/ZeeQL/Access/AccessDataSource.swift @@ -158,8 +158,8 @@ public extension AccessDataSourceType { * } * ``` * - * This calls ``FetchSpecification/fetchSpecificiationWith(bindings:)-585ip`` - * and passes in the given key/value pair (contactId=12345). + * This calls ``FetchSpecification/resolvingBindings(_:)`` and passes in the + * given key/value pair (contactId=12345). * * Finally the fetch will be performed using * ``_primaryFetchObjects``. @@ -174,13 +174,7 @@ public extension AccessDataSourceType { yield: ( Object ) throws -> Void) throws { if !binds.isEmpty { - guard let fs = try fetchSpecification - .fetchSpecificiationWith(bindings: binds) else - { - throw AccessDataSourceError - .CouldNotResolveBindings(fetchSpecification: fetchSpecification, - bindings: binds) - } + let fs = try fetchSpecification.resolvingBindings(binds) try _primaryFetchObjects(fs) { try yield($0) } } else { @@ -202,8 +196,8 @@ public extension AccessDataSourceType { * * This will lookup the `FetchSpecification` named "myContacts" in * the `Entity` of the datasource. It then calls - * ``FetchSpecification/fetchSpecificiationWith(bindings:)-585ip`` - * and passes in the given key/value pair (contactId=12345). + * ``FetchSpecification/resolvingBindings(_:)`` and passes in the given + * key/value pair (contactId=12345). * * Finally the fetch will be performed using * ``_primaryFetchObjects``. @@ -351,15 +345,7 @@ public extension AccessDataSourceType { } /* apply bindings */ - if let qb = qb { - guard let fs = try fs.fetchSpecificiationWith(bindings: qb) else { - throw AccessDataSourceError - .CannotConstructFetchSpecification(.bindingFailed) - } - return fs - } - - return fs + return try fs.resolvingBindings(qb) } } diff --git a/Sources/ZeeQL/Access/AccessDataSourceFinders.swift b/Sources/ZeeQL/Access/AccessDataSourceFinders.swift index f5de242..790ba9b 100644 --- a/Sources/ZeeQL/Access/AccessDataSourceFinders.swift +++ b/Sources/ZeeQL/Access/AccessDataSourceFinders.swift @@ -244,7 +244,7 @@ public extension AccessDataSource { // Finders * * Example: * ```swift - * let a = personDataSource.find("firstCustomer") + * let a = personDataSource.find("firstCustomer") // fetchspec * ``` * or: * ```swift @@ -260,14 +260,7 @@ public extension AccessDataSource { // Finders func find(_ name: String, _ bindings: Any? = nil) throws -> Object? { guard let entity = entity else { return nil } guard var fs = entity[fetchSpecification: name] else { return nil } - - if let bindings = bindings { - guard let cfs = try fs.fetchSpecificiationWith(bindings: bindings) else { - return nil - } - fs = cfs - } - + fs = try fs.resolvingBindings(bindings) return try find(fs) } /** diff --git a/Sources/ZeeQL/Control/FetchSpecification.swift b/Sources/ZeeQL/Control/FetchSpecification.swift index bbd505c..be55b91 100644 --- a/Sources/ZeeQL/Control/FetchSpecification.swift +++ b/Sources/ZeeQL/Control/FetchSpecification.swift @@ -39,7 +39,7 @@ public protocol FetchSpecification : SmartDescription { var hints : [ String : Any ] { get set } subscript(hint h: String) -> Any? { get set } - func fetchSpecificiationWith(bindings: Any?) throws -> FetchSpecification? + func resolvingBindings(_ bindings: Any?) throws -> FetchSpecification } public protocol AdaptorRecordFetchSpecification : FetchSpecification { @@ -111,18 +111,18 @@ extension FetchSpecification { // Default Imp } /** - * Return a copy of the fetch specification which has the qualifier bindings - * resolved against the given argument. Plus all xyzBindPattern hints. + * Return a copy of the ``FetchSpecification`` which has the qualifier + * bindings resolved against the given argument. Plus all xyzBindPattern + * hints. * If the fetch spec has no bindings, the exisiting object is returned. * - * The syntax for bindings in string qualifiers is $binding (e.g. - * lastname = $lastname). + * The syntax for bindings in string qualifiers is `$binding` (e.g. + * `lastname = $lastname`). * - * The syntax for bind-pattern hints is '%(binding)s'. + * The syntax for bind-pattern hints is `%(binding)s` (note the trailing + * format specifier!). */ - public func fetchSpecificiationWithBindings(_ bindings: Any?) throws - -> FetchSpecification? - { + public func resolvingBindings(_ bindings: Any?) throws -> FetchSpecification { var boundFS = self boundFS.hints = resolveHintBindPatternsWith(bindings: bindings) @@ -135,13 +135,6 @@ extension FetchSpecification { // Default Imp return boundFS } - - @inlinable // TODO: deprecate - public func fetchSpecificiationWith(bindings: Any?) throws - -> FetchSpecification? - { - return try fetchSpecificiationWithBindings(bindings) - } } From fe59d540a6df689a34d01399a4b8e420f287f4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20He=C3=9F?= Date: Sat, 7 Dec 2024 16:46:47 +0100 Subject: [PATCH 2/8] Do not resolve if not necessary ... --- .../ZeeQL/Control/FetchSpecification.swift | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/Sources/ZeeQL/Control/FetchSpecification.swift b/Sources/ZeeQL/Control/FetchSpecification.swift index be55b91..87d7072 100644 --- a/Sources/ZeeQL/Control/FetchSpecification.swift +++ b/Sources/ZeeQL/Control/FetchSpecification.swift @@ -80,22 +80,26 @@ extension FetchSpecification { // Default Imp /** * FIXME: document me. This seems to return values for all hints which end in * 'BindPattern'. The values are retrieved by applying the - * KeyValueStringFormatter with the given object. + * `KeyValueStringFormatter` with the given object. * - * This formatter does stuff like '%(lastname)s'. + * This formatter does stuff like `%(lastname)s`. * * Sample: - * - * var fs = FetchSpecification() - * fs[hint: "CustomQueryExpressionHintKeyBindPattern"] = - * "%%(tables)s WHERE id = %(id)s" + * ```swift + * var fs = FetchSpecification() + * fs[hint: "CustomQueryExpressionHintKeyBindPattern"] = + * "%%(tables)s WHERE id = %(id)s" + * ``` */ - func resolveHintBindPatternsWith(bindings: Any?) -> [ String : Any ] { - guard !hints.isEmpty else { return [:] } + @usableFromInline + func resolveHintBindPatterns(with bindings: Any?) -> [ String : Any ]? { + guard !hints.isEmpty else { return nil } + var didBind = false var boundHints = hints for ( key, value ) in hints { guard key.hasSuffix("BindPattern") else { continue } + didBind = true let sValue = "\(value)" // Hm @@ -107,7 +111,10 @@ extension FetchSpecification { // Default Imp boundHints.removeValue(forKey: key) boundHints[bKey] = fValue } - return boundHints + return didBind ? boundHints : nil + } + var hasUnresolvedBindPatterns: Bool { + hints.keys.contains(where: { $0.hasSuffix("BindPattern") }) } /** @@ -122,17 +129,19 @@ extension FetchSpecification { // Default Imp * The syntax for bind-pattern hints is `%(binding)s` (note the trailing * format specifier!). */ + @inlinable public func resolvingBindings(_ bindings: Any?) throws -> FetchSpecification { - var boundFS = self + let newHints = resolveHintBindPatterns(with: bindings) + let hasUnresolved = qualifier?.hasUnresolvedBindings ?? false + if newHints == nil && !hasUnresolved { return self } - boundFS.hints = resolveHintBindPatternsWith(bindings: bindings) - - if let q = qualifier { + var boundFS = self + if let newHints { boundFS.hints = newHints } + if hasUnresolved, let q = boundFS.qualifier { boundFS.qualifier = try q.qualifierWith(bindings: bindings, requiresAll: requiresAllQualifierBindingVariables) } - return boundFS } } From 32e2beb825e4b4cf619e3e96a324deedd8335a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20He=C3=9F?= Date: Sun, 8 Dec 2024 15:41:20 +0100 Subject: [PATCH 3/8] Remove an ambiguous overload ... --- Sources/ZeeQL/Control/KeyValueQualifier.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/ZeeQL/Control/KeyValueQualifier.swift b/Sources/ZeeQL/Control/KeyValueQualifier.swift index d84c402..1676655 100644 --- a/Sources/ZeeQL/Control/KeyValueQualifier.swift +++ b/Sources/ZeeQL/Control/KeyValueQualifier.swift @@ -25,7 +25,7 @@ public struct KeyValueQualifier : Qualifier, Equatable { self.init(StringKey(key), op, value) } @inlinable - public init(_ key: String, _ op: String = "==", _ value: Any?) { + public init(_ key: String, _ op: String, _ value: Any?) { self.init(StringKey(key), ComparisonOperation(string: op), value) } From 75e1c87fa1a6d69c2f00f530b841a7e0b0a30f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20He=C3=9F?= Date: Sun, 8 Dec 2024 15:47:49 +0100 Subject: [PATCH 4/8] Improve support for optional values `Any?` casting easily gets into the way. Adds the popular `AnyOptional` :-) --- Sources/ZeeQL/Control/KeyValueQualifier.swift | 33 ++++++++++- Sources/ZeeQL/Foundation/AnyOptional.swift | 56 +++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 Sources/ZeeQL/Foundation/AnyOptional.swift diff --git a/Sources/ZeeQL/Control/KeyValueQualifier.swift b/Sources/ZeeQL/Control/KeyValueQualifier.swift index 1676655..0bf486d 100644 --- a/Sources/ZeeQL/Control/KeyValueQualifier.swift +++ b/Sources/ZeeQL/Control/KeyValueQualifier.swift @@ -18,20 +18,47 @@ public struct KeyValueQualifier : Qualifier, Equatable { self.value = value self.operation = op } + @inlinable public init(_ key: String, _ op: ComparisonOperation = .EqualTo, _ value: Any?) { self.init(StringKey(key), op, value) } + + @inlinable + public init(_ key: Key, _ op: ComparisonOperation = .EqualTo, _ value: T) + where T: AnyOptional + { + self.keyExpr = key + self.value = value.value + self.operation = op + } + @inlinable + public init(_ key: String, _ op: ComparisonOperation = .EqualTo, + _ value: T) + where T: AnyOptional + { + self.init(StringKey(key), op, value) + } + @inlinable public init(_ key: String, _ op: String, _ value: Any?) { self.init(StringKey(key), ComparisonOperation(string: op), value) } + + // MARK: - Properties + @inlinable public var key : String { return keyExpr.key } + @inlinable + public var isEmpty : Bool { return false } + + + // MARK: - Expressions + @inlinable public var leftExpression : Expression { return keyExpr } public var rightExpression : Expression { @@ -39,14 +66,14 @@ public struct KeyValueQualifier : Qualifier, Equatable { return ConstantValue(value: value) } + + // MARK: - Variables + @inlinable public var variable : QualifierVariable? { return value as? QualifierVariable } - @inlinable - public var isEmpty : Bool { return false } - @inlinable public func addReferencedKeys(to set: inout Set) { set.insert(keyExpr.key) diff --git a/Sources/ZeeQL/Foundation/AnyOptional.swift b/Sources/ZeeQL/Foundation/AnyOptional.swift new file mode 100644 index 0000000..f608d73 --- /dev/null +++ b/Sources/ZeeQL/Foundation/AnyOptional.swift @@ -0,0 +1,56 @@ +// +// Created by Helge Heß. +// Copyright © 2023-2024 ZeeZide GmbH. +// + +/** + * An internal type eraser for the `Optional` enum. + * + * Note that `Optional` is not a protocol, so `any Optional` doesn't fly. + * + * To check whether a type is an optional type: + * ```swift + * Int.self is any AnyOptional.Type // false + * Int?.self is any AnyOptional.Type // true + * ``` + */ +public protocol AnyOptional { + + associatedtype Wrapped + + /// Returns `true` if the optional has a value attached, i.e. is not `nil` + var isSome : Bool { get } + + /// Returns the attached value as an `Any`, or `nil`. + var value : Any? { get } + + /// Returns the dynamic type of the `Wrapped` value of the optional. + static var wrappedType : Any.Type { get } + + static var noneValue : Self { get } +} + +extension Optional : AnyOptional { + + @inlinable + public static var noneValue : Self { .none } + + @inlinable + public var isSome : Bool { + switch self { + case .none: return false + case .some: return true + } + } + + @inlinable + public var value : Any? { + switch self { + case .none: nil + case .some(let unwrapped): unwrapped + } + } + + @inlinable + public static var wrappedType : Any.Type { Wrapped.self } +} From d57a15802a2f293548a790f907bc258714f16b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20He=C3=9F?= Date: Sun, 8 Dec 2024 15:51:40 +0100 Subject: [PATCH 5/8] Intro `TypedKey` and `TypedProperty` Those are `Key`s and `Property`s that statically know the value type they refer too. For example `CodeAttribute`'s. --- Sources/ZeeQL/Access/CodeAttribute.swift | 2 +- Sources/ZeeQL/Access/CodeRelationship.swift | 5 ++++- Sources/ZeeQL/Access/Property.swift | 12 ++++++++++-- Sources/ZeeQL/Control/Key.swift | 4 ++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Sources/ZeeQL/Access/CodeAttribute.swift b/Sources/ZeeQL/Access/CodeAttribute.swift index 67ce3e0..47eecc3 100644 --- a/Sources/ZeeQL/Access/CodeAttribute.swift +++ b/Sources/ZeeQL/Access/CodeAttribute.swift @@ -14,7 +14,7 @@ * Their primary feature over `ModelAttribute`s is that such are generic over * the value type. */ -open class CodeAttribute : ModelAttribute { +open class CodeAttribute : ModelAttribute, TypedProperty { // Note: we remove the keyword @inlinable diff --git a/Sources/ZeeQL/Access/CodeRelationship.swift b/Sources/ZeeQL/Access/CodeRelationship.swift index b05a7fb..0ea41c4 100644 --- a/Sources/ZeeQL/Access/CodeRelationship.swift +++ b/Sources/ZeeQL/Access/CodeRelationship.swift @@ -192,8 +192,11 @@ open class CodeRelationshipBase } open class CodeRelationship - : CodeRelationshipBase, CodeRelationshipType + : CodeRelationshipBase, CodeRelationshipType, + TypedProperty { + public typealias T = Target + public var codeEntity : Entity? = nil override open var entity : Entity { set { diff --git a/Sources/ZeeQL/Access/Property.swift b/Sources/ZeeQL/Access/Property.swift index f6b41f4..4cb6b28 100644 --- a/Sources/ZeeQL/Access/Property.swift +++ b/Sources/ZeeQL/Access/Property.swift @@ -3,11 +3,11 @@ // ZeeQL // // Created by Helge Heß on 18.02.17. -// Copyright © 2017-2021 ZeeZide GmbH. All rights reserved. +// Copyright © 2017-2024 ZeeZide GmbH. All rights reserved. // /** - * A property of an `Entity`: Either an `Attribute` or a `Relationship`. + * A property of an ``Entity``: Either an ``Attribute`` or a ``Relationship``. */ public protocol Property : AnyObject, EquatableType { // `class` because we use identity in some places @@ -16,3 +16,11 @@ public protocol Property : AnyObject, EquatableType { var relationshipPath : String? { get } } + +/** + * A property of an ``Entity``: Either an ``Attribute`` or a ``Relationship``, + * that knows the static type of the property. + */ +public protocol TypedProperty: Property { + associatedtype T +} diff --git a/Sources/ZeeQL/Control/Key.swift b/Sources/ZeeQL/Control/Key.swift index 8cced5d..c70105d 100644 --- a/Sources/ZeeQL/Control/Key.swift +++ b/Sources/ZeeQL/Control/Key.swift @@ -33,6 +33,10 @@ public protocol Key : Expression, ExpressionEvaluation, EquatableType, func append(_ key: Key) -> Key } +public protocol TypedKey: Key { + associatedtype T +} + public extension Key { // MARK: - value From 5d71e3af0a30af625472d3248446b1dfdb86e61b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20He=C3=9F?= Date: Sun, 8 Dec 2024 15:52:59 +0100 Subject: [PATCH 6/8] Rework builders to work w/ any `TypedProperty` Not just `CodeAttribute` and specific `prefetch` relationships. This also allows usage of toOne and toMany in a single prefetch. --- .../ZeeQL/Control/EntityType+Builder.swift | 45 +++++------ .../Control/FetchSpecification+Builder.swift | 79 ++++++------------- 2 files changed, 47 insertions(+), 77 deletions(-) diff --git a/Sources/ZeeQL/Control/EntityType+Builder.swift b/Sources/ZeeQL/Control/EntityType+Builder.swift index 1506b92..f91ae1f 100644 --- a/Sources/ZeeQL/Control/EntityType+Builder.swift +++ b/Sources/ZeeQL/Control/EntityType+Builder.swift @@ -113,53 +113,50 @@ public extension TypedEntityObject { public extension TypedEntityType where FullEntity: CodeEntity { // TODO: select w/ pack iteration + + // Maybe the `where` should work on typed keys! @inlinable - static func `where`( - _ key: Swift.KeyPath>, - _ operation: ComparisonOperation, - _ value: V + static func `where`( + _ key : Swift.KeyPath, + _ operation : ComparisonOperation, + _ value : A.T ) -> TypedFetchSpecification - where V: AttributeValue { // if we need no attributes var fs = TypedFetchSpecification(entity: Self.entity) - let attribute = Self.e[keyPath: key] - fs.qualifier = KeyValueQualifier(AttributeKey(attribute), operation, value) + let property = Self.e[keyPath: key] + fs.qualifier = KeyValueQualifier(StringKey(property.name), operation, value) return fs } @inlinable - static func `where`( - _ key: Swift.KeyPath>, - _ value: V - ) -> TypedFetchSpecification - where V: AttributeValue + static func `where`(_ key: Swift.KeyPath, + _ value: A.T) -> TypedFetchSpecification + where A: TypedProperty { return `where`(key, .EqualTo, value) } @inlinable - static func `where`( - _ key: Swift.KeyPath>, - _ operation: ComparisonOperation, - _ value: V? + static func `where`( + _ key : Swift.KeyPath, + _ operation : ComparisonOperation = .EqualTo, + _ value : A.T ) -> TypedFetchSpecification - where V: AttributeValue + where A: TypedProperty, A.T: AnyOptional { // if we need no attributes var fs = TypedFetchSpecification(entity: Self.entity) - let attribute = Self.e[keyPath: key] - fs.qualifier = KeyValueQualifier(AttributeKey(attribute), operation, value) + let property = Self.e[keyPath: key] + fs.qualifier = KeyValueQualifier(StringKey(property.name), operation, value) return fs } @inlinable - static func `where`( - _ key: Swift.KeyPath>, - _ value: V? - ) -> TypedFetchSpecification - where V: AttributeValue + static func `where`(_ key: Swift.KeyPath, + _ value: A.T) -> TypedFetchSpecification + where A: TypedProperty, A.T: AnyOptional { return `where`(key, .EqualTo, value) } diff --git a/Sources/ZeeQL/Control/FetchSpecification+Builder.swift b/Sources/ZeeQL/Control/FetchSpecification+Builder.swift index 0d46c75..de21b90 100644 --- a/Sources/ZeeQL/Control/FetchSpecification+Builder.swift +++ b/Sources/ZeeQL/Control/FetchSpecification+Builder.swift @@ -195,39 +195,39 @@ public extension DatabaseFetchSpecification // TODO: select w/ pack iteration // MARK: - Qualifier - + + // Maybe the `where` should work on typed keys! + @inlinable - func `where`(_ key: Swift.KeyPath>, - _ operation: ComparisonOperation, - _ value: V) -> Self - where V: AttributeValue + func `where`(_ key: Swift.KeyPath, + _ operation: ComparisonOperation, + _ value: A.T) -> Self { - let attribute = Object.e[keyPath: key] - return `where`(KeyValueQualifier(AttributeKey(attribute), operation, value)) + let property = Object.e[keyPath: key] + return `where`(KeyValueQualifier(StringKey(property.name), operation,value)) } @inlinable - func `where`(_ key: Swift.KeyPath>, - _ value: V) -> Self - where V: AttributeValue + func `where`(_ key: Swift.KeyPath, + _ value: A.T) -> Self { return `where`(key, .EqualTo, value) } @inlinable - func `where`(_ key: Swift.KeyPath>, - _ operation: ComparisonOperation, - _ value: V?) -> Self - where V: AttributeValue + func `where`(_ key: Swift.KeyPath, + _ operation: ComparisonOperation, + _ value: A.T) -> Self + where A: TypedProperty, A.T: AnyOptional { - let attribute = Object.e[keyPath: key] - return `where`(KeyValueQualifier(AttributeKey(attribute), operation, value)) + let property = Object.e[keyPath: key] + return `where`(KeyValueQualifier(StringKey(property.name), operation,value)) } @inlinable - func `where`(_ key: Swift.KeyPath>, - _ value: V?) -> Self - where V: AttributeValue + func `where`(_ key: Swift.KeyPath, + _ value: A.T) -> Self + where A: TypedProperty, A.T: AnyOptional { return `where`(key, .EqualTo, value) } @@ -236,8 +236,9 @@ public extension DatabaseFetchSpecification // MARK: - Ordering #if compiler(>=6) - func order( - by key: repeat Swift.KeyPath>, + @inlinable + func order( + by key: repeat Swift.KeyPath, using selector: SortOrdering.Selector = .CompareAscending ) -> Self { @@ -266,39 +267,10 @@ public extension DatabaseFetchSpecification // MARK: - Prefetch #if compiler(>=6) - // TODO: can we do both toOne and toMany in one? - // a KeyPath that has the parent class (CodeRelationship) doesn't work? - func prefetch( - _ relationship: - repeat Swift.KeyPath>, - clear: Bool = false - ) -> Self - { - transform { - if clear { $0.prefetchingRelationshipKeyPathes = [] } - for relationship in repeat each relationship { - let relationship = Object.e[keyPath: relationship] - $0.prefetchingRelationshipKeyPathes.append(relationship.name) - } - } - } - func prefetch( - _ relationship: - repeat Swift.KeyPath>, - clear: Bool = false - ) -> Self - { - transform { - if clear { $0.prefetchingRelationshipKeyPathes = [] } - for relationship in repeat each relationship { - let relationship = Object.e[keyPath: relationship] - $0.prefetchingRelationshipKeyPathes.append(relationship.name) - } - } - } - func prefetch( + @inlinable + func prefetch( _ relationship: - repeat Swift.KeyPath>, + repeat Swift.KeyPath, clear: Bool = false ) -> Self { @@ -310,5 +282,6 @@ public extension DatabaseFetchSpecification } } } + #endif // compiler(>=6) } From ee8f023acbd556bd424768432213b03a98d9281e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20He=C3=9F?= Date: Sun, 8 Dec 2024 15:58:13 +0100 Subject: [PATCH 7/8] More inlinable ... --- Sources/ZeeQL/Access/Attribute.swift | 5 ++++- Sources/ZeeQL/Access/AttributeKey.swift | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/ZeeQL/Access/Attribute.swift b/Sources/ZeeQL/Access/Attribute.swift index 273e3f1..768712b 100644 --- a/Sources/ZeeQL/Access/Attribute.swift +++ b/Sources/ZeeQL/Access/Attribute.swift @@ -418,12 +418,14 @@ open class ModelAttribute : Attribute, Equatable { public extension Attribute { + @inlinable func eq(_ attr: Attribute) -> KeyComparisonQualifier { let key = AttributeKey(self) let otherKey = AttributeKey(attr) return KeyComparisonQualifier(key, .EqualTo, otherKey) } + @inlinable func eq(_ value : Any?) -> KeyValueQualifier { let key = AttributeKey(self) return KeyValueQualifier(key, .EqualTo, value) @@ -431,7 +433,8 @@ public extension Attribute { } public extension Attribute { - + + @inlinable func like(_ pattern : String) -> KeyValueQualifier { let key = AttributeKey(self) return KeyValueQualifier(key, .Like, pattern) diff --git a/Sources/ZeeQL/Access/AttributeKey.swift b/Sources/ZeeQL/Access/AttributeKey.swift index 541d0b7..9191707 100644 --- a/Sources/ZeeQL/Access/AttributeKey.swift +++ b/Sources/ZeeQL/Access/AttributeKey.swift @@ -14,6 +14,7 @@ */ public struct AttributeKey : Key, Equatable { + @inlinable public var key : String { return attribute.name } public let entity : Entity? From 66cadffea463294b7cbe543a47fc9f30b8822600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20He=C3=9F?= Date: Sun, 8 Dec 2024 16:32:41 +0100 Subject: [PATCH 8/8] Add AnyOptional to pbx ... --- ZeeQL3.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ZeeQL3.xcodeproj/project.pbxproj b/ZeeQL3.xcodeproj/project.pbxproj index fce6116..d65a4c3 100644 --- a/ZeeQL3.xcodeproj/project.pbxproj +++ b/ZeeQL3.xcodeproj/project.pbxproj @@ -77,6 +77,9 @@ E81B62D51E65E39A00D43EFA /* BooleanQualifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81B62D41E65E39A00D43EFA /* BooleanQualifier.swift */; }; E81B62D71E65E3B500D43EFA /* SQLQualifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81B62D61E65E3B500D43EFA /* SQLQualifier.swift */; }; E81B62D91E65E3E200D43EFA /* NotQualifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81B62D81E65E3E200D43EFA /* NotQualifier.swift */; }; + E822957A2D05F38700F4DD57 /* AnyOptional.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82295792D05F38700F4DD57 /* AnyOptional.swift */; }; + E822957B2D05F38700F4DD57 /* AnyOptional.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82295792D05F38700F4DD57 /* AnyOptional.swift */; }; + E822957C2D05F38700F4DD57 /* AnyOptional.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82295792D05F38700F4DD57 /* AnyOptional.swift */; }; E823BC7D1EEC284900483A97 /* SQLForeignKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = E823BC7C1EEC284900483A97 /* SQLForeignKey.swift */; }; E823BC7E1EEC284900483A97 /* SQLForeignKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = E823BC7C1EEC284900483A97 /* SQLForeignKey.swift */; }; E823BC801EEC28AC00483A97 /* SQLAttributeChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = E823BC7F1EEC28AC00483A97 /* SQLAttributeChange.swift */; }; @@ -483,6 +486,7 @@ E81B62D41E65E39A00D43EFA /* BooleanQualifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BooleanQualifier.swift; path = Sources/ZeeQL/Control/BooleanQualifier.swift; sourceTree = SOURCE_ROOT; }; E81B62D61E65E3B500D43EFA /* SQLQualifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SQLQualifier.swift; path = Sources/ZeeQL/Control/SQLQualifier.swift; sourceTree = SOURCE_ROOT; }; E81B62D81E65E3E200D43EFA /* NotQualifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NotQualifier.swift; path = Sources/ZeeQL/Control/NotQualifier.swift; sourceTree = SOURCE_ROOT; }; + E82295792D05F38700F4DD57 /* AnyOptional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyOptional.swift; sourceTree = ""; }; E823BC7C1EEC284900483A97 /* SQLForeignKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SQLForeignKey.swift; path = Sources/ZeeQL/Access/SQLForeignKey.swift; sourceTree = SOURCE_ROOT; }; E823BC7F1EEC28AC00483A97 /* SQLAttributeChange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SQLAttributeChange.swift; path = Sources/ZeeQL/Access/SQLAttributeChange.swift; sourceTree = SOURCE_ROOT; }; E823BC821EEC296900483A97 /* SQLTableGroups.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SQLTableGroups.swift; path = Sources/ZeeQL/Access/SQLTableGroups.swift; sourceTree = SOURCE_ROOT; }; @@ -838,6 +842,7 @@ E8D2797B1E5515E900453BBE /* Foundation */ = { isa = PBXGroup; children = ( + E82295792D05F38700F4DD57 /* AnyOptional.swift */, E80B3FD01E606D4800D6F0ED /* EquatableType.swift */, E80B3FD11E606D4800D6F0ED /* SimpleKVC.swift */, E80B3FD21E606D4800D6F0ED /* TimeRange.swift */, @@ -1283,6 +1288,7 @@ E8263CC31E93C89200508276 /* CodeAttribute.swift in Sources */, E892D1B72D010656003489FC /* FetchSpecification+Builder.swift in Sources */, E8263CA01E93C89200508276 /* KeyValueQualifier.swift in Sources */, + E822957A2D05F38700F4DD57 /* AnyOptional.swift in Sources */, E8263C911E93C89200508276 /* EquatableType.swift in Sources */, E8E480C01EC2033700350EDF /* ArrayDataSource.swift in Sources */, E802854D1EE6CDCF00F25AD7 /* SQLite3SchemaSynchronizationFactory.swift in Sources */, @@ -1414,6 +1420,7 @@ E892D1B62D010656003489FC /* FetchSpecification+Builder.swift in Sources */, E8ACA3512313E48F000F6BEC /* QualifierEvaluation.swift in Sources */, E8ACA37F2313E4A8000F6BEC /* Model.swift in Sources */, + E822957B2D05F38700F4DD57 /* AnyOptional.swift in Sources */, E8ACA3712313E49C000F6BEC /* AdaptorRecord.swift in Sources */, E8ACA36D2313E498000F6BEC /* AccessDataSourceError.swift in Sources */, E8ACA39F2313E4C1000F6BEC /* SQLite3ModelFetch.swift in Sources */, @@ -1518,6 +1525,7 @@ E892D1B52D010656003489FC /* FetchSpecification+Builder.swift in Sources */, E824EA951E63953600215ABA /* StoreKeyValueCoding.swift in Sources */, E802854C1EE6CDCF00F25AD7 /* SQLite3SchemaSynchronizationFactory.swift in Sources */, + E822957C2D05F38700F4DD57 /* AnyOptional.swift in Sources */, E89FCACE1E68DE2000ED9216 /* DatabaseContext.swift in Sources */, E80B3FC41E606D1E00D6F0ED /* Constant.swift in Sources */, E80B3FB21E606D1700D6F0ED /* Join.swift in Sources */,