Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
helje5 committed Dec 5, 2024
2 parents 9edd71e + 251e93d commit dc9060c
Show file tree
Hide file tree
Showing 16 changed files with 685 additions and 500 deletions.
99 changes: 82 additions & 17 deletions Sources/ZeeQL/Access/AccessDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,19 +146,63 @@ open class AccessDataSource<Object: SwiftObject> : DataSource<Object>,

public extension AccessDataSourceType {

/**
* This method takes the name of a fetch specification. It looks up the fetch
* spec in the ``Entity`` associated with the datasource and then binds the
* spec with the given key/value pairs.
*
* Example:
* ```swift
* try ds.fetchObjects(myFetchSpec, ["contactId": 12345]) { contact in
* print("Contact:", contact)
* }
* ```
*
* This calls ``FetchSpecification/fetchSpecificiationWith(bindings:)-585ip``
* and passes in the given key/value pair (contactId=12345).
*
* Finally the fetch will be performed using
* ``_primaryFetchObjects``.
*
* - Parameters:
* - fetchSpecification: The ``FetchSpecification`` to use.
* - keysAndValues: The key/value pairs to apply as bindings.
*/
@inlinable
func fetchObjects(_ fetchSpecification: FetchSpecification,
_ binds: [ String : Any ] = [:],
yield: ( Object ) throws -> Void) throws
{
if !binds.isEmpty {
guard let fs = try fetchSpecification
.fetchSpecificiationWith(bindings: binds) else
{
throw AccessDataSourceError
.CouldNotResolveBindings(fetchSpecification: fetchSpecification,
bindings: binds)
}
try _primaryFetchObjects(fs) { try yield($0) }
}
else {
try _primaryFetchObjects(fetchSpecification) { try yield($0) }
}
}

/**
* This method takes the name of a fetch specification. It looks up the fetch
* spec in the `Entity` associated with the datasource and then binds the
* spec with the given key/value pairs.
*
* Example:
* ```swift
* let persons = try ds.fetchObjects("myContacts", ["contactId": 12345])
* try ds.fetchObjects("myContacts", ["contactId": 12345]) { contact in
* print("Contact:", contact)
* }
* ```
*
* This will lookup the `FetchSpecification` named "myContacts" in
* the `Entity` of the datasource. It then calls
* `fetchSpecificationWithQualifierBindings()`
* ``FetchSpecification/fetchSpecificiationWith(bindings:)-585ip``
* and passes in the given key/value pair (contactId=12345).
*
* Finally the fetch will be performed using
Expand All @@ -167,15 +211,16 @@ public extension AccessDataSourceType {
* - Parameters:
* - fetchSpecificationName: The name of the fetch specification to use.
* - keysAndValues: The key/value pairs to apply as bindings.
* - Returns: The fetched objects.
*/
@inlinable
func fetchObjects(_ fetchSpecificationName: String,
_ binds: [ String : Any ] = [:]) throws -> [ Object ]
_ binds: [ String : Any ] = [:],
yield: ( Object ) throws -> Void) throws
{
guard let findEntity = entity else {
// TBD: improve exception
log.error("did not find entity, cannot construct fetchspec");
log.error("did not find entity, cannot construct fetchspec:",
fetchSpecificationName)
throw AccessDataSourceError.MissingEntity
}

Expand All @@ -184,21 +229,41 @@ public extension AccessDataSourceType {
.DidNotFindFetchSpecification(name: fetchSpecificationName,
entity: findEntity)
}

return try fetchObjects(fs, binds, yield: yield)
}

/**
* This method takes the name of a fetch specification. It looks up the fetch
* spec in the `Entity` associated with the datasource and then binds the
* spec with the given key/value pairs.
*
* Example:
* ```swift
* let persons = try ds.fetchObjects("myContacts", ["contactId": 12345])
* ```
*
* This will lookup the `FetchSpecification` named "myContacts" in
* the `Entity` of the datasource. It then calls
* `fetchSpecificationWithQualifierBindings()`
* and passes in the given key/value pair (contactId=12345).
*
* Finally the fetch will be performed using
* ``_primaryFetchObjects``.
*
* - Parameters:
* - fetchSpecificationName: The name of the fetch specification to use.
* - keysAndValues: The key/value pairs to apply as bindings.
* - Returns: The fetched objects.
*/
@inlinable
func fetchObjects(_ fetchSpecificationName: String,
_ binds: [ String : Any ] = [:]) throws -> [ Object ]
{
var results = [ Object ]()
if !binds.isEmpty {
guard let fs = try fs.fetchSpecificiationWith(bindings: binds) else {
throw AccessDataSourceError
.CouldNotResolveBindings(fetchSpecification: fs, bindings: binds)
}
try _primaryFetchObjects(fs) { results.append($0) }
}
else {
try _primaryFetchObjects(fs) { results.append($0) }
}
try fetchObjects(fetchSpecificationName, binds) { results.append($0) }
return results
}

/**
* This method takes the name of a fetch specification. It looks up the fetch
* spec in the `Entity` associated with the datasource and then binds the
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZeeQL/Access/AccessDataSourceError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ public enum AccessDataSourceError: Swift.Error {

case DidNotFindFetchSpecification(name: String, entity: Entity)
case CouldNotResolveBindings(fetchSpecification: FetchSpecification,
bindings: [ String : Any])
bindings: Any)
}
23 changes: 23 additions & 0 deletions Sources/ZeeQL/Access/ActiveDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,26 @@ public extension Database {
return ActiveDataSource<Object>(database: self)
}
}


// MARK: - Query Runner

public extension DatabaseFetchSpecification where Object: ActiveRecordType {
// hh(2024-12-04): This style probably doesn't make that much sense...

/**
* Evaluate the active record fetch specifiction in a ``Database``.
*
* ```swift
* let _ = try Person.where("login like %@", "*he*")
* .limit(4)
* .fetch(in: db)
* ```
*/
@inlinable
func fetch(in db: Database) throws -> [ Object ] {
let ds = ActiveDataSource<Object>(database: db)
ds.fetchSpecification = self
return try ds.fetchObjects()
}
}
7 changes: 4 additions & 3 deletions Sources/ZeeQL/Access/CodeEntity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ open class CodeObjectEntity<T: CodeObjectType> : CodeEntityBase {
if !fetchSpecifications.isEmpty {
for ( fsName, fs ) in fetchSpecifications where fs.entity == nil {
assert(fs.entityName == self.name)
if var fs = fs as? ModelFetchSpecification {
if var fs = fs as? ModelFetchSpecificationType {
fs.entity = self
fetchSpecifications[fsName] = fs
}
Expand All @@ -208,8 +208,9 @@ fileprivate extension CodeEntityBase {
private func processFetchSpecificationMirror(_ mirror: Mirror) {
for ( propName, propValue ) in mirror.children {
assert(propName != nil)
assert(propValue is ModelFetchSpecification)
guard let fs = propValue as? FetchSpecification, let name = propName else {
// Why?: assert(propValue is ModelFetchSpecificationType)
guard let fs = propValue as? FetchSpecification, let name = propName else
{
continue
}

Expand Down
91 changes: 0 additions & 91 deletions Sources/ZeeQL/Access/CodeFetchSpecification.swift

This file was deleted.

Loading

0 comments on commit dc9060c

Please sign in to comment.