ModelRelation: sort recursive relations by tree
This commit is contained in:
parent
892b830dc4
commit
969ab18b96
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wms-core",
|
||||
"version": "0.22.0-rc.8",
|
||||
"version": "0.22.0-rc.11",
|
||||
"description": "Node web application framework and toolbelt.",
|
||||
"repository": "https://gitlab.com/ArisuOngaku/wms-core",
|
||||
"author": "Alice Gaudon <alice@gaudon.pro>",
|
||||
|
@ -45,6 +45,7 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
|
||||
private _pivot?: string[];
|
||||
private _union?: ModelQueryUnion;
|
||||
private _recursiveRelation?: RelationDatabaseProperties;
|
||||
private _reverseRecursiveRelation?: boolean;
|
||||
|
||||
private constructor(type: QueryType, factory: ModelFactory<M>, fields?: SelectFields) {
|
||||
this.type = type;
|
||||
@ -109,7 +110,7 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
|
||||
public with(...relations: string[]): this {
|
||||
relations.forEach(relation => {
|
||||
const parts = relation.split('.');
|
||||
this.relations.push(parts[0]);
|
||||
if (this.relations.indexOf(parts[0]) < 0) this.relations.push(parts[0]);
|
||||
if (parts.length > 1) {
|
||||
if (!this.subRelations[parts[0]]) this.subRelations[parts[0]] = [];
|
||||
this.subRelations[parts[0]].push(parts.slice(1).join('.'));
|
||||
@ -135,9 +136,10 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
|
||||
return this;
|
||||
}
|
||||
|
||||
public recursive(relation: RelationDatabaseProperties): this {
|
||||
public recursive(relation: RelationDatabaseProperties, reverse: boolean): this {
|
||||
if (this.type !== QueryType.SELECT) throw new Error('Recursive queries are only implemented with SELECT.');
|
||||
this._recursiveRelation = relation;
|
||||
this._reverseRecursiveRelation = reverse;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -190,11 +192,14 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
|
||||
case QueryType.SELECT:
|
||||
if (this._recursiveRelation) {
|
||||
const cteFields = fields.replace(RegExp(`${table}`, 'g'), 'o');
|
||||
const idKey = this._reverseRecursiveRelation ? this._recursiveRelation.foreignKey : this._recursiveRelation.localKey;
|
||||
const sortOrder = this._reverseRecursiveRelation ? 'DESC' : 'ASC';
|
||||
|
||||
query = `WITH RECURSIVE cte AS (`
|
||||
+ `SELECT ${fields} FROM ${table}${where}`
|
||||
+ `SELECT ${fields},1 AS __depth, CONCAT(\`${idKey}\`) AS __path FROM ${table}${where}`
|
||||
+ ` UNION `
|
||||
+ `SELECT ${cteFields} FROM ${table} AS o, cte AS c WHERE o.\`${this._recursiveRelation.foreignKey}\`=c.\`${this._recursiveRelation.localKey}\``
|
||||
+ `) SELECT * FROM cte${join}${orderBy}${limit}`;
|
||||
+ `SELECT ${cteFields},c.__depth + 1,CONCAT(c.__path,'/',o.\`${idKey}\`) AS __path FROM ${table} AS o, cte AS c WHERE o.\`${this._recursiveRelation.foreignKey}\`=c.\`${this._recursiveRelation.localKey}\``
|
||||
+ `) SELECT * FROM cte${join}${orderBy || ` ORDER BY __path ${sortOrder}`}${limit}`;
|
||||
} else {
|
||||
query = `SELECT ${fields} FROM ${table}${join}${where}${orderBy}${limit}`;
|
||||
}
|
||||
|
@ -201,9 +201,12 @@ export class ManyThroughModelRelation<S extends Model, O extends Model> extends
|
||||
}
|
||||
|
||||
export class RecursiveModelRelation<M extends Model> extends ManyModelRelation<M, M> {
|
||||
public constructor(model: M, foreignModelType: ModelType<M>, dbProperties: RelationDatabaseProperties) {
|
||||
private readonly reverse: boolean;
|
||||
|
||||
public constructor(model: M, foreignModelType: ModelType<M>, dbProperties: RelationDatabaseProperties, reverse: boolean = false) {
|
||||
super(model, foreignModelType, dbProperties);
|
||||
this.constraint(query => query.recursive(this.dbProperties));
|
||||
this.constraint(query => query.recursive(this.dbProperties, reverse));
|
||||
this.reverse = reverse;
|
||||
}
|
||||
|
||||
public clone(): RecursiveModelRelation<M> {
|
||||
@ -221,6 +224,8 @@ export class RecursiveModelRelation<M extends Model> extends ManyModelRelation<M
|
||||
this.cachedModels!.find(cached => cached[this.dbProperties.localKey] === model[this.dbProperties.foreignKey])
|
||||
));
|
||||
} while (count !== this.cachedModels.length);
|
||||
|
||||
if (this.reverse) this.cachedModels!.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,11 +59,19 @@ describe('Test ModelQuery', () => {
|
||||
const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory<Model>, '*');
|
||||
query.where('f1', 'v1');
|
||||
query.leftJoin('test').on('model.j1', 'test.j2');
|
||||
query.recursive({localKey: 'local', foreignKey: 'foreign'});
|
||||
query.sortBy('f2', 'ASC').limit(8);
|
||||
query.recursive({localKey: 'local', foreignKey: 'foreign'}, false);
|
||||
query.limit(8);
|
||||
|
||||
expect(query.toString(true)).toBe("WITH RECURSIVE cte AS (SELECT `model`.* FROM `model` WHERE `f1`=? UNION SELECT o.* FROM `model` AS o, cte AS c WHERE o.`foreign`=c.`local`) SELECT * FROM cte LEFT JOIN `test` ON `model`.`j1`=`test`.`j2` ORDER BY `f2` ASC LIMIT 8");
|
||||
expect(query.toString(true)).toBe("WITH RECURSIVE cte AS (SELECT `model`.*,1 AS __depth, CONCAT(`local`) AS __path FROM `model` WHERE `f1`=? UNION SELECT o.*,c.__depth + 1,CONCAT(c.__path,'/',o.`local`) AS __path FROM `model` AS o, cte AS c WHERE o.`foreign`=c.`local`) SELECT * FROM cte LEFT JOIN `test` ON `model`.`j1`=`test`.`j2` ORDER BY __path ASC LIMIT 8");
|
||||
expect(query.variables).toStrictEqual(['v1']);
|
||||
|
||||
const reversedQuery = ModelQuery.select({table: 'model'} as unknown as ModelFactory<Model>, '*');
|
||||
reversedQuery.where('f1', 'v1');
|
||||
reversedQuery.leftJoin('test').on('model.j1', 'test.j2');
|
||||
reversedQuery.recursive({localKey: 'local', foreignKey: 'foreign'}, true);
|
||||
|
||||
expect(reversedQuery.toString(true)).toBe("WITH RECURSIVE cte AS (SELECT `model`.*,1 AS __depth, CONCAT(`foreign`) AS __path FROM `model` WHERE `f1`=? UNION SELECT o.*,c.__depth + 1,CONCAT(c.__path,'/',o.`foreign`) AS __path FROM `model` AS o, cte AS c WHERE o.`foreign`=c.`local`) SELECT * FROM cte LEFT JOIN `test` ON `model`.`j1`=`test`.`j2` ORDER BY __path DESC");
|
||||
expect(reversedQuery.variables).toStrictEqual(['v1']);
|
||||
});
|
||||
|
||||
test('union queries', () => {
|
||||
|
Loading…
Reference in New Issue
Block a user