ModelRelation: add pagination
This commit is contained in:
parent
8358c3fd4e
commit
6a4898cbda
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wms-core",
|
"name": "wms-core",
|
||||||
"version": "0.21.9",
|
"version": "0.21.10-rc.1",
|
||||||
"description": "Node web application framework and toolbelt.",
|
"description": "Node web application framework and toolbelt.",
|
||||||
"repository": "https://gitlab.com/ArisuOngaku/wms-core",
|
"repository": "https://gitlab.com/ArisuOngaku/wms-core",
|
||||||
"author": "Alice Gaudon <alice@gaudon.pro>",
|
"author": "Alice Gaudon <alice@gaudon.pro>",
|
||||||
|
@ -5,7 +5,6 @@ import ModelFactory from "./ModelFactory";
|
|||||||
export default abstract class ModelRelation<S extends Model, O extends Model, R extends O | O[] | null> {
|
export default abstract class ModelRelation<S extends Model, O extends Model, R extends O | O[] | null> {
|
||||||
protected readonly model: S;
|
protected readonly model: S;
|
||||||
protected readonly foreignFactory: ModelFactory<O>;
|
protected readonly foreignFactory: ModelFactory<O>;
|
||||||
private readonly query: ModelQuery<O>;
|
|
||||||
protected readonly queryModifiers: QueryModifier<O>[] = [];
|
protected readonly queryModifiers: QueryModifier<O>[] = [];
|
||||||
protected readonly filters: ModelFilter<O>[] = [];
|
protected readonly filters: ModelFilter<O>[] = [];
|
||||||
protected cachedModels?: R;
|
protected cachedModels?: R;
|
||||||
@ -13,7 +12,6 @@ export default abstract class ModelRelation<S extends Model, O extends Model, R
|
|||||||
protected constructor(model: S, foreignFactory: ModelFactory<O>) {
|
protected constructor(model: S, foreignFactory: ModelFactory<O>) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.foreignFactory = foreignFactory;
|
this.foreignFactory = foreignFactory;
|
||||||
this.query = this.foreignFactory.select();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract clone(): ModelRelation<S, O, R>;
|
public abstract clone(): ModelRelation<S, O, R>;
|
||||||
@ -28,19 +26,23 @@ export default abstract class ModelRelation<S extends Model, O extends Model, R
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getFinalQuery(): ModelQuery<O> {
|
protected makeQuery(): ModelQuery<O> {
|
||||||
for (const modifier of this.queryModifiers) modifier(this.query);
|
const query = this.foreignFactory.select();
|
||||||
this.queryModifiers.splice(0, this.queryModifiers.length); // Empty modifier now that they were applied
|
for (const modifier of this.queryModifiers) modifier(query);
|
||||||
return this.query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract getModelID(): any;
|
public abstract getModelID(): any;
|
||||||
|
|
||||||
protected abstract async compute(query: ModelQuery<O>): Promise<R>;
|
protected abstract async compute(query: ModelQuery<O>): Promise<R>;
|
||||||
|
|
||||||
|
protected abstract applyRegularConstraints(query: ModelQuery<O>): void;
|
||||||
|
|
||||||
public async get(): Promise<R> {
|
public async get(): Promise<R> {
|
||||||
if (this.cachedModels === undefined) {
|
if (this.cachedModels === undefined) {
|
||||||
this.cachedModels = await this.compute(this.getFinalQuery());
|
const query = this.makeQuery();
|
||||||
|
this.applyRegularConstraints(query);
|
||||||
|
this.cachedModels = await this.compute(query);
|
||||||
}
|
}
|
||||||
return this.cachedModels;
|
return this.cachedModels;
|
||||||
}
|
}
|
||||||
@ -84,10 +86,13 @@ export class OneModelRelation<S extends Model, O extends Model> extends ModelRel
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async compute(query: ModelQuery<O>): Promise<O | null> {
|
protected async compute(query: ModelQuery<O>): Promise<O | null> {
|
||||||
this.getFinalQuery().where(this.dbProperties.foreignKey, this.getModelID());
|
|
||||||
return await query.first();
|
return await query.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected applyRegularConstraints(query: ModelQuery<O>): void {
|
||||||
|
query.where(this.dbProperties.foreignKey, this.getModelID());
|
||||||
|
}
|
||||||
|
|
||||||
public async get(): Promise<O | null> {
|
public async get(): Promise<O | null> {
|
||||||
const model = await super.get();
|
const model = await super.get();
|
||||||
if (model) {
|
if (model) {
|
||||||
@ -104,7 +109,7 @@ export class OneModelRelation<S extends Model, O extends Model> extends ModelRel
|
|||||||
const ids = relations.map(r => r.getModelID()).filter(id => id !== null && id !== undefined);
|
const ids = relations.map(r => r.getModelID()).filter(id => id !== null && id !== undefined);
|
||||||
if (ids.length === 0) return [];
|
if (ids.length === 0) return [];
|
||||||
|
|
||||||
const query = this.getFinalQuery();
|
const query = this.makeQuery();
|
||||||
query.where(this.dbProperties.foreignKey, ids, WhereTest.IN);
|
query.where(this.dbProperties.foreignKey, ids, WhereTest.IN);
|
||||||
return await query.get();
|
return await query.get();
|
||||||
}
|
}
|
||||||
@ -124,6 +129,7 @@ export class OneModelRelation<S extends Model, O extends Model> extends ModelRel
|
|||||||
|
|
||||||
export class ManyModelRelation<S extends Model, O extends Model> extends ModelRelation<S, O, O[]> {
|
export class ManyModelRelation<S extends Model, O extends Model> extends ModelRelation<S, O, O[]> {
|
||||||
protected readonly dbProperties: RelationDatabaseProperties;
|
protected readonly dbProperties: RelationDatabaseProperties;
|
||||||
|
protected readonly paginatedCache: { [perPage: number]: { [pageNumber: number]: ModelQueryResult<O> } } = {};
|
||||||
|
|
||||||
constructor(model: S, foreignFactory: ModelFactory<O>, dbProperties: RelationDatabaseProperties) {
|
constructor(model: S, foreignFactory: ModelFactory<O>, dbProperties: RelationDatabaseProperties) {
|
||||||
super(model, foreignFactory);
|
super(model, foreignFactory);
|
||||||
@ -143,10 +149,13 @@ export class ManyModelRelation<S extends Model, O extends Model> extends ModelRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async compute(query: ModelQuery<O>): Promise<O[]> {
|
protected async compute(query: ModelQuery<O>): Promise<O[]> {
|
||||||
this.getFinalQuery().where(this.dbProperties.foreignKey, this.getModelID());
|
|
||||||
return await query.get();
|
return await query.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected applyRegularConstraints(query: ModelQuery<O>): void {
|
||||||
|
query.where(this.dbProperties.foreignKey, this.getModelID());
|
||||||
|
}
|
||||||
|
|
||||||
public async get(): Promise<O[]> {
|
public async get(): Promise<O[]> {
|
||||||
let models = await super.get();
|
let models = await super.get();
|
||||||
for (const filter of this.filters) {
|
for (const filter of this.filters) {
|
||||||
@ -161,11 +170,25 @@ export class ManyModelRelation<S extends Model, O extends Model> extends ModelRe
|
|||||||
return models;
|
return models;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async paginate(page: number, perPage: number): Promise<ModelQueryResult<O>> {
|
||||||
|
if (!this.paginatedCache[perPage]) this.paginatedCache[perPage] = {};
|
||||||
|
|
||||||
|
const cache = this.paginatedCache[perPage];
|
||||||
|
|
||||||
|
if (!cache[page]) {
|
||||||
|
const query = this.makeQuery();
|
||||||
|
this.applyRegularConstraints(query);
|
||||||
|
cache[page] = await query.paginate(page, perPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache[page];
|
||||||
|
}
|
||||||
|
|
||||||
public async eagerLoad(relations: ModelRelation<S, O, O[]>[]): Promise<ModelQueryResult<O>> {
|
public async eagerLoad(relations: ModelRelation<S, O, O[]>[]): Promise<ModelQueryResult<O>> {
|
||||||
const ids = relations.map(r => r.getModelID()).filter(id => id !== null && id !== undefined);
|
const ids = relations.map(r => r.getModelID()).filter(id => id !== null && id !== undefined);
|
||||||
if (ids.length === 0) return [];
|
if (ids.length === 0) return [];
|
||||||
|
|
||||||
const query = this.getFinalQuery();
|
const query = this.makeQuery();
|
||||||
query.where(this.dbProperties.foreignKey, ids, WhereTest.IN);
|
query.where(this.dbProperties.foreignKey, ids, WhereTest.IN);
|
||||||
return await query.get();
|
return await query.get();
|
||||||
}
|
}
|
||||||
@ -175,11 +198,11 @@ export class ManyModelRelation<S extends Model, O extends Model> extends ModelRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ManyThroughModelRelation<S extends Model, O extends Model> extends ModelRelation<S, O, O[]> {
|
export class ManyThroughModelRelation<S extends Model, O extends Model> extends ManyModelRelation<S, O> {
|
||||||
protected readonly dbProperties: PivotRelationDatabaseProperties;
|
protected readonly dbProperties: PivotRelationDatabaseProperties;
|
||||||
|
|
||||||
constructor(model: S, foreignFactory: ModelFactory<O>, dbProperties: PivotRelationDatabaseProperties) {
|
constructor(model: S, foreignFactory: ModelFactory<O>, dbProperties: PivotRelationDatabaseProperties) {
|
||||||
super(model, foreignFactory);
|
super(model, foreignFactory, dbProperties);
|
||||||
this.dbProperties = dbProperties;
|
this.dbProperties = dbProperties;
|
||||||
this.constraint(query => query
|
this.constraint(query => query
|
||||||
.leftJoin(`${this.dbProperties.pivotTable} as pivot`)
|
.leftJoin(`${this.dbProperties.pivotTable} as pivot`)
|
||||||
@ -191,34 +214,27 @@ export class ManyThroughModelRelation<S extends Model, O extends Model> extends
|
|||||||
return new ManyThroughModelRelation<S, O>(this.model, this.foreignFactory, this.dbProperties);
|
return new ManyThroughModelRelation<S, O>(this.model, this.foreignFactory, this.dbProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public cloneReduceToOne(): OneModelRelation<S, O> {
|
||||||
|
throw new Error('Cannot reduce many through relation to one model.');
|
||||||
|
}
|
||||||
|
|
||||||
public getModelID(): any {
|
public getModelID(): any {
|
||||||
return this.model[this.dbProperties.localKey];
|
return this.model[this.dbProperties.localKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async compute(query: ModelQuery<O>): Promise<O[]> {
|
protected async compute(query: ModelQuery<O>): Promise<O[]> {
|
||||||
this.getFinalQuery().where(`pivot.${this.dbProperties.localPivotKey}`, this.getModelID());
|
|
||||||
return await query.get();
|
return await query.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async get(): Promise<O[]> {
|
protected applyRegularConstraints(query: ModelQuery<O>): void {
|
||||||
let models = await super.get();
|
query.where(`pivot.${this.dbProperties.localPivotKey}`, this.getModelID());
|
||||||
for (const filter of this.filters) {
|
|
||||||
const newModels = [];
|
|
||||||
for (const model of models) {
|
|
||||||
if (await filter(model)) {
|
|
||||||
newModels.push(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
models = newModels;
|
|
||||||
}
|
|
||||||
return models;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async eagerLoad(relations: ModelRelation<S, O, O[]>[]): Promise<ModelQueryResult<O>> {
|
public async eagerLoad(relations: ModelRelation<S, O, O[]>[]): Promise<ModelQueryResult<O>> {
|
||||||
const ids = relations.map(r => r.getModelID());
|
const ids = relations.map(r => r.getModelID());
|
||||||
if (ids.length === 0) return [];
|
if (ids.length === 0) return [];
|
||||||
|
|
||||||
const query = this.getFinalQuery();
|
const query = this.makeQuery();
|
||||||
query.where(`pivot.${this.dbProperties.localPivotKey}`, ids, WhereTest.IN);
|
query.where(`pivot.${this.dbProperties.localPivotKey}`, ids, WhereTest.IN);
|
||||||
query.pivot(`pivot.${this.dbProperties.localPivotKey}`, `pivot.${this.dbProperties.foreignPivotKey}`);
|
query.pivot(`pivot.${this.dbProperties.localPivotKey}`, `pivot.${this.dbProperties.foreignPivotKey}`);
|
||||||
return await query.get();
|
return await query.get();
|
||||||
|
Loading…
Reference in New Issue
Block a user