rake-db 1.3.2 → 2.0.0

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 (72) hide show
  1. package/.env +3 -0
  2. package/.env.local +1 -0
  3. package/README.md +1 -545
  4. package/db.ts +16 -0
  5. package/dist/index.d.ts +94 -0
  6. package/dist/index.esm.js +190 -0
  7. package/dist/index.esm.js.map +1 -0
  8. package/dist/index.js +201 -0
  9. package/dist/index.js.map +1 -0
  10. package/jest-setup.ts +3 -0
  11. package/migrations/20221009210157_first.ts +8 -0
  12. package/migrations/20221009210200_second.ts +5 -0
  13. package/package.json +55 -41
  14. package/rollup.config.js +3 -0
  15. package/src/commands/createOrDrop.test.ts +145 -0
  16. package/src/commands/createOrDrop.ts +107 -0
  17. package/src/commands/generate.test.ts +133 -0
  18. package/src/commands/generate.ts +85 -0
  19. package/src/commands/migrateOrRollback.test.ts +118 -0
  20. package/src/commands/migrateOrRollback.ts +108 -0
  21. package/src/common.test.ts +281 -0
  22. package/src/common.ts +224 -0
  23. package/src/index.ts +2 -0
  24. package/src/migration/change.ts +20 -0
  25. package/src/migration/changeTable.test.ts +417 -0
  26. package/src/migration/changeTable.ts +375 -0
  27. package/src/migration/createTable.test.ts +269 -0
  28. package/src/migration/createTable.ts +169 -0
  29. package/src/migration/migration.test.ts +341 -0
  30. package/src/migration/migration.ts +296 -0
  31. package/src/migration/migrationUtils.ts +281 -0
  32. package/src/rakeDb.ts +29 -0
  33. package/src/test-utils.ts +45 -0
  34. package/tsconfig.json +12 -0
  35. package/dist/lib/createAndDrop.d.ts +0 -2
  36. package/dist/lib/createAndDrop.js +0 -63
  37. package/dist/lib/defaults.d.ts +0 -2
  38. package/dist/lib/defaults.js +0 -5
  39. package/dist/lib/errorCodes.d.ts +0 -4
  40. package/dist/lib/errorCodes.js +0 -7
  41. package/dist/lib/generate.d.ts +0 -1
  42. package/dist/lib/generate.js +0 -99
  43. package/dist/lib/help.d.ts +0 -2
  44. package/dist/lib/help.js +0 -24
  45. package/dist/lib/init.d.ts +0 -2
  46. package/dist/lib/init.js +0 -276
  47. package/dist/lib/migrate.d.ts +0 -4
  48. package/dist/lib/migrate.js +0 -189
  49. package/dist/lib/migration.d.ts +0 -37
  50. package/dist/lib/migration.js +0 -159
  51. package/dist/lib/schema/changeTable.d.ts +0 -23
  52. package/dist/lib/schema/changeTable.js +0 -109
  53. package/dist/lib/schema/column.d.ts +0 -31
  54. package/dist/lib/schema/column.js +0 -201
  55. package/dist/lib/schema/createTable.d.ts +0 -10
  56. package/dist/lib/schema/createTable.js +0 -53
  57. package/dist/lib/schema/foreignKey.d.ts +0 -11
  58. package/dist/lib/schema/foreignKey.js +0 -53
  59. package/dist/lib/schema/index.d.ts +0 -3
  60. package/dist/lib/schema/index.js +0 -54
  61. package/dist/lib/schema/primaryKey.d.ts +0 -9
  62. package/dist/lib/schema/primaryKey.js +0 -24
  63. package/dist/lib/schema/table.d.ts +0 -43
  64. package/dist/lib/schema/table.js +0 -110
  65. package/dist/lib/schema/timestamps.d.ts +0 -3
  66. package/dist/lib/schema/timestamps.js +0 -9
  67. package/dist/lib/utils.d.ts +0 -26
  68. package/dist/lib/utils.js +0 -114
  69. package/dist/rake-db.d.ts +0 -2
  70. package/dist/rake-db.js +0 -34
  71. package/dist/types.d.ts +0 -94
  72. package/dist/types.js +0 -40
@@ -1,63 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dropDb = exports.createDb = void 0;
4
- const utils_1 = require("./utils");
5
- const pg_adapter_1 = require("pg-adapter");
6
- const createOrDropDatabase = async ({ sql, successMessage, alreadyMessage, createVersionsTable, }, creds, adminCreds) => {
7
- const db = new pg_adapter_1.Adapter(adminCreds);
8
- await db.connect();
9
- try {
10
- await db.exec(sql);
11
- console.log(successMessage);
12
- }
13
- catch (err) {
14
- if (err.code === '42P04' || err.code === '3D000') {
15
- console.log(alreadyMessage);
16
- }
17
- else if (err.code === '42501') {
18
- Object.assign(adminCreds, await utils_1.askAdminCreds());
19
- await createOrDropDatabase({ sql, successMessage, alreadyMessage, createVersionsTable }, creds, adminCreds);
20
- return;
21
- }
22
- else {
23
- throw err;
24
- }
25
- }
26
- finally {
27
- await db.close();
28
- }
29
- if (!createVersionsTable)
30
- return;
31
- const targetDb = new pg_adapter_1.Adapter(creds);
32
- await utils_1.createSchemaMigrations(targetDb);
33
- await targetDb.close();
34
- };
35
- const createOrDrop = async ({ sql, successMessage, alreadyMessage, createVersionsTable, }) => {
36
- const { configs } = utils_1.getConfig();
37
- const adminCreds = { ...configs[0], database: 'postgres' };
38
- for (const config of configs) {
39
- await createOrDropDatabase({
40
- sql: sql(config),
41
- successMessage: successMessage(config),
42
- alreadyMessage: alreadyMessage(config),
43
- createVersionsTable,
44
- }, config, adminCreds);
45
- }
46
- };
47
- const createDb = () => {
48
- createOrDrop({
49
- sql: ({ database, user }) => `CREATE DATABASE "${database}" OWNER "${user}"`,
50
- successMessage: ({ database }) => `Database ${database} successfully created`,
51
- alreadyMessage: ({ database }) => `Database ${database} already exists`,
52
- createVersionsTable: true,
53
- });
54
- };
55
- exports.createDb = createDb;
56
- const dropDb = () => {
57
- createOrDrop({
58
- sql: ({ database }) => `DROP DATABASE "${database}"`,
59
- successMessage: ({ database }) => `Database ${database} successfully dropped`,
60
- alreadyMessage: ({ database }) => `Database ${database} does not exist`,
61
- });
62
- };
63
- exports.dropDb = dropDb;
@@ -1,2 +0,0 @@
1
- export declare const defaultMigrationsPath = "migrations";
2
- export declare const defaultCamelCase = false;
@@ -1,5 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defaultCamelCase = exports.defaultMigrationsPath = void 0;
4
- exports.defaultMigrationsPath = 'migrations';
5
- exports.defaultCamelCase = false;
@@ -1,4 +0,0 @@
1
- export declare const errorCodes: {
2
- '3D000': string;
3
- '42P01': string;
4
- };
@@ -1,7 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.errorCodes = void 0;
4
- exports.errorCodes = {
5
- '3D000': 'invalid_catalog_name',
6
- '42P01': 'undefined_table',
7
- };
@@ -1 +0,0 @@
1
- export declare const generate: (name: string, ...fields: string[]) => Promise<void>;
@@ -1,99 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
- Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.generate = void 0;
23
- const fs = __importStar(require("fs"));
24
- const path = __importStar(require("path"));
25
- const utils_1 = require("./utils");
26
- const generateFileContent = (name, args) => {
27
- const lines = [
28
- "import { Migration } from 'rake-db'\n\nexport const change = (db: Migration, up: boolean) => {",
29
- ];
30
- let command = undefined;
31
- if (name.startsWith('create_'))
32
- command = 'create';
33
- else if (name.startsWith('change_'))
34
- command = 'change';
35
- else if (name.startsWith('add_'))
36
- command = 'add';
37
- else if (name.startsWith('remove_'))
38
- command = 'remove';
39
- else if (name.startsWith('drop_'))
40
- command = 'drop';
41
- if (command) {
42
- name = name.slice(command.length + 1);
43
- const hasColumns = command === 'drop' && args.find((arg) => arg.indexOf(':') !== -1);
44
- if (command === 'create') {
45
- lines.push(` db.createTable('${name}', (t) => {`);
46
- }
47
- else if (command === 'drop') {
48
- lines.push(` db.dropTable(${name}${hasColumns ? '(t) => {' : ')'}`);
49
- }
50
- else {
51
- lines.push(` db.changeTable('${name}', (t) => {`);
52
- }
53
- args.forEach((pair) => {
54
- if (pair.indexOf(':') !== -1) {
55
- const [column, type] = pair.split(':');
56
- if (command === 'create' || command === 'add') {
57
- lines.push(` t.${type}('${column}')`);
58
- }
59
- else if (command === 'change') {
60
- lines.push(` t.change('${column}', up ? {type: '${type}'} : {?})`);
61
- }
62
- else if (command === 'remove') {
63
- lines.push(` t.drop('${column}', {type: '${type}'})`);
64
- }
65
- }
66
- });
67
- if (command === 'create')
68
- lines.push(` t.timestamps()`);
69
- if (command !== 'drop' || hasColumns)
70
- lines.push(` })`);
71
- }
72
- lines.push('}', '');
73
- return lines.join('\n');
74
- };
75
- const createMigrationFile = (name, content, migrationsPath) => {
76
- const now = new Date();
77
- const prefix = [
78
- now.getUTCFullYear(),
79
- now.getUTCMonth() + 1,
80
- now.getUTCDate(),
81
- now.getUTCHours(),
82
- now.getUTCMinutes(),
83
- now.getUTCSeconds(),
84
- ]
85
- .map((value) => (value < 10 ? `0${value}` : value))
86
- .join('');
87
- const filePath = path.resolve(migrationsPath, `${prefix}_${name}.ts`);
88
- fs.writeFileSync(filePath, content);
89
- console.log(`Created ${filePath}`);
90
- };
91
- const generate = async (name, ...fields) => {
92
- if (!name)
93
- throw new Error('Please provide migration name');
94
- const { migrationsPath } = utils_1.getConfig();
95
- utils_1.mkdirRecursive(migrationsPath);
96
- const content = generateFileContent(name, fields);
97
- await createMigrationFile(name, content, migrationsPath);
98
- };
99
- exports.generate = generate;
@@ -1,2 +0,0 @@
1
- declare const _default: () => void;
2
- export default _default;
package/dist/lib/help.js DELETED
@@ -1,24 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = () => console.log(`Usage: rake-db [command] [arguments]
4
-
5
- Commands:
6
- init creates migrations directory, sets up env config, creates databases
7
- create creates databases
8
- drop drops databases
9
- g, generate generates migration file, see below
10
- migrate migrate all pending migrations in all databases
11
- rollback rollback the last migrated in all databases
12
- no or unknown prints this message
13
-
14
- Generate arguments:
15
- - (required) first argument is migration name
16
- * create_* template for create table
17
- * change_* template for change table
18
- * add_* template for add columns
19
- * remove_* template for remove columns
20
- * drop_* template for drop table
21
-
22
- - other arguments considered as columns with types:
23
- rake-db g create_table name:text createdAt:date
24
- `);
@@ -1,2 +0,0 @@
1
- declare const _default: () => Promise<void>;
2
- export default _default;
package/dist/lib/init.js DELETED
@@ -1,276 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
- Object.defineProperty(exports, "__esModule", { value: true });
22
- const fs = __importStar(require("fs"));
23
- const path = __importStar(require("path"));
24
- const pg_adapter_1 = require("pg-adapter");
25
- const dotenv_1 = require("dotenv");
26
- const utils_1 = require("./utils");
27
- const { Snippet, Confirm, Input, Select } = require('enquirer');
28
- const checkEnv = () => {
29
- let envExists = false;
30
- try {
31
- const stat = fs.statSync(`${process.cwd()}/.env`);
32
- if (!stat.isFile()) {
33
- if (stat.isDirectory()) {
34
- throw new Error("Found .env, but it's a directory, fix it please");
35
- }
36
- else {
37
- throw new Error("Found .env, but not a file, it's something unusual, please fix it");
38
- }
39
- }
40
- console.log('Found .env file');
41
- envExists = true;
42
- }
43
- catch (err) {
44
- if (err.code !== 'ENOENT') {
45
- console.error('Some problem with .env file');
46
- throw err;
47
- }
48
- }
49
- return envExists;
50
- };
51
- const askDatabaseCreds = async ({ database, user, password, host, port }, adminCreds) => {
52
- const credsPrompt = new Snippet({
53
- message: 'Enter database credentials',
54
- fields: [
55
- {
56
- name: 'database',
57
- required: true,
58
- },
59
- {
60
- name: 'user',
61
- required: true,
62
- },
63
- {
64
- name: 'password',
65
- required: false,
66
- },
67
- {
68
- name: 'host',
69
- required: true,
70
- },
71
- {
72
- name: 'port',
73
- required: true,
74
- },
75
- ],
76
- values: {
77
- database,
78
- user,
79
- password,
80
- host,
81
- port: String(port),
82
- },
83
- template: 'Database name: {{database}}\nUser: {{user}}\nPassword: {{password}}\nHost: {{host}}\nPort: {{port}}',
84
- });
85
- const { values } = await credsPrompt.run();
86
- if (!values.password)
87
- values.password = '';
88
- return await tryDatabaseCreds(values, adminCreds);
89
- };
90
- const tryDatabaseCreds = async (creds, adminCreds) => {
91
- const db = new pg_adapter_1.Adapter(creds);
92
- try {
93
- await db.connect();
94
- await db.close();
95
- }
96
- catch (err) {
97
- console.log(`Error: ${err.message}`);
98
- const choices = [
99
- 'Edit config',
100
- `Create database with owner ${creds.user}`,
101
- `Create both user and database`,
102
- `Create a user ${creds.user}`,
103
- ];
104
- const prompt = new Select({
105
- message: 'How can I help?',
106
- choices: [...choices],
107
- });
108
- const answer = await prompt.run();
109
- const index = choices.indexOf(answer);
110
- if (index === 0)
111
- return await askDatabaseCreds(creds, adminCreds);
112
- else if (index === 1)
113
- await createDatabase(creds, adminCreds);
114
- else if (index === 2) {
115
- await createUser(creds, adminCreds);
116
- await createDatabase(creds, adminCreds);
117
- }
118
- else if (index === 3)
119
- await createUser(creds, adminCreds);
120
- return await tryDatabaseCreds(creds, adminCreds);
121
- }
122
- return creds;
123
- };
124
- const askCamelCase = () => new Confirm({
125
- message: 'Should it use camelCase for tables and columns names?',
126
- initial: process.env.DATABASE_CAMEL_CASE === 'true' ? 'y' : 'n',
127
- }).run();
128
- const askTestDb = async (creds, adminCreds) => {
129
- const prompt = new Confirm({
130
- message: 'Do you also want to have database for tests?',
131
- });
132
- if (!(await prompt.run()))
133
- return;
134
- return await askDatabaseCreds({
135
- ...creds,
136
- database: `${creds.database}-test`,
137
- }, adminCreds);
138
- };
139
- const createMigrationsPath = async () => {
140
- const prompt = new Input({
141
- message: 'Where to store migrations files?',
142
- initial: process.env.MIGRATIONS_PATH || `db${path.sep}migrate`,
143
- });
144
- const migrationsPath = await prompt.run();
145
- utils_1.mkdirRecursive(migrationsPath);
146
- return migrationsPath;
147
- };
148
- const createDatabase = async (creds, adminCreds) => {
149
- const db = await adminDatabase(adminCreds);
150
- try {
151
- await db.exec(`CREATE DATABASE "${creds.database}" OWNER "${creds.user}"`);
152
- await db.close();
153
- }
154
- catch (err) {
155
- console.error(`Error: ${err.message}`);
156
- adminCreds.asked = false;
157
- }
158
- };
159
- const createUser = async (creds, adminCreds) => {
160
- const { user } = creds;
161
- const db = await adminDatabase(adminCreds);
162
- const superUserPrompt = new Confirm({
163
- message: `Do you want ${user} to be a "superuser"?`,
164
- });
165
- const isSuperUser = await superUserPrompt.run();
166
- try {
167
- await db.exec(`CREATE ROLE "${user}" ${isSuperUser ? 'SUPERUSER' : 'LOGIN'}`);
168
- await db.close();
169
- }
170
- catch (err) {
171
- await db.close();
172
- console.error(`Error: ${err.message}`);
173
- adminCreds.asked = false;
174
- await createUser(creds, adminCreds);
175
- }
176
- };
177
- const adminDatabase = async (creds) => {
178
- if (!creds.asked) {
179
- Object.assign(creds, await utils_1.askAdminCreds(creds));
180
- creds.asked = true;
181
- }
182
- try {
183
- const db = new pg_adapter_1.Adapter(creds);
184
- await db.connect();
185
- return db;
186
- }
187
- catch (err) {
188
- console.log(`Error: ${err.message}`);
189
- creds.asked = false;
190
- return await adminDatabase(creds);
191
- }
192
- };
193
- const createDatabaseURL = (creds) => `postgres://${creds.user}:${creds.password}@${creds.host}:${creds.port}/${creds.database}`;
194
- const makeEnvData = (creds, camelCase, migrationsPath, testDbCreds) => {
195
- const data = [['DATABASE_URL', createDatabaseURL(creds)]];
196
- const dbs = ['DATABASE_URL'];
197
- if (testDbCreds) {
198
- data.push(['DATABASE_URL_TEST', createDatabaseURL(testDbCreds)]);
199
- dbs.push('DATABASE_URL_TEST');
200
- }
201
- data.push(['DATABASE_CAMEL_CASE', camelCase ? 'true' : 'false']);
202
- data.push(['MIGRATIONS_PATH', migrationsPath]);
203
- data.push(['DATABASES', dbs.join(',')]);
204
- return data;
205
- };
206
- exports.default = async () => {
207
- const envExists = checkEnv();
208
- if (envExists)
209
- dotenv_1.config();
210
- let initialCreds = undefined;
211
- if (process.env.DATABASE_URL)
212
- try {
213
- initialCreds = pg_adapter_1.parseUrl(process.env.DATABASE_URL);
214
- }
215
- catch (err) {
216
- // noop
217
- }
218
- if (!initialCreds) {
219
- const cwdArray = process.cwd().split(path.sep);
220
- const defaultName = cwdArray[cwdArray.length - 1];
221
- initialCreds = {
222
- database: defaultName,
223
- user: process.env.USER || '',
224
- password: '',
225
- host: 'localhost',
226
- port: 5432,
227
- };
228
- }
229
- const adminCreds = {
230
- ...initialCreds,
231
- database: 'postgres',
232
- user: 'postgres',
233
- asked: false,
234
- };
235
- const creds = await askDatabaseCreds(initialCreds, adminCreds);
236
- const initialTestDbCreds = creds;
237
- if (process.env.DATABASE_URL_TEST) {
238
- try {
239
- const parsed = pg_adapter_1.parseUrl(process.env.DATABASE_URL_TEST);
240
- if (parsed.database)
241
- initialTestDbCreds.database = parsed.database;
242
- }
243
- catch (err) {
244
- // noop
245
- }
246
- }
247
- const testDbCreds = await askTestDb(initialTestDbCreds, adminCreds);
248
- const camelCase = await askCamelCase();
249
- const migrationsPath = await createMigrationsPath();
250
- const data = makeEnvData(creds, camelCase, migrationsPath, testDbCreds);
251
- const envPath = path.resolve(process.cwd(), '.env');
252
- let content;
253
- try {
254
- content = fs.readFileSync(envPath, 'utf-8');
255
- data.forEach(([key, value]) => {
256
- let found = false;
257
- content = content.replace(new RegExp(`(\n*)s*${key}*=[^\n]*`), (_, newLine) => {
258
- found = true;
259
- return `${newLine}${key}=${value}`;
260
- });
261
- if (!found)
262
- content = `${content}${content.length ? '\n' : ''}${key}=${value}`;
263
- });
264
- }
265
- catch (err) {
266
- if (err.code === 'ENOENT') {
267
- content = data.map((pair) => pair.join('=')).join('\n');
268
- }
269
- else {
270
- console.log(`Error while accessing the .env file`);
271
- throw err;
272
- }
273
- }
274
- fs.writeFileSync(envPath, content);
275
- console.log("Setup's ready!");
276
- };
@@ -1,4 +0,0 @@
1
- import Migration from './migration';
2
- export declare const run: (db: Migration, fn: (t: Migration, up: boolean) => void | Promise<void>, version: string) => Promise<void>;
3
- export declare const migrate: () => Promise<void>;
4
- export declare const rollback: () => Promise<void>;