@casekit/orm2 0.0.0-20250322230249
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/builders/buildCount.d.ts +23 -0
- package/build/builders/buildCount.js +63 -0
- package/build/builders/buildCount.test.d.ts +1 -0
- package/build/builders/buildCount.test.js +144 -0
- package/build/builders/buildCreate.d.ts +5 -0
- package/build/builders/buildCreate.js +28 -0
- package/build/builders/buildCreate.test.d.ts +1 -0
- package/build/builders/buildCreate.test.js +47 -0
- package/build/builders/buildDelete.d.ts +5 -0
- package/build/builders/buildDelete.js +28 -0
- package/build/builders/buildDelete.test.d.ts +1 -0
- package/build/builders/buildDelete.test.js +108 -0
- package/build/builders/buildFind.d.ts +8 -0
- package/build/builders/buildFind.js +185 -0
- package/build/builders/buildFind.test.d.ts +1 -0
- package/build/builders/buildFind.test.js +263 -0
- package/build/builders/buildUpdate.d.ts +5 -0
- package/build/builders/buildUpdate.js +34 -0
- package/build/builders/buildUpdate.test.d.ts +1 -0
- package/build/builders/buildUpdate.test.js +130 -0
- package/build/builders/buildWhere.d.ts +6 -0
- package/build/builders/buildWhere.js +63 -0
- package/build/builders/buildWhere.test.d.ts +1 -0
- package/build/builders/buildWhere.test.js +154 -0
- package/build/builders/types.d.ts +87 -0
- package/build/builders/types.js +1 -0
- package/build/connection.d.ts +31 -0
- package/build/connection.js +206 -0
- package/build/index.d.ts +10 -0
- package/build/index.js +5 -0
- package/build/operators.d.ts +59 -0
- package/build/operators.js +44 -0
- package/build/orm.count.d.ts +14 -0
- package/build/orm.count.js +22 -0
- package/build/orm.createMany.d.ts +5 -0
- package/build/orm.createMany.js +26 -0
- package/build/orm.createOne.d.ts +5 -0
- package/build/orm.createOne.js +34 -0
- package/build/orm.d.ts +81 -0
- package/build/orm.deleteMany.d.ts +5 -0
- package/build/orm.deleteMany.js +26 -0
- package/build/orm.deleteOne.d.ts +5 -0
- package/build/orm.deleteOne.js +32 -0
- package/build/orm.findMany.d.ts +8 -0
- package/build/orm.findMany.js +64 -0
- package/build/orm.findOne.d.ts +5 -0
- package/build/orm.findOne.js +20 -0
- package/build/orm.js +243 -0
- package/build/orm.restrict.d.ts +6 -0
- package/build/orm.restrict.js +52 -0
- package/build/orm.updateMany.d.ts +5 -0
- package/build/orm.updateMany.js +29 -0
- package/build/orm.updateOne.d.ts +5 -0
- package/build/orm.updateOne.js +35 -0
- package/build/sql/countToSql.d.ts +3 -0
- package/build/sql/countToSql.js +11 -0
- package/build/sql/countToSql.test.d.ts +1 -0
- package/build/sql/countToSql.test.js +218 -0
- package/build/sql/createToSql.d.ts +3 -0
- package/build/sql/createToSql.js +27 -0
- package/build/sql/createToSql.test.d.ts +1 -0
- package/build/sql/createToSql.test.js +186 -0
- package/build/sql/deleteToSql.d.ts +3 -0
- package/build/sql/deleteToSql.js +15 -0
- package/build/sql/deleteToSql.test.d.ts +1 -0
- package/build/sql/deleteToSql.test.js +93 -0
- package/build/sql/findToSql.d.ts +3 -0
- package/build/sql/findToSql.js +33 -0
- package/build/sql/findToSql.test.d.ts +1 -0
- package/build/sql/findToSql.test.js +409 -0
- package/build/sql/updateToSql.d.ts +3 -0
- package/build/sql/updateToSql.js +16 -0
- package/build/sql/updateToSql.test.d.ts +1 -0
- package/build/sql/updateToSql.test.js +165 -0
- package/build/sql/util.d.ts +11 -0
- package/build/sql/util.js +36 -0
- package/build/sql/util.test.d.ts +1 -0
- package/build/sql/util.test.js +163 -0
- package/build/tests/connection.test.d.ts +1 -0
- package/build/tests/connection.test.js +304 -0
- package/build/tests/datatypes.test.d.ts +1 -0
- package/build/tests/datatypes.test.js +239 -0
- package/build/tests/operators.test.d.ts +1 -0
- package/build/tests/operators.test.js +125 -0
- package/build/tests/orm.count.middleware.test.d.ts +1 -0
- package/build/tests/orm.count.middleware.test.js +132 -0
- package/build/tests/orm.count.test-d.d.ts +1 -0
- package/build/tests/orm.count.test-d.js +60 -0
- package/build/tests/orm.count.test.d.ts +1 -0
- package/build/tests/orm.count.test.js +151 -0
- package/build/tests/orm.createMany.middleware.test.d.ts +1 -0
- package/build/tests/orm.createMany.middleware.test.js +63 -0
- package/build/tests/orm.createMany.test-d.d.ts +1 -0
- package/build/tests/orm.createMany.test-d.js +131 -0
- package/build/tests/orm.createMany.test.d.ts +1 -0
- package/build/tests/orm.createMany.test.js +392 -0
- package/build/tests/orm.createOne.middleware.test.d.ts +1 -0
- package/build/tests/orm.createOne.middleware.test.js +54 -0
- package/build/tests/orm.createOne.test-d.d.ts +1 -0
- package/build/tests/orm.createOne.test-d.js +113 -0
- package/build/tests/orm.createOne.test.d.ts +1 -0
- package/build/tests/orm.createOne.test.js +268 -0
- package/build/tests/orm.deleteMany.middleware.test.d.ts +1 -0
- package/build/tests/orm.deleteMany.middleware.test.js +77 -0
- package/build/tests/orm.deleteMany.test-d.d.ts +1 -0
- package/build/tests/orm.deleteMany.test-d.js +179 -0
- package/build/tests/orm.deleteMany.test.d.ts +1 -0
- package/build/tests/orm.deleteMany.test.js +394 -0
- package/build/tests/orm.deleteOne.middleware.test.d.ts +1 -0
- package/build/tests/orm.deleteOne.middleware.test.js +61 -0
- package/build/tests/orm.deleteOne.test-d.d.ts +1 -0
- package/build/tests/orm.deleteOne.test-d.js +179 -0
- package/build/tests/orm.deleteOne.test.d.ts +1 -0
- package/build/tests/orm.deleteOne.test.js +360 -0
- package/build/tests/orm.findMany.includeManyToMany.test.d.ts +1 -0
- package/build/tests/orm.findMany.includeManyToMany.test.js +335 -0
- package/build/tests/orm.findMany.includeManyToOne.test.d.ts +1 -0
- package/build/tests/orm.findMany.includeManyToOne.test.js +286 -0
- package/build/tests/orm.findMany.includeOneToMany.test.d.ts +1 -0
- package/build/tests/orm.findMany.includeOneToMany.test.js +530 -0
- package/build/tests/orm.findMany.middleware.test.d.ts +1 -0
- package/build/tests/orm.findMany.middleware.test.js +66 -0
- package/build/tests/orm.findMany.offsetLimit.test.d.ts +1 -0
- package/build/tests/orm.findMany.offsetLimit.test.js +108 -0
- package/build/tests/orm.findMany.orderBy.test.d.ts +1 -0
- package/build/tests/orm.findMany.orderBy.test.js +304 -0
- package/build/tests/orm.findMany.select.test.d.ts +1 -0
- package/build/tests/orm.findMany.select.test.js +278 -0
- package/build/tests/orm.findMany.test-d.d.ts +1 -0
- package/build/tests/orm.findMany.test-d.js +374 -0
- package/build/tests/orm.findMany.where.test.d.ts +1 -0
- package/build/tests/orm.findMany.where.test.js +383 -0
- package/build/tests/orm.findOne.middleware.test.d.ts +1 -0
- package/build/tests/orm.findOne.middleware.test.js +57 -0
- package/build/tests/orm.findOne.test-d.d.ts +1 -0
- package/build/tests/orm.findOne.test-d.js +377 -0
- package/build/tests/orm.findOne.test.d.ts +1 -0
- package/build/tests/orm.findOne.test.js +247 -0
- package/build/tests/orm.restrict.test-d.d.ts +1 -0
- package/build/tests/orm.restrict.test-d.js +105 -0
- package/build/tests/orm.restrict.test.d.ts +1 -0
- package/build/tests/orm.restrict.test.js +259 -0
- package/build/tests/orm.transact.test.d.ts +1 -0
- package/build/tests/orm.transact.test.js +48 -0
- package/build/tests/orm.updateMany.middleware.test.d.ts +1 -0
- package/build/tests/orm.updateMany.middleware.test.js +72 -0
- package/build/tests/orm.updateMany.test.d.ts +1 -0
- package/build/tests/orm.updateMany.test.js +210 -0
- package/build/tests/orm.updateOne.middleware.test.d.ts +1 -0
- package/build/tests/orm.updateOne.middleware.test.js +62 -0
- package/build/tests/orm.updateOne.test.d.ts +1 -0
- package/build/tests/orm.updateOne.test.js +209 -0
- package/build/tests/util/db.d.ts +1571 -0
- package/build/tests/util/db.js +10 -0
- package/build/tests/util/logger.d.ts +19 -0
- package/build/tests/util/logger.js +40 -0
- package/build/types/BaseFindParams.d.ts +1 -0
- package/build/types/BaseFindParams.js +1 -0
- package/build/types/CountParams.d.ts +16 -0
- package/build/types/CountParams.js +1 -0
- package/build/types/CountParams.test-d.d.ts +1 -0
- package/build/types/CountParams.test-d.js +89 -0
- package/build/types/CreateManyParams.d.ts +11 -0
- package/build/types/CreateManyParams.js +1 -0
- package/build/types/CreateManyParams.test-d.d.ts +1 -0
- package/build/types/CreateManyParams.test-d.js +83 -0
- package/build/types/CreateManyResult.d.ts +5 -0
- package/build/types/CreateManyResult.js +1 -0
- package/build/types/CreateManyResult.test-d.d.ts +1 -0
- package/build/types/CreateManyResult.test-d.js +22 -0
- package/build/types/CreateOneParams.d.ts +11 -0
- package/build/types/CreateOneParams.js +1 -0
- package/build/types/CreateOneParams.test-d.d.ts +1 -0
- package/build/types/CreateOneParams.test-d.js +56 -0
- package/build/types/CreateOneResult.d.ts +5 -0
- package/build/types/CreateOneResult.js +1 -0
- package/build/types/CreateOneResult.test-d.d.ts +1 -0
- package/build/types/CreateOneResult.test-d.js +23 -0
- package/build/types/CreateValues.d.ts +6 -0
- package/build/types/CreateValues.js +1 -0
- package/build/types/CreateValues.test-d.d.ts +1 -0
- package/build/types/CreateValues.test-d.js +60 -0
- package/build/types/DeleteManyResult.d.ts +5 -0
- package/build/types/DeleteManyResult.js +1 -0
- package/build/types/DeleteManyResult.test-d.d.ts +1 -0
- package/build/types/DeleteManyResult.test-d.js +23 -0
- package/build/types/DeleteOneResult.d.ts +5 -0
- package/build/types/DeleteOneResult.js +1 -0
- package/build/types/DeleteOneResult.test-d.d.ts +1 -0
- package/build/types/DeleteOneResult.test-d.js +23 -0
- package/build/types/DeleteParams.d.ts +7 -0
- package/build/types/DeleteParams.js +1 -0
- package/build/types/DeleteParams.test-d.d.ts +1 -0
- package/build/types/DeleteParams.test-d.js +46 -0
- package/build/types/FindParams.d.ts +22 -0
- package/build/types/FindParams.js +1 -0
- package/build/types/FindParams.test-d.d.ts +1 -0
- package/build/types/FindParams.test-d.js +107 -0
- package/build/types/FindResult.d.ts +13 -0
- package/build/types/FindResult.js +1 -0
- package/build/types/FindResult.test-d.d.ts +1 -0
- package/build/types/FindResult.test-d.js +30 -0
- package/build/types/IncludeClause.d.ts +5 -0
- package/build/types/IncludeClause.js +1 -0
- package/build/types/IncludeClause.test-d.d.ts +1 -0
- package/build/types/IncludeClause.test-d.js +69 -0
- package/build/types/Middleware.d.ts +51 -0
- package/build/types/Middleware.js +37 -0
- package/build/types/OptionalValues.d.ts +4 -0
- package/build/types/OptionalValues.js +1 -0
- package/build/types/OptionalValues.test-d.d.ts +1 -0
- package/build/types/OptionalValues.test-d.js +12 -0
- package/build/types/OrderByClause.d.ts +9 -0
- package/build/types/OrderByClause.js +1 -0
- package/build/types/OrderByClause.test-d.d.ts +1 -0
- package/build/types/OrderByClause.test-d.js +44 -0
- package/build/types/RequiredValues.d.ts +4 -0
- package/build/types/RequiredValues.js +1 -0
- package/build/types/RequiredValues.test-d.d.ts +1 -0
- package/build/types/RequiredValues.test-d.js +22 -0
- package/build/types/RestrictModels.d.ts +23 -0
- package/build/types/RestrictModels.js +1 -0
- package/build/types/RestrictModels.test-d.d.ts +1 -0
- package/build/types/RestrictModels.test-d.js +44 -0
- package/build/types/ReturningClause.d.ts +3 -0
- package/build/types/ReturningClause.js +1 -0
- package/build/types/ReturningClause.test-d.d.ts +1 -0
- package/build/types/ReturningClause.test-d.js +15 -0
- package/build/types/SelectClause.d.ts +3 -0
- package/build/types/SelectClause.js +1 -0
- package/build/types/SelectClause.test-d.d.ts +1 -0
- package/build/types/SelectClause.test-d.js +15 -0
- package/build/types/UpdateManyResult.d.ts +5 -0
- package/build/types/UpdateManyResult.js +1 -0
- package/build/types/UpdateManyResult.test-d.d.ts +1 -0
- package/build/types/UpdateManyResult.test-d.js +15 -0
- package/build/types/UpdateOneResult.d.ts +5 -0
- package/build/types/UpdateOneResult.js +1 -0
- package/build/types/UpdateOneResult.test-d.d.ts +1 -0
- package/build/types/UpdateOneResult.test-d.js +15 -0
- package/build/types/UpdateParams.d.ts +9 -0
- package/build/types/UpdateParams.js +1 -0
- package/build/types/UpdateParams.test-d.d.ts +1 -0
- package/build/types/UpdateParams.test-d.js +29 -0
- package/build/types/UpdateValues.d.ts +6 -0
- package/build/types/UpdateValues.js +1 -0
- package/build/types/UpdateValues.test-d.d.ts +1 -0
- package/build/types/UpdateValues.test-d.js +33 -0
- package/build/types/WhereClause.d.ts +29 -0
- package/build/types/WhereClause.js +1 -0
- package/build/types/WhereClause.test-d.d.ts +1 -0
- package/build/types/WhereClause.test-d.js +137 -0
- package/build/util/getIncludedToManySubqueries.d.ts +12 -0
- package/build/util/getIncludedToManySubqueries.js +63 -0
- package/build/util/getIncludedToManySubqueries.test.d.ts +1 -0
- package/build/util/getIncludedToManySubqueries.test.js +121 -0
- package/build/util/getLateralJoinValues.d.ts +4 -0
- package/build/util/getLateralJoinValues.js +30 -0
- package/build/util/getLateralJoinValues.test.d.ts +1 -0
- package/build/util/getLateralJoinValues.test.js +99 -0
- package/build/util/hasClauses.d.ts +1 -0
- package/build/util/hasClauses.js +9 -0
- package/build/util/hasClauses.test.d.ts +1 -0
- package/build/util/hasClauses.test.js +15 -0
- package/build/util/makeTableAlias.d.ts +1 -0
- package/build/util/makeTableAlias.js +10 -0
- package/build/util/makeTableAlias.test.d.ts +1 -0
- package/build/util/makeTableAlias.test.js +18 -0
- package/build/util/resultSchema.d.ts +10 -0
- package/build/util/resultSchema.js +42 -0
- package/build/util/rowToObject.d.ts +8 -0
- package/build/util/rowToObject.js +10 -0
- package/build/util/rowToObject.test.d.ts +1 -0
- package/build/util/rowToObject.test.js +68 -0
- package/package.json +67 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NB. Lots of ! in this file which maybe isn't great but I think for these
|
|
3
|
+
* builders, where we can be fairly confident due to the type-checking at the edges
|
|
4
|
+
* that things are defined, it's better than the alternative of loads of
|
|
5
|
+
* redundant checks for undefined. We've done all the checks we need at the
|
|
6
|
+
* stage of normalizing the model, we can now assume everything is wired up
|
|
7
|
+
* correctly.
|
|
8
|
+
*
|
|
9
|
+
* Also this is a file in which there's a lot of mutation and dependency
|
|
10
|
+
* on the order in which things are done, which is not ideal but is what
|
|
11
|
+
* it is. Refactor and/or add to/change with care.
|
|
12
|
+
*/
|
|
13
|
+
import { NormalizedConfig } from "@casekit/orm2-config";
|
|
14
|
+
import { ModelDefinitions, OperatorDefinitions } from "@casekit/orm2-schema";
|
|
15
|
+
import { WhereClause } from "../types/WhereClause.js";
|
|
16
|
+
import { CountBuilder } from "./types.js";
|
|
17
|
+
type BaseCountParams = {
|
|
18
|
+
where?: WhereClause<ModelDefinitions, OperatorDefinitions, string>;
|
|
19
|
+
include?: Record<string, BaseCountParams>;
|
|
20
|
+
for?: "update" | "no key update" | "share" | "key share";
|
|
21
|
+
};
|
|
22
|
+
export declare const buildCount: (config: NormalizedConfig, modelName: string, query: BaseCountParams, path?: string[], tableIndex?: number) => CountBuilder;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { hasClauses } from "#util/hasClauses.js";
|
|
2
|
+
import { makeTableAlias } from "#util/makeTableAlias.js";
|
|
3
|
+
import { buildWhere } from "./buildWhere.js";
|
|
4
|
+
/**
|
|
5
|
+
* Builds a base CountBuilder, with only columns from the main table.
|
|
6
|
+
* Joins will be added later.
|
|
7
|
+
*/
|
|
8
|
+
const buildBaseCount = (config, m, query, tableIndex = 0) => {
|
|
9
|
+
const model = config.models[m];
|
|
10
|
+
if (!model)
|
|
11
|
+
throw new Error(`Model "${m}" not found`);
|
|
12
|
+
const table = {
|
|
13
|
+
schema: model.schema,
|
|
14
|
+
name: model.table,
|
|
15
|
+
alias: makeTableAlias(tableIndex++),
|
|
16
|
+
model: m,
|
|
17
|
+
};
|
|
18
|
+
const where = hasClauses(query.where)
|
|
19
|
+
? buildWhere(config, table, query.where)
|
|
20
|
+
: null;
|
|
21
|
+
return {
|
|
22
|
+
table,
|
|
23
|
+
where,
|
|
24
|
+
joins: [],
|
|
25
|
+
for: query.for,
|
|
26
|
+
tableIndex,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export const buildCount = (config, modelName, query, path = [], tableIndex = 0) => {
|
|
30
|
+
const model = config.models[modelName];
|
|
31
|
+
if (!model)
|
|
32
|
+
throw new Error(`Model "${modelName}" not found`);
|
|
33
|
+
const builder = buildBaseCount(config, modelName, query, tableIndex);
|
|
34
|
+
for (const [r, subquery] of Object.entries(query.include ?? {})) {
|
|
35
|
+
const relation = model.relations[r];
|
|
36
|
+
if (relation.type !== "N:1") {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const joinBuilder = buildCount(config, relation.model, subquery, [...path, r], builder.tableIndex);
|
|
40
|
+
builder.joins.push({
|
|
41
|
+
path: [...path, r],
|
|
42
|
+
relation: r,
|
|
43
|
+
table: joinBuilder.table,
|
|
44
|
+
where: joinBuilder.where,
|
|
45
|
+
type: "INNER",
|
|
46
|
+
columns: relation.from.columns.map((fk, i) => ({
|
|
47
|
+
from: {
|
|
48
|
+
table: builder.table.alias,
|
|
49
|
+
name: fk,
|
|
50
|
+
},
|
|
51
|
+
to: {
|
|
52
|
+
table: joinBuilder.table.alias,
|
|
53
|
+
name: relation.to.columns[i],
|
|
54
|
+
},
|
|
55
|
+
})),
|
|
56
|
+
});
|
|
57
|
+
// update the parent builder's tableIndex with the one from the
|
|
58
|
+
// joinBuilder, so that we don't have overlapping table indices
|
|
59
|
+
builder.tableIndex = joinBuilder.tableIndex;
|
|
60
|
+
builder.joins.push(...joinBuilder.joins);
|
|
61
|
+
}
|
|
62
|
+
return builder;
|
|
63
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { sql } from "@casekit/sql";
|
|
3
|
+
import { createTestDB } from "../tests/util/db.js";
|
|
4
|
+
import { buildCount } from "./buildCount.js";
|
|
5
|
+
describe("buildCount", () => {
|
|
6
|
+
const { db } = createTestDB();
|
|
7
|
+
test("builds basic count query", () => {
|
|
8
|
+
const result = buildCount(db.config, "post", {});
|
|
9
|
+
expect(result).toEqual({
|
|
10
|
+
table: {
|
|
11
|
+
schema: "orm",
|
|
12
|
+
name: "post",
|
|
13
|
+
alias: "a",
|
|
14
|
+
model: "post",
|
|
15
|
+
},
|
|
16
|
+
where: null,
|
|
17
|
+
joins: [],
|
|
18
|
+
for: undefined,
|
|
19
|
+
tableIndex: 1,
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
test("builds count query with N:1 relation include", () => {
|
|
23
|
+
const result = buildCount(db.config, "post", {
|
|
24
|
+
where: { id: 1 },
|
|
25
|
+
include: {
|
|
26
|
+
author: {
|
|
27
|
+
where: {},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
expect(result).toEqual({
|
|
32
|
+
table: {
|
|
33
|
+
schema: "orm",
|
|
34
|
+
name: "post",
|
|
35
|
+
alias: "a",
|
|
36
|
+
model: "post",
|
|
37
|
+
},
|
|
38
|
+
where: sql `"a"."id" = ${1}`,
|
|
39
|
+
joins: [
|
|
40
|
+
{
|
|
41
|
+
relation: "author",
|
|
42
|
+
table: {
|
|
43
|
+
schema: "orm",
|
|
44
|
+
name: "user",
|
|
45
|
+
alias: "b",
|
|
46
|
+
model: "user",
|
|
47
|
+
},
|
|
48
|
+
where: null,
|
|
49
|
+
type: "INNER",
|
|
50
|
+
path: ["author"],
|
|
51
|
+
columns: [
|
|
52
|
+
{
|
|
53
|
+
from: { table: "a", name: "author_id" },
|
|
54
|
+
to: { table: "b", name: "id" },
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
for: undefined,
|
|
60
|
+
tableIndex: 2,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
test("builds count query with where clause", () => {
|
|
64
|
+
const result = buildCount(db.config, "post", {
|
|
65
|
+
where: {
|
|
66
|
+
title: "Test Post",
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
expect(result).toEqual({
|
|
70
|
+
table: {
|
|
71
|
+
schema: "orm",
|
|
72
|
+
name: "post",
|
|
73
|
+
alias: "a",
|
|
74
|
+
model: "post",
|
|
75
|
+
},
|
|
76
|
+
where: sql `"a"."title" = ${"Test Post"}`,
|
|
77
|
+
joins: [],
|
|
78
|
+
for: undefined,
|
|
79
|
+
tableIndex: 1,
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
test("builds count query with nested includes and where clauses", () => {
|
|
83
|
+
const result = buildCount(db.config, "post", {
|
|
84
|
+
where: {
|
|
85
|
+
title: "Test Post",
|
|
86
|
+
},
|
|
87
|
+
include: {
|
|
88
|
+
author: {
|
|
89
|
+
where: {
|
|
90
|
+
name: "John",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
expect(result).toEqual({
|
|
96
|
+
table: {
|
|
97
|
+
schema: "orm",
|
|
98
|
+
name: "post",
|
|
99
|
+
alias: "a",
|
|
100
|
+
model: "post",
|
|
101
|
+
},
|
|
102
|
+
where: sql `"a"."title" = ${"Test Post"}`,
|
|
103
|
+
joins: [
|
|
104
|
+
{
|
|
105
|
+
relation: "author",
|
|
106
|
+
table: {
|
|
107
|
+
schema: "orm",
|
|
108
|
+
name: "user",
|
|
109
|
+
alias: "b",
|
|
110
|
+
model: "user",
|
|
111
|
+
},
|
|
112
|
+
where: sql `"b"."name" = ${"John"}`,
|
|
113
|
+
type: "INNER",
|
|
114
|
+
path: ["author"],
|
|
115
|
+
columns: [
|
|
116
|
+
{
|
|
117
|
+
from: { table: "a", name: "author_id" },
|
|
118
|
+
to: { table: "b", name: "id" },
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
for: undefined,
|
|
124
|
+
tableIndex: 2,
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
test("builds count query with for parameter", () => {
|
|
128
|
+
const result = buildCount(db.config, "post", {
|
|
129
|
+
for: "update",
|
|
130
|
+
});
|
|
131
|
+
expect(result).toEqual({
|
|
132
|
+
table: {
|
|
133
|
+
schema: "orm",
|
|
134
|
+
name: "post",
|
|
135
|
+
alias: "a",
|
|
136
|
+
model: "post",
|
|
137
|
+
},
|
|
138
|
+
where: null,
|
|
139
|
+
joins: [],
|
|
140
|
+
for: "update",
|
|
141
|
+
tableIndex: 1,
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NormalizedConfig } from "@casekit/orm2-config";
|
|
2
|
+
import { ModelDefinitions, ModelName } from "@casekit/orm2-schema";
|
|
3
|
+
import { CreateManyParams } from "#types/CreateManyParams.js";
|
|
4
|
+
import { CreateBuilder } from "./types.js";
|
|
5
|
+
export declare const buildCreate: (config: NormalizedConfig, modelName: string, query: CreateManyParams<ModelDefinitions, ModelName<ModelDefinitions>>, path?: string[], tableIndex?: number) => CreateBuilder;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { uniq } from "es-toolkit";
|
|
2
|
+
import { makeTableAlias } from "#util/makeTableAlias.js";
|
|
3
|
+
export const buildCreate = (config, modelName, query, path = [], tableIndex = 0) => {
|
|
4
|
+
const model = config.models[modelName];
|
|
5
|
+
if (!model)
|
|
6
|
+
throw new Error(`Model "${modelName}" not found`);
|
|
7
|
+
const fields = uniq(query.values.flatMap(Object.keys));
|
|
8
|
+
const table = {
|
|
9
|
+
schema: model.schema,
|
|
10
|
+
name: model.table,
|
|
11
|
+
alias: makeTableAlias(tableIndex++),
|
|
12
|
+
model: modelName,
|
|
13
|
+
};
|
|
14
|
+
const columns = fields.map((f) => model.fields[f].column);
|
|
15
|
+
const values = query.values.map((v) => fields.map((f) => v[f] ?? null));
|
|
16
|
+
const returning = query.returning?.map((f, index) => ({
|
|
17
|
+
name: model.fields[f].column,
|
|
18
|
+
alias: `${table.alias}_${index}`,
|
|
19
|
+
path: [...path, f],
|
|
20
|
+
})) ?? [];
|
|
21
|
+
return {
|
|
22
|
+
table,
|
|
23
|
+
columns,
|
|
24
|
+
values,
|
|
25
|
+
returning,
|
|
26
|
+
onConflict: query.onConflict,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { createTestDB } from "../tests/util/db.js";
|
|
3
|
+
import { buildCreate } from "./buildCreate.js";
|
|
4
|
+
describe("buildCreate", () => {
|
|
5
|
+
const { db } = createTestDB();
|
|
6
|
+
test("should build a create query", () => {
|
|
7
|
+
const result = buildCreate(db.config, "user", {
|
|
8
|
+
values: [{ id: 1, name: "John Doe", email: "john@example.com" }],
|
|
9
|
+
});
|
|
10
|
+
expect(result).toEqual({
|
|
11
|
+
table: {
|
|
12
|
+
schema: "orm",
|
|
13
|
+
name: "user",
|
|
14
|
+
alias: "a",
|
|
15
|
+
model: "user",
|
|
16
|
+
},
|
|
17
|
+
columns: ["id", "name", "email"],
|
|
18
|
+
values: [[1, "John Doe", "john@example.com"]],
|
|
19
|
+
returning: [],
|
|
20
|
+
onConflict: undefined,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
test("should throw an error if model is not found", () => {
|
|
24
|
+
expect(() => buildCreate(db.config, "NonExistentModel", {
|
|
25
|
+
values: [
|
|
26
|
+
{ id: 1, name: "John Doe", email: "john@example.com" },
|
|
27
|
+
],
|
|
28
|
+
})).toThrow('Model "NonExistentModel" not found');
|
|
29
|
+
});
|
|
30
|
+
test("should handle returning fields", () => {
|
|
31
|
+
const result = buildCreate(db.config, "user", {
|
|
32
|
+
values: [{ id: 1, name: "John Doe", email: "john@example.com" }],
|
|
33
|
+
returning: ["id", "name"],
|
|
34
|
+
});
|
|
35
|
+
expect(result.returning).toEqual([
|
|
36
|
+
{ name: "id", alias: "a_0", path: ["id"] },
|
|
37
|
+
{ name: "name", alias: "a_1", path: ["name"] },
|
|
38
|
+
]);
|
|
39
|
+
});
|
|
40
|
+
test("should handle onConflict", () => {
|
|
41
|
+
const result = buildCreate(db.config, "user", {
|
|
42
|
+
values: [{ id: 1, name: "John Doe", email: "john@example.com" }],
|
|
43
|
+
onConflict: { do: "nothing" },
|
|
44
|
+
});
|
|
45
|
+
expect(result.onConflict).toEqual({ do: "nothing" });
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NormalizedConfig } from "@casekit/orm2-config";
|
|
2
|
+
import { ModelDefinitions, ModelName, OperatorDefinitions } from "@casekit/orm2-schema";
|
|
3
|
+
import { DeleteParams } from "#types/DeleteParams.js";
|
|
4
|
+
import { DeleteBuilder } from "./types.js";
|
|
5
|
+
export declare const buildDelete: (config: NormalizedConfig, modelName: string, query: DeleteParams<ModelDefinitions, OperatorDefinitions, ModelName<ModelDefinitions>>, path?: string[], tableIndex?: number) => DeleteBuilder;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { makeTableAlias } from "#util/makeTableAlias.js";
|
|
2
|
+
import { hasClauses } from "../util/hasClauses.js";
|
|
3
|
+
import { buildWhere } from "./buildWhere.js";
|
|
4
|
+
export const buildDelete = (config, modelName, query, path = [], tableIndex = 0) => {
|
|
5
|
+
const model = config.models[modelName];
|
|
6
|
+
if (!model)
|
|
7
|
+
throw new Error(`Model "${modelName}" not found`);
|
|
8
|
+
const table = {
|
|
9
|
+
schema: model.schema,
|
|
10
|
+
name: model.table,
|
|
11
|
+
alias: makeTableAlias(tableIndex++),
|
|
12
|
+
model: modelName,
|
|
13
|
+
};
|
|
14
|
+
if (!hasClauses(query.where)) {
|
|
15
|
+
throw new Error("Delete queries must have a where clause");
|
|
16
|
+
}
|
|
17
|
+
const where = buildWhere(config, table, query.where);
|
|
18
|
+
const returning = query.returning?.map((f, index) => ({
|
|
19
|
+
name: model.fields[f].column,
|
|
20
|
+
alias: `${table.alias}_${index}`,
|
|
21
|
+
path: [...path, f],
|
|
22
|
+
})) ?? [];
|
|
23
|
+
return {
|
|
24
|
+
table,
|
|
25
|
+
where,
|
|
26
|
+
returning,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { sql } from "@casekit/sql";
|
|
3
|
+
import { createTestDB } from "../tests/util/db.js";
|
|
4
|
+
import { buildDelete } from "./buildDelete.js";
|
|
5
|
+
describe("buildDelete", () => {
|
|
6
|
+
const { db } = createTestDB();
|
|
7
|
+
test("builds basic delete query with where clause", () => {
|
|
8
|
+
const result = buildDelete(db.config, "user", {
|
|
9
|
+
where: { id: 1 },
|
|
10
|
+
});
|
|
11
|
+
expect(result).toEqual({
|
|
12
|
+
table: {
|
|
13
|
+
schema: "orm",
|
|
14
|
+
name: "user",
|
|
15
|
+
alias: "a",
|
|
16
|
+
model: "user",
|
|
17
|
+
},
|
|
18
|
+
where: sql `"a"."id" = ${1}`,
|
|
19
|
+
returning: [],
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
test("builds delete query with returning clause", () => {
|
|
23
|
+
const result = buildDelete(db.config, "user", {
|
|
24
|
+
where: { id: 1 },
|
|
25
|
+
returning: ["id", "name"],
|
|
26
|
+
});
|
|
27
|
+
expect(result).toEqual({
|
|
28
|
+
table: {
|
|
29
|
+
schema: "orm",
|
|
30
|
+
name: "user",
|
|
31
|
+
alias: "a",
|
|
32
|
+
model: "user",
|
|
33
|
+
},
|
|
34
|
+
where: sql `"a"."id" = ${1}`,
|
|
35
|
+
returning: [
|
|
36
|
+
{
|
|
37
|
+
name: "id",
|
|
38
|
+
alias: "a_0",
|
|
39
|
+
path: ["id"],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "name",
|
|
43
|
+
alias: "a_1",
|
|
44
|
+
path: ["name"],
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
test("throws error when model not found", () => {
|
|
50
|
+
expect(() => buildDelete(db.config, "nonexistentModel", {
|
|
51
|
+
where: { id: 1 },
|
|
52
|
+
})).toThrow('Model "nonexistentModel" not found');
|
|
53
|
+
});
|
|
54
|
+
test("throws error when where clause is empty", () => {
|
|
55
|
+
expect(() => buildDelete(db.config, "user", {
|
|
56
|
+
where: {},
|
|
57
|
+
})).toThrow("Delete queries must have a where clause");
|
|
58
|
+
});
|
|
59
|
+
test("throws error when where clause is undefined", () => {
|
|
60
|
+
expect(() => buildDelete(db.config, "user", {
|
|
61
|
+
// @ts-expect-error testing runtime behavior with invalid input
|
|
62
|
+
where: undefined,
|
|
63
|
+
})).toThrow("Delete queries must have a where clause");
|
|
64
|
+
});
|
|
65
|
+
test("handles complex where clauses", () => {
|
|
66
|
+
const result = buildDelete(db.config, "user", {
|
|
67
|
+
where: {
|
|
68
|
+
id: 1,
|
|
69
|
+
name: "test",
|
|
70
|
+
email: { $like: "%@example.com" },
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
expect(result).toEqual({
|
|
74
|
+
table: {
|
|
75
|
+
schema: "orm",
|
|
76
|
+
name: "user",
|
|
77
|
+
alias: "a",
|
|
78
|
+
model: "user",
|
|
79
|
+
},
|
|
80
|
+
where: expect.any(Object), // SQL statement object
|
|
81
|
+
returning: [],
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
test("uses correct path for nested fields in returning clause", () => {
|
|
85
|
+
const result = buildDelete(db.config, "user", {
|
|
86
|
+
where: { id: 1 },
|
|
87
|
+
returning: ["id", "name"],
|
|
88
|
+
}, ["parent"]);
|
|
89
|
+
expect(result.returning).toEqual([
|
|
90
|
+
{
|
|
91
|
+
name: "id",
|
|
92
|
+
alias: "a_0",
|
|
93
|
+
path: ["parent", "id"],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "name",
|
|
97
|
+
alias: "a_1",
|
|
98
|
+
path: ["parent", "name"],
|
|
99
|
+
},
|
|
100
|
+
]);
|
|
101
|
+
});
|
|
102
|
+
test("uses provided table index for alias generation", () => {
|
|
103
|
+
const result = buildDelete(db.config, "user", {
|
|
104
|
+
where: { id: 1 },
|
|
105
|
+
}, [], 5);
|
|
106
|
+
expect(result.table.alias).toBe("f");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { NormalizedConfig } from "@casekit/orm2-config";
|
|
2
|
+
import { ModelDefinition, OperatorDefinitions } from "@casekit/orm2-schema";
|
|
3
|
+
import { FindParams } from "#types/FindParams.js";
|
|
4
|
+
import { FindBuilder } from "./types.js";
|
|
5
|
+
export declare const buildFind: (config: NormalizedConfig, modelName: string, query: FindParams<Record<string, Required<ModelDefinition>>, OperatorDefinitions, string>, lateralBy?: {
|
|
6
|
+
field: string;
|
|
7
|
+
values: unknown[];
|
|
8
|
+
}[], path?: string[], tableIndex?: number) => FindBuilder;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NB. Lots of ! in this file which maybe isn't great but I think for these
|
|
3
|
+
* builders, where we can be fairly confident due to the type-checking at the edges
|
|
4
|
+
* that things are defined, it's better than the alternative of loads of
|
|
5
|
+
* redundant checks for undefined. We've done all the checks we need at the
|
|
6
|
+
* stage of normalizing the model, we can now assume everything is wired up
|
|
7
|
+
* correctly.
|
|
8
|
+
*
|
|
9
|
+
* Also this is a file in which there's a lot of mutation and dependency
|
|
10
|
+
* on the order in which things are done, which is not ideal but is what
|
|
11
|
+
* it is. Refactor and/or add to/change with care.
|
|
12
|
+
*/
|
|
13
|
+
import { pickBy, uniq } from "es-toolkit";
|
|
14
|
+
import { max, min } from "es-toolkit/compat";
|
|
15
|
+
import { getField, } from "@casekit/orm2-config";
|
|
16
|
+
import { hasClauses } from "#util/hasClauses.js";
|
|
17
|
+
import { makeTableAlias } from "#util/makeTableAlias.js";
|
|
18
|
+
import { buildWhere } from "./buildWhere.js";
|
|
19
|
+
/**
|
|
20
|
+
* Builds a base FindBuilder, with only columns from the main table.
|
|
21
|
+
* Joins will be added later.
|
|
22
|
+
*/
|
|
23
|
+
const buildBaseFind = (config, m, query, lateralBy = [], path = [], tableIndex = 0) => {
|
|
24
|
+
const model = config.models[m];
|
|
25
|
+
if (!model)
|
|
26
|
+
throw new Error(`Model "${m}" not found`);
|
|
27
|
+
let colIndex = 0;
|
|
28
|
+
const table = {
|
|
29
|
+
schema: model.schema,
|
|
30
|
+
name: model.table,
|
|
31
|
+
alias: makeTableAlias(tableIndex++),
|
|
32
|
+
model: m,
|
|
33
|
+
};
|
|
34
|
+
const columns = uniq([
|
|
35
|
+
...query.select,
|
|
36
|
+
// we always select the primary key even if it's not explicitly
|
|
37
|
+
// requested so we can use it for wiring up relationships
|
|
38
|
+
...model.primaryKey.map((pk) => pk.field),
|
|
39
|
+
// we also select any foreign keys we're doing a lateral join on
|
|
40
|
+
...lateralBy.map((l) => l.field),
|
|
41
|
+
]).map((f) => {
|
|
42
|
+
const field = getField(model, f);
|
|
43
|
+
return {
|
|
44
|
+
table: table.alias,
|
|
45
|
+
name: field.column,
|
|
46
|
+
alias: `${table.alias}_${colIndex++}`,
|
|
47
|
+
path: [...path, f],
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
const where = hasClauses(query.where)
|
|
51
|
+
? buildWhere(config, table, query.where)
|
|
52
|
+
: null;
|
|
53
|
+
return {
|
|
54
|
+
table,
|
|
55
|
+
columns,
|
|
56
|
+
where,
|
|
57
|
+
joins: [],
|
|
58
|
+
for: query.for,
|
|
59
|
+
orderBy: [],
|
|
60
|
+
offset: query.offset,
|
|
61
|
+
limit: query.limit,
|
|
62
|
+
tableIndex,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
const collectManyToOneQueries = (model, query) => {
|
|
66
|
+
// this slightly complex chain gets all the N:1 relations
|
|
67
|
+
// we're querying. as well as the contents of the include
|
|
68
|
+
// key, we make sure to include a join to any relations
|
|
69
|
+
// we're ordering by (we'll use them later).
|
|
70
|
+
// relations we're ordering by are identified by being a
|
|
71
|
+
// model name and field name separated by a dot.
|
|
72
|
+
// this is a tiny bit brittle in the case where people
|
|
73
|
+
// create a model or field name that contains a dot,
|
|
74
|
+
// but that would be a v weird thing to do as they are
|
|
75
|
+
// both javascript identifiers so would be a real pain
|
|
76
|
+
// to write in code. so i think it's probably fine to
|
|
77
|
+
// not support it.
|
|
78
|
+
return pickBy({
|
|
79
|
+
...query.include,
|
|
80
|
+
...query.orderBy
|
|
81
|
+
// deal with the fact that an order by column
|
|
82
|
+
//can be a single value or an array with a direction
|
|
83
|
+
?.map((ob) => (typeof ob === "string" ? ob : ob[0]))
|
|
84
|
+
// get only the order by columns that are on relation tables
|
|
85
|
+
.filter((ob) => ob.includes("."))
|
|
86
|
+
// get the relation model name
|
|
87
|
+
.map((ob) => ob.split(".")[0])
|
|
88
|
+
// check it's not already something we're joining to
|
|
89
|
+
.filter((f) => !(f in (query.include ?? {})))
|
|
90
|
+
// if not, add a query to it with an empty select
|
|
91
|
+
// (ok because we always select the primary key)
|
|
92
|
+
.reduce((acc, f) => ({ ...acc, [f]: { select: [] } }), {}),
|
|
93
|
+
},
|
|
94
|
+
// finally select only N:1 relations as these
|
|
95
|
+
// are the only kind we join to directly
|
|
96
|
+
(_query, relation) => model.relations[relation].type === "N:1");
|
|
97
|
+
};
|
|
98
|
+
const buildOrderBy = (config, model, query, builder) => {
|
|
99
|
+
return (query.orderBy?.map((ob) => {
|
|
100
|
+
const field = typeof ob === "string" ? ob : ob[0];
|
|
101
|
+
const direction = typeof ob === "string" ? "ASC" : ob[1];
|
|
102
|
+
if (field.includes(".")) {
|
|
103
|
+
const [relation, relationField] = field.split(".");
|
|
104
|
+
const join = builder.joins.find((j) => j.relation === relation);
|
|
105
|
+
const joinedModel = config.models[model.relations[join.relation].model];
|
|
106
|
+
return {
|
|
107
|
+
column: {
|
|
108
|
+
table: join.table.alias,
|
|
109
|
+
name: joinedModel.fields[relationField].column,
|
|
110
|
+
},
|
|
111
|
+
direction: direction.toUpperCase() === "DESC" ? "DESC" : "ASC",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
return {
|
|
116
|
+
column: {
|
|
117
|
+
table: builder.table.alias,
|
|
118
|
+
name: getField(model, field).column,
|
|
119
|
+
},
|
|
120
|
+
direction: direction.toUpperCase() === "DESC" ? "DESC" : "ASC",
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}) ?? []);
|
|
124
|
+
};
|
|
125
|
+
export const buildFind = (config, modelName, query, lateralBy = [], path = [], tableIndex = 0) => {
|
|
126
|
+
const model = config.models[modelName];
|
|
127
|
+
if (!model)
|
|
128
|
+
throw new Error(`Model "${modelName}" not found`);
|
|
129
|
+
const builder = buildBaseFind(config, modelName, query, lateralBy, path, tableIndex);
|
|
130
|
+
const manyToOneQueries = collectManyToOneQueries(model, query);
|
|
131
|
+
for (const [r, subquery] of Object.entries(manyToOneQueries)) {
|
|
132
|
+
const relation = model.relations[r];
|
|
133
|
+
if (relation.type !== "N:1") {
|
|
134
|
+
throw new Error(`Unexpected relation type: ${relation.type}. Should be N:1`);
|
|
135
|
+
}
|
|
136
|
+
const joinBuilder = buildFind(config, relation.model, subquery, [], [...path, r], builder.tableIndex);
|
|
137
|
+
builder.joins.push({
|
|
138
|
+
relation: r,
|
|
139
|
+
path: [...path, r],
|
|
140
|
+
type: relation.optional && !subquery.where ? "LEFT" : "INNER",
|
|
141
|
+
table: joinBuilder.table,
|
|
142
|
+
where: joinBuilder.where,
|
|
143
|
+
orderBy: joinBuilder.orderBy,
|
|
144
|
+
columns: relation.from.columns.map((fk, i) => ({
|
|
145
|
+
from: {
|
|
146
|
+
table: builder.table.alias,
|
|
147
|
+
name: fk,
|
|
148
|
+
},
|
|
149
|
+
to: {
|
|
150
|
+
table: joinBuilder.table.alias,
|
|
151
|
+
name: relation.to.columns[i],
|
|
152
|
+
},
|
|
153
|
+
})),
|
|
154
|
+
});
|
|
155
|
+
// update the parent builder's tableIndex with the one from the
|
|
156
|
+
// joinBuilder, so that we don't have overlapping table indices
|
|
157
|
+
builder.tableIndex = joinBuilder.tableIndex;
|
|
158
|
+
builder.columns.push(...joinBuilder.columns);
|
|
159
|
+
builder.joins.push(...joinBuilder.joins);
|
|
160
|
+
// this is admittedly a bit weird,
|
|
161
|
+
// we wouldn't expect N:1 relations to specify
|
|
162
|
+
// ordering, skipping, and limiting, and typescript
|
|
163
|
+
// prevents users from doing this, but
|
|
164
|
+
// we rely on them being present as part of the N:N
|
|
165
|
+
// implementation
|
|
166
|
+
builder.limit = min([builder.limit, joinBuilder.limit]);
|
|
167
|
+
builder.offset = max([builder.offset, joinBuilder.offset]);
|
|
168
|
+
}
|
|
169
|
+
if (lateralBy.length > 0) {
|
|
170
|
+
builder.lateralBy = {
|
|
171
|
+
outerAlias: makeTableAlias(builder.tableIndex++),
|
|
172
|
+
innerAlias: makeTableAlias(builder.tableIndex++),
|
|
173
|
+
primaryKeys: lateralBy.map(({ field, values }) => ({
|
|
174
|
+
column: getField(model, field).column,
|
|
175
|
+
type: getField(model, field).type,
|
|
176
|
+
values,
|
|
177
|
+
})),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
builder.orderBy = [
|
|
181
|
+
...buildOrderBy(config, model, query, builder),
|
|
182
|
+
...builder.joins.flatMap((j) => j.orderBy ?? []),
|
|
183
|
+
];
|
|
184
|
+
return builder;
|
|
185
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|