orchid-orm 1.5.29 → 1.5.31

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 (59) hide show
  1. package/dist/index.d.ts +6 -14
  2. package/dist/index.js +26 -21
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +26 -21
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +12 -22
  7. package/.env.example +0 -1
  8. package/.turbo/turbo-check.log +0 -26
  9. package/.turbo/turbo-test.log +0 -26
  10. package/.turbo/turbo-test:ci.log +0 -26
  11. package/CHANGELOG.md +0 -382
  12. package/coverage/coverage-summary.json +0 -28
  13. package/jest-setup.ts +0 -11
  14. package/rollup.config.js +0 -18
  15. package/src/bin/bin.ts +0 -3
  16. package/src/bin/init.test.ts +0 -810
  17. package/src/bin/init.ts +0 -529
  18. package/src/codegen/appCodeUpdater.test.ts +0 -75
  19. package/src/codegen/appCodeUpdater.ts +0 -53
  20. package/src/codegen/createBaseTableFile.test.ts +0 -53
  21. package/src/codegen/createBaseTableFile.ts +0 -31
  22. package/src/codegen/fileChanges.ts +0 -41
  23. package/src/codegen/testUtils.ts +0 -56
  24. package/src/codegen/tsUtils.ts +0 -180
  25. package/src/codegen/updateMainFile.test.ts +0 -253
  26. package/src/codegen/updateMainFile.ts +0 -210
  27. package/src/codegen/updateTableFile/changeTable.test.ts +0 -804
  28. package/src/codegen/updateTableFile/changeTable.ts +0 -536
  29. package/src/codegen/updateTableFile/createTable.test.ts +0 -139
  30. package/src/codegen/updateTableFile/createTable.ts +0 -51
  31. package/src/codegen/updateTableFile/renameTable.test.ts +0 -124
  32. package/src/codegen/updateTableFile/renameTable.ts +0 -67
  33. package/src/codegen/updateTableFile/updateTableFile.ts +0 -22
  34. package/src/codegen/utils.ts +0 -13
  35. package/src/index.ts +0 -5
  36. package/src/orm.test.ts +0 -92
  37. package/src/orm.ts +0 -98
  38. package/src/relations/belongsTo.test.ts +0 -1122
  39. package/src/relations/belongsTo.ts +0 -352
  40. package/src/relations/hasAndBelongsToMany.test.ts +0 -1335
  41. package/src/relations/hasAndBelongsToMany.ts +0 -472
  42. package/src/relations/hasMany.test.ts +0 -2616
  43. package/src/relations/hasMany.ts +0 -401
  44. package/src/relations/hasOne.test.ts +0 -1701
  45. package/src/relations/hasOne.ts +0 -351
  46. package/src/relations/relations.test.ts +0 -37
  47. package/src/relations/relations.ts +0 -363
  48. package/src/relations/utils.ts +0 -162
  49. package/src/repo.test.ts +0 -200
  50. package/src/repo.ts +0 -119
  51. package/src/table.test.ts +0 -121
  52. package/src/table.ts +0 -184
  53. package/src/test-utils/test-db.ts +0 -32
  54. package/src/test-utils/test-tables.ts +0 -194
  55. package/src/test-utils/test-utils.ts +0 -119
  56. package/src/transaction.test.ts +0 -47
  57. package/src/transaction.ts +0 -27
  58. package/src/utils.ts +0 -9
  59. 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
- };