orchid-orm 1.4.17 → 1.4.19

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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # orchid-orm
2
2
 
3
+ ## 1.4.19
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - pqb@0.8.3
9
+
10
+ ## 1.4.18
11
+
12
+ ### Patch Changes
13
+
14
+ - Add code generator to change project files after migrations
15
+ - Updated dependencies
16
+ - pqb@0.8.2
17
+
3
18
  ## 1.4.17
4
19
 
5
20
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -231,8 +231,10 @@ declare const createRepo: <T extends Query, Methods extends MethodsBase<T>>(tabl
231
231
 
232
232
  declare type AppCodeUpdaterConfig = {
233
233
  tablePath(tableName: string): string;
234
+ baseTablePath: string;
235
+ baseTableName: string;
234
236
  mainFilePath: string;
235
237
  };
236
- declare const appCodeUpdater: () => AppCodeUpdater;
238
+ declare const appCodeUpdater: (config: AppCodeUpdaterConfig) => AppCodeUpdater;
237
239
 
238
240
  export { AppCodeUpdaterConfig, DbTable, MapMethods, MapQueryMethods, MethodsBase, OrchidORM, QueryMethods, Repo, Table, TableClass, TableClasses, TableToDb, appCodeUpdater, createBaseTable, createRepo, orchidORM };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchid-orm",
3
- "version": "1.4.17",
3
+ "version": "1.4.19",
4
4
  "description": "Postgres ORM",
5
5
  "homepage": "https://orchid-orm.netlify.app/guide/orm-setup-and-overview.html",
6
6
  "repository": {
@@ -31,14 +31,14 @@
31
31
  "author": "Roman Kushyn",
32
32
  "license": "ISC",
33
33
  "dependencies": {
34
- "pqb": "0.8.1"
34
+ "pqb": "0.8.3"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@swc/core": "^1.3.19",
38
38
  "rollup": "^2.79.0",
39
39
  "rollup-plugin-dts": "^4.2.2",
40
40
  "rollup-plugin-esbuild": "^4.10.1",
41
- "orchid-orm-schema-to-zod": "0.2.1",
41
+ "orchid-orm-schema-to-zod": "0.2.3",
42
42
  "@swc/jest": "^0.2.21",
43
43
  "@types/jest": "^28.1.2",
44
44
  "@types/node": "^18.0.1",
@@ -50,7 +50,7 @@
50
50
  "rimraf": "^3.0.2",
51
51
  "tslib": "^2.4.0",
52
52
  "typescript": "^4.7.4",
53
- "rake-db": "2.2.1"
53
+ "rake-db": "2.2.3"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "typescript": "*"
@@ -0,0 +1,42 @@
1
+ import { appCodeUpdater } from './appCodeUpdater';
2
+ import { asMock, ast } from './testUtils';
3
+ import { updateMainFile } from './updateMainFile';
4
+ import * as path from 'path';
5
+ import { updateTableFile } from './updateTableFile/updateTableFile';
6
+
7
+ jest.mock('./updateMainFile', () => ({
8
+ updateMainFile: jest.fn(),
9
+ }));
10
+
11
+ jest.mock('./updateTableFile/updateTableFile', () => ({
12
+ updateTableFile: jest.fn(),
13
+ }));
14
+
15
+ describe('appCodeUpdater', () => {
16
+ it('should call table and file updaters with proper arguments', async () => {
17
+ const params = {
18
+ tablePath: (table: string) => `tables/${table}.ts`,
19
+ baseTablePath: 'baseTable.ts',
20
+ baseTableName: 'BaseTable',
21
+ mainFilePath: 'db.ts',
22
+ };
23
+
24
+ const fn = appCodeUpdater(params);
25
+
26
+ await fn(ast.addTable);
27
+
28
+ const mainFilePath = path.resolve(params.mainFilePath);
29
+ const tablePath = path.resolve(params.tablePath('table'));
30
+
31
+ const main = asMock(updateMainFile).mock.calls[0];
32
+ expect(main[0]).toBe(mainFilePath);
33
+ expect(main[1]('table')).toBe(tablePath);
34
+ expect(main[2]).toBe(ast.addTable);
35
+
36
+ const [table] = asMock(updateTableFile).mock.calls[0];
37
+ expect(table.tablePath('table')).toBe(tablePath);
38
+ expect(table.baseTablePath).toBe(params.baseTablePath);
39
+ expect(table.baseTableName).toBe(params.baseTableName);
40
+ expect(table.mainFilePath).toBe(mainFilePath);
41
+ });
42
+ });
@@ -1,19 +1,30 @@
1
1
  import { AppCodeUpdater } from 'rake-db';
2
- // import * as path from 'path';
2
+ import * as path from 'path';
3
+ import { updateMainFile } from './updateMainFile';
4
+ import { updateTableFile } from './updateTableFile/updateTableFile';
3
5
 
4
6
  export class AppCodeUpdaterError extends Error {}
5
7
 
6
8
  export type AppCodeUpdaterConfig = {
7
9
  tablePath(tableName: string): string;
10
+ baseTablePath: string;
11
+ baseTableName: string;
8
12
  mainFilePath: string;
9
13
  };
10
14
 
11
- export const appCodeUpdater = (): // config: AppCodeUpdaterConfig,
12
- AppCodeUpdater => {
13
- // const tablePath = (name: string) => path.resolve(config.tablePath(name));
14
- // const mainFilePath = path.resolve(config.mainFilePath);
15
+ export const appCodeUpdater = (
16
+ config: AppCodeUpdaterConfig,
17
+ ): AppCodeUpdater => {
18
+ const params = {
19
+ ...config,
20
+ tablePath: (name: string) => path.resolve(config.tablePath(name)),
21
+ mainFilePath: path.resolve(config.mainFilePath),
22
+ };
15
23
 
16
24
  return async (ast) => {
17
- console.log(ast);
25
+ await Promise.all([
26
+ updateMainFile(params.mainFilePath, params.tablePath, ast),
27
+ updateTableFile({ ...params, ast }),
28
+ ]);
18
29
  };
19
30
  };
@@ -1,5 +1,10 @@
1
1
  import { RakeDbAst } from 'rake-db';
2
2
  import { columnTypes } from 'pqb';
3
+ import path from 'path';
4
+ import fs from 'fs/promises';
5
+
6
+ export const asMock = (fn: unknown) => fn as jest.Mock;
7
+ export const tablePath = (table: string) => path.resolve(`tables/${table}.ts`);
3
8
 
4
9
  const makeAst = () => {
5
10
  const addTable: RakeDbAst.Table = {
@@ -9,7 +14,7 @@ const makeAst = () => {
9
14
  shape: {
10
15
  id: columnTypes.serial().primaryKey(),
11
16
  },
12
- noPrimaryKey: 'ignore',
17
+ noPrimaryKey: 'error',
13
18
  indexes: [],
14
19
  foreignKeys: [],
15
20
  };
@@ -25,7 +30,26 @@ const makeAst = () => {
25
30
  to: 'renamedTable',
26
31
  };
27
32
 
28
- return { addTable, dropTable, renameTable };
33
+ const tableData = {
34
+ indexes: [],
35
+ foreignKeys: [],
36
+ };
37
+
38
+ const changeTable: RakeDbAst.ChangeTable = {
39
+ type: 'changeTable',
40
+ name: 'table',
41
+ shape: {},
42
+ add: tableData,
43
+ drop: tableData,
44
+ };
45
+
46
+ return { addTable, dropTable, renameTable, changeTable };
29
47
  };
30
48
 
31
49
  export const ast = makeAst();
50
+
51
+ export const makeTestWritten = (path: string) => (expected: string) => {
52
+ const [args] = asMock(fs.writeFile).mock.calls;
53
+ expect(args[0]).toBe(path);
54
+ expect(args[1]).toBe(expected);
55
+ };
@@ -1,18 +1,33 @@
1
1
  import {
2
2
  CallExpression,
3
+ ClassDeclaration,
4
+ ComputedPropertyName,
5
+ createSourceFile,
3
6
  Expression,
7
+ Identifier,
4
8
  ImportDeclaration,
5
9
  NamedImports,
10
+ Node,
6
11
  NodeArray,
12
+ NumericLiteral,
7
13
  ObjectLiteralElement,
8
14
  ObjectLiteralExpression,
15
+ PrivateIdentifier,
16
+ PropertyAccessExpression,
9
17
  PropertyAssignment,
18
+ ScriptTarget,
10
19
  ShorthandPropertyAssignment,
11
20
  Statement,
21
+ StringLiteral,
12
22
  SyntaxKind,
13
23
  VariableStatement,
24
+ ThisExpression,
25
+ ArrowFunction,
26
+ ParenthesizedExpression,
27
+ PropertyName,
28
+ SpreadAssignment,
29
+ ArrayLiteralExpression,
14
30
  } from 'typescript';
15
- import path from 'path';
16
31
 
17
32
  const iterate = <T>(
18
33
  kind: number,
@@ -26,29 +41,54 @@ const iterate = <T>(
26
41
  };
27
42
  };
28
43
 
29
- const isNode = <T extends { kind: number }>() => {
30
- return <U extends T>(kind: number) => {
31
- return (node?: T): node is U => {
32
- return node?.kind === kind;
33
- };
44
+ const isNode = <T extends Expression | ObjectLiteralElement | Node>(
45
+ kind: number,
46
+ ) => {
47
+ return (node?: Expression | ObjectLiteralElement | Node): node is T => {
48
+ return node?.kind === kind;
34
49
  };
35
50
  };
36
51
 
37
- const isExpression = isNode<Expression>();
38
- const isObjectLiteral = isNode<ObjectLiteralElement>();
39
-
40
52
  export const ts = {
53
+ getStatements(content: string): NodeArray<Statement> {
54
+ const { statements } = createSourceFile(
55
+ 'file.ts',
56
+ content,
57
+ ScriptTarget.Latest,
58
+ true,
59
+ );
60
+ return statements;
61
+ },
41
62
  is: {
42
- call: isExpression<CallExpression>(SyntaxKind.CallExpression),
43
- objectLiteral: isExpression<ObjectLiteralExpression>(
63
+ call: isNode<CallExpression>(SyntaxKind.CallExpression),
64
+ objectLiteral: isNode<ObjectLiteralExpression>(
44
65
  SyntaxKind.ObjectLiteralExpression,
45
66
  ),
46
- propertyAssignment: isObjectLiteral<PropertyAssignment>(
67
+ propertyAssignment: isNode<PropertyAssignment>(
47
68
  SyntaxKind.PropertyAssignment,
48
69
  ),
49
- shorthandPropertyAssignment: isObjectLiteral<ShorthandPropertyAssignment>(
70
+ shorthandPropertyAssignment: isNode<ShorthandPropertyAssignment>(
50
71
  SyntaxKind.ShorthandPropertyAssignment,
51
72
  ),
73
+ identifier: isNode<Identifier>(SyntaxKind.Identifier),
74
+ stringLiteral: isNode<StringLiteral>(SyntaxKind.StringLiteral),
75
+ arrayLiteral: isNode<ArrayLiteralExpression>(
76
+ SyntaxKind.ArrayLiteralExpression,
77
+ ),
78
+ numericLiteral: isNode<NumericLiteral>(SyntaxKind.NumericLiteral),
79
+ computedPropertyName: isNode<ComputedPropertyName>(
80
+ SyntaxKind.ComputedPropertyName,
81
+ ),
82
+ privateIdentifier: isNode<PrivateIdentifier>(SyntaxKind.PrivateIdentifier),
83
+ this: isNode<ThisExpression>(SyntaxKind.ThisKeyword),
84
+ propertyAccess: isNode<PropertyAccessExpression>(
85
+ SyntaxKind.PropertyAccessExpression,
86
+ ),
87
+ arrowFunction: isNode<ArrowFunction>(SyntaxKind.ArrowFunction),
88
+ parenthesizedExpression: isNode<ParenthesizedExpression>(
89
+ SyntaxKind.ParenthesizedExpression,
90
+ ),
91
+ spreadAssignment: isNode<SpreadAssignment>(SyntaxKind.SpreadAssignment),
52
92
  },
53
93
  import: {
54
94
  iterate: iterate<ImportDeclaration>(SyntaxKind.ImportDeclaration),
@@ -110,7 +150,17 @@ export const ts = {
110
150
  }
111
151
  },
112
152
  },
153
+ class: {
154
+ iterate: iterate<ClassDeclaration>(SyntaxKind.ClassDeclaration),
155
+ },
113
156
  prop: {
157
+ getName({ name }: { name?: PropertyName }) {
158
+ if (ts.is.identifier(name)) {
159
+ return name.escapedText;
160
+ } else {
161
+ return name?.getText();
162
+ }
163
+ },
114
164
  getValue(prop: ObjectLiteralElement) {
115
165
  if (ts.is.propertyAssignment(prop)) {
116
166
  return prop.initializer.getText();
@@ -121,12 +171,6 @@ export const ts = {
121
171
  }
122
172
  },
123
173
  },
124
- path: {
125
- getRelative(from: string, to: string) {
126
- const rel = path.relative(path.dirname(from), to);
127
- return rel.startsWith('./') || rel.startsWith('../') ? rel : `./${rel}`;
128
- },
129
- },
130
174
  spaces: {
131
175
  getAtLine(content: string, pos: number) {
132
176
  const lines = content.slice(0, pos).split('\n');
@@ -1,17 +1,15 @@
1
1
  import { updateMainFile } from './updateMainFile';
2
2
  import * as path from 'path';
3
3
  import * as fs from 'fs/promises';
4
- import { ast } from './testUtils';
4
+ import { asMock, ast, makeTestWritten, tablePath } from './testUtils';
5
5
 
6
6
  jest.mock('fs/promises', () => ({
7
7
  readFile: jest.fn(),
8
8
  writeFile: jest.fn(),
9
9
  }));
10
10
 
11
- const asMock = (fn: unknown) => fn as jest.Mock;
12
-
13
11
  const mainFilePath = path.resolve('db.ts');
14
- const tablePath = (table: string) => path.resolve(`tables/${table}`);
12
+ const testWritten = makeTestWritten(mainFilePath);
15
13
 
16
14
  describe('updateMainFile', () => {
17
15
  beforeEach(() => {
@@ -36,17 +34,14 @@ export const db = orchidORM({}, {});
36
34
 
37
35
  await updateMainFile(mainFilePath, tablePath, ast.addTable);
38
36
 
39
- expect(fs.writeFile).toBeCalledWith(
40
- mainFilePath,
41
- `
37
+ testWritten(`
42
38
  import { orchidORM } from 'orchid-orm';
43
39
  import { Table } from './tables/table';
44
40
 
45
41
  export const db = orchidORM({}, {
46
42
  table: Table,
47
43
  });
48
- `,
49
- );
44
+ `);
50
45
  });
51
46
 
52
47
  it('should handle import as', async () => {
@@ -58,17 +53,14 @@ export const db = custom({}, {});
58
53
 
59
54
  await updateMainFile(mainFilePath, tablePath, ast.addTable);
60
55
 
61
- expect(fs.writeFile).toBeCalledWith(
62
- mainFilePath,
63
- `
56
+ testWritten(`
64
57
  import { orchidORM as custom } from 'orchid-orm';
65
58
  import { Table } from './tables/table';
66
59
 
67
60
  export const db = custom({}, {
68
61
  table: Table,
69
62
  });
70
- `,
71
- );
63
+ `);
72
64
  });
73
65
 
74
66
  it('should handle object list with elements', async () => {
@@ -83,9 +75,7 @@ export const db = orchidORM({}, {
83
75
 
84
76
  await updateMainFile(mainFilePath, tablePath, ast.addTable);
85
77
 
86
- expect(fs.writeFile).toBeCalledWith(
87
- mainFilePath,
88
- `
78
+ testWritten(`
89
79
  import { orchidORM } from 'orchid-orm';
90
80
  import { Some } from './tables/some';
91
81
  import { Table } from './tables/table';
@@ -94,8 +84,7 @@ export const db = orchidORM({}, {
94
84
  some: Some,
95
85
  table: Table,
96
86
  });
97
- `,
98
- );
87
+ `);
99
88
  });
100
89
 
101
90
  it('should handle object list without ending coma', async () => {
@@ -110,9 +99,7 @@ export const db = orchidORM({}, {
110
99
 
111
100
  await updateMainFile(mainFilePath, tablePath, ast.addTable);
112
101
 
113
- expect(fs.writeFile).toBeCalledWith(
114
- mainFilePath,
115
- `
102
+ testWritten(`
116
103
  import { orchidORM } from 'orchid-orm';
117
104
  import { Some } from './tables/some';
118
105
  import { Table } from './tables/table';
@@ -121,8 +108,7 @@ export const db = orchidORM({}, {
121
108
  some: Some,
122
109
  table: Table,
123
110
  });
124
- `,
125
- );
111
+ `);
126
112
  });
127
113
  });
128
114
 
@@ -139,15 +125,12 @@ export const db = orchidORM({}, {
139
125
 
140
126
  await updateMainFile(mainFilePath, tablePath, ast.dropTable);
141
127
 
142
- expect(fs.writeFile).toBeCalledWith(
143
- mainFilePath,
144
- `
128
+ testWritten(`
145
129
  import { orchidORM } from 'orchid-orm';
146
130
 
147
131
  export const db = orchidORM({}, {
148
132
  });
149
- `,
150
- );
133
+ `);
151
134
  });
152
135
 
153
136
  it('should remove aliased import', async () => {
@@ -162,15 +145,12 @@ export const db = orchidORM({}, {
162
145
 
163
146
  await updateMainFile(mainFilePath, tablePath, ast.dropTable);
164
147
 
165
- expect(fs.writeFile).toBeCalledWith(
166
- mainFilePath,
167
- `
148
+ testWritten(`
168
149
  import { orchidORM } from 'orchid-orm';
169
150
 
170
151
  export const db = orchidORM({}, {
171
152
  });
172
- `,
173
- );
153
+ `);
174
154
  });
175
155
 
176
156
  it('should remove short form of key and value', async () => {
@@ -185,15 +165,12 @@ export const db = orchidORM({}, {
185
165
 
186
166
  await updateMainFile(mainFilePath, tablePath, ast.dropTable);
187
167
 
188
- expect(fs.writeFile).toBeCalledWith(
189
- mainFilePath,
190
- `
168
+ testWritten(`
191
169
  import { orchidORM } from 'orchid-orm';
192
170
 
193
171
  export const db = orchidORM({}, {
194
172
  });
195
- `,
196
- );
173
+ `);
197
174
  });
198
175
 
199
176
  it('should not remove other tables', async () => {
@@ -212,9 +189,7 @@ export const db = orchidORM({}, {
212
189
 
213
190
  await updateMainFile(mainFilePath, tablePath, ast.dropTable);
214
191
 
215
- expect(fs.writeFile).toBeCalledWith(
216
- mainFilePath,
217
- `
192
+ testWritten(`
218
193
  import { orchidORM } from 'orchid-orm';
219
194
  import { One } from './tables/one';
220
195
  import { Two } from './tables/two';
@@ -223,8 +198,7 @@ export const db = orchidORM({}, {
223
198
  one,
224
199
  two,
225
200
  });
226
- `,
227
- );
201
+ `);
228
202
  });
229
203
  });
230
204
  });
@@ -1,16 +1,11 @@
1
1
  import { RakeDbAst } from 'rake-db';
2
2
  import fs from 'fs/promises';
3
- import {
4
- createSourceFile,
5
- NodeArray,
6
- ObjectLiteralExpression,
7
- ScriptTarget,
8
- Statement,
9
- } from 'typescript';
3
+ import { NodeArray, ObjectLiteralExpression, Statement } from 'typescript';
10
4
  import { toCamelCase, toPascalCase } from '../utils';
11
5
  import { AppCodeUpdaterError } from './appCodeUpdater';
12
6
  import { FileChanges } from './fileChanges';
13
7
  import { ts } from './tsUtils';
8
+ import { getImportPath } from './utils';
14
9
 
15
10
  type Context = {
16
11
  path: string;
@@ -30,13 +25,7 @@ export const updateMainFile = async (
30
25
  ast: RakeDbAst,
31
26
  ) => {
32
27
  const content = await fs.readFile(path, 'utf-8');
33
-
34
- const { statements } = createSourceFile(
35
- 'file.ts',
36
- content,
37
- ScriptTarget.Latest,
38
- true,
39
- );
28
+ const statements = ts.getStatements(content);
40
29
 
41
30
  const importName = ts.import.getStatementsImportedName(
42
31
  statements,
@@ -86,7 +75,7 @@ const createTable = (
86
75
 
87
76
  const changes = new FileChanges(content);
88
77
 
89
- const importPath = ts.path.getRelative(path, tablePath(ast.name));
78
+ const importPath = getImportPath(path, tablePath(ast.name));
90
79
  const importPos = ts.import.getEndPos(statements);
91
80
  changes.add(
92
81
  importPos,
@@ -111,7 +100,7 @@ const dropTable = (
111
100
  ) => {
112
101
  const changes = new FileChanges(content);
113
102
 
114
- const importPath = ts.path.getRelative(path, tablePath(ast.name));
103
+ const importPath = getImportPath(path, tablePath(ast.name));
115
104
  const tableClassName = toPascalCase(ast.name);
116
105
  const importNames: string[] = [];
117
106
  for (const node of ts.import.iterateWithSource(statements, importPath)) {