dataiku-sdk 3.6.0 → 3.7.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 +14 -6
- package/bin/bun-version.js +14 -0
- package/bin/dss.js +23 -12
- package/dist/build-metadata.json +1 -1
- package/dist/packages/types/src/index.d.ts +74 -1
- package/dist/packages/types/src/index.js +53 -1
- package/dist/src/cli/coerce.d.ts +1 -0
- package/dist/src/cli/coerce.js +19 -15
- package/dist/src/cli/command-syntax.json +3521 -416
- package/dist/src/cli/commands/analysis.js +19 -1
- package/dist/src/cli/commands/bundle.js +22 -0
- package/dist/src/cli/commands/connection.js +26 -2
- package/dist/src/cli/commands/data-quality.js +33 -1
- package/dist/src/cli/commands/dataset.js +35 -4
- package/dist/src/cli/commands/discussion.js +15 -0
- package/dist/src/cli/commands/doctor.js +1 -1
- package/dist/src/cli/commands/flow.d.ts +5 -0
- package/dist/src/cli/commands/flow.js +57 -0
- package/dist/src/cli/commands/future.js +8 -0
- package/dist/src/cli/commands/index.js +6 -0
- package/dist/src/cli/commands/job.js +29 -6
- package/dist/src/cli/commands/metrics.js +21 -1
- package/dist/src/cli/commands/ml-task.d.ts +5 -0
- package/dist/src/cli/commands/ml-task.js +86 -16
- package/dist/src/cli/commands/mlflow.d.ts +11 -0
- package/dist/src/cli/commands/mlflow.js +121 -0
- package/dist/src/cli/commands/plugin.js +5 -11
- package/dist/src/cli/commands/project-deployer.js +70 -0
- package/dist/src/cli/commands/project-library.js +2 -5
- package/dist/src/cli/commands/project.js +8 -0
- package/dist/src/cli/commands/recipe.d.ts +9 -0
- package/dist/src/cli/commands/recipe.js +93 -7
- package/dist/src/cli/commands/saved-model.d.ts +1 -1
- package/dist/src/cli/commands/saved-model.js +9 -76
- package/dist/src/cli/commands/streaming-endpoint.js +30 -1
- package/dist/src/cli/commands/webapp.js +8 -0
- package/dist/src/cli/commands/wiki.js +22 -0
- package/dist/src/cli/commands/workspace.js +8 -0
- package/dist/src/cli/contract.d.ts +16 -15
- package/dist/src/cli/contract.js +139 -3404
- package/dist/src/cli/doctor.d.ts +13 -0
- package/dist/src/cli/doctor.js +41 -1
- package/dist/src/cli/flags.d.ts +7 -1
- package/dist/src/cli/flags.js +78 -6
- package/dist/src/cli/helpers/app-successor.js +1 -2
- package/dist/src/cli/helpers/documentation.d.ts +21 -0
- package/dist/src/cli/helpers/documentation.js +53 -0
- package/dist/src/cli/helpers/trained-model.d.ts +26 -0
- package/dist/src/cli/helpers/trained-model.js +144 -0
- package/dist/src/cli/list-output.d.ts +7 -0
- package/dist/src/cli/list-output.js +77 -0
- package/dist/src/cli/list-shapes.d.ts +21 -0
- package/dist/src/cli/list-shapes.js +111 -0
- package/dist/src/cli/output-schemas.d.ts +0 -14
- package/dist/src/cli/output-schemas.js +4 -7
- package/dist/src/cli/output.d.ts +0 -1
- package/dist/src/cli/output.js +27 -19
- package/dist/src/cli/plans.d.ts +14 -0
- package/dist/src/cli/plans.js +3684 -0
- package/dist/src/cli/usage.d.ts +7 -0
- package/dist/src/cli/usage.js +20 -1
- package/dist/src/cli/version.d.ts +2 -2
- package/dist/src/cli/version.js +2 -2
- package/dist/src/cli.js +127 -113
- package/dist/src/client.d.ts +52 -43
- package/dist/src/client.js +267 -96
- package/dist/src/errors.d.ts +11 -1
- package/dist/src/errors.js +31 -47
- package/dist/src/generated/action-output-schemas.json +345 -89
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.js +3 -0
- package/dist/src/resources/analyses.d.ts +8 -0
- package/dist/src/resources/analyses.js +13 -1
- package/dist/src/resources/bundles.d.ts +34 -0
- package/dist/src/resources/bundles.js +67 -0
- package/dist/src/resources/connections.d.ts +9 -0
- package/dist/src/resources/connections.js +15 -0
- package/dist/src/resources/data-quality.d.ts +20 -0
- package/dist/src/resources/data-quality.js +30 -0
- package/dist/src/resources/dataset-create.d.ts +19 -0
- package/dist/src/resources/dataset-create.js +66 -0
- package/dist/src/resources/datasets.d.ts +25 -15
- package/dist/src/resources/datasets.js +59 -111
- package/dist/src/resources/discussions.d.ts +5 -0
- package/dist/src/resources/discussions.js +7 -0
- package/dist/src/resources/documentation.d.ts +25 -0
- package/dist/src/resources/documentation.js +16 -0
- package/dist/src/resources/flow.d.ts +48 -0
- package/dist/src/resources/flow.js +65 -0
- package/dist/src/resources/futures.d.ts +23 -0
- package/dist/src/resources/futures.js +32 -0
- package/dist/src/resources/jobs.js +102 -2
- package/dist/src/resources/metrics.d.ts +10 -0
- package/dist/src/resources/metrics.js +10 -0
- package/dist/src/resources/ml-tasks.d.ts +65 -2
- package/dist/src/resources/ml-tasks.js +102 -28
- package/dist/src/resources/mlflow-extension.d.ts +73 -0
- package/dist/src/resources/mlflow-extension.js +105 -0
- package/dist/src/resources/projects.d.ts +6 -0
- package/dist/src/resources/projects.js +8 -0
- package/dist/src/resources/recipe-create.d.ts +65 -0
- package/dist/src/resources/recipe-create.js +338 -0
- package/dist/src/resources/recipes.d.ts +28 -29
- package/dist/src/resources/recipes.js +126 -245
- package/dist/src/resources/saved-models.d.ts +10 -6
- package/dist/src/resources/saved-models.js +16 -14
- package/dist/src/resources/scenarios.js +8 -14
- package/dist/src/resources/streaming-endpoints.d.ts +12 -0
- package/dist/src/resources/streaming-endpoints.js +15 -0
- package/dist/src/resources/trained-model.d.ts +60 -0
- package/dist/src/resources/trained-model.js +98 -0
- package/dist/src/resources/webapps.d.ts +8 -0
- package/dist/src/resources/webapps.js +10 -0
- package/dist/src/resources/wiki.d.ts +5 -0
- package/dist/src/resources/wiki.js +7 -0
- package/dist/src/resources/workspaces.d.ts +2 -0
- package/dist/src/resources/workspaces.js +4 -0
- package/dist/src/utils/response-file.js +20 -9
- package/dist/src/utils/secret-sanitize.d.ts +7 -0
- package/dist/src/utils/secret-sanitize.js +46 -0
- package/package.json +25 -26
- package/plugin.json +1 -1
- package/skills/dataiku-dss/SKILL.md +1 -1
- package/skills/dataiku-dss/references/authentication.md +3 -1
- package/skills/dataiku-dss/references/coding.md +1 -0
- package/skills/dataiku-dss/references/discovery.md +4 -6
- package/skills/dataiku-dss/references/troubleshooting.md +3 -2
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { ClientValidationError, } from "../errors.js";
|
|
2
|
+
import { asRecord, } from "../utils/records.js";
|
|
3
|
+
/*
|
|
4
|
+
* Pure, schema-free recipe-create request construction. `recipe create --plan`
|
|
5
|
+
* imports this without loading the SDK schema graph.
|
|
6
|
+
*/
|
|
7
|
+
export function asString(value) {
|
|
8
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
9
|
+
}
|
|
10
|
+
export function asStringArray(value) {
|
|
11
|
+
if (!Array.isArray(value))
|
|
12
|
+
return undefined;
|
|
13
|
+
const out = value.filter((v) => typeof v === "string" && v.length > 0);
|
|
14
|
+
return out.length > 0 ? out : undefined;
|
|
15
|
+
}
|
|
16
|
+
export function parseJoinKeyPairs(values, optionName = "joinOn") {
|
|
17
|
+
const pairs = [];
|
|
18
|
+
for (const raw of values) {
|
|
19
|
+
const token = raw.trim();
|
|
20
|
+
if (!token)
|
|
21
|
+
continue;
|
|
22
|
+
const eq = token.indexOf("=");
|
|
23
|
+
if (eq === -1) {
|
|
24
|
+
pairs.push({ left: token, right: token, });
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const left = token.slice(0, eq).trim();
|
|
28
|
+
const right = token.slice(eq + 1).trim();
|
|
29
|
+
if (!left || !right) {
|
|
30
|
+
throw new ClientValidationError(`${optionName} values must use COL or LEFT=RIGHT.`, "validation_failed");
|
|
31
|
+
}
|
|
32
|
+
pairs.push({ left, right, });
|
|
33
|
+
}
|
|
34
|
+
return pairs;
|
|
35
|
+
}
|
|
36
|
+
export function normalizeFuzzyDistance(value) {
|
|
37
|
+
const normalized = typeof value === "string" && value.trim().length > 0
|
|
38
|
+
? value.trim().toUpperCase()
|
|
39
|
+
: "DAMERAU_LEVENSHTEIN";
|
|
40
|
+
if (normalized === "DAMERAU_LEVENSHTEIN")
|
|
41
|
+
return "LEVENSHTEIN";
|
|
42
|
+
if (normalized === "HAMMING" || normalized === "JACCARD" || normalized === "COSINE"
|
|
43
|
+
|| normalized === "EUCLIDEAN") {
|
|
44
|
+
return normalized;
|
|
45
|
+
}
|
|
46
|
+
throw new ClientValidationError("fuzzyDistance must be one of DAMERAU_LEVENSHTEIN, HAMMING, JACCARD, COSINE, or EUCLIDEAN.", "validation_failed");
|
|
47
|
+
}
|
|
48
|
+
export function normalizeJoinType(value) {
|
|
49
|
+
const normalized = typeof value === "string" && value.trim().length > 0
|
|
50
|
+
? value.trim().toUpperCase()
|
|
51
|
+
: "LEFT";
|
|
52
|
+
if (normalized === "LEFT" || normalized === "INNER" || normalized === "RIGHT"
|
|
53
|
+
|| normalized === "FULL") {
|
|
54
|
+
return normalized;
|
|
55
|
+
}
|
|
56
|
+
throw new ClientValidationError("joinType must be one of LEFT, INNER, RIGHT, or FULL.", "validation_failed");
|
|
57
|
+
}
|
|
58
|
+
export function recipeInputItems(recipe) {
|
|
59
|
+
const inputs = asRecord(recipe.inputs);
|
|
60
|
+
if (!inputs)
|
|
61
|
+
return [];
|
|
62
|
+
const result = [];
|
|
63
|
+
const seen = new Set();
|
|
64
|
+
for (const [role, roleValue,] of Object.entries(inputs)) {
|
|
65
|
+
const items = asRecord(roleValue)?.items;
|
|
66
|
+
if (!Array.isArray(items))
|
|
67
|
+
continue;
|
|
68
|
+
for (const itemValue of items) {
|
|
69
|
+
const item = asRecord(itemValue);
|
|
70
|
+
const ref = asString(item?.ref);
|
|
71
|
+
if (!ref || seen.has(ref))
|
|
72
|
+
continue;
|
|
73
|
+
seen.add(ref);
|
|
74
|
+
result.push({ ref, role, });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Recipe types whose output schema DSS refuses to compute ("Output schema can't
|
|
81
|
+
* be automatically computed on 'python' recipes"): the code sets the schema
|
|
82
|
+
* when it runs. Plugin recipes (`CustomCode_*`) are code too.
|
|
83
|
+
*/
|
|
84
|
+
const CODE_RECIPE_TYPES = {
|
|
85
|
+
python: true,
|
|
86
|
+
r: true,
|
|
87
|
+
julia: true,
|
|
88
|
+
pyspark: true,
|
|
89
|
+
sparkr: true,
|
|
90
|
+
spark_scala: true,
|
|
91
|
+
shell: true,
|
|
92
|
+
sql_script: true,
|
|
93
|
+
};
|
|
94
|
+
/** Whether DSS can compute this recipe type's output schema (visual and SQL query recipes). */
|
|
95
|
+
export function recipeOutputSchemaIsComputable(recipeType) {
|
|
96
|
+
const normalized = recipeType.trim().toLowerCase();
|
|
97
|
+
return CODE_RECIPE_TYPES[normalized] !== true && !normalized.startsWith("customcode_");
|
|
98
|
+
}
|
|
99
|
+
/** The id DSS expects in actions/updateOutputSchema (dataikuapi RequiredSchemaUpdates.apply). */
|
|
100
|
+
export function schemaUpdateComputableId(computable) {
|
|
101
|
+
return (computable.type === "DATASET" ? computable.datasetName : computable.id) ?? "";
|
|
102
|
+
}
|
|
103
|
+
/** A computed schema is worth writing when it has columns and differs from (or fills) the current one. */
|
|
104
|
+
export function schemaUpdateIsPending(computable) {
|
|
105
|
+
const columns = computable.newSchema?.columns ?? [];
|
|
106
|
+
if (columns.length === 0)
|
|
107
|
+
return false;
|
|
108
|
+
return computable.previousSchemaWasEmpty === true
|
|
109
|
+
|| (computable.incompatibilities?.length ?? 0) > 0;
|
|
110
|
+
}
|
|
111
|
+
/** DSS grouping aggregate flags on each `values[]` entry, by lowercase name. */
|
|
112
|
+
const GROUPING_AGGREGATES = {
|
|
113
|
+
count: "count",
|
|
114
|
+
countdistinct: "countDistinct",
|
|
115
|
+
sum: "sum",
|
|
116
|
+
avg: "avg",
|
|
117
|
+
min: "min",
|
|
118
|
+
max: "max",
|
|
119
|
+
median: "median",
|
|
120
|
+
stddev: "stddev",
|
|
121
|
+
first: "first",
|
|
122
|
+
last: "last",
|
|
123
|
+
concat: "concat",
|
|
124
|
+
concatdistinct: "concatDistinct",
|
|
125
|
+
sum2: "sum2",
|
|
126
|
+
};
|
|
127
|
+
function splitPair(raw, flag) {
|
|
128
|
+
const eq = raw.indexOf("=");
|
|
129
|
+
const left = eq === -1 ? "" : raw.slice(0, eq).trim();
|
|
130
|
+
const right = eq === -1 ? "" : raw.slice(eq + 1).trim();
|
|
131
|
+
if (left.length === 0 || right.length === 0) {
|
|
132
|
+
throw new ClientValidationError(`${flag} expects NAME=VALUE, got "${raw}".`, "validation_failed");
|
|
133
|
+
}
|
|
134
|
+
return [left, right,];
|
|
135
|
+
}
|
|
136
|
+
/** Grouping configuration from create options, or undefined when none was asked for. */
|
|
137
|
+
export function groupingPayloadConfig(opts) {
|
|
138
|
+
const keys = opts.groupBy ?? [];
|
|
139
|
+
const specs = opts.aggregate ?? [];
|
|
140
|
+
if (keys.length === 0 && specs.length === 0)
|
|
141
|
+
return undefined;
|
|
142
|
+
const aggregates = {};
|
|
143
|
+
for (const spec of specs) {
|
|
144
|
+
const colon = spec.lastIndexOf(":");
|
|
145
|
+
const column = colon === -1 ? "" : spec.slice(0, colon).trim();
|
|
146
|
+
const fns = colon === -1
|
|
147
|
+
? []
|
|
148
|
+
: spec.slice(colon + 1).split("+").map((fn) => fn.trim().toLowerCase());
|
|
149
|
+
if (column.length === 0 || fns.length === 0
|
|
150
|
+
|| fns.some((fn) => GROUPING_AGGREGATES[fn] === undefined)) {
|
|
151
|
+
throw new ClientValidationError(`--aggregate expects COL:FN[+FN] with FN one of ${Object.values(GROUPING_AGGREGATES).join(", ")}; got "${spec}".`, "validation_failed");
|
|
152
|
+
}
|
|
153
|
+
aggregates[column] = [
|
|
154
|
+
...(aggregates[column] ?? []),
|
|
155
|
+
...fns.map((fn) => GROUPING_AGGREGATES[fn]),
|
|
156
|
+
];
|
|
157
|
+
}
|
|
158
|
+
const ordered = Object.values(aggregates).some((fns) => fns.includes("first") || fns.includes("last"));
|
|
159
|
+
if (ordered && !opts.orderBy) {
|
|
160
|
+
throw new ClientValidationError("first/last aggregates need an ordering column: pass --order-by COL.", "validation_failed");
|
|
161
|
+
}
|
|
162
|
+
return { keys, aggregates, ...(opts.orderBy ? { orderBy: opts.orderBy, } : {}), };
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Apply grouping keys and aggregates to the payload DSS created: `keys` lists
|
|
166
|
+
* the group columns; each aggregated column's `values[]` entry gets its
|
|
167
|
+
* aggregate flags (and `orderColumn` for first/last).
|
|
168
|
+
*/
|
|
169
|
+
export function applyGroupingPayload(payload, config) {
|
|
170
|
+
const values = Array.isArray(payload.values)
|
|
171
|
+
? payload.values.map((value) => asRecord(value) ?? {})
|
|
172
|
+
: [];
|
|
173
|
+
for (const [column, fns,] of Object.entries(config.aggregates)) {
|
|
174
|
+
let entry = values.find((value) => value.column === column);
|
|
175
|
+
if (!entry) {
|
|
176
|
+
entry = { column, };
|
|
177
|
+
values.push(entry);
|
|
178
|
+
}
|
|
179
|
+
for (const fn of fns)
|
|
180
|
+
entry[fn] = true;
|
|
181
|
+
if (config.orderBy && (fns.includes("first") || fns.includes("last"))) {
|
|
182
|
+
entry.orderColumn = config.orderBy;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return { ...payload, keys: config.keys.map((column) => ({ column, })), values, };
|
|
186
|
+
}
|
|
187
|
+
function processorStep(type, params) {
|
|
188
|
+
return {
|
|
189
|
+
metaType: "PROCESSOR",
|
|
190
|
+
type,
|
|
191
|
+
params,
|
|
192
|
+
disabled: false,
|
|
193
|
+
preview: false,
|
|
194
|
+
alwaysShowComment: false,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Prepare (shaker) steps from create options, in a fixed order: rename,
|
|
199
|
+
* fill empty, formula column, row filter, drop columns, keep columns. Later
|
|
200
|
+
* steps see renamed columns. Empty when no prepare option was given.
|
|
201
|
+
*/
|
|
202
|
+
export function prepareSteps(opts) {
|
|
203
|
+
const steps = [];
|
|
204
|
+
const renamings = (opts.rename ?? []).map((raw) => {
|
|
205
|
+
const [from, to,] = splitPair(raw, "--rename");
|
|
206
|
+
return { from, to, };
|
|
207
|
+
});
|
|
208
|
+
if (renamings.length > 0)
|
|
209
|
+
steps.push(processorStep("ColumnRenamer", { renamings, }));
|
|
210
|
+
for (const raw of opts.fillEmpty ?? []) {
|
|
211
|
+
const [column, value,] = splitPair(raw, "--fill-empty");
|
|
212
|
+
steps.push(processorStep("FillEmptyWithValue", { appliesTo: "SINGLE_COLUMN", columns: [column,], value, }));
|
|
213
|
+
}
|
|
214
|
+
if (opts.formula) {
|
|
215
|
+
const [column, expression,] = splitPair(opts.formula, "--formula");
|
|
216
|
+
steps.push(processorStep("CreateColumnWithGREL", { column, expression, }));
|
|
217
|
+
}
|
|
218
|
+
if (opts.filter) {
|
|
219
|
+
steps.push(processorStep("FilterOnCustomFormula", { expression: opts.filter, action: "KEEP_ROW", }));
|
|
220
|
+
}
|
|
221
|
+
if (opts.dropColumns?.length) {
|
|
222
|
+
steps.push(processorStep("ColumnsSelector", {
|
|
223
|
+
appliesTo: "COLUMNS",
|
|
224
|
+
columns: opts.dropColumns,
|
|
225
|
+
keep: false,
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
228
|
+
if (opts.keepColumns?.length) {
|
|
229
|
+
steps.push(processorStep("ColumnsSelector", {
|
|
230
|
+
appliesTo: "COLUMNS",
|
|
231
|
+
columns: opts.keepColumns,
|
|
232
|
+
keep: true,
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
return steps;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Pure request construction for POST /recipes/ (no DSS calls). Shared with
|
|
239
|
+
* `recipe create --plan` so the plan equals the request the command sends.
|
|
240
|
+
*/
|
|
241
|
+
export function buildRecipeCreateRequest(opts, pk) {
|
|
242
|
+
const { payload, outputConnection: rawConnection, joinType: rawJoinType, } = opts;
|
|
243
|
+
// dataikuapi and the UI call the shaker recipe "prepare".
|
|
244
|
+
const type = opts.type === "prepare" ? "shaker" : opts.type;
|
|
245
|
+
const grouping = groupingPayloadConfig(opts);
|
|
246
|
+
const steps = prepareSteps(opts);
|
|
247
|
+
if (grouping && type !== "grouping") {
|
|
248
|
+
throw new ClientValidationError("--group-by/--aggregate/--order-by need --type grouping.", "validation_failed");
|
|
249
|
+
}
|
|
250
|
+
if (steps.length > 0 && type !== "shaker") {
|
|
251
|
+
throw new ClientValidationError("--rename/--fill-empty/--formula/--filter/--drop-columns/--keep-columns need --type prepare.", "validation_failed");
|
|
252
|
+
}
|
|
253
|
+
const outputFolder = asString(opts.outputFolder);
|
|
254
|
+
// Build inputs/outputs from simple form (inputDatasets + outputDataset) or
|
|
255
|
+
// advanced form (inputs + outputs); both may coexist — simple form wins when
|
|
256
|
+
// the advanced form is absent.
|
|
257
|
+
const inputDatasets = asStringArray(opts.inputDatasets);
|
|
258
|
+
const requestedOutputDataset = asString(opts.outputDataset);
|
|
259
|
+
let inputs = asRecord(opts.inputs);
|
|
260
|
+
let outputs = asRecord(opts.outputs);
|
|
261
|
+
if (!inputs) {
|
|
262
|
+
inputs = {
|
|
263
|
+
main: {
|
|
264
|
+
items: inputDatasets?.map((ref) => ({ ref, deps: [], })) ?? [],
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
// Auto-generate name if not provided
|
|
269
|
+
const outputNameForDefaultRecipe = requestedOutputDataset ?? outputFolder;
|
|
270
|
+
const name = opts.name ?? (type && outputNameForDefaultRecipe
|
|
271
|
+
? `${type}_${outputNameForDefaultRecipe}`
|
|
272
|
+
: undefined);
|
|
273
|
+
const temporaryOutputDataset = outputFolder && !requestedOutputDataset && name
|
|
274
|
+
? `${name}_folder_output_marker`
|
|
275
|
+
: undefined;
|
|
276
|
+
const outputDataset = requestedOutputDataset ?? temporaryOutputDataset;
|
|
277
|
+
if (!outputs && outputDataset) {
|
|
278
|
+
outputs = {
|
|
279
|
+
main: {
|
|
280
|
+
items: [{ ref: outputDataset, appendMode: false, },],
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
if (!type || !name || !outputs) {
|
|
285
|
+
throw new ClientValidationError("type and outputDataset/outputFolder or (name + outputs) are required for create.", "validation_failed");
|
|
286
|
+
}
|
|
287
|
+
const joinCols = typeof opts.joinOn === "string" ? [opts.joinOn,] : asStringArray(opts.joinOn);
|
|
288
|
+
const joinKeys = type === "join" && joinCols?.length
|
|
289
|
+
? parseJoinKeyPairs(joinCols)
|
|
290
|
+
: undefined;
|
|
291
|
+
const fuzzyOn = opts.fuzzyOn ?? (type === "fuzzyjoin" ? opts.joinOn : undefined);
|
|
292
|
+
const fuzzyCols = typeof fuzzyOn === "string" ? [fuzzyOn,] : asStringArray(fuzzyOn);
|
|
293
|
+
const fuzzyKeys = type === "fuzzyjoin" && fuzzyCols?.length
|
|
294
|
+
? parseJoinKeyPairs(fuzzyCols, "fuzzyOn")
|
|
295
|
+
: undefined;
|
|
296
|
+
const normalizedJoinType = joinKeys?.length || fuzzyKeys?.length
|
|
297
|
+
? normalizeJoinType(rawJoinType)
|
|
298
|
+
: undefined;
|
|
299
|
+
const fuzzyDistance = fuzzyKeys?.length ? normalizeFuzzyDistance(opts.fuzzyDistance) : undefined;
|
|
300
|
+
const fuzzyThreshold = opts.fuzzyThreshold ?? 1;
|
|
301
|
+
if (!Number.isFinite(fuzzyThreshold)) {
|
|
302
|
+
throw new ClientValidationError("fuzzyThreshold must be a finite number.", "validation_failed");
|
|
303
|
+
}
|
|
304
|
+
const recipePrototype = {
|
|
305
|
+
type,
|
|
306
|
+
name,
|
|
307
|
+
projectKey: pk,
|
|
308
|
+
...(type === "fuzzyjoin" ? {} : { inputs, }),
|
|
309
|
+
outputs,
|
|
310
|
+
};
|
|
311
|
+
const creationSettings = {};
|
|
312
|
+
if (payload !== undefined) {
|
|
313
|
+
creationSettings.script = payload;
|
|
314
|
+
}
|
|
315
|
+
if (type === "fuzzyjoin") {
|
|
316
|
+
creationSettings.virtualInputs = recipeInputItems({ inputs, }).map((item) => item.ref);
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
creationSettings,
|
|
320
|
+
fuzzyDistance,
|
|
321
|
+
fuzzyKeys,
|
|
322
|
+
fuzzyThreshold,
|
|
323
|
+
grouping,
|
|
324
|
+
inputDatasets,
|
|
325
|
+
inputs,
|
|
326
|
+
joinKeys,
|
|
327
|
+
name,
|
|
328
|
+
normalizedJoinType,
|
|
329
|
+
outputFolder,
|
|
330
|
+
outputs,
|
|
331
|
+
payload,
|
|
332
|
+
prepareSteps: steps,
|
|
333
|
+
rawConnection,
|
|
334
|
+
recipePrototype,
|
|
335
|
+
temporaryOutputDataset,
|
|
336
|
+
type,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import type { BuildMode, JobWaitResult, ProjectMetadata, RecipeCreateOptions, RecipeCreateResult, RecipeSummary } from "../schemas.js";
|
|
1
|
+
import type { BuildMode, JobWaitResult, ProjectMetadata, RecipeCreateOptions, RecipeCreateResult, RecipeSchemaUpdates, RecipeSummary, RecipeUpdateSchemaResult } from "../schemas.js";
|
|
2
2
|
import { BaseResource } from "./base.js";
|
|
3
3
|
import type { JobBuildTarget, JobBuildTargetType, JobLogFilter, JobLogSummary } from "./jobs.js";
|
|
4
|
-
type JoinType = "LEFT" | "INNER" | "RIGHT" | "FULL";
|
|
5
|
-
type JoinKeyPair = {
|
|
6
|
-
left: string;
|
|
7
|
-
right: string;
|
|
8
|
-
};
|
|
9
4
|
export interface RecipeRunOutput extends JobBuildTarget {
|
|
10
5
|
ref: string;
|
|
11
6
|
role: string;
|
|
@@ -70,28 +65,6 @@ export interface RecipeCloneResult {
|
|
|
70
65
|
payloadTextRewrites: Record<string, string>;
|
|
71
66
|
copiedOutputDatasets: string[];
|
|
72
67
|
}
|
|
73
|
-
/**
|
|
74
|
-
* Pure request construction for POST /recipes/ (no DSS calls). Shared with
|
|
75
|
-
* `recipe create --plan` so the plan equals the request the command sends.
|
|
76
|
-
*/
|
|
77
|
-
export declare function buildRecipeCreateRequest(opts: RecipeCreateOptions, pk: string): {
|
|
78
|
-
creationSettings: Record<string, unknown>;
|
|
79
|
-
fuzzyDistance: string | undefined;
|
|
80
|
-
fuzzyKeys: JoinKeyPair[] | undefined;
|
|
81
|
-
fuzzyThreshold: number;
|
|
82
|
-
inputDatasets: string[] | undefined;
|
|
83
|
-
inputs: Record<string, unknown>;
|
|
84
|
-
joinKeys: JoinKeyPair[] | undefined;
|
|
85
|
-
name: string;
|
|
86
|
-
normalizedJoinType: JoinType | undefined;
|
|
87
|
-
outputFolder: string | undefined;
|
|
88
|
-
outputs: Record<string, unknown>;
|
|
89
|
-
payload: string | undefined;
|
|
90
|
-
rawConnection: string | undefined;
|
|
91
|
-
recipePrototype: Record<string, unknown>;
|
|
92
|
-
temporaryOutputDataset: string | undefined;
|
|
93
|
-
type: string;
|
|
94
|
-
};
|
|
95
68
|
export declare class RecipesResource extends BaseResource {
|
|
96
69
|
/** List all recipes in a project. */
|
|
97
70
|
list(projectKey?: string): Promise<RecipeSummary[]>;
|
|
@@ -134,6 +107,33 @@ export declare class RecipesResource extends BaseResource {
|
|
|
134
107
|
run(recipeName: string, opts?: RecipeRunOptions): Promise<RecipeRunResult>;
|
|
135
108
|
/** Create a recipe, with optional output dataset provisioning and join configuration. */
|
|
136
109
|
create(opts: RecipeCreateOptions): Promise<RecipeCreateResult>;
|
|
110
|
+
/**
|
|
111
|
+
* Compute the output schemas DSS derives from the recipe's current settings
|
|
112
|
+
* (GET /recipes/{name}/schema-update, dataikuapi `compute_schema_updates`).
|
|
113
|
+
* DSS rejects code recipes, whose code sets the schema at run time.
|
|
114
|
+
*/
|
|
115
|
+
computeSchemaUpdates(recipeName: string, projectKey?: string): Promise<RecipeSchemaUpdates>;
|
|
116
|
+
/**
|
|
117
|
+
* Write each pending computed schema accepted by `select` through
|
|
118
|
+
* actions/updateOutputSchema. Pending outputs `select` rejects are reported,
|
|
119
|
+
* not written.
|
|
120
|
+
*/
|
|
121
|
+
private applySchemaUpdates;
|
|
122
|
+
/**
|
|
123
|
+
* Replace each output schema that differs from the DSS-computed one
|
|
124
|
+
* (dataikuapi `compute_schema_updates().apply()`, the UI's "Update schema").
|
|
125
|
+
* With `derivedOutputs`, only outputs whose schema is empty or listed there
|
|
126
|
+
* are written: callers pass the outputs whose schema matched the computed
|
|
127
|
+
* one before an edit, so DSS-derived schemas follow the edit while
|
|
128
|
+
* hand-edited ones are left alone. `dryRun` writes nothing. Skipped
|
|
129
|
+
* differing outputs are listed under `pending`. Code recipes are rejected
|
|
130
|
+
* before the schema computation: DSS cannot compute their output schema.
|
|
131
|
+
*/
|
|
132
|
+
updateSchema(recipeName: string, opts?: {
|
|
133
|
+
projectKey?: string;
|
|
134
|
+
derivedOutputs?: string[];
|
|
135
|
+
dryRun?: boolean;
|
|
136
|
+
}): Promise<RecipeUpdateSchemaResult>;
|
|
137
137
|
/**
|
|
138
138
|
* Update a recipe by merging the patch into the current definition.
|
|
139
139
|
* The `recipe` sub-object is deep-merged to preserve nested fields.
|
|
@@ -171,4 +171,3 @@ export declare class RecipesResource extends BaseResource {
|
|
|
171
171
|
projectKey?: string;
|
|
172
172
|
}): Promise<string>;
|
|
173
173
|
}
|
|
174
|
-
export {};
|