From 5d1d939a891a9aa39f167f28dc35647dc9173321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge=20He=C3=9F?= Date: Wed, 27 Nov 2024 23:43:11 +0100 Subject: [PATCH] Type out the ctx.fetchObjects methods Bind them to a specific DatabaseObject type, makes sense. There is still some `Any` in the stack that should be removed, but this is a better starting point. Also rename the now-outdated method name. --- Sources/ZeeQL/Access/DatabaseChannel.swift | 21 +++++---- Sources/ZeeQL/Access/DatabaseContext.swift | 27 +++++++---- Sources/ZeeQL/Access/DatabaseDataSource.swift | 7 +-- Sources/ZeeQL/Control/ObjectStore.swift | 16 ++++--- .../ZeeQL/Control/ObjectTrackingContext.swift | 47 +++++++++++++------ 5 files changed, 71 insertions(+), 47 deletions(-) diff --git a/Sources/ZeeQL/Access/DatabaseChannel.swift b/Sources/ZeeQL/Access/DatabaseChannel.swift index 59f2ea7..0eecb9d 100644 --- a/Sources/ZeeQL/Access/DatabaseChannel.swift +++ b/Sources/ZeeQL/Access/DatabaseChannel.swift @@ -3,7 +3,7 @@ // ZeeQL // // Created by Helge Hess on 27/02/17. -// Copyright © 2017-2020 ZeeZide GmbH. All rights reserved. +// Copyright © 2017-2024 ZeeZide GmbH. All rights reserved. // open class DatabaseChannelBase { @@ -722,7 +722,7 @@ open class DatabaseChannelBase { * * - returns: null if there are no more objects, or the fetched object/record */ - func fetchObject() -> DatabaseObject? { + public func fetchObject() -> DatabaseObject? { /* use iterator if the objects are already fetched in total */ // TODO: make the function throws @@ -1116,11 +1116,12 @@ open class DatabaseChannelBase { // MARK: - Typed Concrete Class -open class TypedDatabaseChannel : DatabaseChannelBase, - IteratorProtocol +open class TypedDatabaseChannel : DatabaseChannelBase, + IteratorProtocol + where ObjectType: DatabaseObject { - public var objects : IndexingIterator<[ObjectType]>? + public var objects : IndexingIterator<[ ObjectType ]>? override var hasObjectIterator : Bool { return objects != nil } @@ -1166,15 +1167,15 @@ open class TypedDatabaseChannel : DatabaseChannelBas * This is the primary method for fetches and has additional handling for * prefetched relationships. * - * - parameters: + * - Parameters: * - fs: The FetchSpecification which outlines how objects are being * fetched. * - ec: TODO */ - override func selectObjectsWithFetchSpecification(_ fs: FetchSpecification, - _ ec: ObjectTrackingContext? - = nil) - throws + override public func selectObjectsWithFetchSpecification( + _ fs: FetchSpecification, + _ ec: ObjectTrackingContext? = nil + ) throws { guard let prefetchRelPathes = fs.prefetchingRelationshipKeyPathes, !prefetchRelPathes.isEmpty diff --git a/Sources/ZeeQL/Access/DatabaseContext.swift b/Sources/ZeeQL/Access/DatabaseContext.swift index 241d68e..7d2ff39 100644 --- a/Sources/ZeeQL/Access/DatabaseContext.swift +++ b/Sources/ZeeQL/Access/DatabaseContext.swift @@ -3,7 +3,7 @@ // ZeeQL // // Created by Helge Hess on 03/03/2017. -// Copyright © 2017-2019 ZeeZide GmbH. All rights reserved. +// Copyright © 2017-2024 ZeeZide GmbH. All rights reserved. // /** @@ -50,21 +50,28 @@ public class DatabaseContext : ObjectStore, SmartDescription { } } - public func objectsWith(fetchSpecification fs : FetchSpecification, - in tc : ObjectTrackingContext, - _ cb : ( Any ) -> Void) throws + @inlinable + public func objectsWithFetchSpecification( + _ fetchSpecification : FetchSpecification, + in trackingContext : ObjectTrackingContext, + _ yield : ( O ) throws -> Void + ) throws + where O: DatabaseObject { - if fs.requiresAllQualifierBindingVariables { - if let keys = fs.qualifier?.bindingKeys, !keys.isEmpty { - throw Error.FetchSpecificationHasUnresolvedBindings(fs) + if fetchSpecification.requiresAllQualifierBindingVariables { + if let keys = fetchSpecification.qualifier?.bindingKeys, !keys.isEmpty { + throw Error.FetchSpecificationHasUnresolvedBindings(fetchSpecification) } } - let ch = DatabaseChannel(database: database) - try ch.selectObjectsWithFetchSpecification(fs, tc) + let ch = TypedDatabaseChannel(database: database) + try ch + .selectObjectsWithFetchSpecification(fetchSpecification, trackingContext) while let o = ch.fetchObject() { - cb(o) + assert(o is O) + guard let typed = o as? O else { continue } + try yield(typed) } } diff --git a/Sources/ZeeQL/Access/DatabaseDataSource.swift b/Sources/ZeeQL/Access/DatabaseDataSource.swift index 4b8d1ff..c051a5c 100644 --- a/Sources/ZeeQL/Access/DatabaseDataSource.swift +++ b/Sources/ZeeQL/Access/DatabaseDataSource.swift @@ -72,11 +72,6 @@ open class DatabaseDataSource yield: ( Object ) throws -> Void) throws { - let results = try objectContext.objectsWith(fetchSpecification: fs) - for result in results { - assert(result is Object) - guard let object = result as? Object else { continue } - try yield(object) - } + try objectContext.objectsWithFetchSpecification(fs, yield) } } diff --git a/Sources/ZeeQL/Control/ObjectStore.swift b/Sources/ZeeQL/Control/ObjectStore.swift index 366f300..f6e728e 100644 --- a/Sources/ZeeQL/Control/ObjectStore.swift +++ b/Sources/ZeeQL/Control/ObjectStore.swift @@ -3,7 +3,7 @@ // ZeeQL // // Created by Helge Hess on 17/02/17. -// Copyright © 2017-2019 ZeeZide GmbH. All rights reserved. +// Copyright © 2017-2024 ZeeZide GmbH. All rights reserved. // public protocol ObjectWithGlobalID { @@ -15,14 +15,16 @@ public protocol ObjectWithGlobalID { * A store which stores objects :-) * * Current subclasses: - * - `ObjectTrackingContext` (an object uniquer) - * - `DatabaseContext` (a store on top of `Database`) + * - ``ObjectTrackingContext`` (an object uniquer) + * - ``DatabaseContext`` (a store on top of `Database`) */ public protocol ObjectStore { - // TBD: add throws? - func objectsWith(fetchSpecification : FetchSpecification, - in tc : ObjectTrackingContext, - _ cb : ( Any ) -> Void) throws + func objectsWithFetchSpecification( + _ fetchSpecification : FetchSpecification, + in trackingContext : ObjectTrackingContext, + _ yield : ( O ) throws -> Void + ) throws + where O: DatabaseObject } diff --git a/Sources/ZeeQL/Control/ObjectTrackingContext.swift b/Sources/ZeeQL/Control/ObjectTrackingContext.swift index b5c350d..5eeb86e 100644 --- a/Sources/ZeeQL/Control/ObjectTrackingContext.swift +++ b/Sources/ZeeQL/Control/ObjectTrackingContext.swift @@ -46,28 +46,47 @@ open class ObjectTrackingContext : ObjectStore { /** * Fetches the objects for the given specification. This works by calling - * `objectsWith(fetchSpecification:in:)` with the tracking context itself. + * ``objectsWithFetchSpecification(_:in:_:)`` with the tracking context + * itself. */ @inlinable - open func objectsWith(fetchSpecification fs: FetchSpecification) throws - -> [ Any ] + open func objectsWithFetchSpecification(_ type: O.Type = O.self, + _ fs: FetchSpecification) throws + -> [ O ] + where O: DatabaseObject { - var objects = [ Any ]() - try objectsWith(fetchSpecification: fs, in: self) { - objects.append($0) - } + var objects = [ O ]() + try objectsWithFetchSpecification(fs) { objects.append($0) } return objects } /** - * This method asks the `rootObjectStore` to fetch the objects specified - * in the _fs. - * Objects will get registered in the given tracking context. + * Fetches the objects for the given specification. This works by calling + * ``objectsWithFetchSpecification(_:in:_:)`` with the tracking context + * itself. + */ + @inlinable + open func objectsWithFetchSpecification(_ fs: FetchSpecification, + _ cb: ( O ) throws -> Void) throws + where O: DatabaseObject + { + return try objectsWithFetchSpecification(fs, in: self, cb) + } + + /** + * This method asks the ``rootObjectStore`` to fetch the objects specified + * in the _fs (usually a ``DatabaseContext``). + * + * Objects will get registered in the given tracking context (usually `self` + * for ``ObjectTrackingContext``) + * + * This is the primitve method of ``ObjectStore``. */ @inlinable - open func objectsWith(fetchSpecification fs: FetchSpecification, - in tc: ObjectTrackingContext, - _ cb: ( Any ) -> Void) throws + open func objectsWithFetchSpecification(_ fs: FetchSpecification, + in tc: ObjectTrackingContext, + _ cb: ( O ) throws -> Void) throws + where O: DatabaseObject { if fs.requiresAllQualifierBindingVariables { if let q = fs.qualifier { @@ -77,7 +96,7 @@ open class ObjectTrackingContext : ObjectStore { } } - return try rootObjectStore.objectsWith(fetchSpecification: fs, in: tc, cb) + return try rootObjectStore.objectsWithFetchSpecification(fs, in: tc, cb) }