Skip to content

Commit

Permalink
The TypedEntityType actually works now
Browse files Browse the repository at this point in the history
... modern Swift.
  • Loading branch information
helje5 committed Dec 4, 2024
1 parent 48e1c7c commit ec72f37
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 32 deletions.
2 changes: 2 additions & 0 deletions Sources/ZeeQL/Access/TypedFetchSpecification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
public struct TypedFetchSpecification<Object: DatabaseObject>
: DatabaseFetchSpecification
{
// FIXME: Name, should be called "DynamicFetchSpecification" or something

public var _entity : Entity? = nil
public var _entityName : String?

Expand Down
111 changes: 79 additions & 32 deletions Sources/ZeeQL/Control/EntityType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,51 @@
//

/**
* This protocol is used for ORM classes which are guaranteed to have an Entity
* assigned - for example when the Entity is specified in code.
* This protocol is used for ORM classes which are guaranteed to have an
* ``Entity`` assigned, for example when the ``Entity`` is specified in code.
* If a class has a fixed Entity, we can do more tricks in Swift.
*
* Example:
*
* class Address : ActiveRecord, EntityType {
* class Entity : OGoCodeEntity {
* let id = -1
* let street : String? = nil
* let person = ToOne<Person>()
* }
* static let entity : ZeeQL.Entity = CodeEntity<Address>(Entity())
* }
* ```swift
* class Address : ActiveRecord, EntityType {
* class Entity : OGoCodeEntity {
* let id = -1
* let street : String? = nil
* let person = ToOne<Person>()
* }
* static let entity : ZeeQL.Entity = CodeEntity<Address>(Entity())
* }
* ```
*/
public protocol EntityType { // TODO: better name
static var entity : Entity { get }
}


// TBD: This doesn't fly, I'm not completely sure why not. I cannot use it
// in the Object like `Person: ActiveRecord, GEntityType` due to the
// infamous:
// "Protocol … can only be used as a generic constraint because it has
// Self or associated type requirements"
public protocol GEntityType : EntityType { // TODO: better name
/**
* This protocol is used for ORM classes which are guaranteed to have an
* ``Entity`` assigned, for example when the ``Entity`` is specified in code.
* If a class has a fixed Entity, we can do more tricks in Swift.
*
* Example:
* ```swift
* class Address : ActiveRecord, TypedEntityType {
* class Entity : OGoCodeEntity {
* let id = -1
* let street : String? = nil
* let person = ToOne<Person>()
* }
* static let e = CodeEntity<Address>(Entity())
* }
* ```
*/
public protocol TypedEntityType : EntityType { // TODO: better name
associatedtype FullEntity : ZeeQL.Entity
static var e : FullEntity { get }
}
public extension GEntityType {

public extension TypedEntityType {

@inlinable
static var entity : ZeeQL.Entity { return e }
}

Expand All @@ -46,19 +61,7 @@ public extension GEntityType {
public extension EntityType {
// TBD: maybe rename, 'select' should run the actual select, right?

// TBD: what do we want?
// let objects = db.select(from: Persons.self)
// .where(Persons.login.like("*")
// .and(Persons.entity.addresses.zip.eq("39126"))
// .limit(4)
// .prefetch("addresses")
// if FetchSpec would be a generic, we could derive a lot from the type
// let fs = FetchSpecification
// .select(from: Person) -> GFetchSpecification<Person>
// .where(login.like ...) // login can access Person
// TBD: this could return a fetch-spec builder instead of recreating the
// specs all the time (FetchSpecificationRepresentable?)

@inlinable
static func select(_ attributes: String...)
-> FetchSpecification
{
Expand All @@ -68,6 +71,7 @@ public extension EntityType {
}

// TBD: change this, 'select' should run the actual select, right?
@inlinable
static func select(_ a1: Attribute, _ attributes: Attribute...)
-> FetchSpecification
{
Expand All @@ -79,19 +83,62 @@ public extension EntityType {

// MARK: - Qualifiers

@inlinable
static func `where`(_ q: Qualifier) -> FetchSpecification {
// if we need no attributes
var fs = ModelFetchSpecification(entity: Self.entity)
fs.qualifier = q
return fs
}
@inlinable
static func `where`(_ q: String, _ args: Any?...) -> FetchSpecification {
var fs = ModelFetchSpecification(entity: Self.entity)
let parser = QualifierParser(string: q, arguments: args)
fs.qualifier = parser.parseQualifier()
return fs
}
}
public extension TypedEntityType where Self: DatabaseObject {
// TBD: maybe rename, 'select' should run the actual select, right?

@inlinable
static func select(_ attributes: String...)
-> TypedFetchSpecification<Self>
{
var fs = TypedFetchSpecification<Self>(entity: Self.entity)
fs.fetchAttributeNames = attributes.isEmpty ? nil : attributes
return fs
}

// TBD: change this, 'select' should run the actual select, right?
@inlinable
static func select(_ a1: Attribute, _ attributes: Attribute...)
-> TypedFetchSpecification<Self>
{
var fs = TypedFetchSpecification<Self>(entity: Self.entity)
fs.fetchAttributeNames = ([ a1 ] + attributes).map { $0.name }
return fs
}


// MARK: - Qualifiers

@inlinable
static func `where`(_ q: Qualifier) -> TypedFetchSpecification<Self> {
// if we need no attributes
var fs = TypedFetchSpecification<Self>(entity: Self.entity)
fs.qualifier = q
return fs
}
@inlinable
static func `where`(_ q: String, _ args: Any?...)
-> TypedFetchSpecification<Self>
{
var fs = TypedFetchSpecification<Self>(entity: Self.entity)
let parser = QualifierParser(string: q, arguments: args)
fs.qualifier = parser.parseQualifier()
return fs
}
}


Expand Down

0 comments on commit ec72f37

Please sign in to comment.