ModelRelation: sort recursive relations by tree

This commit is contained in:
Alice Gaudon 2020-09-08 18:12:39 +02:00
parent 892b830dc4
commit e08f4fb875
4 changed files with 17 additions and 10 deletions

View File

@ -1,6 +1,6 @@
{
"name": "wms-core",
"version": "0.22.0-rc.8",
"version": "0.22.0-rc.9",
"description": "Node web application framework and toolbelt.",
"repository": "https://gitlab.com/ArisuOngaku/wms-core",
"author": "Alice Gaudon <alice@gaudon.pro>",

View File

@ -2,7 +2,7 @@ import {query, QueryResult} from "./MysqlConnectionManager";
import {Connection} from "mysql";
import Model from "./Model";
import Pagination from "../Pagination";
import ModelRelation, {RelationDatabaseProperties} from "./ModelRelation";
import ModelRelation, {RecursiveRelationDatabaseProperties} from "./ModelRelation";
import ModelFactory from "./ModelFactory";
@ -44,7 +44,7 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
private readonly subRelations: { [relation: string]: string[] } = {};
private _pivot?: string[];
private _union?: ModelQueryUnion;
private _recursiveRelation?: RelationDatabaseProperties;
private _recursiveRelation?: RecursiveRelationDatabaseProperties;
private constructor(type: QueryType, factory: ModelFactory<M>, fields?: SelectFields) {
this.type = type;
@ -135,7 +135,7 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
return this;
}
public recursive(relation: RelationDatabaseProperties): this {
public recursive(relation: RecursiveRelationDatabaseProperties): this {
if (this.type !== QueryType.SELECT) throw new Error('Recursive queries are only implemented with SELECT.');
this._recursiveRelation = relation;
return this;
@ -191,10 +191,10 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
if (this._recursiveRelation) {
const cteFields = fields.replace(RegExp(`${table}`, 'g'), 'o');
query = `WITH RECURSIVE cte AS (`
+ `SELECT ${fields} FROM ${table}${where}`
+ `SELECT ${fields},1 AS __depth, ARRAY[\`${this._recursiveRelation.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,c.__path || o.\`${this._recursiveRelation.idKey}\` FROM ${table} AS o, cte AS c WHERE o.\`${this._recursiveRelation.foreignKey}\`=c.\`${this._recursiveRelation.localKey}\``
+ `) SELECT * FROM cte${join}${orderBy || ` ORDER BY __path`}${limit}`;
} else {
query = `SELECT ${fields} FROM ${table}${join}${where}${orderBy}${limit}`;
}

View File

@ -201,8 +201,11 @@ 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) {
protected readonly dbProperties: RecursiveRelationDatabaseProperties;
public constructor(model: M, foreignModelType: ModelType<M>, dbProperties: RecursiveRelationDatabaseProperties) {
super(model, foreignModelType, dbProperties);
this.dbProperties = dbProperties;
this.constraint(query => query.recursive(this.dbProperties));
}
@ -240,3 +243,7 @@ export type PivotRelationDatabaseProperties = RelationDatabaseProperties & {
localPivotKey: string;
foreignPivotKey: string;
};
export type RecursiveRelationDatabaseProperties = RelationDatabaseProperties & {
idKey: string;
};

View File

@ -59,10 +59,10 @@ 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.recursive({localKey: 'local', foreignKey: 'foreign', idKey: 'foreign'});
query.sortBy('f2', 'ASC').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, ARRAY[`foreign`] AS __path FROM `model` WHERE `f1`=? UNION SELECT o.*, c.__depth + 1,c.__path || o.`foreign` 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.variables).toStrictEqual(['v1']);
});