@casekit/orm 0.0.1-alpha.14 → 0.0.1-alpha.16

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 (215) hide show
  1. package/lib/orm.query.test.d.ts +2 -0
  2. package/lib/orm.query.test.d.ts.map +1 -0
  3. package/lib/orm.query.test.js +22 -0
  4. package/lib/orm.query.test.js.map +1 -0
  5. package/package.json +3 -6
  6. package/src/Connection.ts +65 -0
  7. package/src/errors.ts +18 -0
  8. package/src/index.ts +16 -0
  9. package/src/logger.ts +3 -0
  10. package/src/migrate/commands/implode.ts +46 -0
  11. package/src/migrate/index.ts +1 -0
  12. package/src/migrate/migrator.ts +24 -0
  13. package/src/migrate/sql/createExtensionsSql.test.ts +26 -0
  14. package/src/migrate/sql/createExtensionsSql.ts +16 -0
  15. package/src/migrate/sql/createForeignKeyConstraintSql.test.ts +50 -0
  16. package/src/migrate/sql/createForeignKeyConstraintSql.ts +44 -0
  17. package/src/migrate/sql/createSchemasSql.test.ts +81 -0
  18. package/src/migrate/sql/createSchemasSql.ts +15 -0
  19. package/src/migrate/sql/createTableSql.properties.ts +38 -0
  20. package/src/migrate/sql/createTableSql.test.ts +74 -0
  21. package/src/migrate/sql/createTableSql.ts +53 -0
  22. package/src/migrate/sql/createUniqueConstraintSql.ts +27 -0
  23. package/src/migrate/sql/dropSchemasSql.ts +15 -0
  24. package/src/migrate/sql/dropTableSql.ts +13 -0
  25. package/src/orm.query.test.ts +28 -0
  26. package/src/orm.ts +370 -0
  27. package/src/pull/index.ts +1 -0
  28. package/src/pull/introspect/getForeignKeys.ts +64 -0
  29. package/src/pull/introspect/getPrimaryKeys.ts +26 -0
  30. package/src/pull/introspect/getTables.ts +51 -0
  31. package/src/pull/introspect/getUniqueConstraints.ts +39 -0
  32. package/src/pull/parse/parseCreateUniqueIndexStatement.test.ts +14 -0
  33. package/src/pull/parse/parseCreateUniqueIndexStatement.ts +19 -0
  34. package/src/pull/pull.ts +78 -0
  35. package/src/pull/render/renderModel.test.ts +144 -0
  36. package/src/pull/render/renderModel.ts +141 -0
  37. package/src/pull/render/renderModelsIndex.ts +24 -0
  38. package/src/pull/render/renderRelations.ts +77 -0
  39. package/src/pull/render/renderRelationsIndex.ts +24 -0
  40. package/src/pull/types/ColumnMeta.ts +10 -0
  41. package/src/pull/types/ForeignKey.ts +6 -0
  42. package/src/pull/types/PrimaryKey.ts +6 -0
  43. package/src/pull/types/UniqueConstraint.ts +8 -0
  44. package/src/pull/util/format.ts +17 -0
  45. package/src/pull/util/quote.ts +7 -0
  46. package/src/pull/util/unquote.ts +9 -0
  47. package/src/queries/clauses/IncludeClause.ts +39 -0
  48. package/src/queries/clauses/LateralByClause.ts +4 -0
  49. package/src/queries/clauses/ReturningClause.ts +7 -0
  50. package/src/queries/clauses/SelectClause.ts +7 -0
  51. package/src/queries/clauses/WhereClause.ts +16 -0
  52. package/src/queries/clauses/helpers/OptionalColumn.ts +18 -0
  53. package/src/queries/clauses/helpers/OptionalParams.ts +14 -0
  54. package/src/queries/clauses/helpers/RequiredColumn.ts +8 -0
  55. package/src/queries/clauses/helpers/RequiredParams.ts +14 -0
  56. package/src/queries/clauses/include/IncludedRelationModel.ts +13 -0
  57. package/src/queries/clauses/include/IncludedRelationName.ts +11 -0
  58. package/src/queries/clauses/include/IncludedRelationQuery.ts +20 -0
  59. package/src/queries/clauses/where/buildWhereClause.ts +121 -0
  60. package/src/queries/clauses/where/buildWhereClauses.test.ts +145 -0
  61. package/src/queries/clauses/where/buildWhereClauses.ts +45 -0
  62. package/src/queries/clauses/where/operators.ts +13 -0
  63. package/src/queries/clauses/where/types/WhereClauseValue.ts +39 -0
  64. package/src/queries/count/buildCount.ts +77 -0
  65. package/src/queries/count/countToSql.ts +66 -0
  66. package/src/queries/count/tests/count.test.ts +35 -0
  67. package/src/queries/count/types/BaseCountParams.ts +11 -0
  68. package/src/queries/count/types/CountBuilder.ts +45 -0
  69. package/src/queries/count/types/CountParams.ts +27 -0
  70. package/src/queries/count.ts +33 -0
  71. package/src/queries/create/buildCreate.ts +67 -0
  72. package/src/queries/create/createResultSchema.ts +24 -0
  73. package/src/queries/create/createToSql.ts +44 -0
  74. package/src/queries/create/tests/createMany.varied-keys.test.ts +28 -0
  75. package/src/queries/create/tests/createOne.test-d.ts +116 -0
  76. package/src/queries/create/tests/createOne.test.ts +197 -0
  77. package/src/queries/create/types/BaseCreateManyParams.ts +7 -0
  78. package/src/queries/create/types/BaseCreateOneParams.ts +7 -0
  79. package/src/queries/create/types/CreateManyParams.ts +15 -0
  80. package/src/queries/create/types/CreateManyResult.ts +17 -0
  81. package/src/queries/create/types/CreateOneParams.ts +22 -0
  82. package/src/queries/create/types/CreateOneResult.ts +17 -0
  83. package/src/queries/createMany.ts +38 -0
  84. package/src/queries/createOne.ts +27 -0
  85. package/src/queries/delete/buildDelete.ts +56 -0
  86. package/src/queries/delete/deleteResultSchema.ts +23 -0
  87. package/src/queries/delete/deleteToSql.ts +48 -0
  88. package/src/queries/delete/tests/deleteOne.test.ts +108 -0
  89. package/src/queries/delete/types/BaseDeleteParams.ts +9 -0
  90. package/src/queries/delete/types/DeleteManyResult.ts +16 -0
  91. package/src/queries/delete/types/DeleteOneResult.ts +16 -0
  92. package/src/queries/delete/types/DeleteParams.ts +12 -0
  93. package/src/queries/deleteMany.ts +33 -0
  94. package/src/queries/deleteOne.ts +32 -0
  95. package/src/queries/find/buildFind.ts +138 -0
  96. package/src/queries/find/findResultSchema.ts +32 -0
  97. package/src/queries/find/findToSql.test.ts +123 -0
  98. package/src/queries/find/findToSql.ts +141 -0
  99. package/src/queries/find/getIncludedManyToManyRelations.ts +49 -0
  100. package/src/queries/find/getIncludedOneToManyRelations.ts +44 -0
  101. package/src/queries/find/tests/findMany.include.test.ts +107 -0
  102. package/src/queries/find/tests/findMany.limit.test-d.ts +75 -0
  103. package/src/queries/find/tests/findMany.limit.test.ts +176 -0
  104. package/src/queries/find/tests/findMany.nullable-relations.test.ts +127 -0
  105. package/src/queries/find/tests/findMany.orderBy.test-d.ts +84 -0
  106. package/src/queries/find/tests/findMany.orderBy.test.ts +184 -0
  107. package/src/queries/find/tests/findMany.select.test-d.ts +117 -0
  108. package/src/queries/find/tests/findMany.select.test.ts +188 -0
  109. package/src/queries/find/tests/findMany.too-deep.test-d.ts +154 -0
  110. package/src/queries/find/tests/findMany.where.test-d.ts +85 -0
  111. package/src/queries/find/tests/findMany.where.test.ts +76 -0
  112. package/src/queries/find/tests/middleware.find.where.test.ts +467 -0
  113. package/src/queries/find/types/BaseFindParams.ts +18 -0
  114. package/src/queries/find/types/FindBuilder.ts +73 -0
  115. package/src/queries/find/types/FindManyParams.ts +24 -0
  116. package/src/queries/find/types/FindManyResult.ts +13 -0
  117. package/src/queries/find/types/FindOneParams.ts +17 -0
  118. package/src/queries/find/types/FindOneResult.ts +50 -0
  119. package/src/queries/findMany.ts +134 -0
  120. package/src/queries/findOne.ts +30 -0
  121. package/src/queries/middleware/Middleware.ts +53 -0
  122. package/src/queries/middleware/ValuesMiddleware.ts +9 -0
  123. package/src/queries/middleware/WhereMiddleware.ts +16 -0
  124. package/src/queries/update/buildUpdate.ts +76 -0
  125. package/src/queries/update/tests/updateOne.test.ts +118 -0
  126. package/src/queries/update/types/BaseUpdateParams.ts +10 -0
  127. package/src/queries/update/types/UpdateManyResult.ts +16 -0
  128. package/src/queries/update/types/UpdateOneResult.ts +16 -0
  129. package/src/queries/update/types/UpdateParams.ts +14 -0
  130. package/src/queries/update/types/UpdateValues.ts +12 -0
  131. package/src/queries/update/updateResultSchema.ts +23 -0
  132. package/src/queries/update/updateToSql.ts +43 -0
  133. package/src/queries/updateMany.ts +33 -0
  134. package/src/queries/updateOne.ts +33 -0
  135. package/src/queries/util/hasConditions.test.ts +36 -0
  136. package/src/queries/util/hasConditions.ts +14 -0
  137. package/src/queries/util/rowToObject.test.ts +76 -0
  138. package/src/queries/util/rowToObject.ts +13 -0
  139. package/src/queries/util/tableAlias.test.ts +20 -0
  140. package/src/queries/util/tableAlias.ts +10 -0
  141. package/src/schema/populate/composeMiddleware.ts +51 -0
  142. package/src/schema/populate/populateConfiguration.ts +48 -0
  143. package/src/schema/populate/populateModel.ts +98 -0
  144. package/src/schema/populate/suggestedColumnSchema.ts +62 -0
  145. package/src/schema/types/base/BaseColumn.ts +10 -0
  146. package/src/schema/types/base/BaseConfiguration.ts +14 -0
  147. package/src/schema/types/base/BaseModel.ts +12 -0
  148. package/src/schema/types/base/BaseModels.ts +3 -0
  149. package/src/schema/types/base/BaseOrm.ts +8 -0
  150. package/src/schema/types/base/BaseRelation.ts +19 -0
  151. package/src/schema/types/base/BaseRelations.ts +3 -0
  152. package/src/schema/types/constraints/ForeignKey.ts +13 -0
  153. package/src/schema/types/constraints/UniqueConstraint.ts +9 -0
  154. package/src/schema/types/helpers/ColumnName.ts +6 -0
  155. package/src/schema/types/helpers/ColumnType.ts +23 -0
  156. package/src/schema/types/helpers/Columns.ts +3 -0
  157. package/src/schema/types/helpers/HasDefault.ts +11 -0
  158. package/src/schema/types/helpers/IsNullable.ts +7 -0
  159. package/src/schema/types/helpers/IsProvided.ts +8 -0
  160. package/src/schema/types/helpers/IsSerial.ts +10 -0
  161. package/src/schema/types/helpers/ModelName.ts +6 -0
  162. package/src/schema/types/loose/LooseColumnDefinition.ts +80 -0
  163. package/src/schema/types/loose/LooseModelDefinition.ts +47 -0
  164. package/src/schema/types/loose/LooseModelDefinitions.ts +3 -0
  165. package/src/schema/types/loose/LooseRelationDefinition.ts +10 -0
  166. package/src/schema/types/loose/LooseRelationsDefinition.ts +8 -0
  167. package/src/schema/types/loose/LooseRelationsDefinitions.ts +7 -0
  168. package/src/schema/types/postgres/DataType.ts +65 -0
  169. package/src/schema/types/relations/ManyToManyRelation.ts +15 -0
  170. package/src/schema/types/relations/ManyToOneRelation.ts +14 -0
  171. package/src/schema/types/relations/OneToManyRelation.ts +12 -0
  172. package/src/schema/types/strict/ColumnDefinition.ts +81 -0
  173. package/src/schema/types/strict/ModelDefinition.ts +47 -0
  174. package/src/schema/types/strict/ModelDefinitions.ts +3 -0
  175. package/src/schema/types/strict/RelationDefinition.ts +13 -0
  176. package/src/schema/types/strict/RelationsDefinition.ts +8 -0
  177. package/src/schema/types/strict/RelationsDefinitions.ts +7 -0
  178. package/src/schema/validate/validateConfiguration.ts +9 -0
  179. package/src/schema/validate/validateModel.ts +32 -0
  180. package/src/sql/SQLStatement.test.ts +112 -0
  181. package/src/sql/SQLStatement.ts +86 -0
  182. package/src/sql/index.ts +2 -0
  183. package/src/sql/sql.ts +47 -0
  184. package/src/test/db/index.ts +27 -0
  185. package/src/test/db/models/foo.model.ts +24 -0
  186. package/src/test/db/models/foo.relations.ts +4 -0
  187. package/src/test/db/models/post.model.ts +34 -0
  188. package/src/test/db/models/post.relations.ts +21 -0
  189. package/src/test/db/models/tenant.model.ts +14 -0
  190. package/src/test/db/models/tenant.relations.ts +22 -0
  191. package/src/test/db/models/tenantUser.model.ts +23 -0
  192. package/src/test/db/models/tenantUser.relations.ts +15 -0
  193. package/src/test/db/models/user.model.ts +29 -0
  194. package/src/test/db/models/user.relations.ts +38 -0
  195. package/src/test/db/models.ts +15 -0
  196. package/src/test/db/relations.ts +13 -0
  197. package/src/test/gen/column.ts +39 -0
  198. package/src/test/gen/index.ts +2 -0
  199. package/src/test/gen/model.ts +58 -0
  200. package/src/test/gen/sqldate.ts +8 -0
  201. package/src/test/globalSetup.ts +6 -0
  202. package/src/test/seed/index.ts +75 -0
  203. package/src/test/util/withRollback.ts +18 -0
  204. package/src/test/util/withTransaction.ts +19 -0
  205. package/src/types/ColumnName.ts +6 -0
  206. package/src/types/ColumnType.ts +20 -0
  207. package/src/types/Configuration.ts +21 -0
  208. package/src/types/ModelType.ts +20 -0
  209. package/src/types/util/DeepRequired.ts +7 -0
  210. package/src/types/util/DisallowExtraKeys.ts +5 -0
  211. package/src/types/util/NonEmptyArray.ts +1 -0
  212. package/src/types/util/Simplify.ts +8 -0
  213. package/src/util/ensureArray.ts +4 -0
  214. package/src/util/interleave.test.ts +35 -0
  215. package/src/util/interleave.ts +8 -0
@@ -0,0 +1,176 @@
1
+ import { describe, expect, test } from "vitest";
2
+
3
+ import { db } from "../../../test/db";
4
+ import { seed } from "../../../test/seed";
5
+
6
+ describe("findMany", () => {
7
+ test("it can limit the number of rows returned", async () => {
8
+ await db.transact(
9
+ async (db) => {
10
+ await seed(db, {
11
+ users: [
12
+ {
13
+ username: "Russell",
14
+ tenants: [{ name: "WFMA", posts: 0 }],
15
+ },
16
+ {
17
+ username: "Dan",
18
+ tenants: [{ name: "WFMA", posts: 0 }],
19
+ },
20
+ {
21
+ username: "Fairooz",
22
+ tenants: [{ name: "WFMA", posts: 0 }],
23
+ },
24
+ ],
25
+ });
26
+ const results = await db.findMany("user", {
27
+ select: ["id", "username"],
28
+ orderBy: ["username"],
29
+ limit: 2,
30
+ });
31
+
32
+ expect(results.map((r) => r.username)).toEqual([
33
+ "Dan",
34
+ "Fairooz",
35
+ ]);
36
+ },
37
+ { rollback: true },
38
+ );
39
+ });
40
+
41
+ test("offsets can be applied", async () => {
42
+ await db.transact(
43
+ async (db) => {
44
+ await seed(db, {
45
+ users: [
46
+ {
47
+ username: "Russell",
48
+ tenants: [{ name: "WFMA", posts: 0 }],
49
+ },
50
+ {
51
+ username: "Dan",
52
+ tenants: [{ name: "WFMA", posts: 0 }],
53
+ },
54
+ {
55
+ username: "Fairooz",
56
+ tenants: [{ name: "WFMA", posts: 0 }],
57
+ },
58
+ ],
59
+ });
60
+ const results = await db.findMany("user", {
61
+ select: ["id", "username"],
62
+ orderBy: ["username"],
63
+ limit: 1,
64
+ offset: 2,
65
+ });
66
+
67
+ expect(results.map((r) => r.username)).toEqual(["Russell"]);
68
+ },
69
+ { rollback: true },
70
+ );
71
+ });
72
+
73
+ test("1:N relations can have limits and offsets applied", async () => {
74
+ await db.transact(
75
+ async (db) => {
76
+ await seed(db, {
77
+ users: [
78
+ {
79
+ username: "Russell",
80
+ tenants: [{ name: "WFMA", posts: 3 }],
81
+ },
82
+ {
83
+ username: "Dan",
84
+ tenants: [{ name: "WFMA", posts: 5 }],
85
+ },
86
+ {
87
+ username: "Fairooz",
88
+ tenants: [{ name: "WFMA", posts: 2 }],
89
+ },
90
+ ],
91
+ });
92
+ const results = await db.findMany("user", {
93
+ select: ["id", "username"],
94
+ orderBy: ["username"],
95
+ include: {
96
+ posts: {
97
+ select: ["title"],
98
+ orderBy: ["title"],
99
+ limit: 2,
100
+ offset: 1,
101
+ },
102
+ },
103
+ });
104
+
105
+ expect(
106
+ results.map((r) => [
107
+ r.username,
108
+ r.posts.map((p) => p.title),
109
+ ]),
110
+ ).toEqual([
111
+ ["Dan", ["Post e", "Post f"]],
112
+ ["Fairooz", ["Post j"]],
113
+ ["Russell", ["Post b", "Post c"]],
114
+ ]);
115
+ },
116
+ { rollback: true },
117
+ );
118
+ });
119
+
120
+ test("N:N relations can have limits and offsets applied", async () => {
121
+ await db.transact(
122
+ async (db) => {
123
+ await seed(db, {
124
+ users: [
125
+ {
126
+ username: "Russell",
127
+ tenants: [
128
+ { name: "WFMA", posts: 0 },
129
+ { name: "Popova Park", posts: 0 },
130
+ { name: "LRF", posts: 0 },
131
+ ],
132
+ },
133
+ {
134
+ username: "Dan",
135
+ tenants: [
136
+ { name: "Popova Park", posts: 0 },
137
+ { name: "LRF", posts: 0 },
138
+ ],
139
+ },
140
+ {
141
+ username: "Fairooz",
142
+ tenants: [
143
+ { name: "WFMA", posts: 0 },
144
+ { name: "LRF", posts: 0 },
145
+ ],
146
+ },
147
+ ],
148
+ });
149
+ const results = await db.findMany("user", {
150
+ select: ["id", "username"],
151
+ orderBy: ["username"],
152
+ include: {
153
+ tenants: {
154
+ select: ["name"],
155
+ orderBy: ["name"],
156
+ limit: 2,
157
+ offset: 1,
158
+ },
159
+ },
160
+ });
161
+
162
+ expect(
163
+ results.map((r) => [
164
+ r.username,
165
+ r.tenants.map((p) => p.name),
166
+ ]),
167
+ ).toEqual([
168
+ ["Dan", ["Popova Park"]],
169
+ ["Fairooz", ["WFMA"]],
170
+ ["Russell", ["Popova Park", "WFMA"]],
171
+ ]);
172
+ },
173
+ { rollback: true },
174
+ );
175
+ });
176
+ });
@@ -0,0 +1,127 @@
1
+ import { describe, expect, test } from "vitest";
2
+
3
+ import { db } from "../../../test/db";
4
+ import { seed } from "../../../test/seed";
5
+
6
+ describe("findMany", () => {
7
+ test("optional N:1 relations don't prevent records being returned", async () => {
8
+ await db.transact(
9
+ async (db) => {
10
+ await seed(db, {
11
+ users: [
12
+ {
13
+ username: "Russell",
14
+ tenants: [
15
+ { name: "WFMA", posts: 1 },
16
+ { name: "Popova Park", posts: 0 },
17
+ ],
18
+ },
19
+ {
20
+ username: "Dan",
21
+ tenants: [{ name: "WFMA", posts: 2 }],
22
+ },
23
+ {
24
+ username: "Fairooz",
25
+ tenants: [{ name: "WFMA", posts: 0 }],
26
+ },
27
+ ],
28
+ });
29
+ const results = await db.findMany("post", {
30
+ select: ["id", "title"],
31
+ include: {
32
+ reviewedBy: {
33
+ select: ["id", "username"],
34
+ include: {
35
+ posts: { select: ["id", "title"] },
36
+ invitedBy: { select: ["id", "username"] },
37
+ },
38
+ },
39
+ },
40
+ orderBy: ["title"],
41
+ limit: 2,
42
+ });
43
+
44
+ expect(results.map((p) => [p.title, p.reviewedBy])).toEqual([
45
+ ["Post a", null],
46
+ ["Post b", null],
47
+ ]);
48
+ },
49
+ { rollback: true },
50
+ );
51
+ });
52
+
53
+ test("optional N:1 relations are returned if they exist", async () => {
54
+ await db.transact(
55
+ async (db) => {
56
+ const { users } = await seed(db, {
57
+ users: [
58
+ {
59
+ username: "Russell",
60
+ tenants: [
61
+ { name: "WFMA", posts: 1 },
62
+ { name: "Popova Park", posts: 0 },
63
+ ],
64
+ },
65
+ {
66
+ username: "Dan",
67
+ tenants: [{ name: "WFMA", posts: 2 }],
68
+ },
69
+ {
70
+ username: "Fairooz",
71
+ tenants: [{ name: "WFMA", posts: 0 }],
72
+ },
73
+ ],
74
+ });
75
+ await db.updateOne("user", {
76
+ where: { id: users["Dan"].id },
77
+ set: {
78
+ invitedById: users["Russell"].id,
79
+ },
80
+ });
81
+ const results = await db.findMany("user", {
82
+ select: ["username"],
83
+ include: {
84
+ invitedBy: {
85
+ select: ["username"],
86
+ },
87
+ tenants: {
88
+ select: ["name"],
89
+ orderBy: ["name"],
90
+ },
91
+ reviewedPosts: {
92
+ select: ["title"],
93
+ },
94
+ invitedUsers: {
95
+ select: ["username"],
96
+ },
97
+ },
98
+ orderBy: ["username"],
99
+ });
100
+ expect(results).toEqual([
101
+ {
102
+ username: "Dan",
103
+ invitedBy: { username: "Russell" },
104
+ tenants: [{ name: "WFMA" }],
105
+ reviewedPosts: [],
106
+ invitedUsers: [],
107
+ },
108
+ {
109
+ username: "Fairooz",
110
+ invitedBy: null,
111
+ tenants: [{ name: "WFMA" }],
112
+ reviewedPosts: [],
113
+ invitedUsers: [],
114
+ },
115
+ {
116
+ username: "Russell",
117
+ invitedBy: null,
118
+ tenants: [{ name: "Popova Park" }, { name: "WFMA" }],
119
+ reviewedPosts: [],
120
+ invitedUsers: [{ username: "Dan" }],
121
+ },
122
+ ]);
123
+ },
124
+ { rollback: true },
125
+ );
126
+ });
127
+ });
@@ -0,0 +1,84 @@
1
+ import { assertType, describe, test } from "vitest";
2
+
3
+ import { db } from "../../../test/db";
4
+
5
+ describe("findMany", () => {
6
+ test("queries can only be ordered by columns that exist", () => {
7
+ assertType(
8
+ db.findMany("post", {
9
+ select: ["id", "content"],
10
+ orderBy: [
11
+ "title",
12
+ // @ts-expect-error "wrong" is not a column on the post model
13
+ "wrong",
14
+ ],
15
+ }),
16
+ );
17
+ });
18
+
19
+ test("queries can be ordered by columns ascending, descending, or implicitly ascending", () => {
20
+ assertType(
21
+ db.findMany("post", {
22
+ select: ["id", "content"],
23
+ orderBy: ["title", ["content", "asc"], ["id", "desc"]],
24
+ }),
25
+ );
26
+ });
27
+
28
+ test("anything other than asc or desc as a sort order gives a type error", () => {
29
+ assertType(
30
+ db.findMany("post", {
31
+ select: ["id", "content"],
32
+ orderBy: [
33
+ "title",
34
+ ["content", "asc"],
35
+ // @ts-expect-error "wrong" is not a valid sort order
36
+ ["id", "wrong"],
37
+ ],
38
+ }),
39
+ );
40
+ });
41
+
42
+ test("included N:1 relations cannot be ordered", () => {
43
+ assertType(
44
+ db.findMany("post", {
45
+ select: ["id", "content"],
46
+ include: {
47
+ author: {
48
+ select: ["username"],
49
+ // @ts-expect-error N:1 relations cannot be ordered
50
+ orderBy: ["username"],
51
+ },
52
+ },
53
+ }),
54
+ );
55
+ });
56
+
57
+ test("included 1:N relations can be ordered", () => {
58
+ assertType(
59
+ db.findMany("user", {
60
+ select: ["id", "username"],
61
+ include: {
62
+ posts: {
63
+ select: ["title"],
64
+ orderBy: ["title"],
65
+ },
66
+ },
67
+ }),
68
+ );
69
+ });
70
+
71
+ test("included N:N relations can be ordered", () => {
72
+ assertType(
73
+ db.findMany("user", {
74
+ select: ["id", "username"],
75
+ include: {
76
+ tenants: {
77
+ select: ["name"],
78
+ orderBy: ["name"],
79
+ },
80
+ },
81
+ }),
82
+ );
83
+ });
84
+ });
@@ -0,0 +1,184 @@
1
+ import { describe, expect, test } from "vitest";
2
+
3
+ import { db } from "../../../test/db";
4
+ import { seed } from "../../../test/seed";
5
+
6
+ describe("findMany", () => {
7
+ test("it can return data in the specified order", async () => {
8
+ await db.transact(
9
+ async (db) => {
10
+ await seed(db, {
11
+ users: [
12
+ {
13
+ username: "Russell",
14
+ tenants: [{ name: "WFMA", posts: 0 }],
15
+ },
16
+ {
17
+ username: "Dan",
18
+ tenants: [{ name: "WFMA", posts: 0 }],
19
+ },
20
+ {
21
+ username: "Fairooz",
22
+ tenants: [{ name: "WFMA", posts: 0 }],
23
+ },
24
+ ],
25
+ });
26
+ const results = await db.findMany("user", {
27
+ select: ["id", "username"],
28
+ orderBy: ["username"],
29
+ });
30
+
31
+ expect(results.map((r) => r.username)).toEqual([
32
+ "Dan",
33
+ "Fairooz",
34
+ "Russell",
35
+ ]);
36
+ },
37
+ { rollback: true },
38
+ );
39
+ });
40
+
41
+ test("it can return data in the reverse order", async () => {
42
+ await db.transact(
43
+ async (db) => {
44
+ await seed(db, {
45
+ users: [
46
+ {
47
+ username: "Russell",
48
+ tenants: [{ name: "WFMA", posts: 0 }],
49
+ },
50
+ {
51
+ username: "Dan",
52
+ tenants: [{ name: "WFMA", posts: 0 }],
53
+ },
54
+ {
55
+ username: "Fairooz",
56
+ tenants: [{ name: "WFMA", posts: 0 }],
57
+ },
58
+ ],
59
+ });
60
+ const results = await db.findMany("user", {
61
+ select: ["id", "username"],
62
+ orderBy: [["username", "desc"]],
63
+ });
64
+
65
+ expect(results.map((r) => r.username)).toEqual([
66
+ "Russell",
67
+ "Fairooz",
68
+ "Dan",
69
+ ]);
70
+ },
71
+ { rollback: true },
72
+ );
73
+ });
74
+
75
+ test("it can return 1:N relations in order", async () => {
76
+ await db.transact(
77
+ async (db) => {
78
+ await seed(db, {
79
+ users: [
80
+ {
81
+ username: "Russell",
82
+ tenants: [{ name: "WFMA", posts: 3 }],
83
+ },
84
+ {
85
+ username: "Dan",
86
+ tenants: [{ name: "WFMA", posts: 2 }],
87
+ },
88
+ {
89
+ username: "Fairooz",
90
+ tenants: [{ name: "WFMA", posts: 6 }],
91
+ },
92
+ ],
93
+ });
94
+ const results = await db.findMany("user", {
95
+ select: ["id", "username"],
96
+ include: {
97
+ posts: {
98
+ select: ["id", "title"],
99
+ orderBy: [["title", "desc"]],
100
+ },
101
+ },
102
+ orderBy: ["username"],
103
+ });
104
+
105
+ expect(
106
+ results.map((r) => [
107
+ r.username,
108
+ r.posts.map((p) => p.title),
109
+ ]),
110
+ ).toEqual([
111
+ ["Dan", ["Post e", "Post d"]],
112
+ [
113
+ "Fairooz",
114
+ [
115
+ "Post k",
116
+ "Post j",
117
+ "Post i",
118
+ "Post h",
119
+ "Post g",
120
+ "Post f",
121
+ ],
122
+ ],
123
+ ["Russell", ["Post c", "Post b", "Post a"]],
124
+ ]);
125
+ },
126
+ { rollback: true },
127
+ );
128
+ });
129
+
130
+ test("it can return N:N relations in order", async () => {
131
+ await db.transact(
132
+ async (db) => {
133
+ await seed(db, {
134
+ users: [
135
+ {
136
+ username: "Russell",
137
+ tenants: [
138
+ { name: "WFMA", posts: 0 },
139
+ { name: "Popova Park", posts: 0 },
140
+ { name: "LRF", posts: 0 },
141
+ ],
142
+ },
143
+ {
144
+ username: "Dan",
145
+ tenants: [
146
+ { name: "Popova Park", posts: 0 },
147
+ { name: "LRF", posts: 0 },
148
+ ],
149
+ },
150
+ {
151
+ username: "Fairooz",
152
+ tenants: [
153
+ { name: "WFMA", posts: 0 },
154
+ { name: "LRF", posts: 0 },
155
+ ],
156
+ },
157
+ ],
158
+ });
159
+ const results = await db.findMany("user", {
160
+ select: ["id", "username"],
161
+ include: {
162
+ tenants: {
163
+ select: ["id", "name"],
164
+ orderBy: ["name"],
165
+ },
166
+ },
167
+ orderBy: [["username", "desc"]],
168
+ });
169
+
170
+ expect(
171
+ results.map((r) => [
172
+ r.username,
173
+ r.tenants.map((t) => t.name),
174
+ ]),
175
+ ).toEqual([
176
+ ["Russell", ["LRF", "Popova Park", "WFMA"]],
177
+ ["Fairooz", ["LRF", "WFMA"]],
178
+ ["Dan", ["LRF", "Popova Park"]],
179
+ ]);
180
+ },
181
+ { rollback: true },
182
+ );
183
+ });
184
+ });
@@ -0,0 +1,117 @@
1
+ import { assertType, describe, expectTypeOf, test } from "vitest";
2
+
3
+ import { db } from "../../../test/db";
4
+
5
+ describe("findMany", () => {
6
+ test("only models that exist can be queried", () => {
7
+ assertType(
8
+ db.findMany(
9
+ // @ts-expect-error model does not exist
10
+ "wrong",
11
+ {},
12
+ ),
13
+ );
14
+ });
15
+
16
+ test("a select clause must be included in the query", () => {
17
+ assertType(
18
+ db.findMany(
19
+ "post",
20
+ // @ts-expect-error query is empty
21
+ {},
22
+ ),
23
+ );
24
+ });
25
+
26
+ test("at least one field must be selected", () => {
27
+ assertType(
28
+ db.findMany("post", {
29
+ // @ts-expect-error select clause is empty
30
+ select: [],
31
+ }),
32
+ );
33
+ });
34
+
35
+ test("only fields on the model can be selected", () => {
36
+ assertType(
37
+ db.findMany("post", {
38
+ // @ts-expect-error name is not a field on the post model
39
+ select: ["id", "name", "content"],
40
+ }),
41
+ );
42
+ });
43
+
44
+ test("the return type is an array of objects including the selected fields", async () => {
45
+ expectTypeOf(
46
+ await db.findMany("post", {
47
+ select: ["id", "title", "content", "publishedAt"],
48
+ }),
49
+ ).toMatchTypeOf<
50
+ {
51
+ id: string;
52
+ title: string;
53
+ content: string;
54
+ publishedAt: Date | null;
55
+ }[]
56
+ >();
57
+ });
58
+
59
+ test("non-selected fields are not included in the result type", async () => {
60
+ expectTypeOf(
61
+ await db.findMany("post", {
62
+ select: ["id", "title"],
63
+ }),
64
+ ).not.toMatchTypeOf<{ id: number; title: string; content: string }[]>();
65
+ });
66
+
67
+ test("a model's relations can be included", async () => {
68
+ expectTypeOf(
69
+ await db.findMany("post", {
70
+ select: ["id", "title", "content"],
71
+ include: {
72
+ author: {
73
+ select: ["id", "username", "joinedAt"],
74
+ include: {
75
+ tenants: {
76
+ select: ["id", "name"],
77
+ },
78
+ },
79
+ },
80
+ },
81
+ }),
82
+ ).toMatchTypeOf<
83
+ Readonly<
84
+ {
85
+ id: string;
86
+ title: string;
87
+ content: string;
88
+ author: {
89
+ id: string;
90
+ username: string;
91
+ joinedAt: Date | null;
92
+ tenants: { id: string; name: string }[];
93
+ };
94
+ }[]
95
+ >
96
+ >();
97
+ });
98
+
99
+ test("only fields that exist can be selected from included models", async () => {
100
+ assertType(
101
+ await db.findMany("post", {
102
+ select: ["id", "title", "content"],
103
+ include: {
104
+ author: {
105
+ // @ts-expect-error wrong is not a field on the user model
106
+ select: ["id", "username", "joinedAt", "wrong"],
107
+ include: {
108
+ tenants: {
109
+ select: ["id", "name"],
110
+ },
111
+ },
112
+ },
113
+ },
114
+ }),
115
+ );
116
+ });
117
+ });