svcloud 0.1.0 → 0.1.1
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/src/commands/db.ts +55 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svcloud",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "The SV Cloud CLI. Alpha: login, logout, status, open, projects list, mcp, init, and runs are built; see PLANNING.md for what's still missing.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
package/src/commands/db.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `svcloud db` — PLANNING.md §4 Step 5. Mirrors F8's row editor
|
|
3
|
-
* (`apps/cloud/src/routes/database.ts`) plus the
|
|
4
|
-
* alongside this command (`db_create_table`/`db_run_migration`,
|
|
5
|
-
* MCP-tool-only — see that file's header). Cell/column payloads are taken
|
|
6
|
-
* JSON on the command line rather than a flag-per-field grammar: the primary
|
|
3
|
+
* (`apps/cloud/src/routes/database.ts`) plus the DDL routes added
|
|
4
|
+
* alongside this command (`db_create_table`/`db_run_migration`/`db_create_index`,
|
|
5
|
+
* previously MCP-tool-only — see that file's header). Cell/column payloads are taken
|
|
6
|
+
* as JSON on the command line rather than a flag-per-field grammar: the primary
|
|
7
7
|
* caller for structured data like this is a coding agent, and it goes
|
|
8
8
|
* through `svcloud mcp`'s tools directly (`lib/prompt.ts`'s header), not this
|
|
9
9
|
* command — this path exists for a human or a script at a real terminal.
|
|
10
10
|
*/
|
|
11
11
|
import { apiFetch } from "../lib/api";
|
|
12
12
|
import { findProjectBySlug } from "../lib/find-project";
|
|
13
|
-
import { die, printJson, printTable, takeOption } from "../lib/output";
|
|
13
|
+
import { die, hasFlag, printJson, printTable, takeOption } from "../lib/output";
|
|
14
14
|
|
|
15
15
|
const USAGE = `Usage:
|
|
16
16
|
svcloud db tables <app>
|
|
@@ -18,12 +18,14 @@ const USAGE = `Usage:
|
|
|
18
18
|
svcloud db insert <app> <table> <cells-json>
|
|
19
19
|
svcloud db update <app> <table> <row-id> <cells-json>
|
|
20
20
|
svcloud db delete <app> <table> <row-id>
|
|
21
|
-
svcloud db create-table <app> <table> <columns-json> --primary-key <name>
|
|
21
|
+
svcloud db create-table <app> <table> <columns-json> --primary-key <name> [--indexes <indexes-json>]
|
|
22
|
+
svcloud db create-index <app> <table> <columns-json> [--name <name>] [--unique]
|
|
22
23
|
svcloud db migrate <app> <table> <column-json> [--default <value>]
|
|
23
24
|
|
|
24
25
|
<cells-json> is a JSON object, e.g. '{"title":"Hello"}'
|
|
25
26
|
<columns-json> is a JSON array, e.g. '[{"name":"id","type":"uuid","nullable":false},{"name":"title","type":"text"}]'
|
|
26
27
|
<column-json> is a single column, e.g. '{"name":"count","type":"number","nullable":false}'
|
|
28
|
+
<indexes-json> is a JSON array of indexes, e.g. '[{"columns":["email"],"unique":true}]'
|
|
27
29
|
Column types: text, number, boolean, timestamp, json, uuid`;
|
|
28
30
|
|
|
29
31
|
interface DbColumn {
|
|
@@ -193,13 +195,25 @@ async function dbDelete(argv: string[], json: boolean): Promise<void> {
|
|
|
193
195
|
|
|
194
196
|
async function dbCreateTable(argv: string[], json: boolean): Promise<void> {
|
|
195
197
|
const pkOpt = takeOption(argv, "primary-key");
|
|
196
|
-
const
|
|
198
|
+
const indexesOpt = takeOption(pkOpt.rest, "indexes");
|
|
199
|
+
const [slug, table, columnsJson] = indexesOpt.rest;
|
|
197
200
|
if (!table || !pkOpt.value) die(USAGE);
|
|
198
201
|
const projectId = await resolveProjectId(slug);
|
|
199
202
|
const columns = parseJsonArg<unknown[]>(columnsJson, "<columns-json>");
|
|
203
|
+
const indexes = indexesOpt.value
|
|
204
|
+
? parseJsonArg<unknown[]>(indexesOpt.value, "<indexes-json>")
|
|
205
|
+
: undefined;
|
|
200
206
|
const result = await apiFetch<{ table: string; created: boolean }>(
|
|
201
207
|
`/api/v1/projects/${projectId}/database/tables`,
|
|
202
|
-
{
|
|
208
|
+
{
|
|
209
|
+
method: "POST",
|
|
210
|
+
body: {
|
|
211
|
+
name: table,
|
|
212
|
+
columns,
|
|
213
|
+
primary_key: pkOpt.value,
|
|
214
|
+
...(indexes ? { indexes } : {}),
|
|
215
|
+
},
|
|
216
|
+
},
|
|
203
217
|
);
|
|
204
218
|
if (json) {
|
|
205
219
|
printJson(result);
|
|
@@ -208,6 +222,36 @@ async function dbCreateTable(argv: string[], json: boolean): Promise<void> {
|
|
|
208
222
|
console.log(`Created table "${result.table}".`);
|
|
209
223
|
}
|
|
210
224
|
|
|
225
|
+
async function dbCreateIndex(argv: string[], json: boolean): Promise<void> {
|
|
226
|
+
const nameOpt = takeOption(argv, "name");
|
|
227
|
+
const uniqueFlag = hasFlag(nameOpt.rest, "unique");
|
|
228
|
+
const [slug, table, columnsJson] = uniqueFlag.rest;
|
|
229
|
+
if (!table || !columnsJson) die(USAGE);
|
|
230
|
+
const projectId = await resolveProjectId(slug);
|
|
231
|
+
const parsedColumns = parseJsonArg<unknown>(columnsJson, "<columns-json>");
|
|
232
|
+
const columns = Array.isArray(parsedColumns)
|
|
233
|
+
? parsedColumns
|
|
234
|
+
: typeof parsedColumns === "string"
|
|
235
|
+
? [parsedColumns]
|
|
236
|
+
: die("<columns-json> must be a JSON array of column names or a string.");
|
|
237
|
+
const result = await apiFetch<{ table: string; index: string; created: boolean }>(
|
|
238
|
+
`/api/v1/projects/${projectId}/database/tables/${encodeURIComponent(table)}/indexes`,
|
|
239
|
+
{
|
|
240
|
+
method: "POST",
|
|
241
|
+
body: {
|
|
242
|
+
columns,
|
|
243
|
+
name: nameOpt.value,
|
|
244
|
+
unique: uniqueFlag.present ? true : undefined,
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
);
|
|
248
|
+
if (json) {
|
|
249
|
+
printJson(result);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
console.log(`Created index "${result.index}" on "${result.table}".`);
|
|
253
|
+
}
|
|
254
|
+
|
|
211
255
|
async function dbMigrate(argv: string[], json: boolean): Promise<void> {
|
|
212
256
|
const defaultOpt = takeOption(argv, "default");
|
|
213
257
|
const [slug, table, columnJson] = defaultOpt.rest;
|
|
@@ -241,9 +285,12 @@ export async function dbCommand(argv: string[], json: boolean): Promise<void> {
|
|
|
241
285
|
return dbDelete(rest, json);
|
|
242
286
|
case "create-table":
|
|
243
287
|
return dbCreateTable(rest, json);
|
|
288
|
+
case "create-index":
|
|
289
|
+
return dbCreateIndex(rest, json);
|
|
244
290
|
case "migrate":
|
|
245
291
|
return dbMigrate(rest, json);
|
|
246
292
|
default:
|
|
247
293
|
die(USAGE);
|
|
248
294
|
}
|
|
249
295
|
}
|
|
296
|
+
|