@google-cloud/kcmd 0.1.0 → 0.2.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/README.md +18 -20
- package/build/ts/kcmd/cli.js +6164 -5631
- package/build/ts/kcmd/gcp/biglake.d.ts +2 -0
- package/build/ts/kcmd/gcp/biglake.js +13 -4
- package/build/ts/kcmd/gcp/spanner.d.ts +10 -0
- package/build/ts/kcmd/gcp/spanner.js +6 -3
- package/build/ts/kcmd/layouts/okf.js +49 -7
- package/build/ts/kcmd/layouts/semantic-model.d.ts +13 -0
- package/build/ts/kcmd/layouts/semantic-model.js +129 -50
- package/build/ts/kcmd/okf/concept.d.ts +1 -1
- package/build/ts/kcmd/okf/concept.js +6 -0
- package/build/ts/kcmd/okf/concept_to_entry.d.ts +2 -0
- package/build/ts/kcmd/okf/concept_to_entry.js +29 -2
- package/build/ts/kcmd/okf/init_okf_workspace.js +7 -9
- package/build/ts/kcmd/okf/okf_metadata.js +17 -0
- package/build/ts/kcmd/semantic/bigquery.js +139 -195
- package/build/ts/kcmd/semantic/binding.js +14 -19
- package/build/ts/kcmd/semantic/deploy_bigquery.js +6 -13
- package/build/ts/kcmd/semantic/deploy_knowledge_catalog.d.ts +10 -35
- package/build/ts/kcmd/semantic/deploy_knowledge_catalog.js +105 -162
- package/build/ts/kcmd/semantic/deploy_spanner.js +7 -14
- package/build/ts/kcmd/semantic/deployment_target.d.ts +1 -4
- package/build/ts/kcmd/semantic/deployment_target.js +6 -62
- package/build/ts/kcmd/semantic/graph_ddl.d.ts +10 -0
- package/build/ts/kcmd/semantic/graph_ddl.js +152 -59
- package/build/ts/kcmd/semantic/import_model.d.ts +26 -4
- package/build/ts/kcmd/semantic/import_model.js +531 -111
- package/build/ts/kcmd/semantic/ir.d.ts +2 -4
- package/build/ts/kcmd/semantic/kc_converter.d.ts +7 -1
- package/build/ts/kcmd/semantic/kc_converter.js +32 -27
- package/build/ts/kcmd/semantic/kc_custom_types.d.ts +5 -12
- package/build/ts/kcmd/semantic/kc_custom_types.js +43 -114
- package/build/ts/kcmd/semantic/kc_ids.d.ts +4 -5
- package/build/ts/kcmd/semantic/kc_ids.js +4 -7
- package/build/ts/kcmd/semantic/knowledge_catalog.d.ts +0 -3
- package/build/ts/kcmd/semantic/knowledge_catalog.js +3 -86
- package/build/ts/kcmd/semantic/loader.d.ts +7 -11
- package/build/ts/kcmd/semantic/loader.js +282 -171
- package/build/ts/kcmd/semantic/osi_converter.js +14 -65
- package/build/ts/kcmd/semantic/parameters.d.ts +1 -0
- package/build/ts/kcmd/semantic/parameters.js +22 -3
- package/build/ts/kcmd/semantic/pull_kc.d.ts +1 -5
- package/build/ts/kcmd/semantic/pull_kc.js +38 -112
- package/build/ts/kcmd/semantic/resolve_inheritance.d.ts +7 -2
- package/build/ts/kcmd/semantic/resolve_inheritance.js +37 -21
- package/build/ts/kcmd/semantic/resolve_profiles.d.ts +51 -10
- package/build/ts/kcmd/semantic/resolve_profiles.js +213 -32
- package/build/ts/kcmd/semantic/runtime/runtime.d.ts +4 -12
- package/build/ts/kcmd/semantic/runtime/runtime.js +4 -21
- package/build/ts/kcmd/semantic/runtime/store.d.ts +14 -19
- package/build/ts/kcmd/semantic/runtime/store.js +21 -37
- package/build/ts/kcmd/semantic/source_dialect.d.ts +9 -2
- package/build/ts/kcmd/semantic/source_dialect.js +83 -33
- package/build/ts/kcmd/semantic/source_entries.d.ts +1 -1
- package/build/ts/kcmd/semantic/source_entries.js +95 -36
- package/build/ts/kcmd/semantic/sql_expr_utils.d.ts +13 -7
- package/build/ts/kcmd/semantic/sql_expr_utils.js +240 -67
- package/build/ts/kcmd/semantic/sql_parser.d.ts +5 -2
- package/build/ts/kcmd/semantic/sql_parser.js +22 -0
- package/build/ts/kcmd/semantic/transpile.d.ts +12 -10
- package/build/ts/kcmd/semantic/transpile.js +79 -61
- package/build/ts/kcmd/semantic/validate.d.ts +37 -2
- package/build/ts/kcmd/semantic/validate.js +467 -126
- package/build/ts/kcmd/snapshot.d.ts +4 -0
- package/build/ts/kcmd/snapshot.js +7 -0
- package/build/ts/kcmd/sync.js +44 -7
- package/package.json +1 -1
|
@@ -27,6 +27,10 @@ export declare class CatalogSnapshot {
|
|
|
27
27
|
private _buildTypes;
|
|
28
28
|
_loadEntryType(entryType: string): Promise<void>;
|
|
29
29
|
_storeEntry(entry: dataplex.Entry): Promise<void>;
|
|
30
|
+
_previewStoreEntry(entry: dataplex.Entry): {
|
|
31
|
+
localName: string;
|
|
32
|
+
exists: boolean;
|
|
33
|
+
};
|
|
30
34
|
_fetchEntry(name: string): Promise<dataplex.Entry | undefined>;
|
|
31
35
|
}
|
|
32
36
|
export declare function toLocalEntry(entry: dataplex.Entry, localName: string): md.Entry;
|
|
@@ -233,6 +233,13 @@ class CatalogSnapshot {
|
|
|
233
233
|
}
|
|
234
234
|
await this._layout.saveEntry(localName, local);
|
|
235
235
|
}
|
|
236
|
+
// Reports what _storeEntry would do with a Dataplex entry, without writing:
|
|
237
|
+
// the local name it maps to and whether a local copy already exists. Used by
|
|
238
|
+
// `pull --dry-run`.
|
|
239
|
+
_previewStoreEntry(entry) {
|
|
240
|
+
const localName = this.manifest.source.localName(entry);
|
|
241
|
+
return { localName, exists: this._layout.entryExists(localName) };
|
|
242
|
+
}
|
|
236
243
|
// Fetches a Dataplex entry from its local metadata representation.
|
|
237
244
|
// This is only meant to be used within the syncing process (as part of push operations).
|
|
238
245
|
async _fetchEntry(name) {
|
package/build/ts/kcmd/sync.js
CHANGED
|
@@ -290,6 +290,20 @@ async function fetchEntryLinks(catalog, target, entries) {
|
|
|
290
290
|
}
|
|
291
291
|
return [...byKey.values()];
|
|
292
292
|
}
|
|
293
|
+
async function withLinkRateLimitRetry(fn) {
|
|
294
|
+
const baseDelay = process.env.GCP_RETRY_DELAY_MS !== undefined
|
|
295
|
+
? Math.max(0, Number(process.env.GCP_RETRY_DELAY_MS) || 0)
|
|
296
|
+
: 500;
|
|
297
|
+
let delay = baseDelay;
|
|
298
|
+
let res = await fn();
|
|
299
|
+
for (let attempt = 1; attempt < 4 && res.status === 429; attempt++) {
|
|
300
|
+
if (delay > 0)
|
|
301
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
302
|
+
delay = Math.min(delay * 2, 5000);
|
|
303
|
+
res = await fn();
|
|
304
|
+
}
|
|
305
|
+
return res;
|
|
306
|
+
}
|
|
293
307
|
/** Reconciles `bundle/_links.yaml` against the entry group's EntryLinks. */
|
|
294
308
|
async function reconcileLinks(catalog, target, desiredLinks, entries, existingEntries) {
|
|
295
309
|
const existingLinks = new Map();
|
|
@@ -304,8 +318,14 @@ async function reconcileLinks(catalog, target, desiredLinks, entries, existingEn
|
|
|
304
318
|
const res = await catalog.lookupEntryLinks(target.project, target.location, {
|
|
305
319
|
entry: entryName,
|
|
306
320
|
});
|
|
307
|
-
|
|
321
|
+
// A brand-new entry created milliseconds earlier in batchChangeMetadata
|
|
322
|
+
// can return 403 ("or it may not exist") during regional read-after-create
|
|
323
|
+
// IAM propagation and has no pre-existing links to delete.
|
|
324
|
+
if (res.status === 404 ||
|
|
325
|
+
res.status === 501 ||
|
|
326
|
+
(res.status === 403 && !existingEntries.has(entryName))) {
|
|
308
327
|
return [];
|
|
328
|
+
}
|
|
309
329
|
if (res.status !== 200) {
|
|
310
330
|
console.error(` lookupEntryLinks(${entryName}): HTTP ${res.status} ${res.message ?? ''}`);
|
|
311
331
|
lookupFailed = true;
|
|
@@ -345,7 +365,7 @@ async function reconcileLinks(catalog, target, desiredLinks, entries, existingEn
|
|
|
345
365
|
for (const [id, prev] of existingLinks) {
|
|
346
366
|
const desired = desiredById.get(id);
|
|
347
367
|
if (!desired || (0, links_1.isStaleEntryLink)(prev, desired)) {
|
|
348
|
-
const del = await catalog.deleteEntryLink(target.project, target.location, target.groupId, id);
|
|
368
|
+
const del = await withLinkRateLimitRetry(() => catalog.deleteEntryLink(target.project, target.location, target.groupId, id));
|
|
349
369
|
if (del.status !== 200 && del.status !== 404) {
|
|
350
370
|
console.error(` ${id}: HTTP ${del.status} ${del.message ?? ''}`);
|
|
351
371
|
failed++;
|
|
@@ -359,11 +379,11 @@ async function reconcileLinks(catalog, target, desiredLinks, entries, existingEn
|
|
|
359
379
|
const id = (0, links_1.entryLinkId)(link);
|
|
360
380
|
const prev = existingLinks.get(id);
|
|
361
381
|
if (!prev) {
|
|
362
|
-
const res = await catalog.createEntryLink(target.project, target.location, target.groupId, id, link);
|
|
382
|
+
const res = await withLinkRateLimitRetry(() => catalog.createEntryLink(target.project, target.location, target.groupId, id, link));
|
|
363
383
|
if (res.status === 409) {
|
|
364
|
-
const del = await catalog.deleteEntryLink(target.project, target.location, target.groupId, id);
|
|
384
|
+
const del = await withLinkRateLimitRetry(() => catalog.deleteEntryLink(target.project, target.location, target.groupId, id));
|
|
365
385
|
if (del.status === 200 || del.status === 404) {
|
|
366
|
-
const retry = await catalog.createEntryLink(target.project, target.location, target.groupId, id, link);
|
|
386
|
+
const retry = await withLinkRateLimitRetry(() => catalog.createEntryLink(target.project, target.location, target.groupId, id, link));
|
|
367
387
|
if (retry.status !== 200) {
|
|
368
388
|
console.error(` ${id}: HTTP ${retry.status} ${retry.message ?? ''}`);
|
|
369
389
|
failed++;
|
|
@@ -380,7 +400,7 @@ async function reconcileLinks(catalog, target, desiredLinks, entries, existingEn
|
|
|
380
400
|
}
|
|
381
401
|
}
|
|
382
402
|
else if (JSON.stringify(prev.aspects ?? {}) !== JSON.stringify(link.aspects ?? {})) {
|
|
383
|
-
const upd = await catalog.updateEntryLink(link, Object.keys(link.aspects ?? {}));
|
|
403
|
+
const upd = await withLinkRateLimitRetry(() => catalog.updateEntryLink(link, Object.keys(link.aspects ?? {})));
|
|
384
404
|
if (upd.status !== 200) {
|
|
385
405
|
console.error(` ${id}: HTTP ${upd.status} ${upd.message ?? ''}`);
|
|
386
406
|
failed++;
|
|
@@ -436,6 +456,8 @@ class CatalogSync {
|
|
|
436
456
|
const requested = [...aspectTypes.keys()];
|
|
437
457
|
const system = new Set(this._snapshot.manifest.source.systemAspects);
|
|
438
458
|
const leftOut = new Map();
|
|
459
|
+
let wouldCreate = 0;
|
|
460
|
+
let wouldUpdate = 0;
|
|
439
461
|
for (const entry of entries) {
|
|
440
462
|
// TODO: Handle local modification conflicts.
|
|
441
463
|
// TODO: Handle config changes or service deletions that require removing local entries.
|
|
@@ -450,7 +472,18 @@ class CatalogSync {
|
|
|
450
472
|
// lookupEntry sets every returned aspect's type.
|
|
451
473
|
const stored = new Set(Object.values(res.result.aspects ?? {})
|
|
452
474
|
.map(a => gcp._nameToTypeRef(a.aspectType)));
|
|
453
|
-
|
|
475
|
+
if (options?.dryRun) {
|
|
476
|
+
// Reconstruct and report only; never touch the local snapshot.
|
|
477
|
+
const { localName, exists } = this._snapshot._previewStoreEntry(res.result);
|
|
478
|
+
console.log(`would ${exists ? 'update' : 'create'} ${localName}`);
|
|
479
|
+
if (exists)
|
|
480
|
+
wouldUpdate++;
|
|
481
|
+
else
|
|
482
|
+
wouldCreate++;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
await this._snapshot._storeEntry(res.result);
|
|
486
|
+
}
|
|
454
487
|
const onEntry = await this._catalog.lookupEntryAspectTypes(nameParts[1], nameParts[3], entry.name);
|
|
455
488
|
for (const type of onEntry.result ?? []) {
|
|
456
489
|
if (!stored.has(type) && !aspectTypes.has(type) && !system.has(type)) {
|
|
@@ -463,6 +496,10 @@ class CatalogSync {
|
|
|
463
496
|
`${count === 1 ? 'entry' : 'entries'}; list it under ` +
|
|
464
497
|
`snapshot.aspects in catalog.yaml to pull it.`);
|
|
465
498
|
}
|
|
499
|
+
if (options?.dryRun) {
|
|
500
|
+
console.log(`Dry run: would write ${wouldCreate} new and ${wouldUpdate} updated ` +
|
|
501
|
+
`entr${wouldCreate + wouldUpdate === 1 ? 'y' : 'ies'}; no files written (--dry-run).`);
|
|
502
|
+
}
|
|
466
503
|
return { success: true };
|
|
467
504
|
}
|
|
468
505
|
catch (e) {
|