diff --git a/Sources/ZeeQL/Access/AccessDataSourceFinders.swift b/Sources/ZeeQL/Access/AccessDataSourceFinders.swift index 2a1c787..f5de242 100644 --- a/Sources/ZeeQL/Access/AccessDataSourceFinders.swift +++ b/Sources/ZeeQL/Access/AccessDataSourceFinders.swift @@ -3,7 +3,7 @@ // ZeeQL // // Created by Helge Heß on 22.08.19. -// Copyright © 2019 ZeeZide GmbH. All rights reserved. +// Copyright © 2019-2024 ZeeZide GmbH. All rights reserved. // public extension AccessDataSource { @@ -206,8 +206,8 @@ public extension AccessDataSource { // Finders var fs = try fetchSpecificationForFetch() fs.qualifier = and(q, auxiliaryQualifier) - fs.sortOrderings = nil /* no sorting, makes DB faster */ - fs.fetchLimit = 1 /* we just want to find one record */ + fs.sortOrderings = [] /* no sorting, makes DB faster */ + fs.fetchLimit = 1 /* we just want to find one record */ return fs } diff --git a/Sources/ZeeQL/Access/ActiveDataSource.swift b/Sources/ZeeQL/Access/ActiveDataSource.swift index 6ea716c..3b72b76 100644 --- a/Sources/ZeeQL/Access/ActiveDataSource.swift +++ b/Sources/ZeeQL/Access/ActiveDataSource.swift @@ -139,7 +139,7 @@ open class ActiveDataSource: AccessDataSource, var cfs = fs cfs.fetchesReadOnly = true cfs.fetchAttributeNames = pkeys - cfs.prefetchingRelationshipKeyPathes = nil + cfs.prefetchingRelationshipKeyPathes = [] let pkeyAttrs = pkeys.compactMap { entity[attribute: $0] } assert(pkeyAttrs.count == pkeys.count, "could not lookup all pkeys!") @@ -177,7 +177,7 @@ open class ActiveDataSource: AccessDataSource, // The idea is that this preserves the WHERE part of the query, including // relationships. var cfs = fs - cfs.sortOrderings = nil // no need to sort + cfs.sortOrderings = [] // no need to sort // hm, well, OK. cfs.fetchLimit = 1 // TBD: could use '2' to detect query issues diff --git a/Sources/ZeeQL/Access/AdaptorChannel.swift b/Sources/ZeeQL/Access/AdaptorChannel.swift index 161cf67..e30e823 100644 --- a/Sources/ZeeQL/Access/AdaptorChannel.swift +++ b/Sources/ZeeQL/Access/AdaptorChannel.swift @@ -369,8 +369,8 @@ public extension AdaptorChannel { // MARK: - Operations attributes = attrs } else if let entity = e { - if let fs = fs, let an = fs.fetchAttributeNames { - attributes = entity.attributesWithNames(an) + if let fs = fs, !fs.fetchAttributeNames.isEmpty { + attributes = entity.attributesWithNames(fs.fetchAttributeNames) } else { attributes = entity.attributes diff --git a/Sources/ZeeQL/Access/CodeAttribute.swift b/Sources/ZeeQL/Access/CodeAttribute.swift index 4982487..67ce3e0 100644 --- a/Sources/ZeeQL/Access/CodeAttribute.swift +++ b/Sources/ZeeQL/Access/CodeAttribute.swift @@ -3,7 +3,7 @@ // ZeeQL // // Created by Helge Hess on 01/03/2017. -// Copyright © 2017 ZeeZide GmbH. All rights reserved. +// Copyright © 2017-2024 ZeeZide GmbH. All rights reserved. // /** @@ -17,6 +17,7 @@ open class CodeAttribute : ModelAttribute { // Note: we remove the keyword + @inlinable public init(_ name : String? = nil, column : String? = nil, externalType : String? = nil, @@ -40,16 +41,15 @@ open class CodeAttribute : ModelAttribute { public protocol SQLLikeType {} extension String : SQLLikeType {} -extension Optional : SQLLikeType {} // sigh: to support Optional - // needs: conditional conformance, maybe Swift 4 +extension Optional : SQLLikeType where Wrapped: SQLLikeType {} public extension CodeAttribute where T : SQLLikeType { + @inlinable func like(_ pattern : String) -> KeyValueQualifier { let key = AttributeKey(self) return KeyValueQualifier(key, .Like, pattern) - } - + } } diff --git a/Sources/ZeeQL/Access/DatabaseChannel.swift b/Sources/ZeeQL/Access/DatabaseChannel.swift index 58a1505..fa3dce4 100644 --- a/Sources/ZeeQL/Access/DatabaseChannel.swift +++ b/Sources/ZeeQL/Access/DatabaseChannel.swift @@ -1186,9 +1186,7 @@ open class TypedDatabaseChannel : DatabaseChannelBase, _ ec: ObjectTrackingContext? = nil ) throws { - guard let prefetchRelPathes = fs.prefetchingRelationshipKeyPathes, - !prefetchRelPathes.isEmpty else - { + guard !fs.prefetchingRelationshipKeyPathes.isEmpty else { /* simple case, no prefetches */ return try primarySelectObjectsWithFetchSpecification(fs, ec) } @@ -1273,7 +1271,8 @@ open class TypedDatabaseChannel : DatabaseChannelBase, do { try fetchRelationships(fs.entity, entityName, - prefetchRelPathes, baseObjects, ec) + fs.prefetchingRelationshipKeyPathes, + baseObjects, ec) } catch { cancelFetch() @@ -1347,9 +1346,7 @@ open class DatabaseChannel : DatabaseChannelBase, IteratorProtocol { = nil) throws { - guard let prefetchRelPathes = fs.prefetchingRelationshipKeyPathes, - !prefetchRelPathes.isEmpty - else { + guard !fs.prefetchingRelationshipKeyPathes.isEmpty else { /* simple case, no prefetches */ return try primarySelectObjectsWithFetchSpecification(fs, ec) } @@ -1425,7 +1422,8 @@ open class DatabaseChannel : DatabaseChannelBase, IteratorProtocol { do { try fetchRelationships(fs.entity, entityName, - prefetchRelPathes, baseObjects, ec) + fs.prefetchingRelationshipKeyPathes, + baseObjects, ec) } catch { cancelFetch() diff --git a/Sources/ZeeQL/Access/ModelLoader.swift b/Sources/ZeeQL/Access/ModelLoader.swift index b32b003..30dbfc9 100644 --- a/Sources/ZeeQL/Access/ModelLoader.swift +++ b/Sources/ZeeQL/Access/ModelLoader.swift @@ -320,9 +320,8 @@ open class CoreDataModelLoader : ModelLoader { } else { limit = nil } - let sos : [ SortOrdering ]? = nil var fs = ModelFetchSpecification(entity: entity, qualifier: q, - sortOrderings: sos, limit: limit) + sortOrderings: [], limit: limit) fs.usesDistinct = boolValue(attrs["returnDistinctResults"]) @@ -356,17 +355,11 @@ open class CoreDataModelLoader : ModelLoader { for xml in xml.childElementsWithName("ordering") { // `` (multiple are possible!) guard let ordering = loadSortOrdering(from: xml) else { continue } - if fs.sortOrderings == nil { fs.sortOrderings = [] } - fs.sortOrderings?.append(ordering) + fs.sortOrderings.append(ordering) } if let v = attrs["attributes"]?.split(separator: ","), !v.isEmpty { - if fs.fetchAttributeNames == nil { - fs.fetchAttributeNames = v.map(String.init) - } - else { - fs.fetchAttributeNames?.append(contentsOf: v.map(String.init)) - } + fs.fetchAttributeNames.append(contentsOf: v.map(String.init)) } for xml in xml.childElementsWithName("attributes") { // objectId,permissions @@ -374,12 +367,7 @@ open class CoreDataModelLoader : ModelLoader { assertionFailure(" tag w/o content?") continue } - if fs.fetchAttributeNames == nil { - fs.fetchAttributeNames = v.map(String.init) - } - else { - fs.fetchAttributeNames?.append(contentsOf: v.map(String.init)) - } + fs.fetchAttributeNames.append(contentsOf: v.map(String.init)) } if let xml = xml.firstChildElementWithName("qualifier") { // (principalId IN $authIds) AND (objectId IN $ids) diff --git a/Sources/ZeeQL/Access/TypedFetchSpecification.swift b/Sources/ZeeQL/Access/TypedFetchSpecification.swift index 70a18d9..b197ea1 100644 --- a/Sources/ZeeQL/Access/TypedFetchSpecification.swift +++ b/Sources/ZeeQL/Access/TypedFetchSpecification.swift @@ -42,9 +42,9 @@ public struct TypedFetchSpecification return nil } - public var fetchAttributeNames : [ String ]? + public var fetchAttributeNames = [ String ]() public var qualifier : Qualifier? - public var sortOrderings : [ SortOrdering ]? + public var sortOrderings = [ SortOrdering ]() public var fetchLimit : Int? public var fetchOffset : Int? public var hints = [ String : Any ]() @@ -55,14 +55,14 @@ public struct TypedFetchSpecification public var fetchesRawRows = false public var fetchesReadOnly = false public var requiresAllQualifierBindingVariables = false - public var prefetchingRelationshipKeyPathes : [ String ]? + public var prefetchingRelationshipKeyPathes = [ String ]() @inlinable - public init(entityName : String? = nil, - qualifier : Qualifier? = nil, - sortOrderings : [ SortOrdering ]? = nil, - limit : Int? = nil, - prefetch : [ String ]? = nil, + public init(entityName : String? = nil, + qualifier : Qualifier? = nil, + sortOrderings : [ SortOrdering ] = [], + limit : Int? = nil, + prefetch : [ String ] = [], requiresAllQualifierBindingVariables: Bool = false) { self._entityName = entityName @@ -76,10 +76,10 @@ public struct TypedFetchSpecification @inlinable public init(entity : Entity, - qualifier : Qualifier? = nil, - sortOrderings : [ SortOrdering ]? = nil, - limit : Int? = nil, - prefetch : [ String ]? = nil, + qualifier : Qualifier? = nil, + sortOrderings : [ SortOrdering ] = [], + limit : Int? = nil, + prefetch : [ String ] = [], requiresAllQualifierBindingVariables: Bool = false) { self._entity = entity @@ -94,9 +94,9 @@ public struct TypedFetchSpecification /// Initialize w/ a qualifier string. public init(entity : Entity, _ q : String, - sortOrderings : [ SortOrdering ]? = nil, - limit : Int? = nil, - prefetch : [ String ]? = nil) + sortOrderings : [ SortOrdering ] = [], + limit : Int? = nil, + prefetch : [ String ] = []) { self._entity = entity self.qualifier = qualifierWith(format: q) @@ -106,3 +106,41 @@ public struct TypedFetchSpecification } } + +extension TypedFetchSpecification: Equatable { + + public static func ==(lhs: Self, rhs: Self) -> Bool { + guard lhs.usesDistinct == rhs.usesDistinct, + lhs.locksObjects == rhs.locksObjects, + lhs.deep == rhs.deep, + lhs.requiresAllQualifierBindingVariables == + rhs.requiresAllQualifierBindingVariables, + lhs.prefetchingRelationshipKeyPathes == + rhs.prefetchingRelationshipKeyPathes, + lhs.fetchesRawRows == rhs.fetchesRawRows, + lhs.fetchesReadOnly == rhs.fetchesReadOnly, + lhs.fetchAttributeNames == rhs.fetchAttributeNames, + lhs.sortOrderings == rhs.sortOrderings, + lhs.fetchLimit == rhs.fetchLimit, + lhs.fetchOffset == rhs.fetchOffset else { return false } + + if let lhs = lhs.qualifier { return lhs.isEqual(to: rhs.qualifier) } + else if rhs.qualifier != nil { return false } + + guard lhs.entityName == rhs.entityName else { return false } + if let lhs = lhs.entity { return lhs.isEqual(to: rhs.entity) } + else if rhs.entity != nil { return false } + + if lhs.hints.count != rhs.hints.count { return false } + return eq(lhs.hints, rhs.hints) + } +} +extension TypedFetchSpecification: EquatableType { + + public func isEqual(to object: Any?) -> Bool { + // TBD: Would we want to allow comparison to ModelFS and such? That *might* + // make sense? + guard let typed = object as? Self else { return false } + return self == typed + } +} diff --git a/Sources/ZeeQL/Control/ArrayDataSource.swift b/Sources/ZeeQL/Control/ArrayDataSource.swift index 70623e2..d726a97 100644 --- a/Sources/ZeeQL/Control/ArrayDataSource.swift +++ b/Sources/ZeeQL/Control/ArrayDataSource.swift @@ -66,9 +66,9 @@ open class ArrayDataSource : DataSource, } - if let sos = fs.sortOrderings, !sos.isEmpty { + if !fs.sortOrderings.isEmpty { // TODO: sort - log.warn("not applying sort orderings", self, sos) + log.warn("not applying sort orderings", self, fs.sortOrderings) } let count = filtered.count diff --git a/Sources/ZeeQL/Control/EntityType+Builder.swift b/Sources/ZeeQL/Control/EntityType+Builder.swift index 4f71d67..1506b92 100644 --- a/Sources/ZeeQL/Control/EntityType+Builder.swift +++ b/Sources/ZeeQL/Control/EntityType+Builder.swift @@ -9,11 +9,9 @@ public extension EntityType { // TBD: maybe rename, 'select' should run the actual select, right? @inlinable - static func select(_ attributes: String...) - -> FetchSpecification - { + static func select(_ attributes: String...) -> FetchSpecification { var fs = ModelFetchSpecification(entity: Self.entity) - fs.fetchAttributeNames = attributes.isEmpty ? nil : attributes + fs.fetchAttributeNames = attributes return fs } @@ -57,7 +55,7 @@ public extension TypedEntityType where Self: DatabaseObject { -> TypedFetchSpecification { var fs = TypedFetchSpecification(entity: Self.entity) - fs.fetchAttributeNames = attributes.isEmpty ? nil : attributes + fs.fetchAttributeNames = attributes return fs } @@ -137,11 +135,32 @@ public extension TypedEntityType where FullEntity: CodeEntity { _ value: V ) -> TypedFetchSpecification where V: AttributeValue + { + return `where`(key, .EqualTo, value) + } + + @inlinable + static func `where`( + _ key: Swift.KeyPath>, + _ operation: ComparisonOperation, + _ value: V? + ) -> 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), .EqualTo, value) + fs.qualifier = KeyValueQualifier(AttributeKey(attribute), operation, value) return fs } + + @inlinable + static func `where`( + _ key: Swift.KeyPath>, + _ value: V? + ) -> TypedFetchSpecification + where V: AttributeValue + { + return `where`(key, .EqualTo, value) + } } diff --git a/Sources/ZeeQL/Control/FetchSpecification+Builder.swift b/Sources/ZeeQL/Control/FetchSpecification+Builder.swift index 5d210ba..0d46c75 100644 --- a/Sources/ZeeQL/Control/FetchSpecification+Builder.swift +++ b/Sources/ZeeQL/Control/FetchSpecification+Builder.swift @@ -96,13 +96,8 @@ public extension FetchSpecification { { transform { if clear { $0.prefetchingRelationshipKeyPathes = [] } - if $0.prefetchingRelationshipKeyPathes == nil { - $0.prefetchingRelationshipKeyPathes = [ path ] - } - else { - $0.prefetchingRelationshipKeyPathes?.append(path) - $0.prefetchingRelationshipKeyPathes?.append(contentsOf: more) - } + $0.prefetchingRelationshipKeyPathes.append(path) + $0.prefetchingRelationshipKeyPathes.append(contentsOf: more) } } @inlinable @@ -114,14 +109,8 @@ public extension FetchSpecification { // `fs.prefetch(Person.e.company.addresses)` transform { if clear { $0.prefetchingRelationshipKeyPathes = [] } - if $0.prefetchingRelationshipKeyPathes == nil { - $0.prefetchingRelationshipKeyPathes = [ path.name ] - } - else { - $0.prefetchingRelationshipKeyPathes?.append(path.name) - $0.prefetchingRelationshipKeyPathes? - .append(contentsOf: more.map(\.name)) - } + $0.prefetchingRelationshipKeyPathes.append(path.name) + $0.prefetchingRelationshipKeyPathes.append(contentsOf: more.map(\.name)) } } @@ -131,26 +120,71 @@ public extension FetchSpecification { @inlinable func order(by: SortOrdering, _ e: SortOrdering...) -> Self { transform { - if let old = $0.sortOrderings { $0.sortOrderings = old + [ by ] + e } - else { $0.sortOrderings = [ by ] + e } + $0.sortOrderings.append(by) + $0.sortOrderings.append(contentsOf: e) } } @inlinable func order(by: String, _ e: String...) -> Self { transform { - var ops = [ SortOrdering ]() - if let p = SortOrdering.parse(by) { ops += p } + if let p = SortOrdering.parse(by) { $0.sortOrderings += p } + else { assertionFailure("Could not parse order string")} for by in e { - if let p = SortOrdering.parse(by) { ops += p } + if let p = SortOrdering.parse(by) { + $0.sortOrderings.append(contentsOf: p) + } + else { assertionFailure("Could not parse order string")} + } + } + } + @inlinable + func order(by : Attribute..., + asc : Attribute? = nil, + desc : Attribute? = nil, + iasc : Attribute? = nil, + idesc : Attribute? = nil) + -> Self + { + transform { fs in + for by in by { + let so = SortOrdering(key: AttributeKey(by), selector: .CompareAscending) + fs.sortOrderings.append(so) + } + if let by = asc { + let so = SortOrdering(key: AttributeKey(by), selector: .CompareAscending) + fs.sortOrderings.append(so) + } + if let by = desc { + let so = SortOrdering(key: AttributeKey(by), selector: .CompareDescending) + fs.sortOrderings.append(so) + } + if let by = iasc { + let so = SortOrdering(key: AttributeKey(by), + selector: .CompareCaseInsensitiveAscending) + fs.sortOrderings.append(so) + } + if let by = idesc { + let so = SortOrdering(key: AttributeKey(by), + selector: .CompareCaseInsensitiveDescending) + fs.sortOrderings.append(so) } - - if let old = $0.sortOrderings { $0.sortOrderings = old + ops } - else { $0.sortOrderings = ops } } } } +extension FetchSpecification { + + @inlinable + static func select(_ attributes: String..., from: T.Type) + -> FetchSpecification // <= because we need the entity + { + var fs = ModelFetchSpecification(entity: from.entity) + fs.fetchAttributeNames = attributes + return fs + } +} + // MARK: - Special Builder for CodeEntities @@ -160,6 +194,8 @@ public extension DatabaseFetchSpecification // TODO: select w/ pack iteration + // MARK: - Qualifier + @inlinable func `where`(_ key: Swift.KeyPath>, _ operation: ComparisonOperation, @@ -175,9 +211,30 @@ public extension DatabaseFetchSpecification _ value: V) -> Self where V: AttributeValue { - `where`(key, .EqualTo, value) + return `where`(key, .EqualTo, value) } + @inlinable + func `where`(_ key: Swift.KeyPath>, + _ operation: ComparisonOperation, + _ value: V?) -> Self + where V: AttributeValue + { + let attribute = Object.e[keyPath: key] + return `where`(KeyValueQualifier(AttributeKey(attribute), operation, value)) + } + + @inlinable + func `where`(_ key: Swift.KeyPath>, + _ value: V?) -> Self + where V: AttributeValue + { + return `where`(key, .EqualTo, value) + } + + + // MARK: - Ordering + #if compiler(>=6) func order( by key: repeat Swift.KeyPath>, @@ -188,8 +245,7 @@ public extension DatabaseFetchSpecification for key in repeat each key { let attribute = Object.e[keyPath: key] let so = SortOrdering(key: AttributeKey(attribute), selector: selector) - if $0.sortOrderings == nil { $0.sortOrderings = [ so ] } - else { $0.sortOrderings?.append(so) } + $0.sortOrderings.append(so) } } } @@ -206,6 +262,9 @@ public extension DatabaseFetchSpecification } #endif // !compiler(>=6) + + // 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? @@ -219,7 +278,7 @@ public extension DatabaseFetchSpecification if clear { $0.prefetchingRelationshipKeyPathes = [] } for relationship in repeat each relationship { let relationship = Object.e[keyPath: relationship] - $0.prefetchingRelationshipKeyPathes?.append(relationship.name) + $0.prefetchingRelationshipKeyPathes.append(relationship.name) } } } @@ -233,7 +292,7 @@ public extension DatabaseFetchSpecification if clear { $0.prefetchingRelationshipKeyPathes = [] } for relationship in repeat each relationship { let relationship = Object.e[keyPath: relationship] - $0.prefetchingRelationshipKeyPathes?.append(relationship.name) + $0.prefetchingRelationshipKeyPathes.append(relationship.name) } } } @@ -247,65 +306,9 @@ public extension DatabaseFetchSpecification if clear { $0.prefetchingRelationshipKeyPathes = [] } for relationship in repeat each relationship { let relationship = Object.e[keyPath: relationship] - $0.prefetchingRelationshipKeyPathes?.append(relationship.name) + $0.prefetchingRelationshipKeyPathes.append(relationship.name) } } } #endif // compiler(>=6) } - - -public extension FetchSpecification { - - static func select(_ attributes: String..., from: T.Type) - -> FetchSpecification - { - var fs = ModelFetchSpecification(entity: from.entity) - fs.fetchAttributeNames = attributes.isEmpty ? nil : attributes - return fs - } - - - // MARK: - Ordering - - func order(by : Attribute..., - asc : Attribute? = nil, - desc : Attribute? = nil, - iasc : Attribute? = nil, - idesc : Attribute? = nil) - -> FetchSpecification - { - var fs = self - - var ops = [ SortOrdering ]() - - for by in by { - let so = SortOrdering(key: AttributeKey(by), selector: .CompareAscending) - ops.append(so) - } - if let by = asc { - let so = SortOrdering(key: AttributeKey(by), selector: .CompareAscending) - ops.append(so) - } - if let by = desc { - let so = SortOrdering(key: AttributeKey(by), selector: .CompareDescending) - ops.append(so) - } - if let by = iasc { - let so = SortOrdering(key: AttributeKey(by), - selector: .CompareCaseInsensitiveAscending) - ops.append(so) - } - if let by = idesc { - let so = SortOrdering(key: AttributeKey(by), - selector: .CompareCaseInsensitiveDescending) - ops.append(so) - } - - guard !ops.isEmpty else { return self } - - if let old = fs.sortOrderings { fs.sortOrderings = old + ops } - else { fs.sortOrderings = ops } - return fs - } -} diff --git a/Sources/ZeeQL/Control/FetchSpecification.swift b/Sources/ZeeQL/Control/FetchSpecification.swift index 10c57eb..bbd505c 100644 --- a/Sources/ZeeQL/Control/FetchSpecification.swift +++ b/Sources/ZeeQL/Control/FetchSpecification.swift @@ -19,22 +19,22 @@ public protocol FetchSpecification : SmartDescription { // TODO: This is a little funky now because we refer to Entity. It should be // a protocol. - var entity : Entity? { get } // Access, really - var entityName : String? { get } - var fetchAttributeNames : [ String ]? { get set } - var qualifier : Qualifier? { get set } - var sortOrderings : [ SortOrdering ]? { get set } - var fetchLimit : Int? { get set } - var fetchOffset : Int? { get set } + var entity : Entity? { get } // Access, really + var entityName : String? { get } + var fetchAttributeNames : [ String ] { get set } + var qualifier : Qualifier? { get set } + var sortOrderings : [ SortOrdering ] { get set } + var fetchLimit : Int? { get set } + var fetchOffset : Int? { get set } - var usesDistinct : Bool { get set } - var locksObjects : Bool { get set } - var deep : Bool { get set } - var fetchesRawRows : Bool { get set } - var fetchesReadOnly : Bool { get set } + var usesDistinct : Bool { get set } + var locksObjects : Bool { get set } + var deep : Bool { get set } + var fetchesRawRows : Bool { get set } + var fetchesReadOnly : Bool { get set } var requiresAllQualifierBindingVariables : Bool { get set } - var prefetchingRelationshipKeyPathes : [ String ]? { get set } + var prefetchingRelationshipKeyPathes : [ String ] { get set } var hints : [ String : Any ] { get set } subscript(hint h: String) -> Any? { get set } @@ -120,7 +120,7 @@ extension FetchSpecification { // Default Imp * * The syntax for bind-pattern hints is '%(binding)s'. */ - public func fetchSpecificiationWith(bindings: Any?) throws + public func fetchSpecificiationWithBindings(_ bindings: Any?) throws -> FetchSpecification? { var boundFS = self @@ -135,6 +135,13 @@ extension FetchSpecification { // Default Imp return boundFS } + + @inlinable // TODO: deprecate + public func fetchSpecificiationWith(bindings: Any?) throws + -> FetchSpecification? + { + return try fetchSpecificiationWithBindings(bindings) + } } @@ -150,17 +157,15 @@ public extension FetchSpecification { ms += " '\(ename)'" } - if let fa = fetchAttributeNames, !fa.isEmpty { - ms += " attrs[" - ms += fa.joined(separator: ",") - ms += "]" + if !fetchAttributeNames.isEmpty { + ms += " attrs[\(fetchAttributeNames.joined(separator: ","))]" } if let q = qualifier { ms += " \(q)" } - if let sos = sortOrderings, !sos.isEmpty { + if !sortOrderings.isEmpty { ms += " sort=" - ms += sos.map({ "\($0)" }).joined(separator: ",") + ms += sortOrderings.map({ "\($0)" }).joined(separator: ",") } if let limit = fetchLimit { @@ -175,9 +180,9 @@ public extension FetchSpecification { ms += " offset=\(offset)" } - if let prefetch = prefetchingRelationshipKeyPathes, !prefetch.isEmpty { + if !prefetchingRelationshipKeyPathes.isEmpty { ms += " prefetch[" - ms += prefetch.joined(separator: ",") + ms += prefetchingRelationshipKeyPathes.joined(separator: ",") ms += "]" } @@ -196,6 +201,7 @@ public extension FetchSpecification { public extension FetchSpecification { // Counts + @inlinable var fetchSpecificationForCount : FetchSpecification? { // TODO: this may not be necessary anymore, see _primaryFetchCount() if hints["CustomQueryExpressionHintKey"] != nil { return nil } diff --git a/Sources/ZeeQL/Control/ModelFetchSpecification.swift b/Sources/ZeeQL/Control/ModelFetchSpecification.swift index 3ba18cf..bafbb38 100644 --- a/Sources/ZeeQL/Control/ModelFetchSpecification.swift +++ b/Sources/ZeeQL/Control/ModelFetchSpecification.swift @@ -26,9 +26,9 @@ public struct ModelFetchSpecification : ModelFetchSpecificationType { return nil } - public var fetchAttributeNames : [ String ]? + public var fetchAttributeNames = [ String ]() public var qualifier : Qualifier? - public var sortOrderings : [ SortOrdering ]? + public var sortOrderings : [ SortOrdering ] public var fetchLimit : Int? public var fetchOffset : Int? public var hints = [ String : Any ]() @@ -39,15 +39,15 @@ public struct ModelFetchSpecification : ModelFetchSpecificationType { public var fetchesRawRows = false public var fetchesReadOnly = false public var requiresAllQualifierBindingVariables = false // TBD: why false? - public var prefetchingRelationshipKeyPathes : [ String ]? + public var prefetchingRelationshipKeyPathes : [ String ] @inlinable - public init(entityName : String? = nil, - qualifier : Qualifier? = nil, - sortOrderings : [ SortOrdering ]? = nil, - offset : Int? = nil, - limit : Int? = nil, - prefetch : [ String ]? = nil, + public init(entityName : String? = nil, + qualifier : Qualifier? = nil, + sortOrderings : [ SortOrdering ] = [], + offset : Int? = nil, + limit : Int? = nil, + prefetch : [ String ] = [], requiresAllQualifierBindingVariables: Bool = false) { self._entityName = entityName @@ -62,11 +62,11 @@ public struct ModelFetchSpecification : ModelFetchSpecificationType { @inlinable public init(entity : Entity, - qualifier : Qualifier? = nil, - sortOrderings : [ SortOrdering ]? = nil, - offset : Int? = nil, - limit : Int? = nil, - prefetch : [ String ]? = nil, + qualifier : Qualifier? = nil, + sortOrderings : [ SortOrdering ] = [], + offset : Int? = nil, + limit : Int? = nil, + prefetch : [ String ] = [], requiresAllQualifierBindingVariables: Bool = false) { self.entity = entity @@ -82,10 +82,10 @@ public struct ModelFetchSpecification : ModelFetchSpecificationType { @inlinable public init(entity : Entity, _ q : String, - sortOrderings : [ SortOrdering ]? = nil, - offset : Int? = nil, - limit : Int? = nil, - prefetch : [ String ]? = nil, + sortOrderings : [ SortOrdering ] = [], + offset : Int? = nil, + limit : Int? = nil, + prefetch : [ String ] = [], requiresAllQualifierBindingVariables: Bool = false) { self.entity = entity diff --git a/Sources/ZeeQL/SQLite3Adaptor/SQLite3AdaptorChannel.swift b/Sources/ZeeQL/SQLite3Adaptor/SQLite3AdaptorChannel.swift index bc90125..e66c5f4 100644 --- a/Sources/ZeeQL/SQLite3Adaptor/SQLite3AdaptorChannel.swift +++ b/Sources/ZeeQL/SQLite3Adaptor/SQLite3AdaptorChannel.swift @@ -3,7 +3,7 @@ // ZeeQL // // Created by Helge Hess on 03/03/17. -// Copyright © 2017-2020 ZeeZide GmbH. All rights reserved. +// Copyright © 2017-2024 ZeeZide GmbH. All rights reserved. // import struct Foundation.Data @@ -286,7 +286,7 @@ open class SQLite3AdaptorChannel : AdaptorChannel { if refetchAll { let q = qualifierToMatchAllValues(pkey) let fs = ModelFetchSpecification(entity: entity, qualifier: q, - sortOrderings: nil, limit: 2) + sortOrderings: [], limit: 2) var rec : AdaptorRecord? = nil try selectAttributes(entity.attributes, fs, lock: false, entity) { record in