@ductape/cli 0.3.18 → 0.3.20
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/dist/commands/db-schema.js +5 -0
- package/dist/commands/db.d.ts +18 -0
- package/dist/commands/db.js +67 -1
- package/dist/index.js +38 -1
- package/package.json +1 -1
|
@@ -259,6 +259,11 @@ export async function runDbSchemaGenerate(opts) {
|
|
|
259
259
|
},
|
|
260
260
|
];
|
|
261
261
|
for (const { fieldName, unique } of parsed.indexFields) {
|
|
262
|
+
// createCollection already materializes fields marked unique. Emitting a
|
|
263
|
+
// second named createIndex operation gives MongoDB the same key/options
|
|
264
|
+
// under a different name and fails with IndexOptionsConflict.
|
|
265
|
+
if (unique)
|
|
266
|
+
continue;
|
|
262
267
|
up.push({
|
|
263
268
|
type: 'createIndex',
|
|
264
269
|
collection: tableName,
|
package/dist/commands/db.d.ts
CHANGED
|
@@ -2,4 +2,22 @@ export declare function runDb(method: string, opts: {
|
|
|
2
2
|
file?: string;
|
|
3
3
|
json?: boolean;
|
|
4
4
|
}): Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Database Actions — reusable, parameterized query/mutation definitions saved against a
|
|
7
|
+
* database component (databases.action.* in the SDK). This is administrative metadata
|
|
8
|
+
* (uses the access-key-backed sdk-proxy, same as `resources <type> create`), not a runtime
|
|
9
|
+
* query — it never connects to the live database. Required for any Feature step that calls
|
|
10
|
+
* ctx.database.query/insert/update/delete, since those take an `event` tag pointing at one
|
|
11
|
+
* of these, not a raw {table, where} shape.
|
|
12
|
+
*
|
|
13
|
+
* Tag format is always "product_tag:database_tag:action_tag" — always pass it fully
|
|
14
|
+
* qualified here (the SDK's 2-part fallback only works inside a single long-lived process
|
|
15
|
+
* that already has that product's builder cached, which a fresh CLI invocation never has).
|
|
16
|
+
*/
|
|
17
|
+
export declare function runDbActions(verb: string, opts: {
|
|
18
|
+
tag?: string;
|
|
19
|
+
database?: string;
|
|
20
|
+
file?: string;
|
|
21
|
+
json?: boolean;
|
|
22
|
+
}, extraArgs: string[]): Promise<void>;
|
|
5
23
|
export declare function runDbContext(json: boolean): void;
|
package/dist/commands/db.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readJsonBody } from '../lib/read-body.js';
|
|
2
2
|
import { setDatabaseContext } from '../lib/context-store.js';
|
|
3
3
|
import { DB_PROXY_METHODS } from '../lib/db-methods.js';
|
|
4
|
-
import { getDbContext, getDbProxy, requireSession } from '../lib/proxy/context.js';
|
|
4
|
+
import { getDbContext, getDbProxy, getSdkProxy, requireSession } from '../lib/proxy/context.js';
|
|
5
5
|
import { loadRuntimeContext } from '../lib/context-store.js';
|
|
6
6
|
import { printJson } from '../lib/output.js';
|
|
7
7
|
export async function runDb(method, opts) {
|
|
@@ -47,6 +47,72 @@ export async function runDb(method, opts) {
|
|
|
47
47
|
}
|
|
48
48
|
printJson(result, Boolean(opts.json));
|
|
49
49
|
}
|
|
50
|
+
const DB_ACTION_VERBS = ['create', 'update', 'get', 'list', 'delete'];
|
|
51
|
+
/**
|
|
52
|
+
* Database Actions — reusable, parameterized query/mutation definitions saved against a
|
|
53
|
+
* database component (databases.action.* in the SDK). This is administrative metadata
|
|
54
|
+
* (uses the access-key-backed sdk-proxy, same as `resources <type> create`), not a runtime
|
|
55
|
+
* query — it never connects to the live database. Required for any Feature step that calls
|
|
56
|
+
* ctx.database.query/insert/update/delete, since those take an `event` tag pointing at one
|
|
57
|
+
* of these, not a raw {table, where} shape.
|
|
58
|
+
*
|
|
59
|
+
* Tag format is always "product_tag:database_tag:action_tag" — always pass it fully
|
|
60
|
+
* qualified here (the SDK's 2-part fallback only works inside a single long-lived process
|
|
61
|
+
* that already has that product's builder cached, which a fresh CLI invocation never has).
|
|
62
|
+
*/
|
|
63
|
+
export async function runDbActions(verb, opts, extraArgs) {
|
|
64
|
+
const v = verb.toLowerCase();
|
|
65
|
+
if (!DB_ACTION_VERBS.includes(v)) {
|
|
66
|
+
throw new Error(`Unknown db actions verb "${verb}". Use: ${DB_ACTION_VERBS.join(', ')}`);
|
|
67
|
+
}
|
|
68
|
+
const proxy = getSdkProxy();
|
|
69
|
+
const tag = opts.tag ?? extraArgs[0];
|
|
70
|
+
let method;
|
|
71
|
+
let params;
|
|
72
|
+
switch (v) {
|
|
73
|
+
case 'create': {
|
|
74
|
+
const body = readJsonBody(opts.file);
|
|
75
|
+
if (!body || Object.keys(body).length === 0) {
|
|
76
|
+
throw new Error('create requires a body: { tag: "product:database:action", name, tableName, ' +
|
|
77
|
+
'operation, template, description?, filterTemplate? } (pass -f <file.json>).');
|
|
78
|
+
}
|
|
79
|
+
method = 'action.create';
|
|
80
|
+
params = [body];
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
case 'update': {
|
|
84
|
+
if (!tag)
|
|
85
|
+
throw new Error('update requires the action tag ("product:database:action")');
|
|
86
|
+
const body = readJsonBody(opts.file) ?? {};
|
|
87
|
+
method = 'action.update';
|
|
88
|
+
params = [{ tag, ...body }];
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case 'get':
|
|
92
|
+
if (!tag)
|
|
93
|
+
throw new Error('get requires the action tag ("product:database:action")');
|
|
94
|
+
method = 'action.fetch';
|
|
95
|
+
params = [tag];
|
|
96
|
+
break;
|
|
97
|
+
case 'list': {
|
|
98
|
+
const databaseTag = opts.database ?? tag;
|
|
99
|
+
if (!databaseTag) {
|
|
100
|
+
throw new Error('list requires --database <product_tag:database_tag>');
|
|
101
|
+
}
|
|
102
|
+
method = 'action.fetchAll';
|
|
103
|
+
params = [databaseTag];
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
case 'delete':
|
|
107
|
+
if (!tag)
|
|
108
|
+
throw new Error('delete requires the action tag ("product:database:action")');
|
|
109
|
+
method = 'action.delete';
|
|
110
|
+
params = [tag];
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
const result = await proxy.execute('databases', method, params);
|
|
114
|
+
printJson(result, Boolean(opts.json));
|
|
115
|
+
}
|
|
50
116
|
export function runDbContext(json) {
|
|
51
117
|
const session = requireSession();
|
|
52
118
|
const ctx = getDbContext(session);
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { runInstall } from './commands/install.js';
|
|
|
15
15
|
import { runStart, runStop, runStatus } from './commands/platform.js';
|
|
16
16
|
import { runResourceCrud, runResourcesList, runEventTopicCrud, runNotificationMessageCrud } from './commands/resources.js';
|
|
17
17
|
import { runCloud, runCloudPreflight } from './commands/cloud.js';
|
|
18
|
-
import { runDb, runDbContext } from './commands/db.js';
|
|
18
|
+
import { runDb, runDbActions, runDbContext } from './commands/db.js';
|
|
19
19
|
import { runDbMigrate, runDbMigrateStatus, runDbMigrateRollback } from './commands/db-migrate.js';
|
|
20
20
|
import { runFeaturesSync } from './commands/features-sync.js';
|
|
21
21
|
import { runDbSchemaGenerate, runDbSchemaPush } from './commands/db-schema.js';
|
|
@@ -805,6 +805,43 @@ dbMigrate
|
|
|
805
805
|
.option('--db <tag>', 'Limit to one db entry')
|
|
806
806
|
.option('-n <count>', 'Number of migrations to roll back', '1')
|
|
807
807
|
.action(wrap((opts) => runDbMigrateRollback({ env: opts.env, db: opts.db, n: Number(opts.n) })));
|
|
808
|
+
const dbActions = db
|
|
809
|
+
.command('actions')
|
|
810
|
+
.description('Reusable database action definitions (saved parameterized queries). Required for any ' +
|
|
811
|
+
'Feature step that uses ctx.database.query/insert/update/delete — those take an `event` ' +
|
|
812
|
+
'tag pointing at one of these, not a raw table/where shape. Administrative (access-key), ' +
|
|
813
|
+
'not a runtime query — create/update never touch the live database.');
|
|
814
|
+
dbActions
|
|
815
|
+
.command('create')
|
|
816
|
+
.description('Create a database action from a file: { tag: "product:database:action", name, tableName, operation, template }')
|
|
817
|
+
.requiredOption('-f, --file <path>', 'JSON file with the action definition')
|
|
818
|
+
.option('--json', 'JSON output')
|
|
819
|
+
.action(wrap((opts) => runDbActions('create', { file: opts.file, json: opts.json }, [])));
|
|
820
|
+
dbActions
|
|
821
|
+
.command('update')
|
|
822
|
+
.description('Update an existing database action')
|
|
823
|
+
.requiredOption('-t, --tag <tag>', 'Action tag ("product:database:action")')
|
|
824
|
+
.requiredOption('-f, --file <path>', 'JSON file with the fields to change')
|
|
825
|
+
.option('--json', 'JSON output')
|
|
826
|
+
.action(wrap((opts) => runDbActions('update', { tag: opts.tag, file: opts.file, json: opts.json }, [])));
|
|
827
|
+
dbActions
|
|
828
|
+
.command('get')
|
|
829
|
+
.description('Fetch one database action')
|
|
830
|
+
.argument('<tag>', 'Action tag ("product:database:action")')
|
|
831
|
+
.option('--json', 'JSON output')
|
|
832
|
+
.action(wrap((tag, opts) => runDbActions('get', { tag, json: opts.json }, [])));
|
|
833
|
+
dbActions
|
|
834
|
+
.command('list')
|
|
835
|
+
.description('List all actions on a database')
|
|
836
|
+
.requiredOption('-d, --database <tag>', 'Database tag ("product_tag:database_tag")')
|
|
837
|
+
.option('--json', 'JSON output')
|
|
838
|
+
.action(wrap((opts) => runDbActions('list', { database: opts.database, json: opts.json }, [])));
|
|
839
|
+
dbActions
|
|
840
|
+
.command('delete')
|
|
841
|
+
.description('Delete a database action')
|
|
842
|
+
.argument('<tag>', 'Action tag ("product:database:action")')
|
|
843
|
+
.option('--json', 'JSON output')
|
|
844
|
+
.action(wrap((tag, opts) => runDbActions('delete', { tag, json: opts.json }, [])));
|
|
808
845
|
const dbSchema = db.command('schema').description('Schema management for ductape/database/schema.json');
|
|
809
846
|
dbSchema
|
|
810
847
|
.command('generate')
|
package/package.json
CHANGED