wrangler 2.9.0 → 2.10.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.
- package/README.md +3 -3
- package/miniflare-dist/index.mjs +2 -15
- package/package.json +9 -9
- package/src/__tests__/configuration.test.ts +70 -0
- package/src/__tests__/d1/d1.test.ts +3 -6
- package/src/__tests__/d1/execute.test.ts +64 -0
- package/src/__tests__/d1/migrate.test.ts +107 -0
- package/src/__tests__/deployments.test.ts +40 -16
- package/src/__tests__/dev.test.tsx +3 -3
- package/src/__tests__/generate.test.ts +1 -1
- package/src/__tests__/helpers/end-event-loop.ts +6 -0
- package/src/__tests__/helpers/mock-get-pages-upload-token.ts +25 -0
- package/src/__tests__/helpers/mock-set-timeout.ts +16 -0
- package/src/__tests__/helpers/msw/handlers/deployments.ts +40 -16
- package/src/__tests__/helpers/string-dynamic-values-matcher.ts +28 -0
- package/src/__tests__/index.test.ts +3 -4
- package/src/__tests__/init.test.ts +1 -1
- package/src/__tests__/kv.test.ts +8 -8
- package/src/__tests__/middleware.test.ts +65 -0
- package/src/__tests__/mtls-certificates.test.ts +585 -0
- package/src/__tests__/pages/deployment-list.test.ts +78 -0
- package/src/__tests__/pages/functions-build.test.ts +402 -0
- package/src/__tests__/pages/pages.test.ts +81 -0
- package/src/__tests__/pages/project-create.test.ts +63 -0
- package/src/__tests__/pages/project-list.test.ts +108 -0
- package/src/__tests__/pages/project-upload.test.ts +481 -0
- package/src/__tests__/pages/publish.test.ts +2745 -0
- package/src/__tests__/publish.test.ts +58 -27
- package/src/__tests__/queues.test.ts +2 -2
- package/src/__tests__/secret.test.ts +4 -4
- package/src/__tests__/tsconfig.tsbuildinfo +1 -1
- package/src/__tests__/user.test.ts +1 -1
- package/src/__tests__/whoami.test.tsx +1 -1
- package/src/__tests__/worker-namespace.test.ts +1 -1
- package/src/api/index.ts +8 -0
- package/src/api/mtls-certificate.ts +148 -0
- package/src/api/pages/create-worker-bundle-contents.ts +75 -0
- package/src/api/pages/publish.tsx +52 -8
- package/src/bundle.ts +6 -5
- package/src/config/config.ts +7 -7
- package/src/config/environment.ts +9 -2
- package/src/config/index.ts +13 -0
- package/src/config/validation.ts +50 -3
- package/src/create-worker-upload-form.ts +9 -0
- package/src/d1/execute.tsx +124 -91
- package/src/d1/migrations/apply.tsx +36 -29
- package/src/d1/migrations/create.tsx +10 -8
- package/src/d1/migrations/helpers.ts +63 -38
- package/src/d1/migrations/list.tsx +31 -20
- package/src/d1/migrations/options.ts +6 -1
- package/src/d1/types.ts +1 -0
- package/src/d1/utils.ts +2 -1
- package/src/deployments.ts +62 -39
- package/src/dev/dev.tsx +1 -15
- package/src/dev/remote.tsx +2 -2
- package/src/dev.tsx +9 -6
- package/src/generate/index.ts +1 -1
- package/src/index.ts +15 -5
- package/src/miniflare-cli/assets.ts +1 -1
- package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
- package/src/mtls-certificate/cli.ts +155 -0
- package/src/pages/build.ts +103 -23
- package/src/pages/buildFunctions.ts +32 -31
- package/src/pages/dev.ts +4 -2
- package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
- package/src/pages/publish.tsx +12 -1
- package/src/pages/utils.ts +1 -1
- package/src/publish/publish.ts +3 -2
- package/src/secret/index.ts +1 -0
- package/src/sites.ts +1 -1
- package/src/tail/filters.ts +1 -1
- package/src/user/user.ts +4 -3
- package/src/worker.ts +6 -0
- package/templates/format-dev-errors.ts +1 -0
- package/templates/new-worker.ts +3 -0
- package/templates/serve-static-assets.ts +1 -0
- package/templates/service-bindings-module-facade.js +1 -0
- package/templates/tsconfig.init.json +1 -1
- package/templates/tsconfig.tsbuildinfo +1 -1
- package/wrangler-dist/cli.d.ts +82 -2
- package/wrangler-dist/cli.js +1726 -1616
- package/src/__tests__/pages.test.ts +0 -2905
package/src/d1/execute.tsx
CHANGED
|
@@ -27,17 +27,6 @@ import type {
|
|
|
27
27
|
StrictYargsOptionsToInterface,
|
|
28
28
|
} from "../yargs-types";
|
|
29
29
|
import type { Database } from "./types";
|
|
30
|
-
import type { Statement as StatementType } from "@miniflare/d1";
|
|
31
|
-
import type { createSQLiteDB as createSQLiteDBType } from "@miniflare/shared";
|
|
32
|
-
|
|
33
|
-
type MiniflareNpxImportTypes = [
|
|
34
|
-
{
|
|
35
|
-
Statement: typeof StatementType;
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
createSQLiteDB: typeof createSQLiteDBType;
|
|
39
|
-
}
|
|
40
|
-
];
|
|
41
30
|
|
|
42
31
|
export type QueryResult = {
|
|
43
32
|
results: Record<string, string | number | boolean>[];
|
|
@@ -64,7 +53,7 @@ export function Options(yargs: CommonYargsArgv) {
|
|
|
64
53
|
type: "boolean",
|
|
65
54
|
})
|
|
66
55
|
.option("file", {
|
|
67
|
-
describe: "A .sql file to
|
|
56
|
+
describe: "A .sql file to ingest",
|
|
68
57
|
type: "string",
|
|
69
58
|
})
|
|
70
59
|
.option("command", {
|
|
@@ -80,55 +69,19 @@ export function Options(yargs: CommonYargsArgv) {
|
|
|
80
69
|
describe: "Return output as clean JSON",
|
|
81
70
|
type: "boolean",
|
|
82
71
|
default: false,
|
|
72
|
+
})
|
|
73
|
+
.option("preview", {
|
|
74
|
+
describe: "Execute commands/files against a preview D1 DB",
|
|
75
|
+
type: "boolean",
|
|
76
|
+
default: false,
|
|
83
77
|
});
|
|
84
78
|
}
|
|
85
79
|
|
|
86
|
-
function shorten(query: string | undefined, length: number) {
|
|
87
|
-
return query && query.length > length
|
|
88
|
-
? query.slice(0, length) + "..."
|
|
89
|
-
: query;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export async function executeSql(
|
|
93
|
-
local: undefined | boolean,
|
|
94
|
-
config: ConfigFields<DevConfig> & Environment,
|
|
95
|
-
name: string,
|
|
96
|
-
shouldPrompt: boolean | undefined,
|
|
97
|
-
persistTo: undefined | string,
|
|
98
|
-
file?: string,
|
|
99
|
-
command?: string,
|
|
100
|
-
json?: boolean
|
|
101
|
-
) {
|
|
102
|
-
const sql = file ? readFileSync(file) : command;
|
|
103
|
-
if (!sql) throw new Error(`Error: must provide --command or --file.`);
|
|
104
|
-
if (persistTo && !local)
|
|
105
|
-
throw new Error(`Error: can't use --persist-to without --local`);
|
|
106
|
-
logger.log(`🌀 Mapping SQL input into an array of statements`);
|
|
107
|
-
const queries = splitSqlQuery(sql);
|
|
108
|
-
|
|
109
|
-
if (file && sql) {
|
|
110
|
-
if (queries[0].startsWith("SQLite format 3")) {
|
|
111
|
-
//TODO: update this error to recommend using `wrangler d1 restore` when it exists
|
|
112
|
-
throw new Error(
|
|
113
|
-
"Provided file is a binary SQLite database file instead of an SQL text file.\nThe execute command can only process SQL text files.\nPlease export an SQL file from your SQLite database and try again."
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return local
|
|
119
|
-
? await executeLocally(config, name, shouldPrompt, queries, persistTo, json)
|
|
120
|
-
: await executeRemotely(
|
|
121
|
-
config,
|
|
122
|
-
name,
|
|
123
|
-
shouldPrompt,
|
|
124
|
-
batchSplit(queries),
|
|
125
|
-
json
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
80
|
type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
|
|
129
81
|
|
|
130
82
|
export const Handler = async (args: HandlerOptions): Promise<void> => {
|
|
131
|
-
const { local, database, yes, persistTo, file, command, json } =
|
|
83
|
+
const { local, database, yes, persistTo, file, command, json, preview } =
|
|
84
|
+
args;
|
|
132
85
|
const existingLogLevel = logger.loggerLevel;
|
|
133
86
|
if (json) {
|
|
134
87
|
// set loggerLevel to error to avoid readConfig warnings appearing in JSON output
|
|
@@ -140,16 +93,17 @@ export const Handler = async (args: HandlerOptions): Promise<void> => {
|
|
|
140
93
|
return logger.error(`Error: can't provide both --command and --file.`);
|
|
141
94
|
|
|
142
95
|
const isInteractive = process.stdout.isTTY;
|
|
143
|
-
const response: QueryResult[] | null = await executeSql(
|
|
96
|
+
const response: QueryResult[] | null = await executeSql({
|
|
144
97
|
local,
|
|
145
98
|
config,
|
|
146
|
-
database,
|
|
147
|
-
isInteractive && !yes,
|
|
99
|
+
name: database,
|
|
100
|
+
shouldPrompt: isInteractive && !yes,
|
|
148
101
|
persistTo,
|
|
149
102
|
file,
|
|
150
103
|
command,
|
|
151
|
-
json
|
|
152
|
-
|
|
104
|
+
json,
|
|
105
|
+
preview,
|
|
106
|
+
});
|
|
153
107
|
|
|
154
108
|
// Early exit if prompt rejected
|
|
155
109
|
if (!response) return;
|
|
@@ -183,14 +137,79 @@ export const Handler = async (args: HandlerOptions): Promise<void> => {
|
|
|
183
137
|
}
|
|
184
138
|
};
|
|
185
139
|
|
|
186
|
-
async function
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
persistTo
|
|
192
|
-
|
|
193
|
-
|
|
140
|
+
export async function executeSql({
|
|
141
|
+
local,
|
|
142
|
+
config,
|
|
143
|
+
name,
|
|
144
|
+
shouldPrompt,
|
|
145
|
+
persistTo,
|
|
146
|
+
file,
|
|
147
|
+
command,
|
|
148
|
+
json,
|
|
149
|
+
preview,
|
|
150
|
+
}: {
|
|
151
|
+
local: boolean | undefined;
|
|
152
|
+
config: ConfigFields<DevConfig> & Environment;
|
|
153
|
+
name: string;
|
|
154
|
+
shouldPrompt: boolean | undefined;
|
|
155
|
+
persistTo: string | undefined;
|
|
156
|
+
file: string | undefined;
|
|
157
|
+
command: string | undefined;
|
|
158
|
+
json: boolean | undefined;
|
|
159
|
+
preview: boolean | undefined;
|
|
160
|
+
}) {
|
|
161
|
+
const sql = file ? readFileSync(file) : command;
|
|
162
|
+
if (!sql) throw new Error(`Error: must provide --command or --file.`);
|
|
163
|
+
if (preview && local)
|
|
164
|
+
throw new Error(`Error: can't use --preview with --local`);
|
|
165
|
+
if (persistTo && !local)
|
|
166
|
+
throw new Error(`Error: can't use --persist-to without --local`);
|
|
167
|
+
logger.log(`🌀 Mapping SQL input into an array of statements`);
|
|
168
|
+
const queries = splitSqlQuery(sql);
|
|
169
|
+
|
|
170
|
+
if (file && sql) {
|
|
171
|
+
if (queries[0].startsWith("SQLite format 3")) {
|
|
172
|
+
//TODO: update this error to recommend using `wrangler d1 restore` when it exists
|
|
173
|
+
throw new Error(
|
|
174
|
+
"Provided file is a binary SQLite database file instead of an SQL text file.\nThe execute command can only process SQL text files.\nPlease export an SQL file from your SQLite database and try again."
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return local
|
|
180
|
+
? await executeLocally({
|
|
181
|
+
config,
|
|
182
|
+
name,
|
|
183
|
+
shouldPrompt,
|
|
184
|
+
queries,
|
|
185
|
+
persistTo,
|
|
186
|
+
json,
|
|
187
|
+
})
|
|
188
|
+
: await executeRemotely({
|
|
189
|
+
config,
|
|
190
|
+
name,
|
|
191
|
+
shouldPrompt,
|
|
192
|
+
batches: batchSplit(queries),
|
|
193
|
+
json,
|
|
194
|
+
preview,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function executeLocally({
|
|
199
|
+
config,
|
|
200
|
+
name,
|
|
201
|
+
shouldPrompt,
|
|
202
|
+
queries,
|
|
203
|
+
persistTo,
|
|
204
|
+
json,
|
|
205
|
+
}: {
|
|
206
|
+
config: Config;
|
|
207
|
+
name: string;
|
|
208
|
+
shouldPrompt: boolean | undefined;
|
|
209
|
+
queries: string[];
|
|
210
|
+
persistTo: string | undefined;
|
|
211
|
+
json: boolean | undefined;
|
|
212
|
+
}) {
|
|
194
213
|
const localDB = getDatabaseInfoFromConfig(config, name);
|
|
195
214
|
if (!localDB) {
|
|
196
215
|
throw new Error(
|
|
@@ -206,11 +225,10 @@ async function executeLocally(
|
|
|
206
225
|
|
|
207
226
|
const dbDir = path.join(persistencePath, "d1");
|
|
208
227
|
const dbPath = path.join(dbDir, `${localDB.binding}.sqlite3`);
|
|
209
|
-
const [{
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
);
|
|
228
|
+
const [{ D1Database, D1DatabaseAPI }, { createSQLiteDB }] = await npxImport<
|
|
229
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
230
|
+
[typeof import("@miniflare/d1"), typeof import("@miniflare/shared")]
|
|
231
|
+
>(["@miniflare/d1", "@miniflare/shared"], logger.log);
|
|
214
232
|
|
|
215
233
|
if (!existsSync(dbDir)) {
|
|
216
234
|
const ok =
|
|
@@ -222,24 +240,28 @@ async function executeLocally(
|
|
|
222
240
|
}
|
|
223
241
|
|
|
224
242
|
logger.log(`🌀 Loading DB at ${readableRelative(dbPath)}`);
|
|
225
|
-
const db = await createSQLiteDB(dbPath);
|
|
226
243
|
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return results;
|
|
244
|
+
const sqliteDb = await createSQLiteDB(dbPath);
|
|
245
|
+
const db = new D1Database(new D1DatabaseAPI(sqliteDb));
|
|
246
|
+
const stmts = queries.map((query) => db.prepare(query));
|
|
247
|
+
return (await db.batch(stmts)) as QueryResult[];
|
|
234
248
|
}
|
|
235
249
|
|
|
236
|
-
async function executeRemotely(
|
|
237
|
-
config
|
|
238
|
-
name
|
|
239
|
-
shouldPrompt
|
|
240
|
-
batches
|
|
241
|
-
json
|
|
242
|
-
|
|
250
|
+
async function executeRemotely({
|
|
251
|
+
config,
|
|
252
|
+
name,
|
|
253
|
+
shouldPrompt,
|
|
254
|
+
batches,
|
|
255
|
+
json,
|
|
256
|
+
preview,
|
|
257
|
+
}: {
|
|
258
|
+
config: Config;
|
|
259
|
+
name: string;
|
|
260
|
+
shouldPrompt: boolean | undefined;
|
|
261
|
+
batches: string[];
|
|
262
|
+
json: boolean | undefined;
|
|
263
|
+
preview: boolean | undefined;
|
|
264
|
+
}) {
|
|
243
265
|
const multiple_batches = batches.length > 1;
|
|
244
266
|
// in JSON mode, we don't want a prompt here
|
|
245
267
|
if (multiple_batches && !json) {
|
|
@@ -262,8 +284,13 @@ async function executeRemotely(
|
|
|
262
284
|
accountId,
|
|
263
285
|
name
|
|
264
286
|
);
|
|
265
|
-
|
|
266
|
-
|
|
287
|
+
if (preview && !db.previewDatabaseUuid) {
|
|
288
|
+
throw logger.error(
|
|
289
|
+
"Please define a `preview_database_id` in your wrangler.toml to execute your queries against a preview database"
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
const dbUuid = preview ? db.previewDatabaseUuid : db.uuid;
|
|
293
|
+
logger.log(`🌀 Executing on ${name} (${dbUuid}):`);
|
|
267
294
|
|
|
268
295
|
const results: QueryResult[] = [];
|
|
269
296
|
for (const sql of batches) {
|
|
@@ -273,7 +300,7 @@ async function executeRemotely(
|
|
|
273
300
|
);
|
|
274
301
|
|
|
275
302
|
const result = await fetchResult<QueryResult[]>(
|
|
276
|
-
`/accounts/${accountId}/d1/database/${
|
|
303
|
+
`/accounts/${accountId}/d1/database/${dbUuid}/query`,
|
|
277
304
|
{
|
|
278
305
|
method: "POST",
|
|
279
306
|
headers: {
|
|
@@ -319,3 +346,9 @@ function batchSplit(queries: string[]) {
|
|
|
319
346
|
}
|
|
320
347
|
return batches;
|
|
321
348
|
}
|
|
349
|
+
|
|
350
|
+
function shorten(query: string | undefined, length: number) {
|
|
351
|
+
return query && query.length > length
|
|
352
|
+
? query.slice(0, length) + "..."
|
|
353
|
+
: query;
|
|
354
|
+
}
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
getUnappliedMigrations,
|
|
20
20
|
initMigrationsTable,
|
|
21
21
|
} from "./helpers";
|
|
22
|
-
import {
|
|
22
|
+
import { MigrationOptions } from "./options";
|
|
23
23
|
import type { ParseError } from "../../parse";
|
|
24
24
|
import type {
|
|
25
25
|
CommonYargsArgv,
|
|
@@ -27,14 +27,16 @@ import type {
|
|
|
27
27
|
} from "../../yargs-types";
|
|
28
28
|
|
|
29
29
|
export function ApplyOptions(yargs: CommonYargsArgv) {
|
|
30
|
-
return
|
|
30
|
+
return MigrationOptions(yargs);
|
|
31
31
|
}
|
|
32
|
+
|
|
32
33
|
type ApplyHandlerOptions = StrictYargsOptionsToInterface<typeof ApplyOptions>;
|
|
34
|
+
|
|
33
35
|
export const ApplyHandler = withConfig<ApplyHandlerOptions>(
|
|
34
|
-
async ({ config, database, local, persistTo }): Promise<void> => {
|
|
36
|
+
async ({ config, database, local, persistTo, preview }): Promise<void> => {
|
|
35
37
|
logger.log(d1BetaWarning);
|
|
36
38
|
|
|
37
|
-
const databaseInfo =
|
|
39
|
+
const databaseInfo = getDatabaseInfoFromConfig(config, database);
|
|
38
40
|
if (!databaseInfo && !local) {
|
|
39
41
|
throw new Error(
|
|
40
42
|
`Can't find a DB with name/binding '${database}' in local config. Check info in wrangler.toml...`
|
|
@@ -45,31 +47,34 @@ export const ApplyHandler = withConfig<ApplyHandlerOptions>(
|
|
|
45
47
|
return;
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
const migrationsPath = await getMigrationsPath(
|
|
49
|
-
path.dirname(config.configPath),
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
const migrationsPath = await getMigrationsPath({
|
|
51
|
+
projectPath: path.dirname(config.configPath),
|
|
52
|
+
migrationsFolderPath:
|
|
53
|
+
databaseInfo?.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
|
|
54
|
+
createIfMissing: false,
|
|
55
|
+
});
|
|
53
56
|
|
|
54
|
-
const
|
|
57
|
+
const migrationsTableName =
|
|
55
58
|
databaseInfo?.migrationsTableName ?? DEFAULT_MIGRATION_TABLE;
|
|
56
|
-
await initMigrationsTable(
|
|
57
|
-
|
|
59
|
+
await initMigrationsTable({
|
|
60
|
+
migrationsTableName,
|
|
58
61
|
local,
|
|
59
62
|
config,
|
|
60
|
-
database,
|
|
61
|
-
persistTo
|
|
62
|
-
|
|
63
|
+
name: database,
|
|
64
|
+
persistTo,
|
|
65
|
+
preview,
|
|
66
|
+
});
|
|
63
67
|
|
|
64
68
|
const unappliedMigrations = (
|
|
65
|
-
await getUnappliedMigrations(
|
|
66
|
-
|
|
69
|
+
await getUnappliedMigrations({
|
|
70
|
+
migrationsTableName,
|
|
67
71
|
migrationsPath,
|
|
68
72
|
local,
|
|
69
73
|
config,
|
|
70
|
-
database,
|
|
71
|
-
persistTo
|
|
72
|
-
|
|
74
|
+
name: database,
|
|
75
|
+
persistTo,
|
|
76
|
+
preview,
|
|
77
|
+
})
|
|
73
78
|
)
|
|
74
79
|
.map((migration) => {
|
|
75
80
|
return {
|
|
@@ -107,8 +112,8 @@ Your database may not be available to serve requests during the migration, conti
|
|
|
107
112
|
);
|
|
108
113
|
if (!ok) return;
|
|
109
114
|
|
|
110
|
-
// don't backup prod db when applying migrations locally
|
|
111
|
-
if (!local) {
|
|
115
|
+
// don't backup prod db when applying migrations locally or in preview
|
|
116
|
+
if (!local && !preview) {
|
|
112
117
|
assert(
|
|
113
118
|
databaseInfo,
|
|
114
119
|
"In non-local mode `databaseInfo` should be defined."
|
|
@@ -124,22 +129,24 @@ Your database may not be available to serve requests during the migration, conti
|
|
|
124
129
|
"utf8"
|
|
125
130
|
);
|
|
126
131
|
query += `
|
|
127
|
-
INSERT INTO ${
|
|
132
|
+
INSERT INTO ${migrationsTableName} (name)
|
|
128
133
|
values ('${migration.Name}');
|
|
129
134
|
`;
|
|
130
135
|
|
|
131
136
|
let success = true;
|
|
132
137
|
let errorNotes: Array<string> = [];
|
|
133
138
|
try {
|
|
134
|
-
const response = await executeSql(
|
|
139
|
+
const response = await executeSql({
|
|
135
140
|
local,
|
|
136
141
|
config,
|
|
137
|
-
database,
|
|
138
|
-
isInteractive() && !CI.isCI(),
|
|
142
|
+
name: database,
|
|
143
|
+
shouldPrompt: isInteractive() && !CI.isCI(),
|
|
139
144
|
persistTo,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
145
|
+
command: query,
|
|
146
|
+
file: undefined,
|
|
147
|
+
json: undefined,
|
|
148
|
+
preview,
|
|
149
|
+
});
|
|
143
150
|
|
|
144
151
|
if (response === null) {
|
|
145
152
|
// TODO: return error
|
|
@@ -4,7 +4,7 @@ import { Box, render, Text } from "ink";
|
|
|
4
4
|
import React from "react";
|
|
5
5
|
import { withConfig } from "../../config";
|
|
6
6
|
import { logger } from "../../logger";
|
|
7
|
-
import {
|
|
7
|
+
import { DEFAULT_MIGRATION_PATH } from "../constants";
|
|
8
8
|
import { Database } from "../options";
|
|
9
9
|
import { d1BetaWarning, getDatabaseInfoFromConfig } from "../utils";
|
|
10
10
|
import { getMigrationsPath, getNextMigrationNumber } from "./helpers";
|
|
@@ -20,13 +20,14 @@ export function CreateOptions(yargs: CommonYargsArgv) {
|
|
|
20
20
|
demandOption: true,
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
+
|
|
23
24
|
type CreateHandlerOptions = StrictYargsOptionsToInterface<typeof CreateOptions>;
|
|
25
|
+
|
|
24
26
|
export const CreateHandler = withConfig<CreateHandlerOptions>(
|
|
25
27
|
async ({ config, database, message }): Promise<void> => {
|
|
26
|
-
await requireAuth({});
|
|
27
28
|
logger.log(d1BetaWarning);
|
|
28
29
|
|
|
29
|
-
const databaseInfo =
|
|
30
|
+
const databaseInfo = getDatabaseInfoFromConfig(config, database);
|
|
30
31
|
if (!databaseInfo) {
|
|
31
32
|
throw new Error(
|
|
32
33
|
`Can't find a DB with name/binding '${database}' in local config. Check info in wrangler.toml...`
|
|
@@ -37,11 +38,12 @@ export const CreateHandler = withConfig<CreateHandlerOptions>(
|
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
const migrationsPath = await getMigrationsPath(
|
|
41
|
-
path.dirname(config.configPath),
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
const migrationsPath = await getMigrationsPath({
|
|
42
|
+
projectPath: path.dirname(config.configPath),
|
|
43
|
+
migrationsFolderPath:
|
|
44
|
+
databaseInfo.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
|
|
45
|
+
createIfMissing: true,
|
|
46
|
+
});
|
|
45
47
|
const nextMigrationNumber = pad(getNextMigrationNumber(migrationsPath), 4);
|
|
46
48
|
const migrationName = message.replaceAll(" ", "_");
|
|
47
49
|
|
|
@@ -10,11 +10,15 @@ import type { ConfigFields, DevConfig, Environment } from "../../config";
|
|
|
10
10
|
import type { QueryResult } from "../execute";
|
|
11
11
|
import type { Migration } from "../types";
|
|
12
12
|
|
|
13
|
-
export async function getMigrationsPath(
|
|
14
|
-
projectPath
|
|
15
|
-
migrationsFolderPath
|
|
16
|
-
createIfMissing
|
|
17
|
-
|
|
13
|
+
export async function getMigrationsPath({
|
|
14
|
+
projectPath,
|
|
15
|
+
migrationsFolderPath,
|
|
16
|
+
createIfMissing,
|
|
17
|
+
}: {
|
|
18
|
+
projectPath: string;
|
|
19
|
+
migrationsFolderPath: string;
|
|
20
|
+
createIfMissing: boolean;
|
|
21
|
+
}): Promise<string> {
|
|
18
22
|
const dir = path.resolve(projectPath, migrationsFolderPath);
|
|
19
23
|
if (fs.existsSync(dir)) return dir;
|
|
20
24
|
|
|
@@ -34,21 +38,31 @@ export async function getMigrationsPath(
|
|
|
34
38
|
throw new Error(`No migrations present at ${dir}.`);
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
export async function getUnappliedMigrations(
|
|
38
|
-
migrationsTableName
|
|
39
|
-
migrationsPath
|
|
40
|
-
local
|
|
41
|
-
config
|
|
42
|
-
name
|
|
43
|
-
persistTo
|
|
44
|
-
|
|
41
|
+
export async function getUnappliedMigrations({
|
|
42
|
+
migrationsTableName,
|
|
43
|
+
migrationsPath,
|
|
44
|
+
local,
|
|
45
|
+
config,
|
|
46
|
+
name,
|
|
47
|
+
persistTo,
|
|
48
|
+
preview,
|
|
49
|
+
}: {
|
|
50
|
+
migrationsTableName: string;
|
|
51
|
+
migrationsPath: string;
|
|
52
|
+
local: boolean | undefined;
|
|
53
|
+
config: ConfigFields<DevConfig> & Environment;
|
|
54
|
+
name: string;
|
|
55
|
+
persistTo: string | undefined;
|
|
56
|
+
preview: boolean | undefined;
|
|
57
|
+
}): Promise<Array<string>> {
|
|
45
58
|
const appliedMigrations = (
|
|
46
59
|
await listAppliedMigrations(
|
|
47
60
|
migrationsTableName,
|
|
48
61
|
local,
|
|
49
62
|
config,
|
|
50
63
|
name,
|
|
51
|
-
persistTo
|
|
64
|
+
persistTo,
|
|
65
|
+
preview
|
|
52
66
|
)
|
|
53
67
|
).map((migration) => {
|
|
54
68
|
return migration.name;
|
|
@@ -68,24 +82,25 @@ export async function getUnappliedMigrations(
|
|
|
68
82
|
|
|
69
83
|
const listAppliedMigrations = async (
|
|
70
84
|
migrationsTableName: string,
|
|
71
|
-
local:
|
|
85
|
+
local: boolean | undefined,
|
|
72
86
|
config: ConfigFields<DevConfig> & Environment,
|
|
73
87
|
name: string,
|
|
74
|
-
persistTo:
|
|
88
|
+
persistTo: string | undefined,
|
|
89
|
+
preview: boolean | undefined
|
|
75
90
|
): Promise<Migration[]> => {
|
|
76
|
-
const
|
|
77
|
-
FROM ${migrationsTableName}
|
|
78
|
-
ORDER BY id`;
|
|
79
|
-
|
|
80
|
-
const response: QueryResult[] | null = await executeSql(
|
|
91
|
+
const response: QueryResult[] | null = await executeSql({
|
|
81
92
|
local,
|
|
82
93
|
config,
|
|
83
94
|
name,
|
|
84
|
-
isInteractive() && !CI.isCI(),
|
|
95
|
+
shouldPrompt: isInteractive() && !CI.isCI(),
|
|
85
96
|
persistTo,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
command: `SELECT *
|
|
98
|
+
FROM ${migrationsTableName}
|
|
99
|
+
ORDER BY id`,
|
|
100
|
+
file: undefined,
|
|
101
|
+
json: undefined,
|
|
102
|
+
preview,
|
|
103
|
+
});
|
|
89
104
|
|
|
90
105
|
if (!response || response[0].results.length === 0) return [];
|
|
91
106
|
|
|
@@ -121,27 +136,37 @@ export function getNextMigrationNumber(migrationsPath: string): number {
|
|
|
121
136
|
return highestMigrationNumber + 1;
|
|
122
137
|
}
|
|
123
138
|
|
|
124
|
-
export const initMigrationsTable = async (
|
|
125
|
-
migrationsTableName
|
|
126
|
-
local
|
|
127
|
-
config
|
|
128
|
-
name
|
|
129
|
-
persistTo
|
|
130
|
-
|
|
131
|
-
|
|
139
|
+
export const initMigrationsTable = async ({
|
|
140
|
+
migrationsTableName,
|
|
141
|
+
local,
|
|
142
|
+
config,
|
|
143
|
+
name,
|
|
144
|
+
persistTo,
|
|
145
|
+
preview,
|
|
146
|
+
}: {
|
|
147
|
+
migrationsTableName: string;
|
|
148
|
+
local: boolean | undefined;
|
|
149
|
+
config: ConfigFields<DevConfig> & Environment;
|
|
150
|
+
name: string;
|
|
151
|
+
persistTo: string | undefined;
|
|
152
|
+
preview: boolean | undefined;
|
|
153
|
+
}) => {
|
|
154
|
+
return executeSql({
|
|
132
155
|
local,
|
|
133
156
|
config,
|
|
134
157
|
name,
|
|
135
|
-
isInteractive() && !CI.isCI(),
|
|
158
|
+
shouldPrompt: isInteractive() && !CI.isCI(),
|
|
136
159
|
persistTo,
|
|
137
|
-
|
|
138
|
-
`
|
|
160
|
+
command: `
|
|
139
161
|
CREATE TABLE IF NOT EXISTS ${migrationsTableName}
|
|
140
162
|
(
|
|
141
163
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
142
164
|
name TEXT UNIQUE,
|
|
143
165
|
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
|
144
166
|
);
|
|
145
|
-
|
|
146
|
-
|
|
167
|
+
`,
|
|
168
|
+
file: undefined,
|
|
169
|
+
json: undefined,
|
|
170
|
+
preview,
|
|
171
|
+
});
|
|
147
172
|
};
|
|
@@ -5,29 +5,34 @@ import React from "react";
|
|
|
5
5
|
import { withConfig } from "../../config";
|
|
6
6
|
import { logger } from "../../logger";
|
|
7
7
|
import { requireAuth } from "../../user";
|
|
8
|
+
import { DEFAULT_MIGRATION_PATH, DEFAULT_MIGRATION_TABLE } from "../constants";
|
|
8
9
|
import { d1BetaWarning, getDatabaseInfoFromConfig } from "../utils";
|
|
9
10
|
import {
|
|
10
11
|
getMigrationsPath,
|
|
11
12
|
getUnappliedMigrations,
|
|
12
13
|
initMigrationsTable,
|
|
13
14
|
} from "./helpers";
|
|
14
|
-
import {
|
|
15
|
+
import { MigrationOptions } from "./options";
|
|
15
16
|
import type {
|
|
16
17
|
CommonYargsArgv,
|
|
17
18
|
StrictYargsOptionsToInterface,
|
|
18
19
|
} from "../../yargs-types";
|
|
19
20
|
|
|
20
21
|
export function ListOptions(yargs: CommonYargsArgv) {
|
|
21
|
-
return
|
|
22
|
+
return MigrationOptions(yargs);
|
|
22
23
|
}
|
|
24
|
+
|
|
23
25
|
type ListHandlerOptions = StrictYargsOptionsToInterface<typeof ListOptions>;
|
|
26
|
+
|
|
24
27
|
export const ListHandler = withConfig<ListHandlerOptions>(
|
|
25
|
-
async ({ config, database, local, persistTo }): Promise<void> => {
|
|
26
|
-
|
|
28
|
+
async ({ config, database, local, persistTo, preview }): Promise<void> => {
|
|
29
|
+
if (!local) {
|
|
30
|
+
await requireAuth({});
|
|
31
|
+
}
|
|
27
32
|
logger.log(d1BetaWarning);
|
|
28
33
|
|
|
29
|
-
const databaseInfo =
|
|
30
|
-
if (!databaseInfo) {
|
|
34
|
+
const databaseInfo = getDatabaseInfoFromConfig(config, database);
|
|
35
|
+
if (!databaseInfo && !local) {
|
|
31
36
|
throw new Error(
|
|
32
37
|
`Can't find a DB with name/binding '${database}' in local config. Check info in wrangler.toml...`
|
|
33
38
|
);
|
|
@@ -36,30 +41,36 @@ export const ListHandler = withConfig<ListHandlerOptions>(
|
|
|
36
41
|
if (!config.configPath) {
|
|
37
42
|
return;
|
|
38
43
|
}
|
|
39
|
-
const { migrationsTableName, migrationsFolderPath } = databaseInfo;
|
|
40
44
|
|
|
41
|
-
const migrationsPath = await getMigrationsPath(
|
|
42
|
-
path.dirname(config.configPath),
|
|
43
|
-
migrationsFolderPath
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
const migrationsPath = await getMigrationsPath({
|
|
46
|
+
projectPath: path.dirname(config.configPath),
|
|
47
|
+
migrationsFolderPath:
|
|
48
|
+
databaseInfo?.migrationsFolderPath ?? DEFAULT_MIGRATION_PATH,
|
|
49
|
+
createIfMissing: false,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const migrationsTableName =
|
|
53
|
+
databaseInfo?.migrationsTableName ?? DEFAULT_MIGRATION_TABLE;
|
|
54
|
+
|
|
55
|
+
await initMigrationsTable({
|
|
47
56
|
migrationsTableName,
|
|
48
57
|
local,
|
|
49
58
|
config,
|
|
50
|
-
database,
|
|
51
|
-
persistTo
|
|
52
|
-
|
|
59
|
+
name: database,
|
|
60
|
+
persistTo,
|
|
61
|
+
preview,
|
|
62
|
+
});
|
|
53
63
|
|
|
54
64
|
const unappliedMigrations = (
|
|
55
|
-
await getUnappliedMigrations(
|
|
65
|
+
await getUnappliedMigrations({
|
|
56
66
|
migrationsTableName,
|
|
57
67
|
migrationsPath,
|
|
58
68
|
local,
|
|
59
69
|
config,
|
|
60
|
-
database,
|
|
61
|
-
persistTo
|
|
62
|
-
|
|
70
|
+
name: database,
|
|
71
|
+
persistTo,
|
|
72
|
+
preview,
|
|
73
|
+
})
|
|
63
74
|
).map((migration) => {
|
|
64
75
|
return {
|
|
65
76
|
Name: migration,
|