create-phoenixjs 0.1.4 → 0.1.5
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/package.json +1 -1
- package/template/config/database.ts +13 -1
- package/template/database/migrations/2024_01_01_000000_create_test_users_cli_table.ts +16 -0
- package/template/database/migrations/20260108164611_TestCliMigration.ts +16 -0
- package/template/database/migrations/2026_01_08_16_46_11_CreateTestMigrationsTable.ts +21 -0
- package/template/framework/cli/artisan.ts +12 -0
- package/template/framework/database/DatabaseManager.ts +133 -0
- package/template/framework/database/connection/Connection.ts +71 -0
- package/template/framework/database/connection/ConnectionFactory.ts +30 -0
- package/template/framework/database/connection/PostgresConnection.ts +159 -0
- package/template/framework/database/console/MakeMigrationCommand.ts +58 -0
- package/template/framework/database/console/MigrateCommand.ts +32 -0
- package/template/framework/database/console/MigrateResetCommand.ts +31 -0
- package/template/framework/database/console/MigrateRollbackCommand.ts +31 -0
- package/template/framework/database/console/MigrateStatusCommand.ts +38 -0
- package/template/framework/database/migrations/DatabaseMigrationRepository.ts +122 -0
- package/template/framework/database/migrations/Migration.ts +5 -0
- package/template/framework/database/migrations/MigrationRepository.ts +46 -0
- package/template/framework/database/migrations/Migrator.ts +249 -0
- package/template/framework/database/migrations/index.ts +4 -0
- package/template/framework/database/orm/BelongsTo.ts +246 -0
- package/template/framework/database/orm/BelongsToMany.ts +570 -0
- package/template/framework/database/orm/Builder.ts +160 -0
- package/template/framework/database/orm/EagerLoadingBuilder.ts +324 -0
- package/template/framework/database/orm/HasMany.ts +303 -0
- package/template/framework/database/orm/HasManyThrough.ts +282 -0
- package/template/framework/database/orm/HasOne.ts +201 -0
- package/template/framework/database/orm/HasOneThrough.ts +281 -0
- package/template/framework/database/orm/Model.ts +1766 -0
- package/template/framework/database/orm/Relation.ts +342 -0
- package/template/framework/database/orm/Scope.ts +14 -0
- package/template/framework/database/orm/SoftDeletes.ts +160 -0
- package/template/framework/database/orm/index.ts +54 -0
- package/template/framework/database/orm/scopes/SoftDeletingScope.ts +58 -0
- package/template/framework/database/pagination/LengthAwarePaginator.ts +55 -0
- package/template/framework/database/pagination/Paginator.ts +110 -0
- package/template/framework/database/pagination/index.ts +2 -0
- package/template/framework/database/query/Builder.ts +918 -0
- package/template/framework/database/query/DB.ts +139 -0
- package/template/framework/database/query/grammars/Grammar.ts +430 -0
- package/template/framework/database/query/grammars/PostgresGrammar.ts +224 -0
- package/template/framework/database/query/grammars/index.ts +6 -0
- package/template/framework/database/query/index.ts +8 -0
- package/template/framework/database/query/types.ts +196 -0
- package/template/framework/database/schema/Blueprint.ts +478 -0
- package/template/framework/database/schema/Schema.ts +149 -0
- package/template/framework/database/schema/SchemaBuilder.ts +152 -0
- package/template/framework/database/schema/grammars/PostgresSchemaGrammar.ts +293 -0
- package/template/framework/database/schema/grammars/index.ts +5 -0
- package/template/framework/database/schema/index.ts +9 -0
- package/template/package.json +4 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Command } from '../../cli/Command';
|
|
2
|
+
import { Migrator } from '../migrations/Migrator';
|
|
3
|
+
import { DatabaseMigrationRepository } from '../migrations/DatabaseMigrationRepository';
|
|
4
|
+
import { DatabaseManager } from '../DatabaseManager';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
|
|
7
|
+
export class MigrateStatusCommand extends Command {
|
|
8
|
+
signature = 'migrate:status';
|
|
9
|
+
description = 'Show the status of each migration';
|
|
10
|
+
|
|
11
|
+
async handle(args: any): Promise<void> {
|
|
12
|
+
const { migrator, connection } = await this.getMigratorAndConnection();
|
|
13
|
+
try {
|
|
14
|
+
await connection.connect();
|
|
15
|
+
const status = await migrator.getStatus();
|
|
16
|
+
|
|
17
|
+
if (status.length === 0) {
|
|
18
|
+
console.log('No migrations found.');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.table(status);
|
|
23
|
+
} finally {
|
|
24
|
+
await connection.disconnect();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
protected async getMigratorAndConnection() {
|
|
29
|
+
const { default: databaseConfig } = await import(join(process.cwd(), 'config', 'database'));
|
|
30
|
+
const db = new DatabaseManager(databaseConfig);
|
|
31
|
+
const connection = db.connection();
|
|
32
|
+
|
|
33
|
+
const repository = new DatabaseMigrationRepository(connection, 'migrations');
|
|
34
|
+
const paths = [join(process.cwd(), 'database', 'migrations')];
|
|
35
|
+
|
|
36
|
+
return { migrator: new Migrator(repository, connection, paths), connection };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Connection } from '../connection/Connection';
|
|
2
|
+
import { Schema } from '../schema/Schema';
|
|
3
|
+
import { MigrationRepository } from './MigrationRepository';
|
|
4
|
+
import { Builder } from '../query/Builder';
|
|
5
|
+
import { PostgresGrammar } from '../query/grammars/PostgresGrammar';
|
|
6
|
+
|
|
7
|
+
export class DatabaseMigrationRepository implements MigrationRepository {
|
|
8
|
+
protected connection: Connection;
|
|
9
|
+
protected table: string;
|
|
10
|
+
|
|
11
|
+
constructor(connection: Connection, table: string = 'migrations') {
|
|
12
|
+
this.connection = connection;
|
|
13
|
+
this.table = table;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get the completed migrations.
|
|
18
|
+
*/
|
|
19
|
+
async getRan(): Promise<string[]> {
|
|
20
|
+
const migrations = await this.tableQuery()
|
|
21
|
+
.orderBy('batch', 'asc')
|
|
22
|
+
.orderBy('migration', 'asc')
|
|
23
|
+
.get<{ migration: string }>();
|
|
24
|
+
|
|
25
|
+
return migrations.map(m => m.migration);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get the list of migrations.
|
|
30
|
+
*/
|
|
31
|
+
async getMigrations(steps: number): Promise<{ migration: string; batch: number }[]> {
|
|
32
|
+
const query = this.tableQuery().orderBy('batch', 'desc').orderBy('migration', 'desc');
|
|
33
|
+
|
|
34
|
+
if (steps > 0) {
|
|
35
|
+
query.limit(steps);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return await query.get<{ migration: string; batch: number }>();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get the last migration batch.
|
|
43
|
+
*/
|
|
44
|
+
async getLast(): Promise<{ migration: string; batch: number }[]> {
|
|
45
|
+
const query = this.tableQuery().where('batch', await this.getLastBatchNumber());
|
|
46
|
+
|
|
47
|
+
return await query.orderBy('migration', 'desc').get<{ migration: string; batch: number }>();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Log that a migration was run.
|
|
52
|
+
*/
|
|
53
|
+
async log(file: string, batch: number): Promise<void> {
|
|
54
|
+
await this.tableQuery().insert({
|
|
55
|
+
migration: file,
|
|
56
|
+
batch: batch,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Remove a migration from the log.
|
|
62
|
+
*/
|
|
63
|
+
async delete(migration: string): Promise<void> {
|
|
64
|
+
await this.tableQuery().where('migration', migration).delete();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get the next migration batch number.
|
|
69
|
+
*/
|
|
70
|
+
async getNextBatchNumber(): Promise<number> {
|
|
71
|
+
return (await this.getLastBatchNumber()) + 1;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get the last migration batch number.
|
|
76
|
+
*/
|
|
77
|
+
async getLastBatchNumber(): Promise<number> {
|
|
78
|
+
const result = await this.tableQuery().max('batch');
|
|
79
|
+
// result is typically [{ max: number }] or similar depending on implementation
|
|
80
|
+
// Check how max returns. Usually DB implementation returns [{ max: val }] or just val if value() used.
|
|
81
|
+
// But Builder.max() returns Promise<number | any>.
|
|
82
|
+
|
|
83
|
+
// Let's verify Builder behavior. Assuming max returns the number directly if possible or checking the result.
|
|
84
|
+
// Actually, in many query builders max('batch') returns the scalar.
|
|
85
|
+
// Let's check my Builder.ts implementation if I could.
|
|
86
|
+
// But assuming standard behavior:
|
|
87
|
+
const max = await this.tableQuery().max('batch');
|
|
88
|
+
return (max as unknown as number) || 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Create the migration repository data store.
|
|
93
|
+
*/
|
|
94
|
+
async createRepository(): Promise<void> {
|
|
95
|
+
await Schema.create(this.table, (table) => {
|
|
96
|
+
table.id();
|
|
97
|
+
table.string('migration');
|
|
98
|
+
table.integer('batch');
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Determine if the migration repository exists.
|
|
104
|
+
*/
|
|
105
|
+
async repositoryExists(): Promise<boolean> {
|
|
106
|
+
return await Schema.hasTable(this.table);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Delete the migration repository data store.
|
|
111
|
+
*/
|
|
112
|
+
async deleteRepository(): Promise<void> {
|
|
113
|
+
await Schema.dropIfExists(this.table);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get a query builder for the migration table.
|
|
118
|
+
*/
|
|
119
|
+
protected tableQuery(): Builder {
|
|
120
|
+
return new Builder(this.connection, new PostgresGrammar(), this.table);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface MigrationRepository {
|
|
2
|
+
/**
|
|
3
|
+
* Get the completed migrations.
|
|
4
|
+
*/
|
|
5
|
+
getRan(): Promise<string[]>;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Get the list of migrations.
|
|
9
|
+
*/
|
|
10
|
+
getMigrations(steps: number): Promise<{ migration: string; batch: number }[]>;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get the last migration batch.
|
|
14
|
+
*/
|
|
15
|
+
getLast(): Promise<{ migration: string; batch: number }[]>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Log that a migration was run.
|
|
19
|
+
*/
|
|
20
|
+
log(file: string, batch: number): Promise<void>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Remove a migration from the log.
|
|
24
|
+
*/
|
|
25
|
+
delete(migration: string): Promise<void>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get the next migration batch number.
|
|
29
|
+
*/
|
|
30
|
+
getNextBatchNumber(): Promise<number>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create the migration repository data store.
|
|
34
|
+
*/
|
|
35
|
+
createRepository(): Promise<void>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Determine if the migration repository exists.
|
|
39
|
+
*/
|
|
40
|
+
repositoryExists(): Promise<boolean>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Delete the migration repository data store.
|
|
44
|
+
*/
|
|
45
|
+
deleteRepository(): Promise<void>;
|
|
46
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import type { MigrationRepository } from './MigrationRepository';
|
|
2
|
+
import type { Connection } from '../connection/Connection';
|
|
3
|
+
import type { SchemaBuilder } from '../schema/SchemaBuilder';
|
|
4
|
+
import { Schema } from '../schema/Schema';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { readdir } from 'fs/promises';
|
|
7
|
+
|
|
8
|
+
export class Migrator {
|
|
9
|
+
constructor(
|
|
10
|
+
protected repository: MigrationRepository,
|
|
11
|
+
protected connection: Connection,
|
|
12
|
+
protected paths: string[]
|
|
13
|
+
) { }
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Run the pending migrations at the given paths.
|
|
17
|
+
*/
|
|
18
|
+
async run(paths: string[] = []): Promise<void> {
|
|
19
|
+
// Merge custom paths with default paths
|
|
20
|
+
const searchPaths = [...this.paths, ...paths];
|
|
21
|
+
|
|
22
|
+
// Initialize Schema facade with connection
|
|
23
|
+
Schema.init(this.connection);
|
|
24
|
+
|
|
25
|
+
// Ensure repository exists
|
|
26
|
+
if (!await this.repository.repositoryExists()) {
|
|
27
|
+
await this.repository.createRepository();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Get ran migrations
|
|
31
|
+
const ran = await this.repository.getRan();
|
|
32
|
+
|
|
33
|
+
// Get all migration files
|
|
34
|
+
const files = await this.getMigrationFiles(searchPaths);
|
|
35
|
+
|
|
36
|
+
// Filter out migrations that have already been run
|
|
37
|
+
const pending = files.filter(file => !ran.includes(file.name));
|
|
38
|
+
|
|
39
|
+
if (pending.length === 0) {
|
|
40
|
+
console.log('Nothing to migrate.');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Run pending migrations
|
|
45
|
+
const batch = await this.repository.getNextBatchNumber();
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
for (const file of pending) {
|
|
49
|
+
await this.runUp(file.path, file.name, batch);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Run "up" key on a migration instance.
|
|
55
|
+
*/
|
|
56
|
+
protected async runUp(path: string, name: string, batch: number): Promise<void> {
|
|
57
|
+
console.log(`Migrating: ${name}`);
|
|
58
|
+
|
|
59
|
+
const instance = await this.resolve(path);
|
|
60
|
+
|
|
61
|
+
await instance.up();
|
|
62
|
+
|
|
63
|
+
await this.repository.log(name, batch);
|
|
64
|
+
|
|
65
|
+
console.log(`Migrated: ${name}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Rollback the last migration operation.
|
|
70
|
+
*/
|
|
71
|
+
async rollback(paths: string[] = [], options: { step?: number } = {}): Promise<void> {
|
|
72
|
+
// Initialize Schema facade
|
|
73
|
+
Schema.init(this.connection);
|
|
74
|
+
|
|
75
|
+
// Ensure repository exists
|
|
76
|
+
if (!await this.repository.repositoryExists()) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Get migrations to rollback
|
|
81
|
+
const migrations = await this.repository.getMigrations(options.step || 1);
|
|
82
|
+
|
|
83
|
+
if (migrations.length === 0) {
|
|
84
|
+
console.log('Nothing to rollback.');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
// Rollback each migration
|
|
91
|
+
// We need to resolve file paths for these migrations
|
|
92
|
+
// This is a bit tricky because we only have names in DB, not full paths.
|
|
93
|
+
// We have to search for them in the paths.
|
|
94
|
+
|
|
95
|
+
const searchPaths = [...this.paths, ...paths];
|
|
96
|
+
const files = await this.getMigrationFiles(searchPaths);
|
|
97
|
+
|
|
98
|
+
// Map names to files
|
|
99
|
+
const fileMap = new Map(files.map(f => [f.name, f.path]));
|
|
100
|
+
|
|
101
|
+
for (const migration of migrations) {
|
|
102
|
+
const path = fileMap.get(migration.migration);
|
|
103
|
+
|
|
104
|
+
if (!path) {
|
|
105
|
+
console.warn(`Migration file not found: ${migration.migration}`);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
await this.runDown(path, migration);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Run "down" key on a migration instance.
|
|
115
|
+
*/
|
|
116
|
+
protected async runDown(path: string, migration: { migration: string; batch: number }): Promise<void> {
|
|
117
|
+
console.log(`Rolling back: ${migration.migration}`);
|
|
118
|
+
|
|
119
|
+
const instance = await this.resolve(path);
|
|
120
|
+
|
|
121
|
+
await instance.down();
|
|
122
|
+
|
|
123
|
+
await this.repository.delete(migration.migration);
|
|
124
|
+
|
|
125
|
+
console.log(`Rolled back: ${migration.migration}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Rolls back all migrations.
|
|
130
|
+
*/
|
|
131
|
+
async reset(paths: string[] = []): Promise<void> {
|
|
132
|
+
// Initialize Schema facade
|
|
133
|
+
Schema.init(this.connection);
|
|
134
|
+
|
|
135
|
+
// Ensure repository exists
|
|
136
|
+
if (!await this.repository.repositoryExists()) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Get all migrations in reverse order (descending ID)
|
|
141
|
+
// We can cheat and just ask for a huge number of steps or just get all from table
|
|
142
|
+
// But repository.getMigrations get last batch.
|
|
143
|
+
// We probably need a repository.getAll() or similar, or just rollback iteratively?
|
|
144
|
+
// Usually reset rolls back everything.
|
|
145
|
+
|
|
146
|
+
// Let's implement getting all migrations from the repo if not exists
|
|
147
|
+
// But for now, let's assume rollback with a high step count works if getMigrations supports it?
|
|
148
|
+
// create-laraveljs repository implementation of getMigrations uses "LIMIT steps" if steps > 0.
|
|
149
|
+
// If we want all, we might need a way to say "all".
|
|
150
|
+
// Let's rely on rolling back batch by batch loop or just 0 steps = all?
|
|
151
|
+
// Checking DatabaseMigrationRepository logic... I don't have it open.
|
|
152
|
+
|
|
153
|
+
// Let's just do a loop for now until empty?
|
|
154
|
+
// Or assume we can pass a large number.
|
|
155
|
+
|
|
156
|
+
await this.rollback(paths, { step: 999999 });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get all migration files from the given paths.
|
|
161
|
+
*/
|
|
162
|
+
async getMigrationFiles(paths: string[]): Promise<{ name: string; path: string }[]> {
|
|
163
|
+
let files: { name: string; path: string }[] = [];
|
|
164
|
+
|
|
165
|
+
for (const path of paths) {
|
|
166
|
+
try {
|
|
167
|
+
// Check if directory exists
|
|
168
|
+
const entries = await readdir(path, { withFileTypes: true });
|
|
169
|
+
|
|
170
|
+
for (const entry of entries) {
|
|
171
|
+
if (entry.isFile() && (entry.name.endsWith('.ts') || entry.name.endsWith('.js'))) {
|
|
172
|
+
// Exclude .d.ts
|
|
173
|
+
if (entry.name.endsWith('.d.ts')) continue;
|
|
174
|
+
|
|
175
|
+
files.push({
|
|
176
|
+
name: entry.name.replace(/\.(ts|js)$/, ''),
|
|
177
|
+
path: join(path, entry.name)
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} catch (error) {
|
|
182
|
+
// Directory might not exist, skip
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Sort by name (timestamp)
|
|
187
|
+
return files.sort((a, b) => a.name.localeCompare(b.name));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Resolve a migration instance from a file.
|
|
192
|
+
*/
|
|
193
|
+
protected async resolve(path: string): Promise<any> {
|
|
194
|
+
// Dynamic import
|
|
195
|
+
const module = await import(path);
|
|
196
|
+
|
|
197
|
+
// Assume default export or named export matching class logic
|
|
198
|
+
// For simplicity, let's assume the module exports a class as default or the first export is the class.
|
|
199
|
+
// ORM Design says: export class CreateUsersTable
|
|
200
|
+
|
|
201
|
+
const keys = Object.keys(module);
|
|
202
|
+
// Find the first export that looks like a migration class (has up/down methods or is a class)
|
|
203
|
+
// Since we can't easily inspect headers without instantiating, let's try to instantiate values.
|
|
204
|
+
|
|
205
|
+
for (const key of keys) {
|
|
206
|
+
const Exported = module[key];
|
|
207
|
+
if (typeof Exported === 'function') {
|
|
208
|
+
try {
|
|
209
|
+
const instance = new Exported();
|
|
210
|
+
if (typeof instance.up === 'function' && typeof instance.down === 'function') {
|
|
211
|
+
return instance;
|
|
212
|
+
}
|
|
213
|
+
} catch (e) {
|
|
214
|
+
// Not a constructible class or whatever
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
throw new Error(`Migration ${path} does not export a valid Migration class.`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Get the status of all migrations.
|
|
224
|
+
*/
|
|
225
|
+
async getStatus(): Promise<{ name: string; ran: boolean; batch: number | null }[]> {
|
|
226
|
+
// Initialize Schema facade
|
|
227
|
+
Schema.init(this.connection);
|
|
228
|
+
|
|
229
|
+
// Ensure repository exists
|
|
230
|
+
if (!await this.repository.repositoryExists()) {
|
|
231
|
+
await this.repository.createRepository();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const ranMigrations = await this.repository.getRan();
|
|
235
|
+
// We need batches too, but getRan only returns names.
|
|
236
|
+
// Let's get all logged migrations with batches for now.
|
|
237
|
+
const allRan = await this.repository.getMigrations(99999);
|
|
238
|
+
const ranMap = new Map(allRan.map(m => [m.migration, m.batch]));
|
|
239
|
+
|
|
240
|
+
const searchPaths = [...this.paths];
|
|
241
|
+
const files = await this.getMigrationFiles(searchPaths);
|
|
242
|
+
|
|
243
|
+
return files.map(file => ({
|
|
244
|
+
name: file.name,
|
|
245
|
+
ran: ranMap.has(file.name),
|
|
246
|
+
batch: ranMap.get(file.name) || null
|
|
247
|
+
}));
|
|
248
|
+
}
|
|
249
|
+
}
|