Compare commits

...

1 Commits

Author SHA1 Message Date
395e8e4d1c ORM type refactor 2022-04-05 09:38:58 -05:00
30 changed files with 86 additions and 71 deletions

View File

@ -8,7 +8,7 @@ import {Awaitable, JSONState} from '../../../util'
* A basic ORM-driven user class.
*/
@Injectable()
export class ORMUser extends Model<ORMUser> implements Authenticatable {
export class ORMUser extends Model implements Authenticatable {
protected static table = 'users'

View File

@ -18,7 +18,7 @@ export class ORMUserRepository extends AuthenticatableRepository {
/** Look up the user by their username. */
getByIdentifier(id: AuthenticatableIdentifier): Awaitable<Maybe<Authenticatable>> {
return (this.injector.getStaticOverride(ORMUser) as typeof ORMUser).query<ORMUser>()
return (this.injector.getStaticOverride(ORMUser) as typeof ORMUser).query()
.where('username', '=', id)
.first()
}

View File

@ -1,7 +1,7 @@
import {Field, FieldType, Model} from '../../../orm'
import {OAuth2Token} from '../types'
export class OAuth2TokenModel extends Model<OAuth2TokenModel> implements OAuth2Token {
export class OAuth2TokenModel extends Model implements OAuth2Token {
public static table = 'oauth2_tokens'
public static key = 'oauth2_token_id'

View File

@ -14,7 +14,7 @@ export class ORMTokenRepository extends TokenRepository {
async find(id: string): Promise<Maybe<OAuth2Token>> {
const idNum = parseInt(id, 10)
if ( !isNaN(idNum) ) {
return OAuth2TokenModel.query<OAuth2TokenModel>()
return OAuth2TokenModel.query()
.whereKey(idNum)
.first()
}

View File

@ -36,7 +36,13 @@ export function isInstantiableOf<T>(what: unknown, type: StaticClass<T, any>): w
/**
* Type that identifies a value as a static class, even if it is not instantiable.
*/
export type StaticClass<T, T2, TCtorParams extends any[] = any[]> = Function & {prototype: T} & { new (...args: TCtorParams) : T } & T2 // eslint-disable-line @typescript-eslint/ban-types
export type StaticClass<T, T2, TCtorParams extends any[] = any[]> = T2 & StaticThis<T, TCtorParams> // eslint-disable-line @typescript-eslint/ban-types
/**
* Quasi-reference to a `this` type w/in a static member.
* @see https://github.com/microsoft/TypeScript/issues/5863#issuecomment-302861175
*/
export type StaticThis<T, TCtorParams extends any[]> = { new (...args: TCtorParams): T }
/**
* Type that identifies a value as a static class that instantiates to itself

View File

@ -1,5 +1,5 @@
import {ModelKey, QueryRow, QuerySource} from '../types'
import {Container, Inject, Instantiable, isInstantiable} from '../../di'
import {Container, Inject, Instantiable, isInstantiable, StaticClass, StaticThis} from '../../di'
import {DatabaseService} from '../DatabaseService'
import {ModelBuilder} from './ModelBuilder'
import {getFieldsMeta, ModelField} from './Field'
@ -19,13 +19,13 @@ import {HasOne} from './relation/HasOne'
import {HasMany} from './relation/HasMany'
import {HasOneOrMany} from './relation/HasOneOrMany'
import {Scope, ScopeClosure} from './scope/Scope'
import {LocalBus} from '../../support/bus/LocalBus'
import {LocalBus} from '../../support/bus'
import {ModelEvent} from './events/ModelEvent'
/**
* Base for classes that are mapped to tables in a database.
*/
export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>> {
export abstract class Model extends LocalBus<ModelEvent> {
@Inject()
protected readonly logging!: Logging
@ -88,7 +88,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* Relations that should be eager-loaded by default.
* @protected
*/
protected with: (keyof T)[] = []
protected with: (keyof this)[] = []
/**
* The original row fetched from the database.
@ -100,7 +100,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* Cache of relation instances by property accessor.
* This is used by the `@Relation()` decorator to cache Relation instances.
*/
public relationCache: Collection<{ accessor: string | symbol, relation: Relation<T, any, any> }> = new Collection<{accessor: string | symbol; relation: Relation<T, any, any>}>()
public relationCache: Collection<{ accessor: string | symbol, relation: Relation<any, any, any> }> = new Collection<{accessor: string | symbol; relation: Relation<any, any, any>}>()
protected scopes: Collection<{ accessor: string | Instantiable<Scope>, scope: ScopeClosure }> = new Collection<{accessor: string | Instantiable<Scope>; scope: ScopeClosure}>()
@ -148,7 +148,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* const user = await UserModel.query<UserModel>().where('name', 'LIKE', 'John Doe').first()
* ```
*/
public static query<T2 extends Model<T2>>(): ModelBuilder<T2> {
public static query<T2 extends Model>(this: StaticThis<T2, any[]> & typeof Model): ModelBuilder<T2> {
const builder = <ModelBuilder<T2>> Container.getContainer().make<ModelBuilder<T2>>(ModelBuilder, this)
const source: QuerySource = this.querySource()
@ -174,7 +174,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
} else if ( this.constructor.length < 1 ) {
// Otherwise, if we can instantiate the model without any arguments,
// do that and get the eager-loaded relations directly.
const inst = Container.getContainer().make<Model<any>>(this)
const inst = Container.getContainer().make<Model>(this)
if ( Array.isArray(inst.with) ) {
for (const relation of inst.with) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@ -189,7 +189,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
builder.withScopes(this.prototype.scopes)
} else if ( this.constructor.length < 1 ) {
// Otherwise, try to instantiate the model if possible and load the scopes that way
const inst = Container.getContainer().make<Model<any>>(this)
const inst = Container.getContainer().make<Model>(this)
builder.withScopes(inst.scopes)
}
@ -247,7 +247,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
this.setFieldFromObject(field.modelKey, field.databaseKey, row)
})
await this.push(new ModelRetrievedEvent<T>(this as any))
await this.push(new ModelRetrievedEvent<this>(this as any))
return this
}
@ -329,9 +329,9 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* .update({ username: 'jdoe' })
* ```
*/
public query(): ModelBuilder<T> {
public query(): ModelBuilder<this> {
const ModelClass = this.constructor as typeof Model
const builder = <ModelBuilder<T>> this.app().make<ModelBuilder<T>>(ModelBuilder, ModelClass)
const builder = <ModelBuilder<this>> this.app().make<ModelBuilder<this>>(ModelBuilder, ModelClass)
const source: QuerySource = ModelClass.querySource()
builder.connection(ModelClass.getConnection())
@ -352,6 +352,15 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
builder.withScopes(this.scopes)
return this.newBuilderInstance(builder)
}
/**
* Configure ModelBuilder instances that query this model.
* @param builder
* @protected
*/
protected newBuilderInstance(builder: ModelBuilder<this>): ModelBuilder<this> {
return builder
}
@ -365,7 +374,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
*
* @param key
*/
public static async findByKey<T2 extends Model<T2>>(key: ModelKey): Promise<undefined | T2> {
public static async findByKey<T2 extends Model>(this: StaticThis<T2, any[]> & typeof Model, key: ModelKey): Promise<undefined | T2> {
return this.query<T2>()
.where(this.qualifyKey(), '=', key)
.limit(1)
@ -376,7 +385,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
/**
* Get an array of all instances of this model.
*/
public async all(): Promise<T[]> {
public async all(): Promise<this[]> {
return this.query().get()
.all()
}
@ -616,12 +625,12 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
*
* @param withoutTimestamps
*/
public async save({ withoutTimestamps = false } = {}): Promise<Model<T>> {
await this.push(new ModelSavingEvent<T>(this as any))
public async save({ withoutTimestamps = false } = {}): Promise<this> {
await this.push(new ModelSavingEvent<this>(this))
const ctor = this.constructor as typeof Model
if ( this.exists() && this.isDirty() ) {
await this.push(new ModelUpdatingEvent<T>(this as any))
await this.push(new ModelUpdatingEvent<this>(this))
if ( !withoutTimestamps && ctor.timestamps && ctor.UPDATED_AT ) {
(this as any)[ctor.UPDATED_AT] = new Date()
@ -642,9 +651,9 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
await this.assumeFromSource(data)
}
await this.push(new ModelUpdatedEvent<T>(this as any))
await this.push(new ModelUpdatedEvent<this>(this))
} else if ( !this.exists() ) {
await this.push(new ModelCreatingEvent<T>(this as any))
await this.push(new ModelCreatingEvent<this>(this))
if ( !withoutTimestamps ) {
if ( ctor.timestamps && ctor.CREATED_AT ) {
@ -675,10 +684,10 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
await this.assumeFromSource(data)
}
await this.push(new ModelCreatedEvent<T>(this as any))
await this.push(new ModelCreatedEvent<this>(this))
}
await this.push(new ModelSavedEvent<T>(this as any))
await this.push(new ModelSavedEvent<this>(this))
return this
}
@ -745,7 +754,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* This returns a NEW instance of the SAME record by matching on
* the primary key. It does NOT change the current instance of the record.
*/
public async fresh(): Promise<Model<T> | undefined> {
public async fresh(): Promise<this | undefined> {
return this.query()
.where(this.qualifyKey(), '=', this.key())
.limit(1)
@ -789,7 +798,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
*
* @param model
*/
public async populate(model: T): Promise<T> {
public async populate(model: this): Promise<this> {
const row = this.toQueryRow()
delete row[this.keyName()]
await model.assumeFromSource(row)
@ -803,7 +812,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
*
* @param other
*/
public is(other: Model<any>): boolean {
public is(other: Model): boolean {
return this.key() === other.key() && this.qualifyKey() === other.qualifyKey()
}
@ -811,7 +820,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* Inverse of `is()`.
* @param other
*/
public isNot(other: Model<any>): boolean {
public isNot(other: Model): boolean {
return !this.is(other)
}
@ -886,8 +895,8 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* @param foreignKeyOverride
* @param localKeyOverride
*/
public hasOne<T2 extends Model<T2>>(related: Instantiable<T2>, foreignKeyOverride?: keyof T & string, localKeyOverride?: keyof T2 & string): HasOne<T, T2> {
return new HasOne<T, T2>(this as unknown as T, this.make(related), foreignKeyOverride, localKeyOverride)
public hasOne<T2 extends Model>(related: Instantiable<T2>, foreignKeyOverride?: keyof this & string, localKeyOverride?: keyof T2 & string): HasOne<this, T2> {
return new HasOne<this, T2>(this, this.make(related), foreignKeyOverride, localKeyOverride)
}
@ -908,8 +917,8 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* @param foreignKeyOverride
* @param localKeyOverride
*/
public hasMany<T2 extends Model<T2>>(related: Instantiable<T2>, foreignKeyOverride?: keyof T & string, localKeyOverride?: keyof T2 & string): HasMany<T, T2> {
return new HasMany<T, T2>(this as unknown as T, this.make(related), foreignKeyOverride, localKeyOverride)
public hasMany<T2 extends Model>(related: Instantiable<T2>, foreignKeyOverride?: keyof this & string, localKeyOverride?: keyof T2 & string): HasMany<this, T2> {
return new HasMany<this, T2>(this, this.make(related), foreignKeyOverride, localKeyOverride)
}
/**
@ -935,7 +944,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* @param related
* @param relationName
*/
public belongsToOne<T2 extends Model<T2>>(related: Instantiable<T>, relationName: keyof T2): HasOne<T, T2> {
public belongsToOne<T2 extends Model>(related: Instantiable<T2>, relationName: keyof T2): HasOne<this, T2> {
const relatedInst = this.make(related) as T2
const relation = relatedInst.getRelation(relationName)
@ -946,11 +955,11 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
const localKey = relation.localKey
const foreignKey = relation.foreignKey
if ( !isKeyof(localKey, this as unknown as T) || !isKeyof(foreignKey, relatedInst) ) {
if ( !isKeyof(localKey, this) || !isKeyof(foreignKey, relatedInst) ) {
throw new TypeError('Local or foreign keys do not exist on the base model.')
}
return new HasOne<T, T2>(this as unknown as T, relatedInst, localKey, foreignKey)
return new HasOne(this, relatedInst, localKey, foreignKey)
}
@ -977,7 +986,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* @param related
* @param relationName
*/
public belongsToMany<T2 extends Model<T2>>(related: Instantiable<T>, relationName: keyof T2): HasMany<T, T2> {
public belongsToMany<T2 extends Model>(related: Instantiable<T2>, relationName: keyof T2): HasMany<this, T2> {
const relatedInst = this.make(related) as T2
const relation = relatedInst.getRelation(relationName)
@ -988,11 +997,11 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
const localKey = relation.localKey
const foreignKey = relation.foreignKey
if ( !isKeyof(localKey, this as unknown as T) || !isKeyof(foreignKey, relatedInst) ) {
if ( !isKeyof(localKey, this) || !isKeyof(foreignKey, relatedInst) ) {
throw new TypeError('Local or foreign keys do not exist on the base model.')
}
return new HasMany<T, T2>(this as unknown as T, relatedInst, localKey, foreignKey)
return new HasMany(this, relatedInst, localKey, foreignKey)
}
/**
@ -1000,7 +1009,7 @@ export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>>
* @param name
* @protected
*/
public getRelation<T2 extends Model<T2>>(name: keyof this): Relation<T, T2, RelationValue<T2>> {
public getRelation<T2 extends Model>(name: keyof this): Relation<this, T2, RelationValue<T2>> {
const relFn = this[name]
if ( relFn instanceof Relation ) {

View File

@ -11,7 +11,7 @@ import {Scope, ScopeClosure} from './scope/Scope'
/**
* Implementation of the abstract builder whose results yield instances of a given Model, `T`.
*/
export class ModelBuilder<T extends Model<T>> extends AbstractBuilder<T> {
export class ModelBuilder<T extends Model> extends AbstractBuilder<T> {
protected eagerLoadRelations: (keyof T)[] = []
protected appliedScopes: Collection<{ accessor: string | Instantiable<Scope>, scope: ScopeClosure }> = new Collection<{accessor: string | Instantiable<Scope>; scope: ScopeClosure}>()

View File

@ -9,7 +9,7 @@ import {collect, Collection} from '../../util'
/**
* Implementation of the result iterable that returns query results as instances of the defined model.
*/
export class ModelResultIterable<T extends Model<T>> extends AbstractResultIterable<T> {
export class ModelResultIterable<T extends Model> extends AbstractResultIterable<T> {
constructor(
public readonly builder: ModelBuilder<T>,
public readonly connection: Connection,

View File

@ -13,19 +13,19 @@ export interface ModelSerialPayload extends JSONState {
@ObjectSerializer()
@Injectable()
export class ModelSerializer extends BaseSerializer<Model<any>, ModelSerialPayload> {
export class ModelSerializer extends BaseSerializer<Model, ModelSerialPayload> {
@Inject()
protected readonly canon!: Canon
protected async decodeSerial(serial: ModelSerialPayload): Promise<Model<any>> {
protected async decodeSerial(serial: ModelSerialPayload): Promise<Model> {
const ModelClass = this.canon.getFromFullyQualified(serial.canonicalResolver) as typeof Model
if ( !ModelClass || !(ModelClass.prototype instanceof Model) || !isInstantiable<Model<any>>(ModelClass) ) {
if ( !ModelClass || !(ModelClass.prototype instanceof Model) || !isInstantiable<Model>(ModelClass) ) {
throw new ErrorWithContext('Cannot decode serialized model as canonical resolver is invalid', {
serial,
})
}
let inst: Maybe<Model<any>> = this.make<Model<any>>(ModelClass)
let inst: Maybe<Model> = this.make<Model>(ModelClass)
if ( serial.primaryKey ) {
inst = await ModelClass.query()
.whereKey(serial.primaryKey)
@ -42,7 +42,7 @@ export class ModelSerializer extends BaseSerializer<Model<any>, ModelSerialPaylo
return inst
}
protected encodeActual(actual: Model<any>): Awaitable<ModelSerialPayload> {
protected encodeActual(actual: Model): Awaitable<ModelSerialPayload> {
const ctor = actual.constructor as typeof Model
const canonicalResolver = ctor.getFullyQualifiedCanonicalResolver()
if ( !canonicalResolver ) {
@ -62,7 +62,7 @@ export class ModelSerializer extends BaseSerializer<Model<any>, ModelSerialPaylo
return '@extollo/lib.ModelSerializer'
}
matchActual(some: Model<any>): boolean {
matchActual(some: Model): boolean {
return some instanceof Model
}
}

View File

@ -4,6 +4,6 @@ import {ModelEvent} from './ModelEvent'
/**
* Event fired right after a model is inserted.
*/
export class ModelCreatedEvent<T extends Model<T>> extends ModelEvent<T> {
export class ModelCreatedEvent<T extends Model> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelCreatedEvent'
}

View File

@ -4,6 +4,6 @@ import {ModelEvent} from './ModelEvent'
/**
* Event fired right before a model is inserted.
*/
export class ModelCreatingEvent<T extends Model<T>> extends ModelEvent<T> {
export class ModelCreatingEvent<T extends Model> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelCreatingEvent'
}

View File

@ -4,6 +4,6 @@ import {ModelEvent} from './ModelEvent'
/**
* Event fired right after a model is deleted.
*/
export class ModelDeletedEvent<T extends Model<T>> extends ModelEvent<T> {
export class ModelDeletedEvent<T extends Model> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelDeletedEvent'
}

View File

@ -4,6 +4,6 @@ import {ModelEvent} from './ModelEvent'
/**
* Event fired right before a model is deleted.
*/
export class ModelDeletingEvent<T extends Model<T>> extends ModelEvent<T> {
export class ModelDeletingEvent<T extends Model> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelDeletingEvent'
}

View File

@ -6,7 +6,7 @@ import {Awaitable} from '../../../util'
* Base class for events that concern an instance of a model.
* @fixme support serialization
*/
export abstract class ModelEvent<T extends Model<T>> extends BaseEvent {
export abstract class ModelEvent<T extends Model = Model> extends BaseEvent {
constructor(
public readonly instance: T,
) {

View File

@ -4,6 +4,6 @@ import {ModelEvent} from './ModelEvent'
/**
* Event fired right after a model's data is loaded from the source.
*/
export class ModelRetrievedEvent<T extends Model<T>> extends ModelEvent<T> {
export class ModelRetrievedEvent<T extends Model> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelRetrievedEvent'
}

View File

@ -4,6 +4,6 @@ import {ModelEvent} from './ModelEvent'
/**
* Event fired right after a model is persisted to the source.
*/
export class ModelSavedEvent<T extends Model<T>> extends ModelEvent<T> {
export class ModelSavedEvent<T extends Model> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelSavedEvent'
}

View File

@ -4,6 +4,6 @@ import {ModelEvent} from './ModelEvent'
/**
* Event fired right before a model is persisted to the source.
*/
export class ModelSavingEvent<T extends Model<T>> extends ModelEvent<T> {
export class ModelSavingEvent<T extends Model> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelSavingEvent'
}

View File

@ -4,6 +4,6 @@ import {ModelEvent} from './ModelEvent'
/**
* Event fired right after a model's data is updated.
*/
export class ModelUpdatedEvent<T extends Model<T>> extends ModelEvent<T> {
export class ModelUpdatedEvent<T extends Model> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelUpdatedEvent'
}

View File

@ -4,6 +4,6 @@ import {ModelEvent} from './ModelEvent'
/**
* Event fired right before a model's data is updated.
*/
export class ModelUpdatingEvent<T extends Model<T>> extends ModelEvent<T> {
export class ModelUpdatingEvent<T extends Model> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelUpdatingEvent'
}

View File

@ -6,7 +6,7 @@ import {RelationNotLoadedError} from './Relation'
/**
* One-to-many relation implementation.
*/
export class HasMany<T extends Model<T>, T2 extends Model<T2>> extends HasOneOrMany<T, T2, Collection<T2>> {
export class HasMany<T extends Model, T2 extends Model> extends HasOneOrMany<T, T2, Collection<T2>> {
protected cachedValue?: Collection<T2>
protected cachedLoaded = false

View File

@ -6,7 +6,7 @@ import {Maybe} from '../../../util'
/**
* One-to-one relation implementation.
*/
export class HasOne<T extends Model<T>, T2 extends Model<T2>> extends HasOneOrMany<T, T2, Maybe<T2>> {
export class HasOne<T extends Model, T2 extends Model> extends HasOneOrMany<T, T2, Maybe<T2>> {
protected cachedValue?: T2
protected cachedLoaded = false

View File

@ -9,7 +9,7 @@ import {Collection, toString} from '../../../util'
/**
* Base class for 1:1 and 1:M relations.
*/
export abstract class HasOneOrMany<T extends Model<T>, T2 extends Model<T2>, V extends RelationValue<T2>> extends Relation<T, T2, V> {
export abstract class HasOneOrMany<T extends Model, T2 extends Model, V extends RelationValue<T2>> extends Relation<T, T2, V> {
protected constructor(
parent: T,
related: T2,

View File

@ -22,7 +22,7 @@ export class RelationNotLoadedError extends ErrorWithContext {
/**
* Base class for inter-model relation implementations.
*/
export abstract class Relation<T extends Model<T>, T2 extends Model<T2>, V extends RelationValue<T2>> extends InjectionAware {
export abstract class Relation<T extends Model, T2 extends Model, V extends RelationValue<T2>> extends InjectionAware {
protected constructor(
/** The model related from. */
protected parent: T,

View File

@ -5,7 +5,7 @@ import {Relation} from './Relation'
/**
* ModelBuilder instance that queries the related model in a relation.
*/
export class RelationBuilder<T extends Model<T>> extends ModelBuilder<T> {
export class RelationBuilder<T extends Model> extends ModelBuilder<T> {
constructor(
protected relation: Relation<any, T, any>,
) {

View File

@ -14,7 +14,7 @@ export function Related(): MethodDecorator {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
descriptor.value = function(...args) {
const model = this as Model<any>
const model = this as Model
const cache = model.relationCache
const existing = cache.firstWhere('accessor', '=', propertyKey)

View File

@ -9,7 +9,7 @@ import {CanonicalDefinition} from '../../service/Canonical'
* Canonical unit responsible for loading the model classes defined by the application.
*/
@Singleton()
export class Models extends CanonicalStatic<Model<any>, Instantiable<Model<any>>> {
export class Models extends CanonicalStatic<Model, Instantiable<Model>> {
@Inject()
protected readonly cli!: CommandLine
@ -24,7 +24,7 @@ export class Models extends CanonicalStatic<Model<any>, Instantiable<Model<any>>
this.cli.registerTemplate(templateModel)
}
public async initCanonicalItem(definition: CanonicalDefinition): Promise<Instantiable<Model<any>>> {
public async initCanonicalItem(definition: CanonicalDefinition): Promise<Instantiable<Model>> {
const item = await super.initCanonicalItem(definition)
if ( !(item.prototype instanceof Model) ) {
throw new TypeError(`Invalid controller definition: ${definition.originalName}. Models must extend from @extollo/orm.Model.`)

View File

@ -7,7 +7,7 @@ import {ModelBuilder} from '../model/ModelBuilder'
/**
* A model instance which stores records from the ORMCache driver.
*/
export class CacheModel extends Model<CacheModel> {
export class CacheModel extends Model {
protected static table = 'caches'; // FIXME allow configuring
protected static key = 'cache_key';
@ -22,7 +22,7 @@ export class CacheModel extends Model<CacheModel> {
public cacheExpires?: Date;
public static withCacheKey(key: string): ModelBuilder<CacheModel> {
return this.query<CacheModel>()
return this.query()
.whereKey(key)
.whereProperty('cacheExpires', '>', new Date())
}

View File

@ -11,7 +11,7 @@ export class ORMCache extends Cache {
}
public async put(key: string, value: string, expires?: Date): Promise<void> {
let model = await CacheModel.findByKey<CacheModel>(key)
let model = await CacheModel.findByKey(key)
if ( !model ) {
model = <CacheModel> Container.getContainer().make(CacheModel)
}

View File

@ -29,7 +29,7 @@ export class ORMSession extends Session {
throw new NoSessionKeyError()
}
const session = <SessionModel> await SessionModel.findByKey(this.key)
const session = await SessionModel.findByKey(this.key)
if ( session ) {
this.session = session
this.data = this.session.json

View File

@ -5,7 +5,7 @@ import {FieldType} from '../types'
/**
* Model used to fetch & store sessions from the ORMSession driver.
*/
export class SessionModel extends Model<SessionModel> {
export class SessionModel extends Model {
protected static table = 'sessions' // FIXME allow configuring
protected static key = 'session_uuid'