@google-cloud/kcmd 0.0.0-stage → 0.2.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/LICENSE +203 -0
- package/README.md +264 -2
- package/build/ts/kcmd/cli.js +20252 -0
- package/build/ts/kcmd/gcp/alloydb.d.ts +12 -0
- package/build/ts/kcmd/gcp/alloydb.js +70 -0
- package/build/ts/kcmd/gcp/api.d.ts +29 -0
- package/build/ts/kcmd/gcp/api.js +162 -0
- package/build/ts/kcmd/gcp/biglake.d.ts +18 -0
- package/build/ts/kcmd/gcp/biglake.js +59 -0
- package/build/ts/kcmd/gcp/bigquery.d.ts +57 -0
- package/build/ts/kcmd/gcp/bigquery.js +134 -0
- package/build/ts/kcmd/gcp/context.d.ts +10 -0
- package/build/ts/kcmd/gcp/context.js +74 -0
- package/build/ts/kcmd/gcp/crm.d.ts +13 -0
- package/build/ts/kcmd/gcp/crm.js +91 -0
- package/build/ts/kcmd/gcp/dataplex.d.ts +147 -0
- package/build/ts/kcmd/gcp/dataplex.js +406 -0
- package/build/ts/kcmd/gcp/index.d.ts +3 -0
- package/build/ts/kcmd/gcp/index.js +21 -0
- package/build/ts/kcmd/gcp/spanner.d.ts +73 -0
- package/build/ts/kcmd/gcp/spanner.js +126 -0
- package/build/ts/kcmd/index.d.ts +7 -0
- package/build/ts/kcmd/index.js +46 -0
- package/build/ts/kcmd/layout.d.ts +16 -0
- package/build/ts/kcmd/layout.js +31 -0
- package/build/ts/kcmd/layouts/documents.d.ts +24 -0
- package/build/ts/kcmd/layouts/documents.js +264 -0
- package/build/ts/kcmd/layouts/okf.d.ts +31 -0
- package/build/ts/kcmd/layouts/okf.js +386 -0
- package/build/ts/kcmd/layouts/semantic-model.d.ts +74 -0
- package/build/ts/kcmd/layouts/semantic-model.js +621 -0
- package/build/ts/kcmd/layouts/standard.d.ts +13 -0
- package/build/ts/kcmd/layouts/standard.js +108 -0
- package/build/ts/kcmd/manifest.d.ts +34 -0
- package/build/ts/kcmd/manifest.js +262 -0
- package/build/ts/kcmd/metadata.d.ts +25 -0
- package/build/ts/kcmd/metadata.js +8 -0
- package/build/ts/kcmd/okf/catalog_residue.d.ts +14 -0
- package/build/ts/kcmd/okf/catalog_residue.js +124 -0
- package/build/ts/kcmd/okf/concept.d.ts +14 -0
- package/build/ts/kcmd/okf/concept.js +110 -0
- package/build/ts/kcmd/okf/concept_to_entry.d.ts +10 -0
- package/build/ts/kcmd/okf/concept_to_entry.js +281 -0
- package/build/ts/kcmd/okf/init_okf_workspace.d.ts +15 -0
- package/build/ts/kcmd/okf/init_okf_workspace.js +113 -0
- package/build/ts/kcmd/okf/links.d.ts +23 -0
- package/build/ts/kcmd/okf/links.js +468 -0
- package/build/ts/kcmd/okf/okf_metadata.d.ts +12 -0
- package/build/ts/kcmd/okf/okf_metadata.js +99 -0
- package/build/ts/kcmd/semantic/bigquery.d.ts +22 -0
- package/build/ts/kcmd/semantic/bigquery.js +469 -0
- package/build/ts/kcmd/semantic/binding.d.ts +3 -0
- package/build/ts/kcmd/semantic/binding.js +92 -0
- package/build/ts/kcmd/semantic/catalog_entry.d.ts +24 -0
- package/build/ts/kcmd/semantic/catalog_entry.js +35 -0
- package/build/ts/kcmd/semantic/converters/owl/convert.d.ts +26 -0
- package/build/ts/kcmd/semantic/converters/owl/convert.js +41 -0
- package/build/ts/kcmd/semantic/converters/owl/model.d.ts +98 -0
- package/build/ts/kcmd/semantic/converters/owl/model.js +30 -0
- package/build/ts/kcmd/semantic/converters/owl/parse.d.ts +11 -0
- package/build/ts/kcmd/semantic/converters/owl/parse.js +634 -0
- package/build/ts/kcmd/semantic/converters/owl/to_ir.d.ts +19 -0
- package/build/ts/kcmd/semantic/converters/owl/to_ir.js +390 -0
- package/build/ts/kcmd/semantic/deploy_bigquery.d.ts +20 -0
- package/build/ts/kcmd/semantic/deploy_bigquery.js +226 -0
- package/build/ts/kcmd/semantic/deploy_knowledge_catalog.d.ts +104 -0
- package/build/ts/kcmd/semantic/deploy_knowledge_catalog.js +1367 -0
- package/build/ts/kcmd/semantic/deploy_spanner.d.ts +15 -0
- package/build/ts/kcmd/semantic/deploy_spanner.js +150 -0
- package/build/ts/kcmd/semantic/deployment_target.d.ts +93 -0
- package/build/ts/kcmd/semantic/deployment_target.js +379 -0
- package/build/ts/kcmd/semantic/graph_ddl.d.ts +44 -0
- package/build/ts/kcmd/semantic/graph_ddl.js +656 -0
- package/build/ts/kcmd/semantic/import_model.d.ts +72 -0
- package/build/ts/kcmd/semantic/import_model.js +1698 -0
- package/build/ts/kcmd/semantic/ir.d.ts +589 -0
- package/build/ts/kcmd/semantic/ir.js +247 -0
- package/build/ts/kcmd/semantic/kc_actions.d.ts +45 -0
- package/build/ts/kcmd/semantic/kc_actions.js +531 -0
- package/build/ts/kcmd/semantic/kc_constraints.d.ts +44 -0
- package/build/ts/kcmd/semantic/kc_constraints.js +279 -0
- package/build/ts/kcmd/semantic/kc_converter.d.ts +37 -0
- package/build/ts/kcmd/semantic/kc_converter.js +839 -0
- package/build/ts/kcmd/semantic/kc_custom_types.d.ts +63 -0
- package/build/ts/kcmd/semantic/kc_custom_types.js +751 -0
- package/build/ts/kcmd/semantic/kc_entries.d.ts +155 -0
- package/build/ts/kcmd/semantic/kc_entries.js +284 -0
- package/build/ts/kcmd/semantic/kc_ids.d.ts +102 -0
- package/build/ts/kcmd/semantic/kc_ids.js +188 -0
- package/build/ts/kcmd/semantic/knowledge_catalog.d.ts +29 -0
- package/build/ts/kcmd/semantic/knowledge_catalog.js +960 -0
- package/build/ts/kcmd/semantic/loader.d.ts +258 -0
- package/build/ts/kcmd/semantic/loader.js +3576 -0
- package/build/ts/kcmd/semantic/names.d.ts +10 -0
- package/build/ts/kcmd/semantic/names.js +85 -0
- package/build/ts/kcmd/semantic/osi_converter.d.ts +60 -0
- package/build/ts/kcmd/semantic/osi_converter.js +910 -0
- package/build/ts/kcmd/semantic/parameters.d.ts +19 -0
- package/build/ts/kcmd/semantic/parameters.js +171 -0
- package/build/ts/kcmd/semantic/pull_kc.d.ts +10 -0
- package/build/ts/kcmd/semantic/pull_kc.js +272 -0
- package/build/ts/kcmd/semantic/resolve_inheritance.d.ts +59 -0
- package/build/ts/kcmd/semantic/resolve_inheritance.js +346 -0
- package/build/ts/kcmd/semantic/resolve_profiles.d.ts +291 -0
- package/build/ts/kcmd/semantic/resolve_profiles.js +2003 -0
- package/build/ts/kcmd/semantic/runtime/agent_tools.d.ts +93 -0
- package/build/ts/kcmd/semantic/runtime/agent_tools.js +243 -0
- package/build/ts/kcmd/semantic/runtime/dialect.d.ts +13 -0
- package/build/ts/kcmd/semantic/runtime/dialect.js +39 -0
- package/build/ts/kcmd/semantic/runtime/runtime.d.ts +88 -0
- package/build/ts/kcmd/semantic/runtime/runtime.js +301 -0
- package/build/ts/kcmd/semantic/runtime/store.d.ts +112 -0
- package/build/ts/kcmd/semantic/runtime/store.js +344 -0
- package/build/ts/kcmd/semantic/skills.d.ts +110 -0
- package/build/ts/kcmd/semantic/skills.js +697 -0
- package/build/ts/kcmd/semantic/source_dialect.d.ts +17 -0
- package/build/ts/kcmd/semantic/source_dialect.js +311 -0
- package/build/ts/kcmd/semantic/source_entries.d.ts +12 -0
- package/build/ts/kcmd/semantic/source_entries.js +341 -0
- package/build/ts/kcmd/semantic/spanner.d.ts +18 -0
- package/build/ts/kcmd/semantic/spanner.js +60 -0
- package/build/ts/kcmd/semantic/sql_expr_utils.d.ts +23 -0
- package/build/ts/kcmd/semantic/sql_expr_utils.js +394 -0
- package/build/ts/kcmd/semantic/sql_identifiers.d.ts +6 -0
- package/build/ts/kcmd/semantic/sql_identifiers.js +267 -0
- package/build/ts/kcmd/semantic/sql_parser.d.ts +47 -0
- package/build/ts/kcmd/semantic/sql_parser.js +400 -0
- package/build/ts/kcmd/semantic/transpile.d.ts +76 -0
- package/build/ts/kcmd/semantic/transpile.js +581 -0
- package/build/ts/kcmd/semantic/validate.d.ts +70 -0
- package/build/ts/kcmd/semantic/validate.js +2266 -0
- package/build/ts/kcmd/semantic/yaml_options.d.ts +6 -0
- package/build/ts/kcmd/semantic/yaml_options.js +58 -0
- package/build/ts/kcmd/semantic/yaml_update.d.ts +26 -0
- package/build/ts/kcmd/semantic/yaml_update.js +782 -0
- package/build/ts/kcmd/snapshot.d.ts +37 -0
- package/build/ts/kcmd/snapshot.js +386 -0
- package/build/ts/kcmd/source.d.ts +31 -0
- package/build/ts/kcmd/source.js +119 -0
- package/build/ts/kcmd/sources/bq-dataset.d.ts +17 -0
- package/build/ts/kcmd/sources/bq-dataset.js +131 -0
- package/build/ts/kcmd/sources/entrygroup.d.ts +21 -0
- package/build/ts/kcmd/sources/entrygroup.js +83 -0
- package/build/ts/kcmd/sources/kb.d.ts +21 -0
- package/build/ts/kcmd/sources/kb.js +82 -0
- package/build/ts/kcmd/sources/semantic-model.d.ts +18 -0
- package/build/ts/kcmd/sources/semantic-model.js +48 -0
- package/build/ts/kcmd/sync.d.ts +35 -0
- package/build/ts/kcmd/sync.js +734 -0
- package/package.json +62 -4
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// How a model's CONSTRAINTS are encoded in Knowledge Catalog.
|
|
3
|
+
//
|
|
4
|
+
// One entry per constraint, parented to the model anchor, carrying one aspect
|
|
5
|
+
// that holds the invariant. An action is published the same way. Dataplex has
|
|
6
|
+
// no built-in constraint type, so the entry and aspect types are the custom
|
|
7
|
+
// `semantic-constraint` pair, declared in kc_custom_types.ts and created by
|
|
8
|
+
// `kcmd init --semantic-model`. That file lists what is custom; this one holds
|
|
9
|
+
// the encoding that fills the aspect.
|
|
10
|
+
//
|
|
11
|
+
// An entry of its own is what makes the invariant governable. A search can list
|
|
12
|
+
// every rule a model states, whichever way the rule is settled. Dropping a
|
|
13
|
+
// constraint from the model deletes its entry, so the catalog never advertises
|
|
14
|
+
// a rule the model stopped requiring.
|
|
15
|
+
//
|
|
16
|
+
// The five authored fields land in two places. `judgment`, `on_violation`,
|
|
17
|
+
// `severity` and `ai_context` go on the aspect, the last whole --
|
|
18
|
+
// aiContextField in kc_custom_types.ts says why. `description` goes on the
|
|
19
|
+
// entry source, where a pull of an action already reads it, and because a
|
|
20
|
+
// violation quotes that sentence back to the caller as the error, which makes
|
|
21
|
+
// it the entry's summary.
|
|
22
|
+
//
|
|
23
|
+
// The aspect type still DECLARES `expression` and `evaluation`, the two fields
|
|
24
|
+
// of the removed deterministic body, and nothing here writes either. They stay
|
|
25
|
+
// declared so an aspect type already created in a project keeps matching the
|
|
26
|
+
// one `kcmd init` would create, and so a catalog that still holds an
|
|
27
|
+
// expression-only constraint from an older push reads back as a skip with a
|
|
28
|
+
// reason rather than as a silent empty rule. See readConstraint.
|
|
29
|
+
//
|
|
30
|
+
// Both routing words are on the aspect because they are machine-readable, and
|
|
31
|
+
// they are two fields because they answer different questions: what the engine
|
|
32
|
+
// does about a breach, and how grave the breach is. A constraint that states
|
|
33
|
+
// neither is published without them and reads back the same way, so a default
|
|
34
|
+
// stays the IR's to define and a pull never invents a value the model never
|
|
35
|
+
// stated.
|
|
36
|
+
//
|
|
37
|
+
// Call sites: knowledge_catalog.ts emits the entries, kc_converter.ts reads
|
|
38
|
+
// them back, pull_kc.ts hydrates the aspect.
|
|
39
|
+
//
|
|
40
|
+
// WHEN A BUILT-IN CONSTRAINT TYPE SHIPS, follow the instructions at the top of
|
|
41
|
+
// kc_custom_types.ts. Nothing in this file changes, because the readers below
|
|
42
|
+
// match a type by its id suffix and ignore the project it lives in.
|
|
43
|
+
//
|
|
44
|
+
// The helpers at the bottom repeat a few lines from the modules above on
|
|
45
|
+
// purpose. This module imports only the IR, the entry shape and the type
|
|
46
|
+
// registry, so it can be swapped or deleted as a unit.
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.constraintEntryTypeName = constraintEntryTypeName;
|
|
49
|
+
exports.constraintAspectTypeName = constraintAspectTypeName;
|
|
50
|
+
exports.constraintAspectKey = constraintAspectKey;
|
|
51
|
+
exports.constraintEntryId = constraintEntryId;
|
|
52
|
+
exports.constraintOwnedPrefix = constraintOwnedPrefix;
|
|
53
|
+
exports.constraintEntries = constraintEntries;
|
|
54
|
+
exports.isConstraintEntry = isConstraintEntry;
|
|
55
|
+
exports.constraintAspectTypes = constraintAspectTypes;
|
|
56
|
+
exports.readConstraint = readConstraint;
|
|
57
|
+
const ir_1 = require("./ir");
|
|
58
|
+
const kc_custom_types_1 = require("./kc_custom_types");
|
|
59
|
+
// Full resource name of the constraint entry type for a destination.
|
|
60
|
+
function constraintEntryTypeName(dest) {
|
|
61
|
+
return (0, kc_custom_types_1.customEntryTypeName)(kc_custom_types_1.CONSTRAINT_TYPE_ID, dest);
|
|
62
|
+
}
|
|
63
|
+
// Full resource name of the constraint aspect type for a destination.
|
|
64
|
+
function constraintAspectTypeName(dest) {
|
|
65
|
+
return (0, kc_custom_types_1.customAspectTypeName)(kc_custom_types_1.CONSTRAINT_TYPE_ID, dest);
|
|
66
|
+
}
|
|
67
|
+
// Aspect-map key: the `project.location.type` reference form the client keys an
|
|
68
|
+
// entry's aspects by.
|
|
69
|
+
function constraintAspectKey(dest) {
|
|
70
|
+
return (0, kc_custom_types_1.customAspectKey)(kc_custom_types_1.CONSTRAINT_TYPE_ID, dest);
|
|
71
|
+
}
|
|
72
|
+
// The entry id of one constraint: `<model>.constraints.<name>`, alongside
|
|
73
|
+
// `<model>.metrics.<name>` and `<model>.actions.<name>`.
|
|
74
|
+
function constraintEntryId(modelId, constraintName) {
|
|
75
|
+
return `${modelId}.constraints.${slug(constraintName)}`;
|
|
76
|
+
}
|
|
77
|
+
// The entry-id prefix a model's constraints occupy, so delete reconciliation
|
|
78
|
+
// removes the entry of a constraint dropped from the model.
|
|
79
|
+
function constraintOwnedPrefix(modelId) {
|
|
80
|
+
return `${modelId}.constraints.`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* One entry per constraint, to append to the model's entries.
|
|
84
|
+
*
|
|
85
|
+
* Empty when the model declares no constraints, so a model without them is
|
|
86
|
+
* unchanged from before constraints existed. Warns once when it is non-empty:
|
|
87
|
+
* constraints reach Knowledge Catalog and nowhere else, which is worth saying
|
|
88
|
+
* out loud on a push that also deploys a graph.
|
|
89
|
+
*/
|
|
90
|
+
function constraintEntries(model, modelId, ctx, warnings) {
|
|
91
|
+
const constraints = model.constraints ?? [];
|
|
92
|
+
if (!constraints.length)
|
|
93
|
+
return [];
|
|
94
|
+
const entries = [];
|
|
95
|
+
for (const constraint of constraints) {
|
|
96
|
+
const id = constraintEntryId(modelId, constraint.name);
|
|
97
|
+
if (!ctx.claim(id, `constraint '${constraint.name}'`))
|
|
98
|
+
continue;
|
|
99
|
+
entries.push({
|
|
100
|
+
name: ctx.entry(id),
|
|
101
|
+
entryType: constraintEntryTypeName(ctx),
|
|
102
|
+
parentEntry: ctx.anchor,
|
|
103
|
+
entrySource: compact({
|
|
104
|
+
displayName: constraint.name,
|
|
105
|
+
description: constraint.description,
|
|
106
|
+
}),
|
|
107
|
+
aspects: {
|
|
108
|
+
[constraintAspectKey(ctx)]: {
|
|
109
|
+
aspectType: constraintAspectTypeName(ctx),
|
|
110
|
+
data: constraintAspectData(constraint),
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
// Counted from what was emitted rather than from the model, so a name
|
|
116
|
+
// collision that skipped a constraint does not inflate the number.
|
|
117
|
+
if (entries.length)
|
|
118
|
+
warnings.push(`model '${model.name}': ${entries.length} constraint(s) published as ` +
|
|
119
|
+
`${kc_custom_types_1.CONSTRAINT_TYPE_ID} entries (Knowledge Catalog is the only ` +
|
|
120
|
+
`system a constraint reaches).`);
|
|
121
|
+
return entries;
|
|
122
|
+
}
|
|
123
|
+
// The aspect payload for one constraint: the invariant, what a violation of it
|
|
124
|
+
// does, how grave it is, and the whole of any `ai_context` declared on it.
|
|
125
|
+
//
|
|
126
|
+
// Every field here is read off the model. Nothing is computed, and in
|
|
127
|
+
// particular the aspect type's `evaluation` field is left unwritten: it existed
|
|
128
|
+
// to say which of two bodies a constraint used, and there is one body.
|
|
129
|
+
function constraintAspectData(constraint) {
|
|
130
|
+
return compact({
|
|
131
|
+
judgment: constraint.judgment,
|
|
132
|
+
aiContext: (0, kc_custom_types_1.aiContextAspectValue)(constraint.aiContext),
|
|
133
|
+
onViolation: constraint.onViolation,
|
|
134
|
+
severity: constraint.severity,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// Read side: a constraint entry -> the IR.
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
// True when an entry is one of a model's constraints. The match is on the entry
|
|
141
|
+
// type's id suffix, so the project the type lives in need not be known. That is
|
|
142
|
+
// what lets a pull keep working once the custom type is replaced by a built-in
|
|
143
|
+
// one.
|
|
144
|
+
function isConstraintEntry(entry) {
|
|
145
|
+
return entry.entryType?.endsWith(`/entryTypes/${kc_custom_types_1.CONSTRAINT_TYPE_ID}`) ??
|
|
146
|
+
false;
|
|
147
|
+
}
|
|
148
|
+
// The aspect type resource names to hydrate for a constraint entry. Named
|
|
149
|
+
// through the entry type's own project so the pull follows the type wherever it
|
|
150
|
+
// lives.
|
|
151
|
+
function constraintAspectTypes(entryTypeBase) {
|
|
152
|
+
return [`${entryTypeBase}/aspectTypes/${kc_custom_types_1.CONSTRAINT_TYPE_ID}`];
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Recovers one constraint from its entry, the inverse of constraintEntries.
|
|
156
|
+
*
|
|
157
|
+
* Returns undefined, with a warning, for an entry that states no judgment: an
|
|
158
|
+
* invariant that states no rule would be pulled into a model that then fails
|
|
159
|
+
* its own push-side validation, so one bad entry degrades itself rather than
|
|
160
|
+
* the pull. An entry left over from a push that wrote the removed `expression`
|
|
161
|
+
* body lands there too, and the warning says so by name -- that catalog holds a
|
|
162
|
+
* rule this model can no longer state, and the author has to restate it.
|
|
163
|
+
*
|
|
164
|
+
* `evaluation` is not read. There is one body, so the word it carried says
|
|
165
|
+
* nothing the entry does not.
|
|
166
|
+
*/
|
|
167
|
+
function readConstraint(entry, warnings) {
|
|
168
|
+
const name = entry.entrySource?.displayName || idOf(entry.name);
|
|
169
|
+
const data = constraintAspectDataOf(entry);
|
|
170
|
+
const judgment = aspectText(data.judgment);
|
|
171
|
+
if (!judgment) {
|
|
172
|
+
const stale = aspectText(data.expression) ?
|
|
173
|
+
`, though it states an expression -- the deterministic body was ` +
|
|
174
|
+
`removed, and the rule has to be restated in words` :
|
|
175
|
+
'';
|
|
176
|
+
warnings.push(`constraint '${name}': the ${kc_custom_types_1.CONSTRAINT_TYPE_ID} aspect has no ` +
|
|
177
|
+
`judgment${stale}; the constraint is skipped, and pushing this model ` +
|
|
178
|
+
`back will delete the entry`);
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
const constraint = { name, judgment };
|
|
182
|
+
const description = entry.entrySource?.description;
|
|
183
|
+
if (description !== undefined && description !== '')
|
|
184
|
+
constraint.description = description;
|
|
185
|
+
const onViolation = readEnum(name, 'onViolation', data.onViolation, ir_1.VIOLATION_EFFECTS, warnings);
|
|
186
|
+
if (onViolation)
|
|
187
|
+
constraint.onViolation = onViolation;
|
|
188
|
+
// A constraint must say what a violation does, so a pulled one that states no
|
|
189
|
+
// routing word is a model that will not push. Saying so here names the
|
|
190
|
+
// constraint while the pull is in front of the author; the alternative is a
|
|
191
|
+
// push error about a key they never wrote.
|
|
192
|
+
if (constraint.onViolation === undefined) {
|
|
193
|
+
warnings.push(`constraint '${name}': the ${kc_custom_types_1.CONSTRAINT_TYPE_ID} aspect states a ` +
|
|
194
|
+
`judgment but no onViolation, so the pulled constraint will not push ` +
|
|
195
|
+
`until one is added; a constraint must say whether a breach rejects, ` +
|
|
196
|
+
`escalates or warns`);
|
|
197
|
+
}
|
|
198
|
+
const severity = readEnum(name, 'severity', data.severity, ir_1.CONSTRAINT_SEVERITIES, warnings);
|
|
199
|
+
if (severity)
|
|
200
|
+
constraint.severity = severity;
|
|
201
|
+
const aiContext = (0, kc_custom_types_1.aiContextFromAspect)(data.aiContext);
|
|
202
|
+
if (aiContext)
|
|
203
|
+
constraint.aiContext = aiContext;
|
|
204
|
+
return constraint;
|
|
205
|
+
}
|
|
206
|
+
// The value an aspect field states, or undefined when it states none.
|
|
207
|
+
//
|
|
208
|
+
// A value outside the ones the IR defines is dropped with a warning rather than
|
|
209
|
+
// kept, because an unrecognized word would fail the pulled model's own
|
|
210
|
+
// push-side validation. What dropping costs differs by field. An unreadable
|
|
211
|
+
// `severity` leaves a rule unranked, which nothing reads yet. An unreadable
|
|
212
|
+
// `onViolation` has nothing to fall back to, because a constraint must state
|
|
213
|
+
// its routing word: the pulled model names the constraint and says the word is
|
|
214
|
+
// missing, which is the outcome to want when the catalog no longer says how a
|
|
215
|
+
// breach routes.
|
|
216
|
+
function readEnum(name, field, value, allowed, warnings) {
|
|
217
|
+
if (value === undefined || value === null)
|
|
218
|
+
return undefined;
|
|
219
|
+
// Only a string can be one of these words, and the check says so rather than
|
|
220
|
+
// coercing: `String(["escalate"])` is `escalate`, so a coercing reader would
|
|
221
|
+
// invent a routing word the catalog never stated. A blank or whitespace-only
|
|
222
|
+
// value is unset rather than wrong, the same reading a blank judgment gets.
|
|
223
|
+
if (typeof value === 'string') {
|
|
224
|
+
const text = value.trim();
|
|
225
|
+
if (text === '')
|
|
226
|
+
return undefined;
|
|
227
|
+
if (allowed.includes(text))
|
|
228
|
+
return text;
|
|
229
|
+
}
|
|
230
|
+
warnings.push(`constraint '${name}': the ${kc_custom_types_1.CONSTRAINT_TYPE_ID} aspect states ` +
|
|
231
|
+
`${field} ${showAspectValue(value)}, which is not one of ${allowed.join(', ')}; the constraint reads back without one`);
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
// How an unusable aspect value is quoted back in a warning: a string in single
|
|
235
|
+
// quotes, so the word reads plainly, and anything else as JSON, so the reader
|
|
236
|
+
// can see it was never a word at all.
|
|
237
|
+
function showAspectValue(value) {
|
|
238
|
+
return typeof value === 'string' ? `'${value.trim()}'` :
|
|
239
|
+
JSON.stringify(value);
|
|
240
|
+
}
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
// Local helpers (see the file header on why they are not shared).
|
|
243
|
+
// ---------------------------------------------------------------------------
|
|
244
|
+
// The constraint aspect's `data` from an entry, matched by the aspect key's
|
|
245
|
+
// `.semantic-constraint` suffix or the aspectType's
|
|
246
|
+
// `/aspectTypes/semantic-constraint` suffix, so it is found whichever project
|
|
247
|
+
// the type was provisioned in.
|
|
248
|
+
function constraintAspectDataOf(entry) {
|
|
249
|
+
for (const [key, aspect] of Object.entries(entry.aspects ?? {})) {
|
|
250
|
+
if (key.endsWith(`.${kc_custom_types_1.CONSTRAINT_TYPE_ID}`) ||
|
|
251
|
+
aspect.aspectType?.endsWith(`/aspectTypes/${kc_custom_types_1.CONSTRAINT_TYPE_ID}`)) {
|
|
252
|
+
return aspect.data ?? {};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return {};
|
|
256
|
+
}
|
|
257
|
+
// The trimmed text an aspect field states, or '' when it states none. A blank
|
|
258
|
+
// or whitespace-only value reads as unset, the same reading readEnum gives.
|
|
259
|
+
function aspectText(value) {
|
|
260
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
261
|
+
}
|
|
262
|
+
// Entry ids allow letters, numbers, underscores, hyphens, and periods.
|
|
263
|
+
function slug(s) {
|
|
264
|
+
return s.replace(/[^A-Za-z0-9_.-]/g, '_');
|
|
265
|
+
}
|
|
266
|
+
// The id segment of a full entry resource name.
|
|
267
|
+
function idOf(name) {
|
|
268
|
+
return name.split('/').pop() ?? name;
|
|
269
|
+
}
|
|
270
|
+
// Drops undefined-valued keys so the emitted aspect (and its golden) only shows
|
|
271
|
+
// fields the model actually set.
|
|
272
|
+
function compact(obj) {
|
|
273
|
+
const out = {};
|
|
274
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
275
|
+
if (v !== undefined)
|
|
276
|
+
out[k] = v;
|
|
277
|
+
}
|
|
278
|
+
return out;
|
|
279
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Entry, EntryLink } from '../gcp/dataplex';
|
|
2
|
+
import type { OverviewSidecar } from '../layouts/semantic-model';
|
|
3
|
+
import { SemanticModel } from './ir';
|
|
4
|
+
export interface ReadResult {
|
|
5
|
+
models: SemanticModel[];
|
|
6
|
+
warnings: string[];
|
|
7
|
+
secondGeneration?: boolean;
|
|
8
|
+
overviews?: Map<string, OverviewSidecar>;
|
|
9
|
+
firstGeneration?: FirstGenerationModel[];
|
|
10
|
+
}
|
|
11
|
+
export interface FirstGenerationModel {
|
|
12
|
+
name: string;
|
|
13
|
+
entries: Entry[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Reconstructs the Semantic Model IR from Knowledge Catalog entries.
|
|
17
|
+
*
|
|
18
|
+
* Returns one model per `semantic-model` anchor plus any warnings (no anchor,
|
|
19
|
+
* an orphaned child, an entry missing its aspect data). Entries must already be
|
|
20
|
+
* hydrated with their `semantic-*` (and, for entities, `schema`) aspect data; a
|
|
21
|
+
* BASIC list omits aspect data, so the puller re-fetches each entry first.
|
|
22
|
+
*
|
|
23
|
+
* `entryLinks` are the `schema-join` links a pull fetched for the group (see
|
|
24
|
+
* `pull_kc`); each link between two of a model's entity entries is
|
|
25
|
+
* reconstructed as a 1:1 / 1:N relationship. Pass `[]` (the default) to
|
|
26
|
+
* reconstruct entities and metrics only.
|
|
27
|
+
*
|
|
28
|
+
* With `opts.v2Aspects` set, a model whose `semantic-model` aspect has
|
|
29
|
+
* `specVersion` is rebuilt from the second-generation types (see
|
|
30
|
+
* readModelV2), which reads no entry link. A model without it is returned in
|
|
31
|
+
* `firstGeneration` instead of being rebuilt.
|
|
32
|
+
*/
|
|
33
|
+
export declare function modelsFromCatalogResources(entries: Entry[], entryLinks?: EntryLink[], opts?: {
|
|
34
|
+
v2Aspects?: boolean;
|
|
35
|
+
}): ReadResult;
|
|
36
|
+
export declare function linkDedupKey(link: EntryLink): string;
|
|
37
|
+
export declare function linkNamePrefix(modelName: string): string;
|