orchid-orm 1.3.15 → 1.4.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 (38) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/index.d.ts +59 -54
  3. package/dist/index.esm.js +777 -547
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +776 -546
  6. package/dist/index.js.map +1 -1
  7. package/jest-setup.ts +4 -0
  8. package/package.json +8 -4
  9. package/src/appCodeUpdater/appCodeUpdater.ts +19 -0
  10. package/src/appCodeUpdater/fileChanges.ts +41 -0
  11. package/src/appCodeUpdater/testUtils.ts +31 -0
  12. package/src/appCodeUpdater/tsUtils.ts +137 -0
  13. package/src/appCodeUpdater/updateMainFile.test.ts +230 -0
  14. package/src/appCodeUpdater/updateMainFile.ts +163 -0
  15. package/src/appCodeUpdater/updateTableFile.ts +19 -0
  16. package/src/index.ts +5 -1
  17. package/src/orm.test.ts +13 -13
  18. package/src/orm.ts +21 -21
  19. package/src/relations/belongsTo.test.ts +1 -1
  20. package/src/relations/belongsTo.ts +291 -186
  21. package/src/relations/hasAndBelongsToMany.test.ts +1 -1
  22. package/src/relations/hasAndBelongsToMany.ts +292 -218
  23. package/src/relations/hasMany.test.ts +16 -10
  24. package/src/relations/hasMany.ts +243 -172
  25. package/src/relations/hasOne.test.ts +10 -10
  26. package/src/relations/hasOne.ts +211 -138
  27. package/src/relations/relations.ts +85 -77
  28. package/src/relations/utils.ts +154 -4
  29. package/src/repo.test.ts +29 -29
  30. package/src/repo.ts +6 -6
  31. package/src/{model.test.ts → table.test.ts} +15 -15
  32. package/src/{model.ts → table.ts} +17 -17
  33. package/src/test-utils/test-db.ts +15 -15
  34. package/src/test-utils/{test-models.ts → test-tables.ts} +42 -42
  35. package/src/transaction.test.ts +1 -1
  36. package/src/transaction.ts +4 -4
  37. package/src/utils.ts +9 -0
  38. package/tsconfig.json +1 -0
@@ -1,19 +1,22 @@
1
1
  import { RelationData, RelationThunkBase } from './relations';
2
- import { Model } from '../model';
2
+ import { Table } from '../table';
3
3
  import {
4
+ CreateCtx,
4
5
  getQueryAs,
5
6
  HasAndBelongsToManyRelation,
6
- HasManyNestedInsert,
7
- HasManyNestedUpdate,
8
7
  MaybeArray,
9
8
  NotFoundError,
10
9
  pushQueryValue,
11
10
  Query,
12
11
  QueryBase,
13
12
  toSqlCacheKey,
13
+ UpdateCtx,
14
+ VirtualColumn,
14
15
  WhereArg,
15
16
  WhereResult,
16
17
  } from 'pqb';
18
+ import { hasRelationHandleCreate, hasRelationHandleUpdate } from './utils';
19
+ import { HasManyNestedInsert, HasManyNestedUpdate } from './hasMany';
17
20
 
18
21
  export interface HasAndBelongsToMany extends RelationThunkBase {
19
22
  type: 'hasAndBelongsToMany';
@@ -22,7 +25,7 @@ export interface HasAndBelongsToMany extends RelationThunkBase {
22
25
  }
23
26
 
24
27
  export type HasAndBelongsToManyInfo<
25
- T extends Model,
28
+ T extends Table,
26
29
  Relation extends HasAndBelongsToMany,
27
30
  > = {
28
31
  params: Record<
@@ -41,12 +44,55 @@ type State = {
41
44
  foreignKey: string;
42
45
  associationPrimaryKey: string;
43
46
  associationForeignKey: string;
47
+ foreignKeyFull: string;
48
+ associationPrimaryKeyFull: string;
49
+ associationForeignKeyFull: string;
44
50
  };
45
51
 
52
+ class HasAndBelongsToManyVirtualColumn extends VirtualColumn {
53
+ private readonly nestedInsert: HasManyNestedInsert;
54
+ private readonly nestedUpdate: HasManyNestedUpdate;
55
+
56
+ constructor(private key: string, private state: State) {
57
+ super();
58
+ this.nestedInsert = nestedInsert(state);
59
+ this.nestedUpdate = nestedUpdate(state);
60
+ }
61
+
62
+ create(
63
+ q: Query,
64
+ ctx: CreateCtx,
65
+ item: Record<string, unknown>,
66
+ rowIndex: number,
67
+ ) {
68
+ hasRelationHandleCreate(
69
+ q,
70
+ ctx,
71
+ item,
72
+ rowIndex,
73
+ this.key,
74
+ this.state.primaryKey,
75
+ this.nestedInsert,
76
+ );
77
+ }
78
+
79
+ update(q: Query, ctx: UpdateCtx, set: Record<string, unknown>) {
80
+ hasRelationHandleUpdate(
81
+ q,
82
+ ctx,
83
+ set,
84
+ this.key,
85
+ this.state.primaryKey,
86
+ this.nestedUpdate,
87
+ );
88
+ }
89
+ }
90
+
46
91
  export const makeHasAndBelongsToManyMethod = (
47
- model: Query,
92
+ table: Query,
48
93
  qb: Query,
49
94
  relation: HasAndBelongsToMany,
95
+ relationName: string,
50
96
  query: Query,
51
97
  ): RelationData => {
52
98
  const {
@@ -61,14 +107,14 @@ export const makeHasAndBelongsToManyMethod = (
61
107
  const associationForeignKeyFull = `${joinTable}.${afk}`;
62
108
  const associationPrimaryKeyFull = `${getQueryAs(query)}.${apk}`;
63
109
 
64
- const __model = Object.create(qb.__model);
65
- __model.__model = __model;
66
- __model.table = joinTable;
67
- __model.shape = {
68
- [fk]: model.shape[pk],
110
+ const __table = Object.create(qb.__table);
111
+ __table.__table = __table;
112
+ __table.table = joinTable;
113
+ __table.shape = {
114
+ [fk]: table.shape[pk],
69
115
  [afk]: query.shape[apk],
70
116
  };
71
- const subQuery = Object.create(__model);
117
+ const subQuery = Object.create(__table);
72
118
  subQuery.query = { ...subQuery.query };
73
119
 
74
120
  const state: State = {
@@ -78,6 +124,9 @@ export const makeHasAndBelongsToManyMethod = (
78
124
  foreignKey: fk,
79
125
  associationPrimaryKey: apk,
80
126
  associationForeignKey: afk,
127
+ foreignKeyFull,
128
+ associationForeignKeyFull,
129
+ associationPrimaryKeyFull,
81
130
  };
82
131
 
83
132
  return {
@@ -89,213 +138,7 @@ export const makeHasAndBelongsToManyMethod = (
89
138
  }),
90
139
  );
91
140
  },
92
- nestedInsert: (async (q, data) => {
93
- const connect = data.filter(
94
- (
95
- item,
96
- ): item is [
97
- selfData: Record<string, unknown>,
98
- relationData: {
99
- connect: WhereArg<QueryBase>[];
100
- },
101
- ] => Boolean(item[1].connect),
102
- );
103
-
104
- const t = query.transacting(q);
105
-
106
- let connected: Record<string, unknown>[];
107
- if (connect.length) {
108
- connected = (await Promise.all(
109
- connect.flatMap(([, { connect }]) =>
110
- connect.map((item) => t.select(apk)._findBy(item)._take()),
111
- ),
112
- )) as Record<string, unknown[]>[];
113
- } else {
114
- connected = [];
115
- }
116
-
117
- const connectOrCreate = data.filter(
118
- (
119
- item,
120
- ): item is [
121
- Record<string, unknown>,
122
- {
123
- connectOrCreate: {
124
- where: WhereArg<QueryBase>;
125
- create: Record<string, unknown>;
126
- }[];
127
- },
128
- ] => Boolean(item[1].connectOrCreate),
129
- );
130
-
131
- let connectOrCreated: (Record<string, unknown> | undefined)[];
132
- if (connectOrCreate.length) {
133
- connectOrCreated = await Promise.all(
134
- connectOrCreate.flatMap(([, { connectOrCreate }]) =>
135
- connectOrCreate.map((item) =>
136
- t.select(apk)._findBy(item.where)._takeOptional(),
137
- ),
138
- ),
139
- );
140
- } else {
141
- connectOrCreated = [];
142
- }
143
-
144
- let connectOrCreateI = 0;
145
- const create = data.filter(
146
- (
147
- item,
148
- ): item is [
149
- Record<string, unknown>,
150
- {
151
- create?: Record<string, unknown>[];
152
- connectOrCreate?: {
153
- where: WhereArg<QueryBase>;
154
- create: Record<string, unknown>;
155
- }[];
156
- },
157
- ] => {
158
- if (item[1].connectOrCreate) {
159
- const length = item[1].connectOrCreate.length;
160
- connectOrCreateI += length;
161
- for (let i = length; i > 0; i--) {
162
- if (!connectOrCreated[connectOrCreateI - i]) return true;
163
- }
164
- }
165
- return Boolean(item[1].create);
166
- },
167
- );
168
-
169
- connectOrCreateI = 0;
170
- let created: Record<string, unknown>[];
171
- if (create.length) {
172
- created = (await t
173
- .select(apk)
174
- ._createMany(
175
- create.flatMap(([, { create = [], connectOrCreate = [] }]) => [
176
- ...create,
177
- ...connectOrCreate
178
- .filter(() => !connectOrCreated[connectOrCreateI++])
179
- .map((item) => item.create),
180
- ]),
181
- )) as Record<string, unknown>[];
182
- } else {
183
- created = [];
184
- }
185
-
186
- const allKeys = data as unknown as [
187
- selfData: Record<string, unknown>,
188
- relationKeys: Record<string, unknown>[],
189
- ][];
190
-
191
- let createI = 0;
192
- let connectI = 0;
193
- connectOrCreateI = 0;
194
- data.forEach(([, data], index) => {
195
- if (data.create || data.connectOrCreate) {
196
- if (data.create) {
197
- const len = data.create.length;
198
- allKeys[index][1] = created.slice(createI, createI + len);
199
- createI += len;
200
- }
201
- if (data.connectOrCreate) {
202
- const arr: Record<string, unknown>[] = [];
203
- allKeys[index][1] = arr;
204
-
205
- const len = data.connectOrCreate.length;
206
- for (let i = 0; i < len; i++) {
207
- const item = connectOrCreated[connectOrCreateI++];
208
- if (item) {
209
- arr.push(item);
210
- } else {
211
- arr.push(created[createI++]);
212
- }
213
- }
214
- }
215
- }
216
-
217
- if (data.connect) {
218
- const len = data.connect.length;
219
- allKeys[index][1] = connected.slice(connectI, connectI + len);
220
- connectI += len;
221
- }
222
- });
223
-
224
- await subQuery
225
- .transacting(q)
226
- ._count()
227
- ._createMany(
228
- allKeys.flatMap(([selfData, relationKeys]) => {
229
- const selfKey = selfData[pk];
230
- return relationKeys.map((relationData) => ({
231
- [fk]: selfKey,
232
- [afk]: relationData[apk],
233
- }));
234
- }),
235
- );
236
- }) as HasManyNestedInsert,
237
- nestedUpdate: (async (q, data, params) => {
238
- if (params.create) {
239
- const ids = await query
240
- .transacting(q)
241
- ._pluck(apk)
242
- ._createMany(params.create);
243
-
244
- await subQuery.transacting(q)._createMany(
245
- data.flatMap((item) =>
246
- ids.map((id) => ({
247
- [fk]: item[pk],
248
- [afk]: id,
249
- })),
250
- ),
251
- );
252
- }
253
-
254
- if (params.update) {
255
- await (
256
- query
257
- .transacting(q)
258
- ._whereExists(subQuery, (q) =>
259
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
260
- (q as any)
261
- ._on(associationForeignKeyFull, associationPrimaryKeyFull)
262
- ._where({
263
- IN: {
264
- columns: [foreignKeyFull],
265
- values: [data.map((item) => item[pk])],
266
- },
267
- }),
268
- )
269
- ._where(
270
- Array.isArray(params.update.where)
271
- ? { OR: params.update.where }
272
- : params.update.where,
273
- ) as WhereResult<Query>
274
- )._update<WhereResult<Query>>(params.update.data);
275
- }
276
-
277
- if (params.disconnect) {
278
- await queryJoinTable(state, q, data, params.disconnect)._delete();
279
- }
280
-
281
- if (params.delete) {
282
- const j = queryJoinTable(state, q, data, params.delete);
283
-
284
- const ids = await j._pluck(afk)._delete();
285
-
286
- await queryRelatedTable(query, q, { [apk]: { in: ids } })._delete();
287
- }
288
-
289
- if (params.set) {
290
- const j = queryJoinTable(state, q, data);
291
- await j._delete();
292
- delete j.query[toSqlCacheKey];
293
-
294
- const ids = await queryRelatedTable(query, q, params.set)._pluck(apk);
295
-
296
- await insertToJoinTable(state, j, data, ids);
297
- }
298
- }) as HasManyNestedUpdate,
141
+ virtualColumn: new HasAndBelongsToManyVirtualColumn(relationName, state),
299
142
  // joinQuery can be a property of RelationQuery and be used by whereExists and other stuff which needs it
300
143
  // and the chained query itself may be a query around this joinQuery
301
144
  joinQuery(fromQuery, toQuery) {
@@ -396,3 +239,234 @@ const insertToJoinTable = (
396
239
  ),
397
240
  );
398
241
  };
242
+
243
+ const nestedInsert = ({
244
+ relatedTableQuery,
245
+ joinTableQuery,
246
+ primaryKey,
247
+ foreignKey,
248
+ associationPrimaryKey,
249
+ associationForeignKey,
250
+ }: State) => {
251
+ return (async (q, data) => {
252
+ const connect = data.filter(
253
+ (
254
+ item,
255
+ ): item is [
256
+ selfData: Record<string, unknown>,
257
+ relationData: {
258
+ connect: WhereArg<QueryBase>[];
259
+ },
260
+ ] => Boolean(item[1].connect),
261
+ );
262
+
263
+ const t = relatedTableQuery.transacting(q);
264
+
265
+ let connected: Record<string, unknown>[];
266
+ if (connect.length) {
267
+ connected = (await Promise.all(
268
+ connect.flatMap(([, { connect }]) =>
269
+ connect.map((item) =>
270
+ t.select(associationPrimaryKey)._findBy(item)._take(),
271
+ ),
272
+ ),
273
+ )) as Record<string, unknown[]>[];
274
+ } else {
275
+ connected = [];
276
+ }
277
+
278
+ const connectOrCreate = data.filter(
279
+ (
280
+ item,
281
+ ): item is [
282
+ Record<string, unknown>,
283
+ {
284
+ connectOrCreate: {
285
+ where: WhereArg<QueryBase>;
286
+ create: Record<string, unknown>;
287
+ }[];
288
+ },
289
+ ] => Boolean(item[1].connectOrCreate),
290
+ );
291
+
292
+ let connectOrCreated: (Record<string, unknown> | undefined)[];
293
+ if (connectOrCreate.length) {
294
+ connectOrCreated = await Promise.all(
295
+ connectOrCreate.flatMap(([, { connectOrCreate }]) =>
296
+ connectOrCreate.map((item) =>
297
+ t.select(associationPrimaryKey)._findBy(item.where)._takeOptional(),
298
+ ),
299
+ ),
300
+ );
301
+ } else {
302
+ connectOrCreated = [];
303
+ }
304
+
305
+ let connectOrCreateI = 0;
306
+ const create = data.filter(
307
+ (
308
+ item,
309
+ ): item is [
310
+ Record<string, unknown>,
311
+ {
312
+ create?: Record<string, unknown>[];
313
+ connectOrCreate?: {
314
+ where: WhereArg<QueryBase>;
315
+ create: Record<string, unknown>;
316
+ }[];
317
+ },
318
+ ] => {
319
+ if (item[1].connectOrCreate) {
320
+ const length = item[1].connectOrCreate.length;
321
+ connectOrCreateI += length;
322
+ for (let i = length; i > 0; i--) {
323
+ if (!connectOrCreated[connectOrCreateI - i]) return true;
324
+ }
325
+ }
326
+ return Boolean(item[1].create);
327
+ },
328
+ );
329
+
330
+ connectOrCreateI = 0;
331
+ let created: Record<string, unknown>[];
332
+ if (create.length) {
333
+ created = (await t
334
+ .select(associationPrimaryKey)
335
+ ._createMany(
336
+ create.flatMap(([, { create = [], connectOrCreate = [] }]) => [
337
+ ...create,
338
+ ...connectOrCreate
339
+ .filter(() => !connectOrCreated[connectOrCreateI++])
340
+ .map((item) => item.create),
341
+ ]),
342
+ )) as Record<string, unknown>[];
343
+ } else {
344
+ created = [];
345
+ }
346
+
347
+ const allKeys = data as unknown as [
348
+ selfData: Record<string, unknown>,
349
+ relationKeys: Record<string, unknown>[],
350
+ ][];
351
+
352
+ let createI = 0;
353
+ let connectI = 0;
354
+ connectOrCreateI = 0;
355
+ data.forEach(([, data], index) => {
356
+ if (data.create || data.connectOrCreate) {
357
+ if (data.create) {
358
+ const len = data.create.length;
359
+ allKeys[index][1] = created.slice(createI, createI + len);
360
+ createI += len;
361
+ }
362
+ if (data.connectOrCreate) {
363
+ const arr: Record<string, unknown>[] = [];
364
+ allKeys[index][1] = arr;
365
+
366
+ const len = data.connectOrCreate.length;
367
+ for (let i = 0; i < len; i++) {
368
+ const item = connectOrCreated[connectOrCreateI++];
369
+ if (item) {
370
+ arr.push(item);
371
+ } else {
372
+ arr.push(created[createI++]);
373
+ }
374
+ }
375
+ }
376
+ }
377
+
378
+ if (data.connect) {
379
+ const len = data.connect.length;
380
+ allKeys[index][1] = connected.slice(connectI, connectI + len);
381
+ connectI += len;
382
+ }
383
+ });
384
+
385
+ await joinTableQuery
386
+ .transacting(q)
387
+ ._count()
388
+ ._createMany(
389
+ allKeys.flatMap(([selfData, relationKeys]) => {
390
+ const selfKey = selfData[primaryKey];
391
+ return relationKeys.map((relationData) => ({
392
+ [foreignKey]: selfKey,
393
+ [associationForeignKey]: relationData[associationPrimaryKey],
394
+ }));
395
+ }),
396
+ );
397
+ }) as HasManyNestedInsert;
398
+ };
399
+
400
+ const nestedUpdate = (state: State) => {
401
+ return (async (q, data, params) => {
402
+ if (params.create) {
403
+ const ids = await state.relatedTableQuery
404
+ .transacting(q)
405
+ ._pluck(state.associationPrimaryKey)
406
+ ._createMany(params.create);
407
+
408
+ await state.joinTableQuery.transacting(q)._createMany(
409
+ data.flatMap((item) =>
410
+ ids.map((id) => ({
411
+ [state.foreignKey]: item[state.primaryKey],
412
+ [state.associationForeignKey]: id,
413
+ })),
414
+ ),
415
+ );
416
+ }
417
+
418
+ if (params.update) {
419
+ await (
420
+ state.relatedTableQuery
421
+ .transacting(q)
422
+ ._whereExists(state.joinTableQuery, (q) =>
423
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
424
+ (q as any)
425
+ ._on(
426
+ state.associationForeignKeyFull,
427
+ state.associationPrimaryKeyFull,
428
+ )
429
+ ._where({
430
+ IN: {
431
+ columns: [state.foreignKeyFull],
432
+ values: [data.map((item) => item[state.primaryKey])],
433
+ },
434
+ }),
435
+ )
436
+ ._where(
437
+ Array.isArray(params.update.where)
438
+ ? { OR: params.update.where }
439
+ : params.update.where,
440
+ ) as WhereResult<Query>
441
+ )._update<WhereResult<Query>>(params.update.data);
442
+ }
443
+
444
+ if (params.disconnect) {
445
+ await queryJoinTable(state, q, data, params.disconnect)._delete();
446
+ }
447
+
448
+ if (params.delete) {
449
+ const j = queryJoinTable(state, q, data, params.delete);
450
+
451
+ const ids = await j._pluck(state.associationForeignKey)._delete();
452
+
453
+ await queryRelatedTable(state.relatedTableQuery, q, {
454
+ [state.associationPrimaryKey]: { in: ids },
455
+ })._delete();
456
+ }
457
+
458
+ if (params.set) {
459
+ const j = queryJoinTable(state, q, data);
460
+ await j._delete();
461
+ delete j.query[toSqlCacheKey];
462
+
463
+ const ids = await queryRelatedTable(
464
+ state.relatedTableQuery,
465
+ q,
466
+ params.set,
467
+ )._pluck(state.associationPrimaryKey);
468
+
469
+ await insertToJoinTable(state, j, data, ids);
470
+ }
471
+ }) as HasManyNestedUpdate;
472
+ };
@@ -9,7 +9,13 @@ import {
9
9
  useTestDatabase,
10
10
  } from '../test-utils/test-utils';
11
11
  import { RelationQuery } from 'pqb';
12
- import { Chat, Message, Model, Profile, User } from '../test-utils/test-models';
12
+ import {
13
+ Chat,
14
+ Message,
15
+ BaseTable,
16
+ Profile,
17
+ User,
18
+ } from '../test-utils/test-tables';
13
19
  import { orchidORM } from '../orm';
14
20
 
15
21
  describe('hasMany', () => {
@@ -1653,8 +1659,8 @@ describe('hasMany', () => {
1653
1659
  });
1654
1660
 
1655
1661
  describe('hasMany through', () => {
1656
- it('should resolve recursive situation when both models depends on each other', () => {
1657
- class Post extends Model {
1662
+ it('should resolve recursive situation when both tables depends on each other', () => {
1663
+ class Post extends BaseTable {
1658
1664
  table = 'post';
1659
1665
  columns = this.setColumns((t) => ({
1660
1666
  id: t.serial().primaryKey(),
@@ -1673,7 +1679,7 @@ describe('hasMany through', () => {
1673
1679
  };
1674
1680
  }
1675
1681
 
1676
- class Tag extends Model {
1682
+ class Tag extends BaseTable {
1677
1683
  table = 'tag';
1678
1684
  columns = this.setColumns((t) => ({
1679
1685
  id: t.serial().primaryKey(),
@@ -1692,7 +1698,7 @@ describe('hasMany through', () => {
1692
1698
  };
1693
1699
  }
1694
1700
 
1695
- class PostTag extends Model {
1701
+ class PostTag extends BaseTable {
1696
1702
  table = 'postTag';
1697
1703
  columns = this.setColumns((t) => ({
1698
1704
  postId: t.integer().foreignKey(() => Post, 'id'),
@@ -1730,7 +1736,7 @@ describe('hasMany through', () => {
1730
1736
  });
1731
1737
 
1732
1738
  it('should throw if through relation is not defined', () => {
1733
- class Post extends Model {
1739
+ class Post extends BaseTable {
1734
1740
  table = 'post';
1735
1741
  columns = this.setColumns((t) => ({
1736
1742
  id: t.serial().primaryKey(),
@@ -1744,7 +1750,7 @@ describe('hasMany through', () => {
1744
1750
  };
1745
1751
  }
1746
1752
 
1747
- class Tag extends Model {
1753
+ class Tag extends BaseTable {
1748
1754
  table = 'tag';
1749
1755
  columns = this.setColumns((t) => ({
1750
1756
  id: t.serial().primaryKey(),
@@ -1768,7 +1774,7 @@ describe('hasMany through', () => {
1768
1774
  });
1769
1775
 
1770
1776
  it('should throw if source relation is not defined', () => {
1771
- class Post extends Model {
1777
+ class Post extends BaseTable {
1772
1778
  table = 'post';
1773
1779
  columns = this.setColumns((t) => ({
1774
1780
  id: t.serial().primaryKey(),
@@ -1787,14 +1793,14 @@ describe('hasMany through', () => {
1787
1793
  };
1788
1794
  }
1789
1795
 
1790
- class Tag extends Model {
1796
+ class Tag extends BaseTable {
1791
1797
  table = 'tag';
1792
1798
  columns = this.setColumns((t) => ({
1793
1799
  id: t.serial().primaryKey(),
1794
1800
  }));
1795
1801
  }
1796
1802
 
1797
- class PostTag extends Model {
1803
+ class PostTag extends BaseTable {
1798
1804
  table = 'postTag';
1799
1805
  columns = this.setColumns((t) => ({
1800
1806
  postId: t.integer().foreignKey(() => Post, 'id'),