@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,26 @@
|
|
|
1
|
+
import { buildDelete } from "./builders/buildDelete.js";
|
|
2
|
+
import { deleteToSql } from "./sql/deleteToSql.js";
|
|
3
|
+
import { rowToObject } from "./util/rowToObject.js";
|
|
4
|
+
export const deleteMany = async (config, conn, modelName, query) => {
|
|
5
|
+
const builder = buildDelete(config, modelName, query);
|
|
6
|
+
const statement = deleteToSql(builder);
|
|
7
|
+
config.logger.info("Executing deleteMany", {
|
|
8
|
+
sql: statement.pretty,
|
|
9
|
+
values: statement.values,
|
|
10
|
+
});
|
|
11
|
+
const tx = await conn.startTransaction();
|
|
12
|
+
try {
|
|
13
|
+
const result = await tx.query(statement);
|
|
14
|
+
await tx.commit();
|
|
15
|
+
if (query.returning) {
|
|
16
|
+
return result.rows.map((row) => rowToObject(row, builder.returning));
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
return result.rowCount ?? 0;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
await tx.rollback();
|
|
24
|
+
throw e;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NormalizedConfig } from "@casekit/orm2-config";
|
|
2
|
+
import { ModelDefinitions, OperatorDefinitions } from "@casekit/orm2-schema";
|
|
3
|
+
import { Connection } from "./connection.js";
|
|
4
|
+
import { DeleteParams } from "./types/DeleteParams.js";
|
|
5
|
+
export declare const deleteOne: (config: NormalizedConfig, conn: Connection, modelName: string, query: DeleteParams<ModelDefinitions, OperatorDefinitions, string>) => Promise<Record<string, unknown> | number | null>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { buildDelete } from "./builders/buildDelete.js";
|
|
2
|
+
import { deleteToSql } from "./sql/deleteToSql.js";
|
|
3
|
+
import { rowToObject } from "./util/rowToObject.js";
|
|
4
|
+
export const deleteOne = async (config, conn, modelName, query) => {
|
|
5
|
+
const builder = buildDelete(config, modelName, query);
|
|
6
|
+
const statement = deleteToSql(builder);
|
|
7
|
+
config.logger.info("Executing deleteOne", {
|
|
8
|
+
sql: statement.pretty,
|
|
9
|
+
values: statement.values,
|
|
10
|
+
});
|
|
11
|
+
const tx = await conn.startTransaction();
|
|
12
|
+
try {
|
|
13
|
+
const result = await tx.query(statement);
|
|
14
|
+
if (!result.rowCount || result.rowCount === 0) {
|
|
15
|
+
throw new Error("Delete one failed to delete a row");
|
|
16
|
+
}
|
|
17
|
+
else if (result.rowCount > 1) {
|
|
18
|
+
throw new Error("Delete one would have deleted more than one row");
|
|
19
|
+
}
|
|
20
|
+
await tx.commit();
|
|
21
|
+
if (query.returning) {
|
|
22
|
+
return rowToObject(result.rows[0], builder.returning);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return result.rowCount;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
await tx.rollback();
|
|
30
|
+
throw e;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { NormalizedConfig } from "@casekit/orm2-config";
|
|
2
|
+
import { ModelDefinition, OperatorDefinitions } from "@casekit/orm2-schema";
|
|
3
|
+
import { Connection } from "./connection.js";
|
|
4
|
+
import { FindParams } from "./types/FindParams.js";
|
|
5
|
+
export declare const findMany: (config: NormalizedConfig, conn: Connection, modelName: string, query: FindParams<Record<string, Required<ModelDefinition>>, OperatorDefinitions, string>, lateralBy?: {
|
|
6
|
+
field: string;
|
|
7
|
+
values: unknown[];
|
|
8
|
+
}[]) => Promise<Record<string, unknown>[]>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { dropRight, groupBy } from "es-toolkit";
|
|
2
|
+
import { get, set } from "es-toolkit/compat";
|
|
3
|
+
import hash from "object-hash";
|
|
4
|
+
import { buildFind } from "./builders/buildFind.js";
|
|
5
|
+
import { findToSql } from "./sql/findToSql.js";
|
|
6
|
+
import { getIncludedToManySubqueries } from "./util/getIncludedToManySubqueries.js";
|
|
7
|
+
import { getLateralJoinValues } from "./util/getLateralJoinValues.js";
|
|
8
|
+
import { rowToObject } from "./util/rowToObject.js";
|
|
9
|
+
export const findMany = async (config, conn, modelName, query, lateralBy = []) => {
|
|
10
|
+
const builder = buildFind(config, modelName, query, lateralBy);
|
|
11
|
+
const statement = findToSql(builder);
|
|
12
|
+
config.logger.info("Executing findMany", {
|
|
13
|
+
sql: statement.pretty,
|
|
14
|
+
values: statement.values,
|
|
15
|
+
});
|
|
16
|
+
const results = await conn
|
|
17
|
+
.query(statement)
|
|
18
|
+
.then((res) => res.rows.map((row) => rowToObject(row, builder.columns)));
|
|
19
|
+
const relationQueries = [];
|
|
20
|
+
const includedToManySubqueries = getIncludedToManySubqueries(config, modelName, query);
|
|
21
|
+
// There's no getting around it, this bit is fiddly.
|
|
22
|
+
// Will do my best to explain what's going on.
|
|
23
|
+
for (const { modelName, query, path, from, to, extract, } of includedToManySubqueries) {
|
|
24
|
+
// this gets all the values of the 'from' columns on whichever the parent model
|
|
25
|
+
// is - either the top level model or one of the N:1 joined models.
|
|
26
|
+
const lateralBy = getLateralJoinValues(results, dropRight(path, 1), from, to);
|
|
27
|
+
// rather than awaiting the findMany query here, we'll push a promise
|
|
28
|
+
// into an array that we can await in parallel later.
|
|
29
|
+
const promise = findMany(config, conn, modelName, query, lateralBy).then((relationResults) => {
|
|
30
|
+
// we group the results by the hash of the 'to' columns so
|
|
31
|
+
// we can find the right list of values for each result
|
|
32
|
+
const lookup = groupBy(relationResults, (result) => hash(to.map((f) => result[f])));
|
|
33
|
+
for (const result of results) {
|
|
34
|
+
// if the relation is on the top level model of the query,
|
|
35
|
+
// the path length will be 1 and the parent of the relation
|
|
36
|
+
// will be the result itself. otherwise the relation
|
|
37
|
+
// will be on one of the N:1 relations of the top level model,
|
|
38
|
+
// so we need to look up this object in the result by path
|
|
39
|
+
const parent = path.length === 1
|
|
40
|
+
? result
|
|
41
|
+
: get(result, dropRight(path, 1));
|
|
42
|
+
// if the relation is on an _optional_ N:1 relation of
|
|
43
|
+
// the query's top level model, then the value being joined from
|
|
44
|
+
// may not exist on the result. in that case there won't be any
|
|
45
|
+
// children to join so we ignore it.
|
|
46
|
+
if (parent !== undefined) {
|
|
47
|
+
// finally we can look up the relation values for the result
|
|
48
|
+
// and insert them into the result object at the correct path.
|
|
49
|
+
const key = hash(from.map((c) => get(parent, c)));
|
|
50
|
+
// if the relation is an N:N relation, the query we will have
|
|
51
|
+
// done will be wrapped in an 1:N relation query on the join
|
|
52
|
+
// model - so the result will be results of a _join model_
|
|
53
|
+
// query, not the actual relation model. the extract function
|
|
54
|
+
// makes sure that if this is the case, we extract the relevant
|
|
55
|
+
// field from the results so everything is wired up correctly
|
|
56
|
+
set(result, path, extract(lookup[key] ?? []));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
relationQueries.push(promise);
|
|
61
|
+
}
|
|
62
|
+
await Promise.all(relationQueries);
|
|
63
|
+
return results;
|
|
64
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NormalizedConfig } from "@casekit/orm2-config";
|
|
2
|
+
import { ModelDefinitions, OperatorDefinitions } from "@casekit/orm2-schema";
|
|
3
|
+
import { Connection } from "./connection.js";
|
|
4
|
+
import { FindParams } from "./types/FindParams.js";
|
|
5
|
+
export declare const findOne: (config: NormalizedConfig, conn: Connection, model: string, query: FindParams<ModelDefinitions, OperatorDefinitions, string>) => Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { buildFind } from "./builders/buildFind.js";
|
|
2
|
+
import { findToSql } from "./sql/findToSql.js";
|
|
3
|
+
import { rowToObject } from "./util/rowToObject.js";
|
|
4
|
+
export const findOne = async (config, conn, model, query) => {
|
|
5
|
+
const builder = buildFind(config, model, { ...query, limit: 2 });
|
|
6
|
+
const statement = findToSql(builder);
|
|
7
|
+
config.logger.info("Executing findOne", {
|
|
8
|
+
sql: statement.pretty,
|
|
9
|
+
values: statement.values,
|
|
10
|
+
});
|
|
11
|
+
return await conn.query(statement).then((res) => {
|
|
12
|
+
if (res.rows.length === 0) {
|
|
13
|
+
throw new Error("Expected one row, but found none");
|
|
14
|
+
}
|
|
15
|
+
if (res.rows.length > 1) {
|
|
16
|
+
throw new Error("Expected one row, but found more");
|
|
17
|
+
}
|
|
18
|
+
return res.rows.map((row) => rowToObject(row, builder.columns))[0];
|
|
19
|
+
});
|
|
20
|
+
};
|
package/build/orm.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NB. You'll see a lot of `as unknown as` and other nasty looking typecasting
|
|
3
|
+
* in this file. This is because this is the boundary between the very specific
|
|
4
|
+
* types of the ORM as used by the user and the more general types of the ORMs
|
|
5
|
+
* implementation. The specific types are not helpful for the internals (in
|
|
6
|
+
* fact they would make it much harder if not impossible to write) - so we
|
|
7
|
+
* have this one specific place where we forcibly cast between the specific to
|
|
8
|
+
* the general - and nowhere else in the project should be doing this.
|
|
9
|
+
*/
|
|
10
|
+
import { mapValues, pick, pickBy } from "es-toolkit";
|
|
11
|
+
import { ZodSchema, z } from "zod";
|
|
12
|
+
import { getModel, normalizeConfig, } from "@casekit/orm2-config";
|
|
13
|
+
import { SQLStatement, sql } from "@casekit/sql";
|
|
14
|
+
import { Connection } from "./connection.js";
|
|
15
|
+
import { count } from "./orm.count.js";
|
|
16
|
+
import { createMany } from "./orm.createMany.js";
|
|
17
|
+
import { createOne } from "./orm.createOne.js";
|
|
18
|
+
import { deleteMany } from "./orm.deleteMany.js";
|
|
19
|
+
import { deleteOne } from "./orm.deleteOne.js";
|
|
20
|
+
import { findMany } from "./orm.findMany.js";
|
|
21
|
+
import { findOne } from "./orm.findOne.js";
|
|
22
|
+
import { updateMany } from "./orm.updateMany.js";
|
|
23
|
+
import { updateOne } from "./orm.updateOne.js";
|
|
24
|
+
import { findManyResultSchema, findOneResultSchema, returningManyResultSchema, returningOneResultSchema, } from "./util/resultSchema.js";
|
|
25
|
+
export const orm = (config) => {
|
|
26
|
+
return new Orm(normalizeConfig(config));
|
|
27
|
+
};
|
|
28
|
+
export class Orm {
|
|
29
|
+
config;
|
|
30
|
+
_connection;
|
|
31
|
+
_middleware;
|
|
32
|
+
constructor(config, connection, middleware) {
|
|
33
|
+
this.config = config;
|
|
34
|
+
this._connection = connection ?? new Connection(config);
|
|
35
|
+
this._middleware = middleware ?? [];
|
|
36
|
+
}
|
|
37
|
+
async connect() {
|
|
38
|
+
await this._connection.connect();
|
|
39
|
+
}
|
|
40
|
+
async close() {
|
|
41
|
+
await this._connection.close();
|
|
42
|
+
}
|
|
43
|
+
async transact(fn, options = { rollback: false }) {
|
|
44
|
+
const tx = await this._connection.startTransaction();
|
|
45
|
+
try {
|
|
46
|
+
const result = await fn(new Orm(this.config, tx));
|
|
47
|
+
if (options.rollback) {
|
|
48
|
+
await tx.rollback();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
await tx.commit();
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
if (tx.open) {
|
|
57
|
+
await tx.rollback();
|
|
58
|
+
}
|
|
59
|
+
throw e;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
getNextMiddleware(type) {
|
|
63
|
+
const mwIndex = this._middleware.findIndex((mw) => !!mw[type]);
|
|
64
|
+
if (mwIndex > -1) {
|
|
65
|
+
const next = this._middleware.map((mw, index) => index === mwIndex ? { ...mw, [type]: undefined } : mw);
|
|
66
|
+
const mw = this._middleware[mwIndex][type];
|
|
67
|
+
return [mw, next];
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
return [null, this._middleware];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async findOne(modelName, query) {
|
|
74
|
+
const [mw, next] = this.getNextMiddleware("findOne");
|
|
75
|
+
if (mw) {
|
|
76
|
+
const db = new Orm(this.config, this._connection, next);
|
|
77
|
+
// the type cast here is needed for the recursive call because
|
|
78
|
+
// otherwise typescript goes absolutely haywire causing an OOM error
|
|
79
|
+
return (await mw(db, modelName, query));
|
|
80
|
+
}
|
|
81
|
+
const result = await findOne(this.config, this._connection, modelName, query);
|
|
82
|
+
const schema = findOneResultSchema(this.config, modelName, query);
|
|
83
|
+
return schema.parse(result);
|
|
84
|
+
}
|
|
85
|
+
async findMany(modelName, query) {
|
|
86
|
+
const [mw, next] = this.getNextMiddleware("findMany");
|
|
87
|
+
if (mw) {
|
|
88
|
+
const db = new Orm(this.config, this._connection, next);
|
|
89
|
+
// the type cast here is needed for the recursive call because
|
|
90
|
+
// otherwise typescript goes absolutely haywire causing an OOM error
|
|
91
|
+
return (await mw(db, modelName, query));
|
|
92
|
+
}
|
|
93
|
+
const result = await findMany(this.config, this._connection, modelName, query);
|
|
94
|
+
const schema = findManyResultSchema(this.config, modelName, query);
|
|
95
|
+
return schema.parse(result);
|
|
96
|
+
}
|
|
97
|
+
async count(modelName, query) {
|
|
98
|
+
const [mw, next] = this.getNextMiddleware("count");
|
|
99
|
+
if (mw) {
|
|
100
|
+
const db = new Orm(this.config, this._connection, next);
|
|
101
|
+
// the type cast here is needed for the recursive call because
|
|
102
|
+
// otherwise typescript goes absolutely haywire causing an OOM error
|
|
103
|
+
return (await mw(db, modelName, query));
|
|
104
|
+
}
|
|
105
|
+
return await count(this.config, this._connection, modelName, query);
|
|
106
|
+
}
|
|
107
|
+
async createOne(modelName, query) {
|
|
108
|
+
const [mw, next] = this.getNextMiddleware("createOne");
|
|
109
|
+
if (mw) {
|
|
110
|
+
const db = new Orm(this.config, this._connection, next);
|
|
111
|
+
// the type cast here is needed for the recursive call because
|
|
112
|
+
// otherwise typescript goes absolutely haywire causing an OOM error
|
|
113
|
+
return (await mw(db, modelName, query));
|
|
114
|
+
}
|
|
115
|
+
const result = await createOne(this.config, this._connection, modelName, query);
|
|
116
|
+
const schema = returningOneResultSchema(getModel(this.config.models, modelName), query.returning);
|
|
117
|
+
return schema.parse(result);
|
|
118
|
+
}
|
|
119
|
+
async createMany(modelName, query) {
|
|
120
|
+
const [mw, next] = this.getNextMiddleware("createMany");
|
|
121
|
+
if (mw) {
|
|
122
|
+
const db = new Orm(this.config, this._connection, next);
|
|
123
|
+
// the type cast here is needed for the recursive call because
|
|
124
|
+
// otherwise typescript goes absolutely haywire causing an OOM error
|
|
125
|
+
return (await mw(db, modelName, query));
|
|
126
|
+
}
|
|
127
|
+
const result = await createMany(this.config, this._connection, modelName, query);
|
|
128
|
+
const schema = returningManyResultSchema(getModel(this.config.models, modelName), query.returning);
|
|
129
|
+
return schema.parse(result);
|
|
130
|
+
}
|
|
131
|
+
async updateOne(modelName, query) {
|
|
132
|
+
const [mw, next] = this.getNextMiddleware("updateOne");
|
|
133
|
+
if (mw) {
|
|
134
|
+
const db = new Orm(this.config, this._connection, next);
|
|
135
|
+
// the type cast here is needed for the recursive call because
|
|
136
|
+
// otherwise typescript goes absolutely haywire causing an OOM error
|
|
137
|
+
return (await mw(db, modelName, query));
|
|
138
|
+
}
|
|
139
|
+
const result = await updateOne(this.config, this._connection, modelName, query);
|
|
140
|
+
const schema = returningOneResultSchema(getModel(this.config.models, modelName), query.returning);
|
|
141
|
+
return schema.parse(result);
|
|
142
|
+
}
|
|
143
|
+
async updateMany(modelName, query) {
|
|
144
|
+
const [mw, next] = this.getNextMiddleware("updateMany");
|
|
145
|
+
if (mw) {
|
|
146
|
+
const db = new Orm(this.config, this._connection, next);
|
|
147
|
+
// the type cast here is needed for the recursive call because
|
|
148
|
+
// otherwise typescript goes absolutely haywire causing an OOM error
|
|
149
|
+
return (await mw(db, modelName, query));
|
|
150
|
+
}
|
|
151
|
+
const result = await updateMany(this.config, this._connection, modelName, query);
|
|
152
|
+
const schema = returningManyResultSchema(getModel(this.config.models, modelName), query.returning);
|
|
153
|
+
return schema.parse(result);
|
|
154
|
+
}
|
|
155
|
+
async deleteOne(modelName, query) {
|
|
156
|
+
const [mw, next] = this.getNextMiddleware("deleteOne");
|
|
157
|
+
if (mw) {
|
|
158
|
+
const db = new Orm(this.config, this._connection, next);
|
|
159
|
+
// the type cast here is needed for the recursive call because
|
|
160
|
+
// otherwise typescript goes absolutely haywire causing an OOM error
|
|
161
|
+
return (await mw(db, modelName, query));
|
|
162
|
+
}
|
|
163
|
+
const result = await deleteOne(this.config, this._connection, modelName, query);
|
|
164
|
+
const schema = returningOneResultSchema(getModel(this.config.models, modelName), query.returning);
|
|
165
|
+
return schema.parse(result);
|
|
166
|
+
}
|
|
167
|
+
async deleteMany(modelName, query) {
|
|
168
|
+
const [mw, next] = this.getNextMiddleware("deleteMany");
|
|
169
|
+
if (mw) {
|
|
170
|
+
const db = new Orm(this.config, this._connection, next);
|
|
171
|
+
// the type cast here is needed for the recursive call because
|
|
172
|
+
// otherwise typescript goes absolutely haywire causing an OOM error
|
|
173
|
+
return (await mw(db, modelName, query));
|
|
174
|
+
}
|
|
175
|
+
const result = await deleteMany(this.config, this._connection, modelName, query);
|
|
176
|
+
const schema = returningManyResultSchema(getModel(this.config.models, modelName), query.returning);
|
|
177
|
+
return schema.parse(result);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* In some parts of your app - e.g. in the non-tenant specific parts of
|
|
181
|
+
* a multi-tenant app, where you don't want to restrict by tenant_id -
|
|
182
|
+
* you may want to only make a subset of models available for querying.
|
|
183
|
+
* This method allows you to do that by creating a restricted copy of
|
|
184
|
+
* the ORM with access only to the models you specify.
|
|
185
|
+
*/
|
|
186
|
+
restrict(allowed) {
|
|
187
|
+
if (this._connection.isTransaction()) {
|
|
188
|
+
throw new Error("Cannot create restricted ORM in a transaction");
|
|
189
|
+
}
|
|
190
|
+
// TODO - update this to also include join models for N:N relations
|
|
191
|
+
const config = {
|
|
192
|
+
...this.config,
|
|
193
|
+
models: mapValues(pick(this.config.models, allowed), (model) => ({
|
|
194
|
+
...model,
|
|
195
|
+
relations: pickBy(model.relations, (r) =>
|
|
196
|
+
// @ts-expect-error - need TS to treat allowed as a string[] here
|
|
197
|
+
// but it wants to treat it as the more specific "Allowed" type
|
|
198
|
+
allowed.includes(r.model)),
|
|
199
|
+
})),
|
|
200
|
+
};
|
|
201
|
+
return new Orm(config, this._connection);
|
|
202
|
+
}
|
|
203
|
+
/** Returns a new ORM instance with middleware applied.
|
|
204
|
+
* The new ORM instance shares the same connection as
|
|
205
|
+
* the one it is called on, but the original instance
|
|
206
|
+
* does not have the middleware applied. This means
|
|
207
|
+
* this method can be called multiple times to apply
|
|
208
|
+
* different middleware to different ORM instances.
|
|
209
|
+
*/
|
|
210
|
+
middleware(middleware) {
|
|
211
|
+
return new Orm(this.config, this._connection, middleware);
|
|
212
|
+
}
|
|
213
|
+
query(schemaOrStatementOrFragments, ...values) {
|
|
214
|
+
if (schemaOrStatementOrFragments instanceof ZodSchema) {
|
|
215
|
+
return this.queryWithSchema(schemaOrStatementOrFragments);
|
|
216
|
+
}
|
|
217
|
+
if (schemaOrStatementOrFragments instanceof SQLStatement) {
|
|
218
|
+
return this.queryWithSQLStatement(schemaOrStatementOrFragments);
|
|
219
|
+
}
|
|
220
|
+
return this.queryWithTemplateLiteral(schemaOrStatementOrFragments, ...values);
|
|
221
|
+
}
|
|
222
|
+
queryWithTemplateLiteral(fragments, ...values) {
|
|
223
|
+
return this._connection
|
|
224
|
+
.query(sql(fragments, ...values))
|
|
225
|
+
.then((result) => result.rows);
|
|
226
|
+
}
|
|
227
|
+
queryWithSQLStatement(statement) {
|
|
228
|
+
const result = this._connection.query(statement);
|
|
229
|
+
if (statement.schema) {
|
|
230
|
+
const schema = statement.schema;
|
|
231
|
+
return result.then((result) => z.array(schema).parse(result.rows));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
return result.then((result) => result.rows);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
queryWithSchema(schema) {
|
|
238
|
+
return (fragments, ...values) => {
|
|
239
|
+
const result = this._connection.query(sql(fragments, ...values));
|
|
240
|
+
return result.then((result) => z.array(schema).parse(result.rows));
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { NormalizedConfig } from "@casekit/orm2-config";
|
|
2
|
+
import { Config, ModelName } from "@casekit/orm2-schema";
|
|
3
|
+
import { Connection } from "./connection.js";
|
|
4
|
+
import { Orm } from "./orm.js";
|
|
5
|
+
import { RestrictModels } from "./types/RestrictModels.js";
|
|
6
|
+
export declare const restrict: <const C extends Config, const Allowed extends [...ModelName<C["models"]>[]]>(config: NormalizedConfig, allowed: string[], connection: Connection) => Orm<RestrictModels<C, Allowed[number]>>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Orm } from "./orm.js";
|
|
2
|
+
export const restrict = (config, allowed, connection) => {
|
|
3
|
+
if (connection.isTransaction()) {
|
|
4
|
+
throw new Error("Cannot create restricted ORM in a transaction");
|
|
5
|
+
}
|
|
6
|
+
const lookup = new Set(allowed);
|
|
7
|
+
const models = Object.keys(config.models).reduce((acc, name) => {
|
|
8
|
+
if (lookup.has(name)) {
|
|
9
|
+
return {
|
|
10
|
+
...acc,
|
|
11
|
+
[name]: {
|
|
12
|
+
...config.models[name],
|
|
13
|
+
relations: Object.keys(config.models[name].relations).reduce((acc, name) => {
|
|
14
|
+
const relation = config.models[name].relations[name];
|
|
15
|
+
if (!lookup.has(relation.model)) {
|
|
16
|
+
return {
|
|
17
|
+
...acc,
|
|
18
|
+
get [name]() {
|
|
19
|
+
throw new Error(`Relation "${name}" references model "${relation.model}" which is not permitted in this restricted ORM instance`);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
else if (relation.type === "N:N" &&
|
|
24
|
+
!lookup.has(relation.through.model)) {
|
|
25
|
+
return {
|
|
26
|
+
...acc,
|
|
27
|
+
get [name]() {
|
|
28
|
+
throw new Error(`Relation "${name}" references model "${relation.through.model}" which is not permitted in this restricted ORM instance`);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return {
|
|
34
|
+
...acc,
|
|
35
|
+
[name]: relation,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}, {}),
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return {
|
|
44
|
+
...acc,
|
|
45
|
+
get [name]() {
|
|
46
|
+
throw new Error(`Model ${name} is not permitted in this restricted ORM instance`);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}, {});
|
|
51
|
+
return new Orm({ ...config, models }, connection);
|
|
52
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NormalizedConfig } from "@casekit/orm2-config";
|
|
2
|
+
import { ModelDefinitions, OperatorDefinitions } from "@casekit/orm2-schema";
|
|
3
|
+
import { Connection } from "./connection.js";
|
|
4
|
+
import { UpdateParams } from "./types/UpdateParams.js";
|
|
5
|
+
export declare const updateMany: (config: NormalizedConfig, conn: Connection, modelName: string, query: UpdateParams<ModelDefinitions, OperatorDefinitions, string>) => Promise<Record<string, unknown>[] | number>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { buildUpdate } from "./builders/buildUpdate.js";
|
|
2
|
+
import { updateToSql } from "./sql/updateToSql.js";
|
|
3
|
+
import { rowToObject } from "./util/rowToObject.js";
|
|
4
|
+
export const updateMany = async (config, conn, modelName, query) => {
|
|
5
|
+
if (Object.keys(query.set).length === 0) {
|
|
6
|
+
throw new Error("Update requires at least one value to set");
|
|
7
|
+
}
|
|
8
|
+
const builder = buildUpdate(config, modelName, query);
|
|
9
|
+
const statement = updateToSql(builder);
|
|
10
|
+
config.logger.info("Executing updateOne", {
|
|
11
|
+
sql: statement.pretty,
|
|
12
|
+
values: statement.values,
|
|
13
|
+
});
|
|
14
|
+
const tx = await conn.startTransaction();
|
|
15
|
+
try {
|
|
16
|
+
const result = await tx.query(statement);
|
|
17
|
+
await tx.commit();
|
|
18
|
+
if (query.returning) {
|
|
19
|
+
return result.rows.map((row) => rowToObject(row, builder.returning));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return result.rowCount ?? 0;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
await tx.rollback();
|
|
27
|
+
throw e;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NormalizedConfig } from "@casekit/orm2-config";
|
|
2
|
+
import { ModelDefinitions, OperatorDefinitions } from "@casekit/orm2-schema";
|
|
3
|
+
import { Connection } from "./connection.js";
|
|
4
|
+
import { UpdateParams } from "./types/UpdateParams.js";
|
|
5
|
+
export declare const updateOne: (config: NormalizedConfig, conn: Connection, modelName: string, query: UpdateParams<ModelDefinitions, OperatorDefinitions, string>) => Promise<Record<string, unknown> | number | null>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { buildUpdate } from "./builders/buildUpdate.js";
|
|
2
|
+
import { updateToSql } from "./sql/updateToSql.js";
|
|
3
|
+
import { rowToObject } from "./util/rowToObject.js";
|
|
4
|
+
export const updateOne = async (config, conn, modelName, query) => {
|
|
5
|
+
if (Object.keys(query.set).length === 0) {
|
|
6
|
+
throw new Error("Update requires at least one value to set");
|
|
7
|
+
}
|
|
8
|
+
const builder = buildUpdate(config, modelName, query);
|
|
9
|
+
const statement = updateToSql(builder);
|
|
10
|
+
config.logger.info("Executing updateOne", {
|
|
11
|
+
sql: statement.pretty,
|
|
12
|
+
values: statement.values,
|
|
13
|
+
});
|
|
14
|
+
const tx = await conn.startTransaction();
|
|
15
|
+
try {
|
|
16
|
+
const result = await tx.query(statement);
|
|
17
|
+
if (!result.rowCount || result.rowCount === 0) {
|
|
18
|
+
throw new Error("Update one failed to update a row");
|
|
19
|
+
}
|
|
20
|
+
else if (result.rowCount > 1) {
|
|
21
|
+
throw new Error("Update one would have updated more than one row");
|
|
22
|
+
}
|
|
23
|
+
await tx.commit();
|
|
24
|
+
if (query.returning) {
|
|
25
|
+
return rowToObject(result.rows[0], builder.returning);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return result.rowCount;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
await tx.rollback();
|
|
33
|
+
throw e;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { sql } from "@casekit/sql";
|
|
2
|
+
import { joinClause, tableName } from "./util.js";
|
|
3
|
+
export const countToSql = (builder) => {
|
|
4
|
+
const { table, joins, where } = builder;
|
|
5
|
+
return sql `
|
|
6
|
+
SELECT count(1) AS "count"
|
|
7
|
+
FROM ${tableName(table)}
|
|
8
|
+
${sql.join(joins.map(joinClause), "\n")}
|
|
9
|
+
${where ? sql `WHERE ${where}\n` : sql ``}
|
|
10
|
+
`;
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|