rake-db 2.3.29 → 2.3.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 (51) hide show
  1. package/package.json +11 -21
  2. package/.env +0 -1
  3. package/.env.local +0 -2
  4. package/.turbo/turbo-test.log +0 -22
  5. package/.turbo/turbo-test:ci.log +0 -22
  6. package/CHANGELOG.md +0 -388
  7. package/app/dbScript.ts +0 -33
  8. package/app/migrations/20221017181504_createUser.ts +0 -14
  9. package/app/migrations/20221017200111_createProfile.ts +0 -10
  10. package/app/migrations/20221017200252_createChat.ts +0 -9
  11. package/app/migrations/20221017200326_createChatUser.ts +0 -10
  12. package/app/migrations/20221017200900_createMessage.ts +0 -12
  13. package/app/migrations/20221017201235_createGeoSchema.ts +0 -5
  14. package/app/migrations/20221017210011_createCountry.ts +0 -8
  15. package/app/migrations/20221017210133_createCity.ts +0 -9
  16. package/app/migrations/20221105202843_createUniqueTable.ts +0 -12
  17. package/jest-setup.ts +0 -3
  18. package/rollup.config.js +0 -3
  19. package/src/ast.ts +0 -130
  20. package/src/commands/createOrDrop.test.ts +0 -214
  21. package/src/commands/createOrDrop.ts +0 -151
  22. package/src/commands/generate.test.ts +0 -136
  23. package/src/commands/generate.ts +0 -93
  24. package/src/commands/migrateOrRollback.test.ts +0 -267
  25. package/src/commands/migrateOrRollback.ts +0 -190
  26. package/src/common.test.ts +0 -295
  27. package/src/common.ts +0 -353
  28. package/src/errors.ts +0 -3
  29. package/src/index.ts +0 -8
  30. package/src/migration/change.test.ts +0 -16
  31. package/src/migration/change.ts +0 -15
  32. package/src/migration/changeTable.test.ts +0 -897
  33. package/src/migration/changeTable.ts +0 -566
  34. package/src/migration/createTable.test.ts +0 -384
  35. package/src/migration/createTable.ts +0 -193
  36. package/src/migration/migration.test.ts +0 -430
  37. package/src/migration/migration.ts +0 -518
  38. package/src/migration/migrationUtils.ts +0 -307
  39. package/src/migration/tableMethods.ts +0 -8
  40. package/src/pull/astToMigration.test.ts +0 -275
  41. package/src/pull/astToMigration.ts +0 -173
  42. package/src/pull/dbStructure.test.ts +0 -180
  43. package/src/pull/dbStructure.ts +0 -413
  44. package/src/pull/pull.test.ts +0 -115
  45. package/src/pull/pull.ts +0 -22
  46. package/src/pull/structureToAst.test.ts +0 -841
  47. package/src/pull/structureToAst.ts +0 -372
  48. package/src/rakeDb.test.ts +0 -131
  49. package/src/rakeDb.ts +0 -84
  50. package/src/test-utils.ts +0 -64
  51. package/tsconfig.json +0 -12
package/src/ast.ts DELETED
@@ -1,130 +0,0 @@
1
- import {
2
- ColumnsShape,
3
- ColumnType,
4
- ForeignKeyOptions,
5
- NoPrimaryKeyOption,
6
- RawExpression,
7
- SingleColumnIndexOptions,
8
- TableData,
9
- } from 'pqb';
10
- import { DropMode } from './migration/migration';
11
-
12
- export type RakeDbAst =
13
- | RakeDbAst.Table
14
- | RakeDbAst.ChangeTable
15
- | RakeDbAst.RenameTable
16
- | RakeDbAst.Schema
17
- | RakeDbAst.Extension
18
- | RakeDbAst.Enum
19
- | RakeDbAst.ForeignKey;
20
-
21
- export namespace RakeDbAst {
22
- export type Table = {
23
- type: 'table';
24
- action: 'create' | 'drop';
25
- schema?: string;
26
- name: string;
27
- shape: ColumnsShape;
28
- noPrimaryKey: NoPrimaryKeyOption;
29
- dropMode?: DropMode;
30
- comment?: string;
31
- } & TableData;
32
-
33
- export type ChangeTable = {
34
- type: 'changeTable';
35
- schema?: string;
36
- name: string;
37
- comment?: string | null;
38
- shape: Record<string, ChangeTableItem>;
39
- add: TableData;
40
- drop: TableData;
41
- };
42
-
43
- export type ChangeTableItem =
44
- | ChangeTableItem.Column
45
- | ChangeTableItem.Change
46
- | ChangeTableItem.Rename;
47
-
48
- export namespace ChangeTableItem {
49
- export type Column = {
50
- type: 'add' | 'drop';
51
- item: ColumnType;
52
- dropMode?: DropMode;
53
- };
54
-
55
- export type Change = {
56
- type: 'change';
57
- from: ColumnChange;
58
- to: ColumnChange;
59
- using?: RawExpression;
60
- };
61
-
62
- export type Rename = {
63
- type: 'rename';
64
- name: string;
65
- };
66
- }
67
-
68
- export type ColumnChange = {
69
- column?: ColumnType;
70
- type?: string;
71
- collate?: string;
72
- default?: unknown | RawExpression;
73
- nullable?: boolean;
74
- comment?: string | null;
75
- compression?: string;
76
- primaryKey?: boolean;
77
- foreignKeys?: ({
78
- table: string;
79
- columns: string[];
80
- } & ForeignKeyOptions)[];
81
- indexes?: Omit<SingleColumnIndexOptions, 'column' | 'expression'>[];
82
- };
83
-
84
- export type RenameTable = {
85
- type: 'renameTable';
86
- fromSchema?: string;
87
- from: string;
88
- toSchema?: string;
89
- to: string;
90
- };
91
-
92
- export type Schema = {
93
- type: 'schema';
94
- action: 'create' | 'drop';
95
- name: string;
96
- };
97
-
98
- export type Extension = {
99
- type: 'extension';
100
- action: 'create' | 'drop';
101
- name: string;
102
- schema?: string;
103
- version?: string;
104
- cascade?: boolean;
105
- createIfNotExists?: boolean;
106
- dropIfExists?: boolean;
107
- };
108
-
109
- export type Enum = {
110
- type: 'enum';
111
- action: 'create' | 'drop';
112
- schema?: string;
113
- name: string;
114
- values: string[];
115
- cascade?: boolean;
116
- dropIfExists?: boolean;
117
- };
118
-
119
- export type EnumOptions = {
120
- createIfNotExists?: boolean;
121
- dropIfExists?: boolean;
122
- };
123
-
124
- export type ForeignKey = {
125
- type: 'foreignKey';
126
- action: 'create';
127
- tableSchema?: string;
128
- tableName: string;
129
- } & TableData.ForeignKey;
130
- }
@@ -1,214 +0,0 @@
1
- import { createDb, dropDb, resetDb } from './createOrDrop';
2
- import { Adapter } from 'pqb';
3
- import {
4
- createSchemaMigrations,
5
- migrationConfigDefaults,
6
- setAdminCredentialsToOptions,
7
- } from '../common';
8
- import { migrate } from './migrateOrRollback';
9
-
10
- jest.mock('../common', () => ({
11
- ...jest.requireActual('../common'),
12
- setAdminCredentialsToOptions: jest.fn((options: Record<string, unknown>) => ({
13
- ...options,
14
- user: 'admin-user',
15
- password: 'admin-password',
16
- })),
17
- createSchemaMigrations: jest.fn(),
18
- }));
19
-
20
- jest.mock('./migrateOrRollback', () => ({
21
- migrate: jest.fn(),
22
- }));
23
-
24
- const options = { database: 'dbname', user: 'user', password: 'password' };
25
- const queryMock = jest.fn();
26
- Adapter.prototype.query = queryMock;
27
-
28
- const logMock = jest.fn();
29
- console.log = logMock;
30
-
31
- const config = {
32
- ...migrationConfigDefaults,
33
- basePath: __dirname,
34
- };
35
-
36
- describe('createOrDrop', () => {
37
- beforeEach(() => {
38
- jest.clearAllMocks();
39
- });
40
-
41
- describe('createDb', () => {
42
- it('should create database when user is an admin', async () => {
43
- queryMock.mockResolvedValueOnce(undefined);
44
-
45
- await createDb(options, config);
46
-
47
- expect(queryMock.mock.calls).toEqual([
48
- [`CREATE DATABASE "dbname" OWNER "user"`],
49
- ]);
50
- expect(logMock.mock.calls).toEqual([
51
- [`Database dbname successfully created`],
52
- ]);
53
- expect(createSchemaMigrations).toHaveBeenCalled();
54
- });
55
-
56
- it('should create databases for each provided option', async () => {
57
- queryMock.mockResolvedValue(undefined);
58
-
59
- await createDb(
60
- [options, { ...options, database: 'dbname-test' }],
61
- config,
62
- );
63
-
64
- expect(queryMock.mock.calls).toEqual([
65
- [`CREATE DATABASE "dbname" OWNER "user"`],
66
- [`CREATE DATABASE "dbname-test" OWNER "user"`],
67
- ]);
68
- expect(logMock.mock.calls).toEqual([
69
- [`Database dbname successfully created`],
70
- [`Database dbname-test successfully created`],
71
- ]);
72
- expect(createSchemaMigrations).toHaveBeenCalledTimes(2);
73
- });
74
-
75
- it('should inform if database already exists', async () => {
76
- queryMock.mockRejectedValueOnce({ code: '42P04' });
77
-
78
- await createDb(options, config);
79
-
80
- expect(queryMock.mock.calls).toEqual([
81
- [`CREATE DATABASE "dbname" OWNER "user"`],
82
- ]);
83
- expect(logMock.mock.calls).toEqual([[`Database dbname already exists`]]);
84
- expect(createSchemaMigrations).toHaveBeenCalled();
85
- });
86
-
87
- it('should inform if ssl is required', async () => {
88
- queryMock.mockRejectedValueOnce({
89
- code: 'XX000',
90
- message: 'sslmode=require',
91
- });
92
-
93
- await createDb(options, config);
94
-
95
- expect(queryMock.mock.calls).toEqual([
96
- [`CREATE DATABASE "dbname" OWNER "user"`],
97
- ]);
98
- expect(logMock.mock.calls).toEqual([
99
- ['SSL is required: append ?ssl=true to the database url string'],
100
- ]);
101
- expect(createSchemaMigrations).not.toHaveBeenCalled();
102
- });
103
-
104
- it('should ask and use admin credentials when cannot connect', async () => {
105
- queryMock.mockRejectedValueOnce({ code: '42501' });
106
-
107
- await createDb(options, config);
108
-
109
- expect(setAdminCredentialsToOptions).toHaveBeenCalled();
110
- expect(queryMock.mock.calls).toEqual([
111
- [`CREATE DATABASE "dbname" OWNER "user"`],
112
- [`CREATE DATABASE "dbname" OWNER "user"`],
113
- ]);
114
- expect(logMock.mock.calls).toEqual([
115
- [
116
- `Permission denied to create database.\nDon't use this command for database service providers, only for a local db.`,
117
- ],
118
- [`Database dbname successfully created`],
119
- ]);
120
- expect(createSchemaMigrations).toHaveBeenCalled();
121
- });
122
- });
123
-
124
- describe('dropDb', () => {
125
- it('should drop database when user is an admin', async () => {
126
- queryMock.mockResolvedValueOnce(undefined);
127
-
128
- await dropDb(options);
129
-
130
- expect(queryMock.mock.calls).toEqual([[`DROP DATABASE "dbname"`]]);
131
- expect(logMock.mock.calls).toEqual([
132
- [`Database dbname was successfully dropped`],
133
- ]);
134
- });
135
-
136
- it('should drop databases for each provided option', async () => {
137
- queryMock.mockResolvedValue(undefined);
138
-
139
- await dropDb([options, { ...options, database: 'dbname-test' }]);
140
-
141
- expect(queryMock.mock.calls).toEqual([
142
- [`DROP DATABASE "dbname"`],
143
- [`DROP DATABASE "dbname-test"`],
144
- ]);
145
- expect(logMock.mock.calls).toEqual([
146
- [`Database dbname was successfully dropped`],
147
- [`Database dbname-test was successfully dropped`],
148
- ]);
149
- });
150
-
151
- it('should inform if database does not exist', async () => {
152
- queryMock.mockRejectedValueOnce({ code: '3D000' });
153
-
154
- await dropDb(options);
155
-
156
- expect(queryMock.mock.calls).toEqual([[`DROP DATABASE "dbname"`]]);
157
- expect(logMock.mock.calls).toEqual([[`Database dbname does not exist`]]);
158
- });
159
-
160
- it('should inform if ssl is required', async () => {
161
- queryMock.mockRejectedValueOnce({
162
- code: 'XX000',
163
- message: 'sslmode=require',
164
- });
165
-
166
- await createDb(options, config);
167
-
168
- expect(queryMock.mock.calls).toEqual([
169
- [`CREATE DATABASE "dbname" OWNER "user"`],
170
- ]);
171
- expect(logMock.mock.calls).toEqual([
172
- ['SSL is required: append ?ssl=true to the database url string'],
173
- ]);
174
- expect(createSchemaMigrations).not.toHaveBeenCalled();
175
- });
176
-
177
- it('should ask and use admin credentials when cannot connect', async () => {
178
- queryMock.mockRejectedValueOnce({ code: '42501' });
179
-
180
- await dropDb(options);
181
-
182
- expect(setAdminCredentialsToOptions).toHaveBeenCalled();
183
- expect(queryMock.mock.calls).toEqual([
184
- [`DROP DATABASE "dbname"`],
185
- [`DROP DATABASE "dbname"`],
186
- ]);
187
- expect(logMock.mock.calls).toEqual([
188
- [
189
- `Permission denied to drop database.\nDon't use this command for database service providers, only for a local db.`,
190
- ],
191
- [`Database dbname was successfully dropped`],
192
- ]);
193
- });
194
- });
195
-
196
- describe('reset', () => {
197
- it('should drop and create database', async () => {
198
- queryMock.mockResolvedValue(undefined);
199
-
200
- await resetDb(options, config);
201
-
202
- expect(queryMock.mock.calls).toEqual([
203
- [`DROP DATABASE "dbname"`],
204
- [`CREATE DATABASE "dbname" OWNER "user"`],
205
- ]);
206
- expect(logMock.mock.calls).toEqual([
207
- [`Database dbname was successfully dropped`],
208
- [`Database dbname successfully created`],
209
- ]);
210
- expect(createSchemaMigrations).toHaveBeenCalled();
211
- expect(migrate).toBeCalled();
212
- });
213
- });
214
- });
@@ -1,151 +0,0 @@
1
- import { Adapter, AdapterOptions, MaybeArray, toArray } from 'pqb';
2
- import {
3
- getDatabaseAndUserFromOptions,
4
- setAdminCredentialsToOptions,
5
- setAdapterOptions,
6
- createSchemaMigrations,
7
- RakeDbConfig,
8
- migrationConfigDefaults,
9
- } from '../common';
10
- import { migrate } from './migrateOrRollback';
11
-
12
- const execute = async (
13
- options: AdapterOptions,
14
- sql: string,
15
- ): Promise<
16
- 'ok' | 'already' | 'forbidden' | 'ssl required' | { error: unknown }
17
- > => {
18
- const db = new Adapter(options);
19
-
20
- try {
21
- await db.query(sql);
22
- return 'ok';
23
- } catch (error) {
24
- const err = error as Record<string, unknown>;
25
-
26
- if (
27
- typeof err.message === 'string' &&
28
- err.message.includes('sslmode=require')
29
- ) {
30
- return 'ssl required';
31
- }
32
-
33
- if (err.code === '42P04' || err.code === '3D000') {
34
- return 'already';
35
- } else if (
36
- err.code === '42501' ||
37
- (typeof err.message === 'string' &&
38
- err.message.includes('password authentication failed'))
39
- ) {
40
- return 'forbidden';
41
- } else {
42
- return { error };
43
- }
44
- } finally {
45
- await db.close();
46
- }
47
- };
48
-
49
- const createOrDrop = async (
50
- options: AdapterOptions,
51
- adminOptions: AdapterOptions,
52
- config: Pick<RakeDbConfig, 'migrationsTable'>,
53
- args: {
54
- sql(params: { database: string; user: string }): string;
55
- successMessage(params: { database: string }): string;
56
- alreadyMessage(params: { database: string }): string;
57
- create?: boolean;
58
- },
59
- ) => {
60
- const params = getDatabaseAndUserFromOptions(options);
61
-
62
- const result = await execute(
63
- setAdapterOptions(adminOptions, { database: 'postgres' }),
64
- args.sql(params),
65
- );
66
- if (result === 'ok') {
67
- console.log(args.successMessage(params));
68
- } else if (result === 'already') {
69
- console.log(args.alreadyMessage(params));
70
- } else if (result === 'ssl required') {
71
- console.log('SSL is required: append ?ssl=true to the database url string');
72
- return;
73
- } else if (result === 'forbidden') {
74
- let message = `Permission denied to ${
75
- args.create ? 'create' : 'drop'
76
- } database.`;
77
-
78
- const host = adminOptions.databaseURL
79
- ? new URL(adminOptions.databaseURL).hostname
80
- : adminOptions.host;
81
-
82
- const isLocal = host === 'localhost';
83
- if (!isLocal) {
84
- message += `\nDon't use this command for database service providers, only for a local db.`;
85
- }
86
-
87
- console.log(message);
88
-
89
- const updatedOptions = await setAdminCredentialsToOptions(
90
- options,
91
- args.create,
92
- );
93
- if (!updatedOptions) return;
94
-
95
- await createOrDrop(options, updatedOptions, config, args);
96
- return;
97
- } else {
98
- throw result.error;
99
- }
100
-
101
- if (!args.create) return;
102
-
103
- const db = new Adapter(options);
104
- await createSchemaMigrations(db, config);
105
- await db.close();
106
- };
107
-
108
- export const createDb = async (
109
- arg: MaybeArray<AdapterOptions>,
110
- config: RakeDbConfig,
111
- ) => {
112
- for (const options of toArray(arg)) {
113
- await createOrDrop(options, options, config, {
114
- sql({ database, user }) {
115
- return `CREATE DATABASE "${database}" OWNER "${user}"`;
116
- },
117
- successMessage({ database }) {
118
- return `Database ${database} successfully created`;
119
- },
120
- alreadyMessage({ database }) {
121
- return `Database ${database} already exists`;
122
- },
123
- create: true,
124
- });
125
- }
126
- };
127
-
128
- export const dropDb = async (arg: MaybeArray<AdapterOptions>) => {
129
- for (const options of toArray(arg)) {
130
- await createOrDrop(options, options, migrationConfigDefaults, {
131
- sql({ database }) {
132
- return `DROP DATABASE "${database}"`;
133
- },
134
- successMessage({ database }) {
135
- return `Database ${database} was successfully dropped`;
136
- },
137
- alreadyMessage({ database }) {
138
- return `Database ${database} does not exist`;
139
- },
140
- });
141
- }
142
- };
143
-
144
- export const resetDb = async (
145
- arg: MaybeArray<AdapterOptions>,
146
- config: RakeDbConfig,
147
- ) => {
148
- await dropDb(arg);
149
- await createDb(arg, config);
150
- await migrate(arg, config);
151
- };
@@ -1,136 +0,0 @@
1
- import { generate } from './generate';
2
- import { migrationConfigDefaults, RakeDbConfig } from '../common';
3
- import { mkdir, writeFile } from 'fs/promises';
4
- import path from 'path';
5
-
6
- jest.mock('fs/promises', () => ({
7
- mkdir: jest.fn(),
8
- writeFile: jest.fn(),
9
- }));
10
-
11
- const logMock = jest.fn();
12
- console.log = logMock;
13
-
14
- const migrationsPath = migrationConfigDefaults.migrationsPath;
15
-
16
- const config: RakeDbConfig = {
17
- ...migrationConfigDefaults,
18
- basePath: __dirname,
19
- };
20
-
21
- const testGenerate = async (args: string[], content: string) => {
22
- const name = args[0];
23
- await generate(config, args);
24
-
25
- expect(mkdir).toHaveBeenCalledWith(migrationsPath, { recursive: true });
26
-
27
- const filePath = path.resolve(migrationsPath, `20000101000000_${name}.ts`);
28
- expect(writeFile).toHaveBeenCalledWith(filePath, content);
29
-
30
- expect(logMock.mock.calls).toEqual([[`Created ${filePath}`]]);
31
- };
32
-
33
- describe('generate', () => {
34
- beforeEach(() => {
35
- jest.useFakeTimers().setSystemTime(new Date(2000, 0, 1, 0, 0, 0));
36
- jest.clearAllMocks();
37
- });
38
-
39
- it('should throw if migration name is not provided', async () => {
40
- expect(generate(config, [])).rejects.toThrow('Migration name is missing');
41
- });
42
-
43
- it('should create a file for create table migration', async () => {
44
- await testGenerate(
45
- ['createTable', 'id:integer.primaryKey', 'name:varchar(20).nullable'],
46
- `import { change } from 'rake-db';
47
-
48
- change(async (db) => {
49
- await db.createTable('table', (t) => ({
50
- id: t.integer().primaryKey(),
51
- name: t.varchar(20).nullable(),
52
- }));
53
- });
54
- `,
55
- );
56
- });
57
-
58
- it('should create a file for change migration', async () => {
59
- await testGenerate(
60
- ['changeTable'],
61
- `import { change } from 'rake-db';
62
-
63
- change(async (db) => {
64
- await db.changeTable('table', (t) => ({
65
- }));
66
- });
67
- `,
68
- );
69
- });
70
-
71
- it('should create a file for add columns migration', async () => {
72
- await testGenerate(
73
- ['addColumns'],
74
- `import { change } from 'rake-db';
75
-
76
- change(async (db) => {
77
- await db.changeTable(tableName, (t) => ({
78
- }));
79
- });
80
- `,
81
- );
82
- });
83
-
84
- it('should create a file for add columns migration with table', async () => {
85
- await testGenerate(
86
- [
87
- 'addColumnsToTable',
88
- 'id:integer.primaryKey',
89
- 'name:varchar(20).nullable',
90
- ],
91
- `import { change } from 'rake-db';
92
-
93
- change(async (db) => {
94
- await db.changeTable('table', (t) => ({
95
- id: t.add(t.integer().primaryKey()),
96
- name: t.add(t.varchar(20).nullable()),
97
- }));
98
- });
99
- `,
100
- );
101
- });
102
-
103
- it('should create a file for remove columns migration with table', async () => {
104
- await testGenerate(
105
- [
106
- 'removeColumnsFromTable',
107
- 'id:integer.primaryKey',
108
- 'name:varchar(20).nullable',
109
- ],
110
- `import { change } from 'rake-db';
111
-
112
- change(async (db) => {
113
- await db.changeTable('table', (t) => ({
114
- id: t.remove(t.integer().primaryKey()),
115
- name: t.remove(t.varchar(20).nullable()),
116
- }));
117
- });
118
- `,
119
- );
120
- });
121
-
122
- it('should create a file for drop table migration', async () => {
123
- await testGenerate(
124
- ['dropTable', 'id:integer.primaryKey', 'name:varchar(20).nullable'],
125
- `import { change } from 'rake-db';
126
-
127
- change(async (db) => {
128
- await db.dropTable('table', (t) => ({
129
- id: t.integer().primaryKey(),
130
- name: t.varchar(20).nullable(),
131
- }));
132
- });
133
- `,
134
- );
135
- });
136
- });