@apisr/drizzle-model 0.0.1

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 (47) hide show
  1. package/.turbo/turbo-check-types.log +2 -0
  2. package/ROADMAP.md +1 -0
  3. package/TODO.md +64 -0
  4. package/drizzle.config.ts +11 -0
  5. package/package.json +35 -0
  6. package/src/index.ts +1 -0
  7. package/src/model/builder.ts +46 -0
  8. package/src/model/config.ts +35 -0
  9. package/src/model/core/joins.ts +279 -0
  10. package/src/model/core/projection.ts +47 -0
  11. package/src/model/core/runtime.ts +249 -0
  12. package/src/model/core/thenable.ts +85 -0
  13. package/src/model/core/transform.ts +45 -0
  14. package/src/model/core/where.ts +183 -0
  15. package/src/model/core/with.ts +28 -0
  16. package/src/model/dialect.ts +11 -0
  17. package/src/model/foreigns.ts +31 -0
  18. package/src/model/format.ts +19 -0
  19. package/src/model/index.ts +1 -0
  20. package/src/model/methods/exclude.ts +32 -0
  21. package/src/model/methods/include.ts +3 -0
  22. package/src/model/methods/insert.ts +16 -0
  23. package/src/model/methods/levels.ts +2 -0
  24. package/src/model/methods/query/where.ts +48 -0
  25. package/src/model/methods/return.ts +39 -0
  26. package/src/model/methods/select.ts +38 -0
  27. package/src/model/methods/update.ts +4 -0
  28. package/src/model/methods/upsert.ts +54 -0
  29. package/src/model/methods/with.ts +40 -0
  30. package/src/model/model.ts +148 -0
  31. package/src/model/options.ts +64 -0
  32. package/src/model/query/operations.ts +170 -0
  33. package/src/model/relation.ts +121 -0
  34. package/src/model/result.ts +91 -0
  35. package/src/model/shape.ts +8 -0
  36. package/src/model/table.ts +127 -0
  37. package/src/types.ts +16 -0
  38. package/tests/builder-v2-mysql.type-test.ts +40 -0
  39. package/tests/builder-v2.type-test.ts +343 -0
  40. package/tests/builder.test.ts +63 -0
  41. package/tests/db.ts +25 -0
  42. package/tests/find.test.ts +155 -0
  43. package/tests/insert.test.ts +233 -0
  44. package/tests/relations.ts +38 -0
  45. package/tests/schema.ts +49 -0
  46. package/tsconfig.json +36 -0
  47. package/tsdown.config.ts +12 -0
@@ -0,0 +1,343 @@
1
+ import * as schema from "./schema";
2
+ import { db } from "./db";
3
+ import { relations } from "./relations";
4
+ import { modelBuilder } from "src/model";
5
+ import { gte, sql, eq, or } from "drizzle-orm";
6
+ import { esc } from "@/model/query/operations";
7
+
8
+ const model = modelBuilder({
9
+ schema,
10
+ db,
11
+ relations,
12
+ dialect: "PostgreSQL"
13
+ });
14
+
15
+ const userModel = model("user", {
16
+ methods: {
17
+ whereName(name: string) {
18
+ return userModel.where({
19
+ name: esc(eq, name)
20
+ });
21
+ },
22
+ findByName(name: string) {
23
+ return userModel
24
+ .where({
25
+ name: esc(name)
26
+ })
27
+ .findFirst()
28
+ .select({
29
+ id: true,
30
+ name: true
31
+ });
32
+ }
33
+ },
34
+ format: ({ secretField, ...rest }) => ({
35
+ ...rest,
36
+ customField: "123"
37
+ })
38
+ });
39
+ const userIdeasModel = model("userIdeas", {});
40
+
41
+ // userModel.
42
+ // userModel.
43
+
44
+ // userModel.
45
+
46
+ const testRaw = await userModel
47
+ .where({
48
+ id: {
49
+ or: [
50
+ esc(1),
51
+ esc(2),
52
+ ]
53
+ }
54
+ })
55
+ .findFirst()
56
+ .with({
57
+ posts: {
58
+ comments: true,
59
+ },
60
+ })
61
+ .select({
62
+ age: true,
63
+ posts: {
64
+ title: true,
65
+ comments: {
66
+ content: true,
67
+ },
68
+ },
69
+ });
70
+
71
+ // testRaw.posts[0]?.comments[0]?.content;
72
+ const testRaw1 = await userModel
73
+ .where({
74
+ age: esc(12)
75
+ })
76
+ .findFirst()
77
+ .with({
78
+ posts: {
79
+ comments: true,
80
+ },
81
+ })
82
+ .exclude({
83
+ age: true,
84
+ posts: {
85
+ id: true,
86
+ comments: {
87
+ content: true,
88
+ },
89
+ },
90
+ });
91
+
92
+ // testRaw1.posts[0]?.comments[0].;
93
+
94
+ const postsModel = model("userPosts", {});
95
+ const commentsModel = model("postComments", {});
96
+
97
+ const testRaw2 = await userModel
98
+ .where({
99
+ age: esc(12)
100
+ })
101
+ .findFirst()
102
+ .with({
103
+ // Fix is relations in here are from userModel not from posts
104
+ posts: postsModel.where({
105
+ id: esc(12)
106
+ }).include({
107
+ comments: true,
108
+ }),
109
+ });
110
+
111
+ // testRaw2.posts[0]?.comments;
112
+
113
+ const testRaw3 = await userModel
114
+ .where({
115
+ id: {
116
+ or: [
117
+ {
118
+ equal: 1,
119
+ },
120
+ esc(12),
121
+ ],
122
+ }
123
+ })
124
+ .findFirst()
125
+ .with({
126
+ // Fix is relations in here are from userModel not from posts
127
+ posts: postsModel
128
+ .where({
129
+ id: esc(12)
130
+ })
131
+ .include({
132
+ comments: commentsModel.where({ id: esc(12) }).include({
133
+ author: true
134
+ }),
135
+ }),
136
+ });
137
+
138
+ // testRaw3.posts[0]?.comments[0]?.author;
139
+
140
+ const testRaw4 = await userModel
141
+ .where({
142
+ age: {
143
+ or: [
144
+ {
145
+ equal: 1,
146
+ },
147
+ esc(2),
148
+ ],
149
+ }
150
+ })
151
+ .findMany()
152
+ .with({
153
+ // Fix is relations in here are from userModel not from posts
154
+ posts: postsModel
155
+ .where({
156
+ id: esc(12)
157
+ })
158
+ .include({
159
+ comments: true,
160
+ }),
161
+ })
162
+ .select({
163
+ posts: {
164
+ description: true,
165
+ comments: true,
166
+ },
167
+ });
168
+
169
+ // testRaw4[0]?.posts[0].
170
+
171
+ const testRaw5 = await userModel
172
+ .where({
173
+ age: {
174
+ or: [
175
+ {
176
+ equal: 1,
177
+ },
178
+ esc(12),
179
+ ]
180
+ },
181
+ })
182
+ .findMany()
183
+ .with({
184
+ // Fix is relations in here are from userModel not from posts
185
+ posts: postsModel
186
+ .where({
187
+ id: esc(12)
188
+ })
189
+ .include({
190
+ comments: true,
191
+ }),
192
+ })
193
+ .exclude({
194
+ posts: {
195
+ description: true,
196
+ comments: true,
197
+ },
198
+ });
199
+
200
+ // testRaw5[0]?.posts[0].
201
+
202
+ const testRaw6 = await userModel
203
+ .insert({
204
+ email: "email@email",
205
+ name: "Nameie",
206
+ age: 123,
207
+ })
208
+ .return();
209
+
210
+ // testRaw6.
211
+
212
+ // testRaw6.
213
+
214
+ // testRaw6.
215
+
216
+ const testRaw7 = await userModel
217
+ .where({ id: esc(12) })
218
+ .update({
219
+ age: 12
220
+ })
221
+ .return();
222
+
223
+ // testRaw7?.[0]?.;
224
+
225
+ const testRaw8 = await userModel
226
+ .where({ id: esc(12) })
227
+ .delete()
228
+ .return();
229
+
230
+ // testRaw8[0].
231
+
232
+ // postsModel.
233
+
234
+ const testRaw9 = await postsModel
235
+ .where({
236
+ user: {
237
+ id: esc(12)
238
+ },
239
+ })
240
+ .update({
241
+ description: ""
242
+ })
243
+ .return();
244
+
245
+ const testRaw10 = await postsModel
246
+ .where(
247
+ userModel.where({ id: esc(12) })
248
+ )
249
+ .update({
250
+ description: ""
251
+ })
252
+ .return();
253
+
254
+ const testRaw11 = await postsModel
255
+ .where(
256
+ sql``
257
+ )
258
+ .update({
259
+ description: ""
260
+ })
261
+ .return();
262
+
263
+ // testRaw11[0].
264
+
265
+ const testRaw12 = await postsModel
266
+ .where(
267
+ gte(schema.postComments.id, 123)
268
+ )
269
+ .update({
270
+ description: ""
271
+ })
272
+ .return();
273
+
274
+ db.transaction(async tx => {
275
+ const result = await postsModel
276
+ .db(tx)
277
+ .where(
278
+ gte(schema.postComments.id, 123)
279
+ )
280
+ .update({
281
+ description: ""
282
+ })
283
+ .return({
284
+ id: true
285
+ });
286
+ });
287
+
288
+ const testRaw13 = await userModel.whereName("Alex").findFirst();
289
+ const testRaw14 = await userModel.findByName("Alex");
290
+ // testRaw13.
291
+ // testRaw14.
292
+
293
+ // userModel.$form.methods.
294
+
295
+ // userModel.w
296
+
297
+ const testRaw15 = await userModel
298
+ .where({
299
+ name: esc("Alex"),
300
+ })
301
+ .findFirst()
302
+ .raw();
303
+
304
+ const userModel2 = userModel.extend({
305
+ methods: {
306
+ whereName(name: string) {
307
+ return userModel2.where({
308
+ name: esc(name)
309
+ });
310
+ }
311
+ },
312
+ format: (output) => {
313
+ return {
314
+ ...output,
315
+ isJoke: true
316
+ };
317
+ }
318
+ });
319
+
320
+ const testRaw16 = await userModel2.upsert({
321
+ insert: {
322
+ email: "123",
323
+ name: "123",
324
+ age: 123,
325
+ },
326
+ update: (c) => ({
327
+ name: c.inserted("name")
328
+ }),
329
+ updateWhere: (c) => ({
330
+ name: {
331
+ not: c.excluded("name")
332
+ }
333
+ }),
334
+ target: ["id"]
335
+ }).return({
336
+ age: true
337
+ });
338
+
339
+ // testRaw16.
340
+
341
+ // testRaw16.
342
+
343
+ // userModel2.
@@ -0,0 +1,63 @@
1
+ import { modelBuilder } from "../src";
2
+ import * as schema from "./schema";
3
+ import { db } from "./db";
4
+ import { relations } from "./relations";
5
+
6
+ const model = modelBuilder({
7
+ schema,
8
+ db,
9
+ relations,
10
+ });
11
+
12
+ const userModel = model("user", {});
13
+ const postsModel = model("userPosts", {});
14
+ const commentsModel = model("postComments", {});
15
+
16
+ const testRaw1 = await userModel
17
+ .age(123)
18
+ .findOne()
19
+ .with({
20
+ // Fix is relations in here are from userModel not from posts
21
+ posts: postsModel.id(123),
22
+ });
23
+
24
+ testRaw1.posts;
25
+
26
+ const testRaw2 = await userModel
27
+ .age(123)
28
+ .findOne()
29
+ .with({
30
+ posts: true,
31
+ })
32
+ .select({
33
+ age: true,
34
+ email: true,
35
+ posts: {
36
+ id: true,
37
+ },
38
+ });
39
+
40
+ // testRaw2.posts[0]?.id
41
+
42
+ const testRaw3 = await userModel.age(123).findOne().with({
43
+ invitee: true,
44
+ });
45
+
46
+ const testRaw4 = await postsModel.id(1).findOne().with({
47
+ user: true,
48
+ });
49
+
50
+ const testRaw5 = await userModel
51
+ .age(123)
52
+ .findOne()
53
+ .with({
54
+ posts: true,
55
+ })
56
+ .select({
57
+ age: true,
58
+ email: true,
59
+ posts: {
60
+ id: true,
61
+ },
62
+ });
63
+ // testRaw4.user.
package/tests/db.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { drizzle } from "drizzle-orm/node-postgres";
2
+ // import { drizzle as drizzleMysql } from "drizzle-orm/mysql2";
3
+ import * as schema from "./schema";
4
+ import { relations } from "./relations";
5
+
6
+ // export const mysqlDb = drizzleMysql("nothing");
7
+
8
+ // mysqlDb.insert().values().$returningId;
9
+
10
+ export const db = drizzle(process.env.DATABASE_URL!, {
11
+ schema,
12
+ relations,
13
+ });
14
+
15
+ // db.transaction
16
+
17
+ // db.select().from().where
18
+
19
+ // db.query.user.findFirst({
20
+ // with: {
21
+ // posts: {
22
+ // with: {},
23
+ // },
24
+ // },
25
+ // });
@@ -0,0 +1,155 @@
1
+ import { modelBuilder } from "../src";
2
+ import * as schema from "./schema";
3
+ import { db } from "./db";
4
+ import { relations } from "./relations";
5
+ import { test, describe, expect } from "bun:test";
6
+ import { esc } from "@/model/query/operations";
7
+ import { and, eq, gte, like, or } from "drizzle-orm";
8
+
9
+ const model = modelBuilder({
10
+ schema,
11
+ db,
12
+ relations,
13
+ dialect: "PostgreSQL",
14
+ });
15
+
16
+ const userModel = model("user", {});
17
+
18
+ async function rawUsers(where?: any) {
19
+ if (where) {
20
+ return await db.select().from(schema.user).where(where);
21
+ }
22
+ return await db.select().from(schema.user);
23
+ }
24
+
25
+ function sortById<T extends { id: number }>(rows: T[]) {
26
+ return [...rows].sort((a, b) => a.id - b.id);
27
+ }
28
+
29
+ describe("Model Find Test", () => {
30
+ test(".find | one filter", async () => {
31
+ // Eq to:
32
+ // await db.select().from(userTable).where(eq(userTable.name, "Alex"));
33
+ const raw = await userModel.where({ name: esc("Alex") }).findMany();
34
+
35
+ const expected = await rawUsers(eq(schema.user.name, "Alex"));
36
+
37
+ console.dir(raw, {
38
+ depth: null,
39
+ });
40
+
41
+ expect(raw).toBeArray();
42
+ expect(raw[0]).toBeDefined();
43
+ expect(sortById(raw as any)).toEqual(sortById(expected as any));
44
+ });
45
+
46
+ test(".find | no filters returns all users", async () => {
47
+ const raw = await userModel.findMany();
48
+
49
+ const expected = await rawUsers();
50
+
51
+ expect(raw).toBeArray();
52
+ expect(raw).toHaveLength((expected as any[]).length);
53
+ expect(sortById(raw as any)).toEqual(sortById(expected as any));
54
+ });
55
+
56
+ test(".find | multiple filters", async () => {
57
+ const raw = await userModel.where({
58
+ name: esc("Alex"),
59
+ isVerified: esc(false),
60
+ age: esc(12),
61
+ }).findMany();
62
+
63
+ const expected = await rawUsers(and(
64
+ eq(schema.user.name, "Alex"),
65
+ eq(schema.user.isVerified, false),
66
+ eq(schema.user.age, 12),
67
+ ));
68
+
69
+ console.dir(raw, {
70
+ depth: null,
71
+ });
72
+
73
+ expect(raw).toBeArray();
74
+ expect(raw[0]).toBeDefined();
75
+ expect(sortById(raw as any)).toEqual(sortById(expected as any));
76
+ });
77
+
78
+ test(".find | complex filters 01", async () => {
79
+ const raw = await userModel.where({
80
+ name: {
81
+ or: [esc("Alex"), esc("Dino")],
82
+ },
83
+ }).findMany();
84
+
85
+ const expected = await rawUsers(or(
86
+ eq(schema.user.name, "Alex"),
87
+ eq(schema.user.name, "Dino"),
88
+ ));
89
+
90
+ console.dir(raw, {
91
+ depth: null,
92
+ });
93
+
94
+ expect(raw).toBeArray();
95
+ expect(raw[0]).toBeDefined();
96
+ expect(sortById(raw as any)).toEqual(sortById(expected as any));
97
+ });
98
+
99
+ test(".find | complex filters 02", async () => {
100
+ const raw = await userModel.where({
101
+ name: {
102
+ or: [esc("Alex"), esc("Dino"), esc("Anna")],
103
+ },
104
+ age: {
105
+ gte: esc(18),
106
+ },
107
+ }).findMany();
108
+
109
+ const expected = await rawUsers(and(
110
+ or(
111
+ eq(schema.user.name, "Alex"),
112
+ eq(schema.user.name, "Dino"),
113
+ eq(schema.user.name, "Anna"),
114
+ ),
115
+ gte(schema.user.age, 18),
116
+ ));
117
+
118
+ console.dir(raw, {
119
+ depth: null,
120
+ });
121
+
122
+ expect(raw).toBeArray();
123
+ expect(raw[0]).toBeDefined();
124
+ expect(sortById(raw as any)).toEqual(sortById(expected as any));
125
+ });
126
+
127
+ test(".find | complex filters 03", async () => {
128
+ const raw = await userModel.where({
129
+ name: {
130
+ like: esc("A%"),
131
+ },
132
+ }).findMany();
133
+
134
+ const expected = await rawUsers(like(schema.user.name, "A%"));
135
+
136
+ console.dir(raw, {
137
+ depth: null,
138
+ });
139
+
140
+ expect(raw).toBeArray();
141
+ expect(raw[0]).toBeDefined();
142
+ expect(sortById(raw as any)).toEqual(sortById(expected as any));
143
+ });
144
+
145
+ test(".findOne | returns a single matching user", async () => {
146
+ const anna = await userModel.where({ name: esc("Anna") }).findFirst();
147
+
148
+ const expected = (await rawUsers(eq(schema.user.name, "Anna")))[0];
149
+
150
+ expect(anna).toBeDefined();
151
+ expect((anna as any).id).toBe(5);
152
+ expect(anna?.email).toBe("an.na@example.com");
153
+ expect(anna as any).toEqual(expected as any);
154
+ });
155
+ });