@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.
Files changed (275) hide show
  1. package/build/builders/buildCount.d.ts +23 -0
  2. package/build/builders/buildCount.js +63 -0
  3. package/build/builders/buildCount.test.d.ts +1 -0
  4. package/build/builders/buildCount.test.js +144 -0
  5. package/build/builders/buildCreate.d.ts +5 -0
  6. package/build/builders/buildCreate.js +28 -0
  7. package/build/builders/buildCreate.test.d.ts +1 -0
  8. package/build/builders/buildCreate.test.js +47 -0
  9. package/build/builders/buildDelete.d.ts +5 -0
  10. package/build/builders/buildDelete.js +28 -0
  11. package/build/builders/buildDelete.test.d.ts +1 -0
  12. package/build/builders/buildDelete.test.js +108 -0
  13. package/build/builders/buildFind.d.ts +8 -0
  14. package/build/builders/buildFind.js +185 -0
  15. package/build/builders/buildFind.test.d.ts +1 -0
  16. package/build/builders/buildFind.test.js +263 -0
  17. package/build/builders/buildUpdate.d.ts +5 -0
  18. package/build/builders/buildUpdate.js +34 -0
  19. package/build/builders/buildUpdate.test.d.ts +1 -0
  20. package/build/builders/buildUpdate.test.js +130 -0
  21. package/build/builders/buildWhere.d.ts +6 -0
  22. package/build/builders/buildWhere.js +63 -0
  23. package/build/builders/buildWhere.test.d.ts +1 -0
  24. package/build/builders/buildWhere.test.js +154 -0
  25. package/build/builders/types.d.ts +87 -0
  26. package/build/builders/types.js +1 -0
  27. package/build/connection.d.ts +31 -0
  28. package/build/connection.js +206 -0
  29. package/build/index.d.ts +10 -0
  30. package/build/index.js +5 -0
  31. package/build/operators.d.ts +59 -0
  32. package/build/operators.js +44 -0
  33. package/build/orm.count.d.ts +14 -0
  34. package/build/orm.count.js +22 -0
  35. package/build/orm.createMany.d.ts +5 -0
  36. package/build/orm.createMany.js +26 -0
  37. package/build/orm.createOne.d.ts +5 -0
  38. package/build/orm.createOne.js +34 -0
  39. package/build/orm.d.ts +81 -0
  40. package/build/orm.deleteMany.d.ts +5 -0
  41. package/build/orm.deleteMany.js +26 -0
  42. package/build/orm.deleteOne.d.ts +5 -0
  43. package/build/orm.deleteOne.js +32 -0
  44. package/build/orm.findMany.d.ts +8 -0
  45. package/build/orm.findMany.js +64 -0
  46. package/build/orm.findOne.d.ts +5 -0
  47. package/build/orm.findOne.js +20 -0
  48. package/build/orm.js +243 -0
  49. package/build/orm.restrict.d.ts +6 -0
  50. package/build/orm.restrict.js +52 -0
  51. package/build/orm.updateMany.d.ts +5 -0
  52. package/build/orm.updateMany.js +29 -0
  53. package/build/orm.updateOne.d.ts +5 -0
  54. package/build/orm.updateOne.js +35 -0
  55. package/build/sql/countToSql.d.ts +3 -0
  56. package/build/sql/countToSql.js +11 -0
  57. package/build/sql/countToSql.test.d.ts +1 -0
  58. package/build/sql/countToSql.test.js +218 -0
  59. package/build/sql/createToSql.d.ts +3 -0
  60. package/build/sql/createToSql.js +27 -0
  61. package/build/sql/createToSql.test.d.ts +1 -0
  62. package/build/sql/createToSql.test.js +186 -0
  63. package/build/sql/deleteToSql.d.ts +3 -0
  64. package/build/sql/deleteToSql.js +15 -0
  65. package/build/sql/deleteToSql.test.d.ts +1 -0
  66. package/build/sql/deleteToSql.test.js +93 -0
  67. package/build/sql/findToSql.d.ts +3 -0
  68. package/build/sql/findToSql.js +33 -0
  69. package/build/sql/findToSql.test.d.ts +1 -0
  70. package/build/sql/findToSql.test.js +409 -0
  71. package/build/sql/updateToSql.d.ts +3 -0
  72. package/build/sql/updateToSql.js +16 -0
  73. package/build/sql/updateToSql.test.d.ts +1 -0
  74. package/build/sql/updateToSql.test.js +165 -0
  75. package/build/sql/util.d.ts +11 -0
  76. package/build/sql/util.js +36 -0
  77. package/build/sql/util.test.d.ts +1 -0
  78. package/build/sql/util.test.js +163 -0
  79. package/build/tests/connection.test.d.ts +1 -0
  80. package/build/tests/connection.test.js +304 -0
  81. package/build/tests/datatypes.test.d.ts +1 -0
  82. package/build/tests/datatypes.test.js +239 -0
  83. package/build/tests/operators.test.d.ts +1 -0
  84. package/build/tests/operators.test.js +125 -0
  85. package/build/tests/orm.count.middleware.test.d.ts +1 -0
  86. package/build/tests/orm.count.middleware.test.js +132 -0
  87. package/build/tests/orm.count.test-d.d.ts +1 -0
  88. package/build/tests/orm.count.test-d.js +60 -0
  89. package/build/tests/orm.count.test.d.ts +1 -0
  90. package/build/tests/orm.count.test.js +151 -0
  91. package/build/tests/orm.createMany.middleware.test.d.ts +1 -0
  92. package/build/tests/orm.createMany.middleware.test.js +63 -0
  93. package/build/tests/orm.createMany.test-d.d.ts +1 -0
  94. package/build/tests/orm.createMany.test-d.js +131 -0
  95. package/build/tests/orm.createMany.test.d.ts +1 -0
  96. package/build/tests/orm.createMany.test.js +392 -0
  97. package/build/tests/orm.createOne.middleware.test.d.ts +1 -0
  98. package/build/tests/orm.createOne.middleware.test.js +54 -0
  99. package/build/tests/orm.createOne.test-d.d.ts +1 -0
  100. package/build/tests/orm.createOne.test-d.js +113 -0
  101. package/build/tests/orm.createOne.test.d.ts +1 -0
  102. package/build/tests/orm.createOne.test.js +268 -0
  103. package/build/tests/orm.deleteMany.middleware.test.d.ts +1 -0
  104. package/build/tests/orm.deleteMany.middleware.test.js +77 -0
  105. package/build/tests/orm.deleteMany.test-d.d.ts +1 -0
  106. package/build/tests/orm.deleteMany.test-d.js +179 -0
  107. package/build/tests/orm.deleteMany.test.d.ts +1 -0
  108. package/build/tests/orm.deleteMany.test.js +394 -0
  109. package/build/tests/orm.deleteOne.middleware.test.d.ts +1 -0
  110. package/build/tests/orm.deleteOne.middleware.test.js +61 -0
  111. package/build/tests/orm.deleteOne.test-d.d.ts +1 -0
  112. package/build/tests/orm.deleteOne.test-d.js +179 -0
  113. package/build/tests/orm.deleteOne.test.d.ts +1 -0
  114. package/build/tests/orm.deleteOne.test.js +360 -0
  115. package/build/tests/orm.findMany.includeManyToMany.test.d.ts +1 -0
  116. package/build/tests/orm.findMany.includeManyToMany.test.js +335 -0
  117. package/build/tests/orm.findMany.includeManyToOne.test.d.ts +1 -0
  118. package/build/tests/orm.findMany.includeManyToOne.test.js +286 -0
  119. package/build/tests/orm.findMany.includeOneToMany.test.d.ts +1 -0
  120. package/build/tests/orm.findMany.includeOneToMany.test.js +530 -0
  121. package/build/tests/orm.findMany.middleware.test.d.ts +1 -0
  122. package/build/tests/orm.findMany.middleware.test.js +66 -0
  123. package/build/tests/orm.findMany.offsetLimit.test.d.ts +1 -0
  124. package/build/tests/orm.findMany.offsetLimit.test.js +108 -0
  125. package/build/tests/orm.findMany.orderBy.test.d.ts +1 -0
  126. package/build/tests/orm.findMany.orderBy.test.js +304 -0
  127. package/build/tests/orm.findMany.select.test.d.ts +1 -0
  128. package/build/tests/orm.findMany.select.test.js +278 -0
  129. package/build/tests/orm.findMany.test-d.d.ts +1 -0
  130. package/build/tests/orm.findMany.test-d.js +374 -0
  131. package/build/tests/orm.findMany.where.test.d.ts +1 -0
  132. package/build/tests/orm.findMany.where.test.js +383 -0
  133. package/build/tests/orm.findOne.middleware.test.d.ts +1 -0
  134. package/build/tests/orm.findOne.middleware.test.js +57 -0
  135. package/build/tests/orm.findOne.test-d.d.ts +1 -0
  136. package/build/tests/orm.findOne.test-d.js +377 -0
  137. package/build/tests/orm.findOne.test.d.ts +1 -0
  138. package/build/tests/orm.findOne.test.js +247 -0
  139. package/build/tests/orm.restrict.test-d.d.ts +1 -0
  140. package/build/tests/orm.restrict.test-d.js +105 -0
  141. package/build/tests/orm.restrict.test.d.ts +1 -0
  142. package/build/tests/orm.restrict.test.js +259 -0
  143. package/build/tests/orm.transact.test.d.ts +1 -0
  144. package/build/tests/orm.transact.test.js +48 -0
  145. package/build/tests/orm.updateMany.middleware.test.d.ts +1 -0
  146. package/build/tests/orm.updateMany.middleware.test.js +72 -0
  147. package/build/tests/orm.updateMany.test.d.ts +1 -0
  148. package/build/tests/orm.updateMany.test.js +210 -0
  149. package/build/tests/orm.updateOne.middleware.test.d.ts +1 -0
  150. package/build/tests/orm.updateOne.middleware.test.js +62 -0
  151. package/build/tests/orm.updateOne.test.d.ts +1 -0
  152. package/build/tests/orm.updateOne.test.js +209 -0
  153. package/build/tests/util/db.d.ts +1571 -0
  154. package/build/tests/util/db.js +10 -0
  155. package/build/tests/util/logger.d.ts +19 -0
  156. package/build/tests/util/logger.js +40 -0
  157. package/build/types/BaseFindParams.d.ts +1 -0
  158. package/build/types/BaseFindParams.js +1 -0
  159. package/build/types/CountParams.d.ts +16 -0
  160. package/build/types/CountParams.js +1 -0
  161. package/build/types/CountParams.test-d.d.ts +1 -0
  162. package/build/types/CountParams.test-d.js +89 -0
  163. package/build/types/CreateManyParams.d.ts +11 -0
  164. package/build/types/CreateManyParams.js +1 -0
  165. package/build/types/CreateManyParams.test-d.d.ts +1 -0
  166. package/build/types/CreateManyParams.test-d.js +83 -0
  167. package/build/types/CreateManyResult.d.ts +5 -0
  168. package/build/types/CreateManyResult.js +1 -0
  169. package/build/types/CreateManyResult.test-d.d.ts +1 -0
  170. package/build/types/CreateManyResult.test-d.js +22 -0
  171. package/build/types/CreateOneParams.d.ts +11 -0
  172. package/build/types/CreateOneParams.js +1 -0
  173. package/build/types/CreateOneParams.test-d.d.ts +1 -0
  174. package/build/types/CreateOneParams.test-d.js +56 -0
  175. package/build/types/CreateOneResult.d.ts +5 -0
  176. package/build/types/CreateOneResult.js +1 -0
  177. package/build/types/CreateOneResult.test-d.d.ts +1 -0
  178. package/build/types/CreateOneResult.test-d.js +23 -0
  179. package/build/types/CreateValues.d.ts +6 -0
  180. package/build/types/CreateValues.js +1 -0
  181. package/build/types/CreateValues.test-d.d.ts +1 -0
  182. package/build/types/CreateValues.test-d.js +60 -0
  183. package/build/types/DeleteManyResult.d.ts +5 -0
  184. package/build/types/DeleteManyResult.js +1 -0
  185. package/build/types/DeleteManyResult.test-d.d.ts +1 -0
  186. package/build/types/DeleteManyResult.test-d.js +23 -0
  187. package/build/types/DeleteOneResult.d.ts +5 -0
  188. package/build/types/DeleteOneResult.js +1 -0
  189. package/build/types/DeleteOneResult.test-d.d.ts +1 -0
  190. package/build/types/DeleteOneResult.test-d.js +23 -0
  191. package/build/types/DeleteParams.d.ts +7 -0
  192. package/build/types/DeleteParams.js +1 -0
  193. package/build/types/DeleteParams.test-d.d.ts +1 -0
  194. package/build/types/DeleteParams.test-d.js +46 -0
  195. package/build/types/FindParams.d.ts +22 -0
  196. package/build/types/FindParams.js +1 -0
  197. package/build/types/FindParams.test-d.d.ts +1 -0
  198. package/build/types/FindParams.test-d.js +107 -0
  199. package/build/types/FindResult.d.ts +13 -0
  200. package/build/types/FindResult.js +1 -0
  201. package/build/types/FindResult.test-d.d.ts +1 -0
  202. package/build/types/FindResult.test-d.js +30 -0
  203. package/build/types/IncludeClause.d.ts +5 -0
  204. package/build/types/IncludeClause.js +1 -0
  205. package/build/types/IncludeClause.test-d.d.ts +1 -0
  206. package/build/types/IncludeClause.test-d.js +69 -0
  207. package/build/types/Middleware.d.ts +51 -0
  208. package/build/types/Middleware.js +37 -0
  209. package/build/types/OptionalValues.d.ts +4 -0
  210. package/build/types/OptionalValues.js +1 -0
  211. package/build/types/OptionalValues.test-d.d.ts +1 -0
  212. package/build/types/OptionalValues.test-d.js +12 -0
  213. package/build/types/OrderByClause.d.ts +9 -0
  214. package/build/types/OrderByClause.js +1 -0
  215. package/build/types/OrderByClause.test-d.d.ts +1 -0
  216. package/build/types/OrderByClause.test-d.js +44 -0
  217. package/build/types/RequiredValues.d.ts +4 -0
  218. package/build/types/RequiredValues.js +1 -0
  219. package/build/types/RequiredValues.test-d.d.ts +1 -0
  220. package/build/types/RequiredValues.test-d.js +22 -0
  221. package/build/types/RestrictModels.d.ts +23 -0
  222. package/build/types/RestrictModels.js +1 -0
  223. package/build/types/RestrictModels.test-d.d.ts +1 -0
  224. package/build/types/RestrictModels.test-d.js +44 -0
  225. package/build/types/ReturningClause.d.ts +3 -0
  226. package/build/types/ReturningClause.js +1 -0
  227. package/build/types/ReturningClause.test-d.d.ts +1 -0
  228. package/build/types/ReturningClause.test-d.js +15 -0
  229. package/build/types/SelectClause.d.ts +3 -0
  230. package/build/types/SelectClause.js +1 -0
  231. package/build/types/SelectClause.test-d.d.ts +1 -0
  232. package/build/types/SelectClause.test-d.js +15 -0
  233. package/build/types/UpdateManyResult.d.ts +5 -0
  234. package/build/types/UpdateManyResult.js +1 -0
  235. package/build/types/UpdateManyResult.test-d.d.ts +1 -0
  236. package/build/types/UpdateManyResult.test-d.js +15 -0
  237. package/build/types/UpdateOneResult.d.ts +5 -0
  238. package/build/types/UpdateOneResult.js +1 -0
  239. package/build/types/UpdateOneResult.test-d.d.ts +1 -0
  240. package/build/types/UpdateOneResult.test-d.js +15 -0
  241. package/build/types/UpdateParams.d.ts +9 -0
  242. package/build/types/UpdateParams.js +1 -0
  243. package/build/types/UpdateParams.test-d.d.ts +1 -0
  244. package/build/types/UpdateParams.test-d.js +29 -0
  245. package/build/types/UpdateValues.d.ts +6 -0
  246. package/build/types/UpdateValues.js +1 -0
  247. package/build/types/UpdateValues.test-d.d.ts +1 -0
  248. package/build/types/UpdateValues.test-d.js +33 -0
  249. package/build/types/WhereClause.d.ts +29 -0
  250. package/build/types/WhereClause.js +1 -0
  251. package/build/types/WhereClause.test-d.d.ts +1 -0
  252. package/build/types/WhereClause.test-d.js +137 -0
  253. package/build/util/getIncludedToManySubqueries.d.ts +12 -0
  254. package/build/util/getIncludedToManySubqueries.js +63 -0
  255. package/build/util/getIncludedToManySubqueries.test.d.ts +1 -0
  256. package/build/util/getIncludedToManySubqueries.test.js +121 -0
  257. package/build/util/getLateralJoinValues.d.ts +4 -0
  258. package/build/util/getLateralJoinValues.js +30 -0
  259. package/build/util/getLateralJoinValues.test.d.ts +1 -0
  260. package/build/util/getLateralJoinValues.test.js +99 -0
  261. package/build/util/hasClauses.d.ts +1 -0
  262. package/build/util/hasClauses.js +9 -0
  263. package/build/util/hasClauses.test.d.ts +1 -0
  264. package/build/util/hasClauses.test.js +15 -0
  265. package/build/util/makeTableAlias.d.ts +1 -0
  266. package/build/util/makeTableAlias.js +10 -0
  267. package/build/util/makeTableAlias.test.d.ts +1 -0
  268. package/build/util/makeTableAlias.test.js +18 -0
  269. package/build/util/resultSchema.d.ts +10 -0
  270. package/build/util/resultSchema.js +42 -0
  271. package/build/util/rowToObject.d.ts +8 -0
  272. package/build/util/rowToObject.js +10 -0
  273. package/build/util/rowToObject.test.d.ts +1 -0
  274. package/build/util/rowToObject.test.js +68 -0
  275. 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,3 @@
1
+ import { SQLStatement } from "@casekit/sql";
2
+ import { CountBuilder } from "#builders/types.js";
3
+ export declare const countToSql: (builder: CountBuilder) => SQLStatement;
@@ -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 {};