orchid-orm 1.5.28 → 1.5.30

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 (57) hide show
  1. package/dist/index.js +10 -10
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +10 -10
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +13 -22
  6. package/.env.example +0 -1
  7. package/.turbo/turbo-test.log +0 -26
  8. package/.turbo/turbo-test:ci.log +0 -26
  9. package/CHANGELOG.md +0 -375
  10. package/coverage/coverage-summary.json +0 -28
  11. package/jest-setup.ts +0 -11
  12. package/rollup.config.js +0 -18
  13. package/src/bin/bin.ts +0 -3
  14. package/src/bin/init.test.ts +0 -810
  15. package/src/bin/init.ts +0 -529
  16. package/src/codegen/appCodeUpdater.test.ts +0 -75
  17. package/src/codegen/appCodeUpdater.ts +0 -53
  18. package/src/codegen/createBaseTableFile.test.ts +0 -53
  19. package/src/codegen/createBaseTableFile.ts +0 -31
  20. package/src/codegen/fileChanges.ts +0 -41
  21. package/src/codegen/testUtils.ts +0 -56
  22. package/src/codegen/tsUtils.ts +0 -180
  23. package/src/codegen/updateMainFile.test.ts +0 -253
  24. package/src/codegen/updateMainFile.ts +0 -210
  25. package/src/codegen/updateTableFile/changeTable.test.ts +0 -804
  26. package/src/codegen/updateTableFile/changeTable.ts +0 -536
  27. package/src/codegen/updateTableFile/createTable.test.ts +0 -139
  28. package/src/codegen/updateTableFile/createTable.ts +0 -51
  29. package/src/codegen/updateTableFile/renameTable.test.ts +0 -124
  30. package/src/codegen/updateTableFile/renameTable.ts +0 -67
  31. package/src/codegen/updateTableFile/updateTableFile.ts +0 -22
  32. package/src/codegen/utils.ts +0 -13
  33. package/src/index.ts +0 -5
  34. package/src/orm.test.ts +0 -92
  35. package/src/orm.ts +0 -98
  36. package/src/relations/belongsTo.test.ts +0 -1122
  37. package/src/relations/belongsTo.ts +0 -352
  38. package/src/relations/hasAndBelongsToMany.test.ts +0 -1335
  39. package/src/relations/hasAndBelongsToMany.ts +0 -472
  40. package/src/relations/hasMany.test.ts +0 -2616
  41. package/src/relations/hasMany.ts +0 -401
  42. package/src/relations/hasOne.test.ts +0 -1701
  43. package/src/relations/hasOne.ts +0 -351
  44. package/src/relations/relations.test.ts +0 -37
  45. package/src/relations/relations.ts +0 -363
  46. package/src/relations/utils.ts +0 -162
  47. package/src/repo.test.ts +0 -200
  48. package/src/repo.ts +0 -119
  49. package/src/table.test.ts +0 -121
  50. package/src/table.ts +0 -184
  51. package/src/test-utils/test-db.ts +0 -32
  52. package/src/test-utils/test-tables.ts +0 -194
  53. package/src/test-utils/test-utils.ts +0 -119
  54. package/src/transaction.test.ts +0 -47
  55. package/src/transaction.ts +0 -27
  56. package/src/utils.ts +0 -9
  57. package/tsconfig.json +0 -14
@@ -1,363 +0,0 @@
1
- import { BelongsTo, BelongsToInfo, makeBelongsToMethod } from './belongsTo';
2
- import { HasOne, HasOneInfo, makeHasOneMethod } from './hasOne';
3
- import { DbTable, Table, TableClass, TableClasses } from '../table';
4
- import { OrchidORM } from '../orm';
5
- import {
6
- Query,
7
- QueryWithTable,
8
- RelationQuery,
9
- SetQueryReturnsAll,
10
- SetQueryReturnsOne,
11
- SetQueryReturnsOneOptional,
12
- BaseRelation,
13
- defaultsKey,
14
- relationQueryKey,
15
- EmptyObject,
16
- VirtualColumn,
17
- } from 'pqb';
18
- import { HasMany, HasManyInfo, makeHasManyMethod } from './hasMany';
19
- import {
20
- HasAndBelongsToMany,
21
- HasAndBelongsToManyInfo,
22
- makeHasAndBelongsToManyMethod,
23
- } from './hasAndBelongsToMany';
24
- import { getSourceRelation, getThroughRelation } from './utils';
25
-
26
- export interface RelationThunkBase {
27
- type: string;
28
- returns: 'one' | 'many';
29
- fn(): TableClass;
30
- options: BaseRelation['options'];
31
- }
32
-
33
- export type RelationThunk = BelongsTo | HasOne | HasMany | HasAndBelongsToMany;
34
-
35
- export type RelationThunks = Record<string, RelationThunk>;
36
-
37
- export type RelationData = {
38
- returns: 'one' | 'many';
39
- method(params: Record<string, unknown>): Query;
40
- virtualColumn?: VirtualColumn;
41
- joinQuery(fromQuery: Query, toQuery: Query): Query;
42
- reverseJoin(fromQuery: Query, toQuery: Query): Query;
43
- primaryKey: string;
44
- modifyRelatedQuery?(relatedQuery: Query): (query: Query) => void;
45
- };
46
-
47
- export type Relation<
48
- T extends Table,
49
- Relations extends RelationThunks,
50
- K extends keyof Relations,
51
- M extends Query = DbTable<ReturnType<Relations[K]['fn']>>,
52
- Info extends RelationInfo = RelationInfo<T, Relations, Relations[K]>,
53
- > = {
54
- type: Relations[K]['type'];
55
- returns: Relations[K]['returns'];
56
- key: K;
57
- table: M;
58
- query: M;
59
- joinQuery(fromQuery: Query, toQuery: Query): Query;
60
- defaults: Info['populate'];
61
- nestedCreateQuery: [Info['populate']] extends [never]
62
- ? M
63
- : M & {
64
- [defaultsKey]: Record<Info['populate'], true>;
65
- };
66
- primaryKey: string;
67
- options: Relations[K]['options'];
68
- };
69
-
70
- export type RelationScopeOrTable<Relation extends RelationThunkBase> =
71
- Relation['options']['scope'] extends (q: Query) => Query
72
- ? ReturnType<Relation['options']['scope']>
73
- : DbTable<ReturnType<Relation['fn']>>;
74
-
75
- export type RelationInfo<
76
- T extends Table = Table,
77
- Relations extends RelationThunks = RelationThunks,
78
- Relation extends RelationThunk = RelationThunk,
79
- > = Relation extends BelongsTo
80
- ? BelongsToInfo<T, Relation>
81
- : Relation extends HasOne
82
- ? HasOneInfo<T, Relations, Relation>
83
- : Relation extends HasMany
84
- ? HasManyInfo<T, Relations, Relation>
85
- : Relation extends HasAndBelongsToMany
86
- ? HasAndBelongsToManyInfo<T, Relation>
87
- : never;
88
-
89
- export type MapRelation<
90
- T extends Table,
91
- Relations extends RelationThunks,
92
- RelationName extends keyof Relations,
93
- Relation extends RelationThunk = Relations[RelationName],
94
- RelatedQuery extends Query = RelationScopeOrTable<Relation>,
95
- Info extends {
96
- params: Record<string, unknown>;
97
- populate: string;
98
- chainedCreate: boolean;
99
- chainedDelete: boolean;
100
- } = RelationInfo<T, Relations, Relation>,
101
- > = RelationQuery<
102
- RelationName,
103
- Info['params'],
104
- Info['populate'],
105
- Relation['returns'] extends 'one'
106
- ? Relation['options']['required'] extends true
107
- ? SetQueryReturnsOne<RelatedQuery>
108
- : SetQueryReturnsOneOptional<RelatedQuery>
109
- : SetQueryReturnsAll<RelatedQuery>,
110
- Relation['options']['required'] extends boolean
111
- ? Relation['options']['required']
112
- : false,
113
- Info['chainedCreate'],
114
- Info['chainedDelete']
115
- >;
116
-
117
- export type MapRelations<T extends Table> = 'relations' extends keyof T
118
- ? T['relations'] extends RelationThunks
119
- ? {
120
- [K in keyof T['relations']]: MapRelation<T, T['relations'], K>;
121
- }
122
- : EmptyObject
123
- : EmptyObject;
124
-
125
- type ApplyRelationData = {
126
- relationName: string;
127
- relation: RelationThunk;
128
- dbTable: DbTable<TableClass>;
129
- otherDbTable: DbTable<TableClass>;
130
- };
131
-
132
- type DelayedRelations = Map<Query, Record<string, ApplyRelationData[]>>;
133
-
134
- export const applyRelations = (
135
- qb: Query,
136
- tables: Record<string, Table>,
137
- result: OrchidORM<TableClasses>,
138
- ) => {
139
- const tableEntries = Object.entries(tables);
140
-
141
- const delayedRelations: DelayedRelations = new Map();
142
-
143
- for (const name in tables) {
144
- const table = tables[name] as Table & {
145
- relations?: RelationThunks;
146
- };
147
- if (!('relations' in table) || typeof table.relations !== 'object')
148
- continue;
149
-
150
- const dbTable = result[name];
151
- for (const relationName in table.relations) {
152
- const relation = table.relations[relationName];
153
- const otherTableClass = relation.fn();
154
- const otherTable = tableEntries.find(
155
- (pair) => pair[1] instanceof otherTableClass,
156
- );
157
- if (!otherTable) {
158
- throw new Error(
159
- `Cannot find table class for class ${otherTableClass.name}`,
160
- );
161
- }
162
- const otherTableName = otherTable[0];
163
- const otherDbTable = result[otherTableName];
164
- if (!otherDbTable)
165
- throw new Error(`Cannot find table class by name ${otherTableName}`);
166
-
167
- const data: ApplyRelationData = {
168
- relationName,
169
- relation,
170
- dbTable,
171
- otherDbTable,
172
- };
173
-
174
- const options = relation.options as { through?: string; source?: string };
175
- if (
176
- typeof options.through === 'string' &&
177
- typeof options.source === 'string'
178
- ) {
179
- const throughRelation = getThroughRelation(dbTable, options.through);
180
- if (!throughRelation) {
181
- delayRelation(delayedRelations, dbTable, options.through, data);
182
- continue;
183
- }
184
-
185
- const sourceRelation = getSourceRelation(
186
- throughRelation,
187
- options.source,
188
- );
189
- if (!sourceRelation) {
190
- delayRelation(
191
- delayedRelations,
192
- throughRelation.table,
193
- options.source,
194
- data,
195
- );
196
- continue;
197
- }
198
- }
199
-
200
- applyRelation(qb, data, delayedRelations);
201
- }
202
- }
203
-
204
- if (delayedRelations.size) {
205
- const { value } = delayedRelations.values().next() as {
206
- value: Record<string, ApplyRelationData[]>;
207
- };
208
- for (const key in value) {
209
- for (const item of value[key]) {
210
- const { relation } = item;
211
-
212
- if (item.dbTable.relations[item.relationName as never]) continue;
213
-
214
- const as = item.dbTable.definedAs;
215
- let message = `Cannot define a \`${item.relationName}\` relation on \`${as}\``;
216
- const table = result[as];
217
-
218
- const { through, source } = relation.options as {
219
- through: string;
220
- source: string;
221
- };
222
- const throughRel = table.relations[
223
- through as never
224
- ] as unknown as BaseRelation;
225
-
226
- if (through && !throughRel) {
227
- message += `: cannot find \`${through}\` relation required by the \`through\` option`;
228
- } else if (
229
- source &&
230
- throughRel &&
231
- !throughRel.table.relations[source as never]
232
- ) {
233
- message += `: cannot find \`${source}\` relation in \`${
234
- (throughRel.table as DbTable<TableClass>).definedAs
235
- }\` required by the \`source\` option`;
236
- }
237
-
238
- throw new Error(message);
239
- }
240
- }
241
- }
242
- };
243
-
244
- const delayRelation = (
245
- delayedRelations: DelayedRelations,
246
- table: Query,
247
- relationName: string,
248
- data: ApplyRelationData,
249
- ) => {
250
- let tableRelations = delayedRelations.get(table);
251
- if (!tableRelations) {
252
- tableRelations = {};
253
- delayedRelations.set(table, tableRelations);
254
- }
255
- if (tableRelations[relationName]) {
256
- tableRelations[relationName].push(data);
257
- } else {
258
- tableRelations[relationName] = [data];
259
- }
260
- };
261
-
262
- const applyRelation = (
263
- qb: Query,
264
- { relationName, relation, dbTable, otherDbTable }: ApplyRelationData,
265
- delayedRelations: DelayedRelations,
266
- ) => {
267
- const query = (
268
- relation.options.scope
269
- ? relation.options.scope(otherDbTable)
270
- : (otherDbTable as unknown as QueryWithTable)
271
- ).as(relationName);
272
-
273
- const definedAs = (query as unknown as { definedAs?: string }).definedAs;
274
- if (!definedAs) {
275
- throw new Error(
276
- `Table class for table ${query.table} is not attached to db instance`,
277
- );
278
- }
279
-
280
- const { type } = relation;
281
- let data;
282
- if (type === 'belongsTo') {
283
- data = makeBelongsToMethod(relation, relationName, query);
284
- } else if (type === 'hasOne') {
285
- data = makeHasOneMethod(dbTable, relation, relationName, query);
286
- } else if (type === 'hasMany') {
287
- data = makeHasManyMethod(dbTable, relation, relationName, query);
288
- } else if (type === 'hasAndBelongsToMany') {
289
- data = makeHasAndBelongsToManyMethod(
290
- dbTable,
291
- qb,
292
- relation,
293
- relationName,
294
- query,
295
- );
296
- } else {
297
- throw new Error(`Unknown relation type ${type}`);
298
- }
299
-
300
- if (data.returns === 'one') {
301
- query._take();
302
- }
303
-
304
- if (data.virtualColumn) {
305
- dbTable.shape[relationName] = data.virtualColumn;
306
- }
307
-
308
- makeRelationQuery(dbTable, definedAs, relationName, data);
309
-
310
- (dbTable.relations as Record<string, unknown>)[relationName] = {
311
- type,
312
- key: relationName,
313
- table: otherDbTable,
314
- query,
315
- joinQuery: data.joinQuery,
316
- primaryKey: data.primaryKey,
317
- options: relation.options,
318
- };
319
-
320
- const tableRelations = delayedRelations.get(dbTable);
321
- if (!tableRelations) return;
322
-
323
- tableRelations[relationName]?.forEach((data) => {
324
- applyRelation(qb, data, delayedRelations);
325
- });
326
- };
327
-
328
- const makeRelationQuery = (
329
- table: Query,
330
- definedAs: string,
331
- relationName: string,
332
- data: RelationData,
333
- ) => {
334
- Object.defineProperty(table, relationName, {
335
- get() {
336
- const toTable = this.db[definedAs].as(relationName) as Query;
337
-
338
- if (data.returns === 'one') {
339
- toTable._take();
340
- }
341
-
342
- const query = this.isSubQuery
343
- ? toTable
344
- : toTable._whereExists(data.reverseJoin(this, toTable), (q) => q);
345
-
346
- query.query[relationQueryKey] = {
347
- relationName,
348
- sourceQuery: this,
349
- relationQuery: toTable,
350
- joinQuery: data.joinQuery,
351
- };
352
-
353
- const setQuery = data.modifyRelatedQuery?.(query);
354
- setQuery?.(this);
355
-
356
- return new Proxy(data.method, {
357
- get(_, prop) {
358
- return (query as unknown as Record<string, unknown>)[prop as string];
359
- },
360
- }) as unknown as RelationQuery;
361
- },
362
- });
363
- };
@@ -1,162 +0,0 @@
1
- import {
2
- CreateCtx,
3
- MaybeArray,
4
- pushQueryValue,
5
- Query,
6
- QueryBase,
7
- Relation,
8
- UpdateCtx,
9
- UpdateData,
10
- WhereArg,
11
- } from 'pqb';
12
- import { HasOneNestedInsert, HasOneNestedUpdate } from './hasOne';
13
- import { HasManyNestedInsert, HasManyNestedUpdate } from './hasMany';
14
-
15
- export type NestedInsertOneItem = {
16
- create?: Record<string, unknown>;
17
- connect?: WhereArg<QueryBase>;
18
- connectOrCreate?: {
19
- where: WhereArg<QueryBase>;
20
- create: Record<string, unknown>;
21
- };
22
- };
23
-
24
- export type NestedInsertManyItems = {
25
- create?: Record<string, unknown>[];
26
- connect?: WhereArg<QueryBase>[];
27
- connectOrCreate?: {
28
- where: WhereArg<QueryBase>;
29
- create: Record<string, unknown>;
30
- }[];
31
- };
32
-
33
- export type NestedInsertItem = NestedInsertOneItem | NestedInsertManyItems;
34
-
35
- export type NestedUpdateOneItem = {
36
- disconnect?: boolean;
37
- set?: WhereArg<QueryBase>;
38
- delete?: boolean;
39
- update?: UpdateData<Query>;
40
- upsert?: {
41
- update: UpdateData<Query>;
42
- create: Record<string, unknown>;
43
- };
44
- create: Record<string, unknown>;
45
- };
46
-
47
- export type NestedUpdateManyItems = {
48
- disconnect?: MaybeArray<WhereArg<QueryBase>>;
49
- set?: MaybeArray<WhereArg<QueryBase>>;
50
- delete?: MaybeArray<WhereArg<QueryBase>>;
51
- update?: {
52
- where: MaybeArray<WhereArg<QueryBase>>;
53
- data: UpdateData<Query>;
54
- };
55
- create: Record<string, unknown>[];
56
- };
57
-
58
- export type NestedUpdateItem = NestedUpdateOneItem | NestedUpdateManyItems;
59
-
60
- export const getThroughRelation = (table: Query, through: string) => {
61
- return (table.relations as Record<string, Relation>)[through];
62
- };
63
-
64
- export const getSourceRelation = (
65
- throughRelation: Relation,
66
- source: string,
67
- ) => {
68
- return (throughRelation.table.relations as Record<string, Relation>)[source];
69
- };
70
-
71
- export const hasRelationHandleCreate = (
72
- q: Query,
73
- ctx: CreateCtx,
74
- item: Record<string, unknown>,
75
- rowIndex: number,
76
- key: string,
77
- primaryKey: string,
78
- nestedInsert: HasOneNestedInsert | HasManyNestedInsert,
79
- ) => {
80
- const value = item[key] as NestedInsertItem;
81
- if (
82
- (!value.create ||
83
- (Array.isArray(value.create) && value.create.length === 0)) &&
84
- (!value.connect ||
85
- (Array.isArray(value.connect) && value.connect.length === 0)) &&
86
- (!value.connectOrCreate ||
87
- (Array.isArray(value.connectOrCreate) &&
88
- value.connectOrCreate.length === 0))
89
- )
90
- return;
91
-
92
- const store = ctx as unknown as {
93
- hasRelation?: Record<string, [number, NestedInsertItem][]>;
94
- };
95
-
96
- if (!store.hasRelation) store.hasRelation = {};
97
-
98
- const values = [rowIndex, value] as [number, NestedInsertItem];
99
-
100
- if (store.hasRelation[key]) {
101
- store.hasRelation[key].push(values);
102
- return;
103
- }
104
-
105
- q.query.wrapInTransaction = true;
106
- ctx.returnTypeAll = true;
107
- ctx.requiredReturning[primaryKey] = true;
108
-
109
- const relationData = [values];
110
- store.hasRelation[key] = relationData;
111
-
112
- pushQueryValue(q, 'afterCreate', async (q: Query) => {
113
- const { resultAll } = ctx;
114
- return (nestedInsert as HasOneNestedInsert)(
115
- q,
116
- relationData.map(([rowIndex, data]) => [
117
- resultAll[rowIndex],
118
- data as NestedInsertOneItem,
119
- ]),
120
- );
121
- });
122
- };
123
-
124
- export const hasRelationHandleUpdate = (
125
- q: Query,
126
- ctx: UpdateCtx,
127
- set: Record<string, unknown>,
128
- key: string,
129
- primaryKey: string,
130
- nestedUpdate: HasOneNestedUpdate | HasManyNestedUpdate,
131
- ) => {
132
- const value = set[key] as NestedUpdateItem;
133
-
134
- if (
135
- !value.set &&
136
- !('upsert' in value) &&
137
- (!value.disconnect ||
138
- (Array.isArray(value.disconnect) && value.disconnect.length === 0)) &&
139
- (!value.delete ||
140
- (Array.isArray(value.delete) && value.delete.length === 0)) &&
141
- (!value.update ||
142
- (Array.isArray(value.update.where) && value.update.where.length === 0)) &&
143
- (!value.create ||
144
- (Array.isArray(value.create) && value.create.length === 0))
145
- )
146
- return;
147
-
148
- if (!q.query.select?.includes('*') && !q.query.select?.includes(primaryKey)) {
149
- q._select(primaryKey);
150
- }
151
-
152
- q.query.wrapInTransaction = true;
153
- ctx.returnTypeAll = true;
154
-
155
- pushQueryValue(q, 'afterUpdate', (q: Query) => {
156
- return (nestedUpdate as HasOneNestedUpdate)(
157
- q,
158
- ctx.resultAll,
159
- value as NestedUpdateOneItem,
160
- );
161
- });
162
- };