@ghom/orm 1.10.0 → 2.1.0

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/readme.md CHANGED
@@ -62,46 +62,117 @@ orm.raw("SELECT 1") // throws Error
62
62
 
63
63
  ## Add tables
64
64
 
65
- The tables are automatically loaded from the `location` directory.
65
+ The tables are automatically loaded from the `tableLocation` directory. Types are automatically inferred from the column definitions.
66
66
 
67
67
  ```typescript
68
68
  // tables/user.ts
69
69
 
70
- import { Table } from "@ghom/orm"
70
+ import { Table, col } from "@ghom/orm"
71
71
 
72
- interface User {
73
- username: string
74
- password: string
75
- }
76
-
77
- export default new Table<User>({
72
+ export default new Table({
78
73
  name: "user",
79
74
 
80
75
  // the higher the priority, the earlier the table is compiled
81
76
  priority: 0,
82
77
 
83
- // the migration are executed in order of version number
78
+ // typed columns definition with automatic type inference
79
+ columns: (col) => ({
80
+ id: col.increments(),
81
+ username: col.string().unique(),
82
+ password: col.string(),
83
+ age: col.integer().nullable(),
84
+ role: col.enum(["admin", "user"]).defaultTo("user"),
85
+ }),
86
+
87
+ // migrations are executed in order based on key pattern (see Migration Keys section)
84
88
  migrations: {
85
- 1: (table) => {
89
+ "1": (table) => {
86
90
  table.renameColumn("name", "username")
87
91
  }
88
92
  },
89
93
 
90
- // the setup is executed only once for table creation
91
- setup: (table) => {
92
- table.string("name").notNullable()
93
- table.string("password").notNullable()
94
- },
95
-
96
- // the then is executed after the table is created and the migrations are runned
94
+ // then is executed after the table is created and the migrations are run (only if table is empty)
97
95
  then: ({ query }) => {
98
- query.insert({ username: "admin", password: "admin" })
96
+ query.insert({ username: "admin", password: "admin", role: "admin" })
99
97
  },
100
98
 
101
99
  caching: 10 * 60 * 1000 // The table cache. Default to the ORM cache or Infinity
102
100
  })
101
+
102
+ // Type is automatically inferred:
103
+ // { id: number; username: string; password: string; age: number | null; role: "admin" | "user" }
104
+ type User = typeof userTable.$type
105
+ ```
106
+
107
+ ### Typed Migrations
108
+
109
+ You can also use typed migrations that automatically update the TypeScript type:
110
+
111
+ ```typescript
112
+ import { Table, col, migrate } from "@ghom/orm"
113
+
114
+ export default new Table({
115
+ name: "user",
116
+ columns: (col) => ({
117
+ id: col.increments(),
118
+ name: col.string(), // will be renamed to username
119
+ }),
120
+ migrations: {
121
+ "001_rename_name": migrate.renameColumn("name", "username"),
122
+ "002_add_email": migrate.addColumn("email", col.string()),
123
+ "003_add_age": migrate.addColumn("age", col.integer().nullable()),
124
+ },
125
+ })
126
+
127
+ // Final type: { id: number; username: string; email: string; age: number | null }
128
+ ```
129
+
130
+ Available migration helpers:
131
+ - `migrate.addColumn(name, columnDef)` - Add a new column
132
+ - `migrate.dropColumn(name)` - Remove a column
133
+ - `migrate.renameColumn(oldName, newName)` - Rename a column
134
+ - `migrate.alterColumn(name, newColumnDef)` - Change column type/constraints
135
+ - `migrate.addIndex(columns, name?)` - Add an index
136
+ - `migrate.dropIndex(name)` - Remove an index
137
+ - `migrate.addUnique(columns, name?)` - Add a unique constraint
138
+ - `migrate.dropUnique(name)` - Remove a unique constraint
139
+ - `migrate.raw(callback)` - Custom migration callback
140
+
141
+ ## Migration Keys
142
+
143
+ The ORM supports three patterns for migration keys:
144
+
145
+ 1. **Numeric keys** (`"1"`, `"2"`, `"10"`): Sorted numerically
146
+ 2. **Numeric-prefixed keys** (`"001_init"`, `"002_add_users"`, `"010_fix"`): Sorted by numeric prefix
147
+ 3. **Pure string keys** (`"init"`, `"add_users"`): Uses insertion order (ES2015+)
148
+
149
+ > **Warning**: Mixing key patterns is not allowed and will throw an error at runtime.
150
+
151
+ ### Migration Configuration
152
+
153
+ ```typescript
154
+ const orm = new ORM({
155
+ tableLocation: "./tables",
156
+ migrations: {
157
+ /**
158
+ * NOT RECOMMENDED
159
+ * Force alphabetical sorting for string migration keys.
160
+ *
161
+ * If your keys start with numbers (e.g., "001_init"),
162
+ * they are automatically sorted by those numbers,
163
+ * not alphabetically.
164
+ */
165
+ alphabeticalOrder: false // default
166
+ }
167
+ })
103
168
  ```
104
169
 
170
+ ### ES2015+ Requirement
171
+
172
+ This ORM requires ES2015+ for guaranteed object key insertion order. Node.js 6+ and all modern browsers are supported.
173
+
174
+ The ORM performs a runtime check on initialization and will throw an error if the environment doesn't support ES2015+ key ordering.
175
+
105
176
  ## Launch a query
106
177
 
107
178
  For more information about the query builder, see [knexjs.org](https://knexjs.org/).
@@ -192,8 +263,9 @@ The cache of the `<ORM>.cache.raw` method is automatically invalidated when the
192
263
 
193
264
  - [x] Add timed caching system
194
265
  - [x] Add backup option
266
+ - [x] Auto typings for tables from the column definitions
267
+ - [x] Typed migrations with automatic type inference
195
268
  - [ ] Dependency management between tables
196
- - [ ] Auto typings for tables from the column definitions
197
269
  - [ ] Add specific methods for relations and joins
198
270
  - [ ] Add admin panel
199
271
  - [ ] Make possible to switch the data between all possible clients (pg, mysql, sqlite3)
@@ -0,0 +1,431 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test"
2
+ import fs from "fs"
3
+ import path from "path"
4
+ import { rimraf } from "rimraf"
5
+
6
+ import { col, migrate, ORM, type ORMConfig, Table } from "../src"
7
+
8
+ import a from "./tables/a"
9
+ import b from "./tables/b"
10
+ import c from "./tables/c"
11
+ import d from "./tables/d"
12
+
13
+ describe("typed columns", () => {
14
+ test("new Table() infers types correctly", () => {
15
+ const userTable = new Table({
16
+ name: "test_user",
17
+ columns: (col) => ({
18
+ id: col.increments(),
19
+ username: col.string().unique(),
20
+ age: col.integer().nullable(),
21
+ role: col.enum(["admin", "user"] as const),
22
+ isActive: col.boolean().defaultTo(true),
23
+ }),
24
+ })
25
+
26
+ expect(userTable).toBeInstanceOf(Table)
27
+ expect(userTable.options.name).toBe("test_user")
28
+ expect("columns" in userTable.options).toBe(true)
29
+
30
+ // Type inference check - this line would fail at compile time if types weren't inferred
31
+ type ExpectedType = typeof userTable.$type
32
+ const _typeCheck: ExpectedType = {
33
+ id: 1,
34
+ username: "test",
35
+ age: null,
36
+ role: "admin",
37
+ isActive: true,
38
+ }
39
+ })
40
+
41
+ test("col factory creates column definitions", () => {
42
+ const idCol = col.increments()
43
+ const stringCol = col.string()
44
+ const nullableInt = col.integer().nullable()
45
+ const enumCol = col.enum(["a", "b", "c"] as const)
46
+
47
+ expect(idCol).toBeDefined()
48
+ expect(stringCol).toBeDefined()
49
+ expect(nullableInt._isNullable).toBe(true)
50
+ expect(enumCol).toBeDefined()
51
+ })
52
+
53
+ test("typed table d has correct options", () => {
54
+ expect(d).toBeInstanceOf(Table)
55
+ expect(d.options.name).toBe("d")
56
+ expect("columns" in d.options).toBe(true)
57
+ })
58
+ })
59
+
60
+ describe("typed migrations", () => {
61
+ test("migrate.addColumn creates TypedMigration", () => {
62
+ const migration = migrate.addColumn("email", col.string())
63
+
64
+ expect(migration).toBeDefined()
65
+ expect(migration.apply).toBeInstanceOf(Function)
66
+ expect("_from" in migration).toBe(true)
67
+ expect("_to" in migration).toBe(true)
68
+ })
69
+
70
+ test("migrate.dropColumn creates TypedMigration", () => {
71
+ const migration = migrate.dropColumn("oldField")
72
+
73
+ expect(migration).toBeDefined()
74
+ expect(migration.apply).toBeInstanceOf(Function)
75
+ })
76
+
77
+ test("migrate.renameColumn creates TypedMigration", () => {
78
+ const migration = migrate.renameColumn("name", "username")
79
+
80
+ expect(migration).toBeDefined()
81
+ expect(migration.apply).toBeInstanceOf(Function)
82
+ })
83
+
84
+ test("migrate.alterColumn creates TypedMigration", () => {
85
+ const migration = migrate.alterColumn("age", col.integer().nullable())
86
+
87
+ expect(migration).toBeDefined()
88
+ expect(migration.apply).toBeInstanceOf(Function)
89
+ })
90
+
91
+ test("migrate.addIndex creates TypedMigration", () => {
92
+ const migration = migrate.addIndex(["email"], "idx_email")
93
+
94
+ expect(migration).toBeDefined()
95
+ expect(migration.apply).toBeInstanceOf(Function)
96
+ })
97
+
98
+ test("migrate.addUnique creates TypedMigration", () => {
99
+ const migration = migrate.addUnique(["email"], "uniq_email")
100
+
101
+ expect(migration).toBeDefined()
102
+ expect(migration.apply).toBeInstanceOf(Function)
103
+ })
104
+
105
+ test("migrate.raw creates TypedMigration", () => {
106
+ const migration = migrate.raw((builder) => {
107
+ builder.dropColumn("temp")
108
+ })
109
+
110
+ expect(migration).toBeDefined()
111
+ expect(migration.apply).toBeInstanceOf(Function)
112
+ })
113
+
114
+ test("Table with typed migrations has correct options", () => {
115
+ const userTable = new Table({
116
+ name: "test_typed_migrations",
117
+ columns: (col) => ({
118
+ id: col.increments(),
119
+ name: col.string(),
120
+ }),
121
+ migrations: {
122
+ "001_add_email": migrate.addColumn("email", col.string()),
123
+ "002_add_age": migrate.addColumn("age", col.integer().nullable()),
124
+ "003_rename_name": migrate.renameColumn("name", "username"),
125
+ },
126
+ })
127
+
128
+ expect(userTable).toBeInstanceOf(Table)
129
+ expect(userTable.options.migrations).toBeDefined()
130
+ expect(Object.keys(userTable.options.migrations!).length).toBe(3)
131
+
132
+ // Type inference check - final type includes base columns + migrations
133
+ // "name" is removed by renameColumn, "username" is added
134
+ type ExpectedType = typeof userTable.$type
135
+ const _typeCheck: ExpectedType = {
136
+ id: 1,
137
+ username: "test", // renamed from "name"
138
+ // @ts-expect-error - name is removed by renameColumn
139
+ name: "test",
140
+ email: "test@example.com",
141
+ age: null,
142
+ }
143
+ })
144
+ })
145
+
146
+ describe("migration key patterns", () => {
147
+ test("Table accepts pure numeric keys", () => {
148
+ const table = new Table({
149
+ name: "test_numeric_keys",
150
+ columns: (col) => ({
151
+ id: col.increments(),
152
+ }),
153
+ migrations: {
154
+ "1": (_builder) => {},
155
+ "2": (_builder) => {},
156
+ "10": (_builder) => {},
157
+ },
158
+ })
159
+
160
+ expect(table.options.migrations).toBeDefined()
161
+ expect(Object.keys(table.options.migrations!)).toEqual(["1", "2", "10"])
162
+ })
163
+
164
+ test("Table accepts numeric-prefixed keys", () => {
165
+ const table = new Table({
166
+ name: "test_prefixed_keys",
167
+ columns: (col) => ({
168
+ id: col.increments(),
169
+ }),
170
+ migrations: {
171
+ "001_init": (_builder) => {},
172
+ "002_add_column": (_builder) => {},
173
+ "010_fix": (_builder) => {},
174
+ },
175
+ })
176
+
177
+ expect(table.options.migrations).toBeDefined()
178
+ expect(Object.keys(table.options.migrations!)).toEqual([
179
+ "001_init",
180
+ "002_add_column",
181
+ "010_fix",
182
+ ])
183
+ })
184
+
185
+ test("Table accepts pure string keys", () => {
186
+ const table = new Table({
187
+ name: "test_string_keys",
188
+ columns: (col) => ({
189
+ id: col.increments(),
190
+ }),
191
+ migrations: {
192
+ init: (_builder) => {},
193
+ add_column: (_builder) => {},
194
+ fix: (_builder) => {},
195
+ },
196
+ })
197
+
198
+ expect(table.options.migrations).toBeDefined()
199
+ expect(Object.keys(table.options.migrations!)).toEqual(["init", "add_column", "fix"])
200
+ })
201
+ })
202
+
203
+ describe("unconnected ORM", () => {
204
+ test("can be initialized with false", () => {
205
+ const unconnectedOrm = new ORM(false)
206
+
207
+ expect(unconnectedOrm).toBeInstanceOf(ORM)
208
+ expect(unconnectedOrm.isConnected).toBe(false)
209
+ expect(unconnectedOrm.config).toBe(false)
210
+ expect(unconnectedOrm.handler).toBeUndefined()
211
+ expect(unconnectedOrm.cachedTables).toEqual([])
212
+ expect(unconnectedOrm.cachedTableNames).toEqual([])
213
+ })
214
+
215
+ test("throws when calling methods requiring client", async () => {
216
+ const unconnectedOrm = new ORM(false)
217
+
218
+ expect(() => unconnectedOrm.client).toThrow()
219
+ expect(unconnectedOrm.init()).rejects.toThrow()
220
+ expect(unconnectedOrm.hasTable("test")).rejects.toThrow()
221
+ expect(() => unconnectedOrm.raw("SELECT 1")).toThrow()
222
+ expect(unconnectedOrm.createBackup()).rejects.toThrow()
223
+ expect(unconnectedOrm.restoreBackup()).rejects.toThrow()
224
+ })
225
+ })
226
+
227
+ const orm = new ORM({
228
+ tableLocation: path.join(process.cwd(), "tests", "tables"),
229
+ backups: {
230
+ location: path.join(process.cwd(), "backups"),
231
+ },
232
+ })
233
+
234
+ beforeAll(async () => {
235
+ await orm.init()
236
+ })
237
+
238
+ describe("table management", () => {
239
+ test("tables created", async () => {
240
+ expect(await orm.hasTable("migration")).toBeTruthy()
241
+ expect(await orm.hasTable("a")).toBeTruthy()
242
+ expect(await orm.hasTable("b")).toBeTruthy()
243
+ expect(await orm.hasTable("c")).toBeTruthy()
244
+ expect(await orm.hasTable("d")).toBeTruthy()
245
+ })
246
+
247
+ test("table cached", () => {
248
+ expect(orm.hasCachedTable("migration")).toBeTruthy()
249
+ expect(orm.hasCachedTable("a")).toBeTruthy()
250
+ expect(orm.hasCachedTable("b")).toBeTruthy()
251
+ expect(orm.hasCachedTable("c")).toBeTruthy()
252
+ expect(orm.hasCachedTable("d")).toBeTruthy()
253
+ })
254
+
255
+ test("table migrations ran", async () => {
256
+ expect(await b.hasColumn("c_id")).toBeTruthy()
257
+ })
258
+
259
+ test("table then ran", async () => {
260
+ const rows = await a.query.select()
261
+ expect(rows.length).toBe(1)
262
+ })
263
+
264
+ test("typed table d was created with correct columns", async () => {
265
+ expect(await d.hasColumn("id")).toBeTruthy()
266
+ expect(await d.hasColumn("name")).toBeTruthy()
267
+ expect(await d.hasColumn("email")).toBeTruthy()
268
+ expect(await d.hasColumn("age")).toBeTruthy()
269
+ expect(await d.hasColumn("role")).toBeTruthy()
270
+ expect(await d.hasColumn("isActive")).toBeTruthy()
271
+ expect(await d.hasColumn("metadata")).toBeTruthy()
272
+ expect(await d.hasColumn("createdAt")).toBeTruthy()
273
+ })
274
+
275
+ test("typed table d then ran", async () => {
276
+ const rows = await d.query.select()
277
+ expect(rows.length).toBe(1)
278
+ expect(rows[0].name).toBe("Test User")
279
+ expect(rows[0].role).toBe("admin")
280
+ })
281
+ })
282
+
283
+ describe("table column types", () => {
284
+ test("increments", async () => {
285
+ const info = await orm.client!("a").columnInfo("id")
286
+ expect(info.type).toMatch(/^int/)
287
+ })
288
+
289
+ test("integer", async () => {
290
+ const info = await orm.client!("a").columnInfo("b_id")
291
+ expect(info.type).toMatch(/^int/)
292
+ })
293
+
294
+ test("typed table d column types", async () => {
295
+ const nameInfo = await orm.client!("d").columnInfo("name")
296
+ expect(nameInfo.type).toMatch(/varchar|text|character/i)
297
+
298
+ const ageInfo = await orm.client!("d").columnInfo("age")
299
+ expect(ageInfo.type).toMatch(/^int/)
300
+ expect(ageInfo.nullable).toBe(true)
301
+ })
302
+ })
303
+
304
+ describe("database extraction", () => {
305
+ test("create backup", async () => {
306
+ await orm.createBackup()
307
+
308
+ const config = orm.config as ORMConfig
309
+ expect(fs.existsSync(path.join(config.backups!.location!, "a_chunk_0.csv"))).toBeTruthy()
310
+ expect(fs.existsSync(path.join(config.backups!.location!, "b_chunk_0.csv"))).toBeTruthy()
311
+ expect(fs.existsSync(path.join(config.backups!.location!, "c_chunk_0.csv"))).toBeTruthy()
312
+ expect(fs.existsSync(path.join(config.backups!.location!, "d_chunk_0.csv"))).toBeTruthy()
313
+ })
314
+
315
+ test("cascade delete", async () => {
316
+ expect(await a.isEmpty()).toBeFalsy()
317
+ await c.query.del()
318
+ expect(await a.isEmpty()).toBeTruthy()
319
+ })
320
+
321
+ test("restore backup", async () => {
322
+ await orm.restoreBackup()
323
+
324
+ expect(await a.isEmpty()).toBeFalsy()
325
+ expect(await b.isEmpty()).toBeFalsy()
326
+ expect(await c.isEmpty()).toBeFalsy()
327
+ expect(await d.isEmpty()).toBeFalsy()
328
+ })
329
+
330
+ afterAll(async () => {
331
+ const config = orm.config as ORMConfig
332
+ await rimraf(config.backups!.location!)
333
+ })
334
+ })
335
+
336
+ describe("table getters", () => {
337
+ test("table info", async () => {
338
+ expect(await a.getColumnNames()).toContain("id")
339
+ expect(await a.getColumnNames()).toContain("b_id")
340
+
341
+ expect(await b.getColumnNames()).toContain("id")
342
+ expect(await b.getColumnNames()).toContain("c_id")
343
+
344
+ expect(await c.getColumnNames()).toContain("id")
345
+
346
+ expect(await d.getColumnNames()).toContain("id")
347
+ expect(await d.getColumnNames()).toContain("name")
348
+ expect(await d.getColumnNames()).toContain("role")
349
+ })
350
+
351
+ test("table names", () => {
352
+ expect(orm.cachedTableNames).toContain("a")
353
+ expect(orm.cachedTableNames).toContain("b")
354
+ expect(orm.cachedTableNames).toContain("c")
355
+ expect(orm.cachedTableNames).toContain("d")
356
+ })
357
+ })
358
+
359
+ describe("data caching", () => {
360
+ beforeAll(async () => {
361
+ await c.query.del()
362
+ await c.query.insert([{ id: 1 }, { id: 2 }, { id: 3 }])
363
+ await b.query.insert([
364
+ { id: 1, c_id: 1 },
365
+ { id: 2, c_id: 2 },
366
+ { id: 3, c_id: 3 },
367
+ ])
368
+ await a.query.insert([
369
+ { id: 1, b_id: 1 },
370
+ { id: 2, b_id: 2 },
371
+ { id: 3, b_id: 3 },
372
+ ])
373
+ })
374
+
375
+ test("select with caching", async () => {
376
+ const rows = await a.cache.get("all a", (query) => {
377
+ return query.select("*")
378
+ })
379
+
380
+ expect(rows.length).toBe(3)
381
+ })
382
+
383
+ test("insert with caching", async () => {
384
+ await a.cache.set((query) => {
385
+ return query.insert({ id: 4, b_id: 1 })
386
+ })
387
+
388
+ expect(await a.cache.count()).toBe(4)
389
+ })
390
+
391
+ test("update with caching", async () => {
392
+ await a.cache.set((query) => {
393
+ return query.update({ b_id: 3 }).where({ id: 1 })
394
+ })
395
+
396
+ const row = await a.cache.get("a 1", (query) => {
397
+ return query.select("b_id").where({ id: 1 }).first()
398
+ })
399
+
400
+ expect(row!.b_id).toBe(3)
401
+ })
402
+
403
+ test("delete with caching", async () => {
404
+ await a.cache.set((query) => {
405
+ return query.delete().where({ id: 1 })
406
+ })
407
+
408
+ expect(await a.cache.count()).toBe(3)
409
+ })
410
+
411
+ test("cache invalidation", async () => {
412
+ expect(await a.cache.count()).toBe(3)
413
+
414
+ await a.query.insert({ id: 5, b_id: 1 })
415
+
416
+ expect(await a.cache.count()).toBe(3)
417
+
418
+ orm.cache.invalidate()
419
+
420
+ expect(await a.cache.count()).toBe(4)
421
+ })
422
+ })
423
+
424
+ afterAll(async () => {
425
+ await orm.client!.schema.dropTable("migration")
426
+ await orm.client!.schema.dropTable("a")
427
+ await orm.client!.schema.dropTable("b")
428
+ await orm.client!.schema.dropTable("c")
429
+ await orm.client!.schema.dropTable("d")
430
+ await orm.client!.destroy()
431
+ })
@@ -0,0 +1,16 @@
1
+ import { Table } from "../../src"
2
+
3
+ export default new Table({
4
+ name: "a",
5
+ priority: 0,
6
+ columns: (col) => ({
7
+ id: col.increments(),
8
+ b_id: col.integer().unsigned().references("id").inTable("b").onDelete("CASCADE"),
9
+ }),
10
+ async then({ query }) {
11
+ await query.insert({
12
+ id: 1,
13
+ b_id: 1,
14
+ })
15
+ },
16
+ })
@@ -0,0 +1,16 @@
1
+ import { Table } from "../../src"
2
+
3
+ export default new Table({
4
+ name: "b",
5
+ priority: 1,
6
+ columns: (col) => ({
7
+ id: col.increments(),
8
+ c_id: col.integer().unsigned().references("id").inTable("c").onDelete("CASCADE"),
9
+ }),
10
+ async then({ query }) {
11
+ await query.insert({
12
+ id: 1,
13
+ c_id: 1,
14
+ })
15
+ },
16
+ })
@@ -0,0 +1,14 @@
1
+ import { Table } from "../../src"
2
+
3
+ export default new Table({
4
+ name: "c",
5
+ priority: 2,
6
+ columns: (col) => ({
7
+ id: col.increments(),
8
+ }),
9
+ async then({ query }) {
10
+ await query.insert({
11
+ id: 1,
12
+ })
13
+ },
14
+ })
@@ -0,0 +1,28 @@
1
+ import { Table } from "../../src"
2
+
3
+ export default new Table({
4
+ name: "d",
5
+ priority: 0,
6
+ columns: (col) => ({
7
+ id: col.increments(),
8
+ name: col.string(100).unique(),
9
+ email: col.string(255),
10
+ age: col.integer().nullable().unsigned(),
11
+ role: col.enum(["admin", "user", "guest"] as const).defaultTo("user"),
12
+ isActive: col.boolean().defaultTo(true),
13
+ metadata: col.json<{ tags: string[]; score: number }>().nullable(),
14
+ createdAt: col.timestamp().nullable(),
15
+ }),
16
+ async then({ query }) {
17
+ await query.insert({
18
+ id: 1,
19
+ name: "Test User",
20
+ email: "test@example.com",
21
+ age: 25,
22
+ role: "admin",
23
+ isActive: true,
24
+ metadata: { tags: ["test"], score: 100 },
25
+ createdAt: new Date(),
26
+ })
27
+ },
28
+ })
package/tsconfig.json CHANGED
@@ -9,6 +9,7 @@
9
9
  "moduleResolution": "NodeNext",
10
10
  "esModuleInterop": true,
11
11
  "declaration": true,
12
+ "skipLibCheck": true,
12
13
  "typeRoots": ["./node_modules/@types", "./dist/typings"]
13
14
  },
14
15
  "include": ["src/**/*", "dist/typings/**/*"]
package/tests/tables/a.js DELETED
@@ -1,25 +0,0 @@
1
- import { Table } from "../.."
2
-
3
- /**
4
- * @type {Table<{ id: number; b_id: number }>}
5
- */
6
- export default new Table({
7
- name: "a",
8
- priority: 0,
9
- setup(table) {
10
- table.increments("id").primary().notNullable()
11
- table
12
- .integer("b_id")
13
- .unsigned()
14
- .references("id")
15
- .inTable("b")
16
- .onDelete("cascade")
17
- .notNullable()
18
- },
19
- async then({ query }) {
20
- await query.insert({
21
- id: 1,
22
- b_id: 1,
23
- })
24
- },
25
- })