windmill-client 1.733.1 → 1.734.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/dist/client.d.ts +2 -1
- package/dist/client.mjs +2 -2
- package/dist/core/OpenAPI.mjs +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +126 -1
- package/dist/index.mjs +4 -2
- package/dist/sqlUtils.d.ts +35 -0
- package/dist/sqlUtils.mjs +129 -7
- package/dist/types.gen.d.ts +4 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DenoS3LightClientSettings, S3ObjectRecord, type S3Object } from "./s3Types";
|
|
2
2
|
export { type S3Object, type S3ObjectRecord, type S3ObjectURI, } from "./s3Types";
|
|
3
|
-
export { datatable, ducklake, type SqlTemplateFunction, type DatatableSqlTemplateFunction, } from "./sqlUtils";
|
|
3
|
+
export { datatable, ducklake, upsertPartition, appendPartition, type SqlTemplateFunction, type DatatableSqlTemplateFunction, type DucklakeMaterializeOptions, type SqlStatement, } from "./sqlUtils";
|
|
4
4
|
export type Sql = string;
|
|
5
5
|
export type Email = string;
|
|
6
6
|
export type Base64 = string;
|
|
@@ -13,6 +13,7 @@ export declare function workerHasInternalServer(): boolean;
|
|
|
13
13
|
* @param baseUrl - API base URL (defaults to BASE_INTERNAL_URL or BASE_URL env variable)
|
|
14
14
|
*/
|
|
15
15
|
export declare function setClient(token?: string, baseUrl?: string): void;
|
|
16
|
+
export declare const getEnv: (key: string) => string | undefined;
|
|
16
17
|
/**
|
|
17
18
|
* Create a client configuration from env variables
|
|
18
19
|
* @returns client configuration
|
package/dist/client.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OpenAPI } from "./core/OpenAPI.mjs";
|
|
2
2
|
import { AppService, HelpersService, JobService, KafkaTriggerService, MetricsService, OidcService, ResourceService, UserService, VariableService } from "./services.gen.mjs";
|
|
3
|
-
import { datatable, ducklake } from "./sqlUtils.mjs";
|
|
3
|
+
import { appendPartition, datatable, ducklake, upsertPartition } from "./sqlUtils.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/client.ts
|
|
6
6
|
const SHARED_FOLDER = "/shared";
|
|
@@ -1346,4 +1346,4 @@ async function commitKafkaOffsets(triggerPath, topic, partition, offset) {
|
|
|
1346
1346
|
}
|
|
1347
1347
|
|
|
1348
1348
|
//#endregion
|
|
1349
|
-
export { SHARED_FOLDER, StepSuspend, WorkflowCtx, _workflowCtx, appendToResultStream, base64ToUint8Array, commitKafkaOffsets, databaseUrlFromResource, deleteS3File, denoS3LightClientSettings, getFlowUserState, getIdToken, getInternalState, getPresignedS3PublicUrl, getPresignedS3PublicUrls, getProgress, getResource, getResult, getResultMaybe, getResumeEndpoints, getResumeUrls, getRootJobId, getState, getStatePath, getVariable, getWorkspace, loadS3File, loadS3FileStream, parallel, parseS3Object, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, resolveDefaultResource, runFlow, runFlowAsync, runScript, runScriptAsync, runScriptByHash, runScriptByHashAsync, runScriptByPath, runScriptByPathAsync, setClient, setFlowUserState, setInternalState, setProgress, setResource, setState, setVariable, setWorkflowCtx, signS3Object, signS3Objects, sleep, step, streamResult, task, taskFlow, taskScript, uint8ArrayToBase64, usernameToEmail, waitForApproval, waitJob, workerHasInternalServer, workflow, writeS3File };
|
|
1349
|
+
export { SHARED_FOLDER, StepSuspend, WorkflowCtx, _workflowCtx, appendToResultStream, base64ToUint8Array, commitKafkaOffsets, databaseUrlFromResource, deleteS3File, denoS3LightClientSettings, getEnv, getFlowUserState, getIdToken, getInternalState, getPresignedS3PublicUrl, getPresignedS3PublicUrls, getProgress, getResource, getResult, getResultMaybe, getResumeEndpoints, getResumeUrls, getRootJobId, getState, getStatePath, getVariable, getWorkspace, loadS3File, loadS3FileStream, parallel, parseS3Object, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, resolveDefaultResource, runFlow, runFlowAsync, runScript, runScriptAsync, runScriptByHash, runScriptByHashAsync, runScriptByPath, runScriptByPathAsync, setClient, setFlowUserState, setInternalState, setProgress, setResource, setState, setVariable, setWorkflowCtx, signS3Object, signS3Objects, sleep, step, streamResult, task, taskFlow, taskScript, uint8ArrayToBase64, usernameToEmail, waitForApproval, waitJob, workerHasInternalServer, workflow, writeS3File };
|
package/dist/core/OpenAPI.mjs
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -4,8 +4,8 @@ export { OpenAPI, type OpenAPIConfig } from './core/OpenAPI';
|
|
|
4
4
|
export * from './services.gen';
|
|
5
5
|
export * from './types.gen';
|
|
6
6
|
export type { DenoS3LightClientSettings } from "./s3Types";
|
|
7
|
-
export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, deleteS3File, signS3Objects, signS3Object, getPresignedS3PublicUrls, getPresignedS3PublicUrl, task, taskScript, taskFlow, workflow, step, sleep, parallel, waitForApproval, type TaskOptions, WorkflowCtx, _workflowCtx, setWorkflowCtx, StepSuspend, runScript, runScriptAsync, runScriptByPath, runScriptByHash, runScriptByPathAsync, runScriptByHashAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, type Sql, requestInteractiveTeamsApproval, appendToResultStream, streamResult, datatable, ducklake, type DatatableSqlTemplateFunction, type SqlTemplateFunction, type S3Object, type S3ObjectRecord, type S3ObjectURI, commitKafkaOffsets } from "./client";
|
|
8
|
-
import { setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, deleteS3File, signS3Objects, signS3Object, getPresignedS3PublicUrls, getPresignedS3PublicUrl, task, taskScript, taskFlow, workflow, step, sleep, parallel, waitForApproval, WorkflowCtx, setWorkflowCtx, StepSuspend, runScript, runScriptAsync, runScriptByPath, runScriptByHash, runScriptByPathAsync, runScriptByHashAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, appendToResultStream, streamResult, datatable, ducklake, getWorkspace, getStatePath, getInternalState, setInternalState, getResumeEndpoints, getResult, getResultMaybe, resolveDefaultResource, databaseUrlFromResource, base64ToUint8Array, uint8ArrayToBase64, parseS3Object, commitKafkaOffsets } from "./client";
|
|
7
|
+
export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, deleteS3File, signS3Objects, signS3Object, getPresignedS3PublicUrls, getPresignedS3PublicUrl, task, taskScript, taskFlow, workflow, step, sleep, parallel, waitForApproval, type TaskOptions, WorkflowCtx, _workflowCtx, setWorkflowCtx, StepSuspend, runScript, runScriptAsync, runScriptByPath, runScriptByHash, runScriptByPathAsync, runScriptByHashAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, type Sql, requestInteractiveTeamsApproval, appendToResultStream, streamResult, datatable, ducklake, upsertPartition, appendPartition, type DucklakeMaterializeOptions, type SqlStatement, type DatatableSqlTemplateFunction, type SqlTemplateFunction, type S3Object, type S3ObjectRecord, type S3ObjectURI, commitKafkaOffsets } from "./client";
|
|
8
|
+
import { setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, deleteS3File, signS3Objects, signS3Object, getPresignedS3PublicUrls, getPresignedS3PublicUrl, task, taskScript, taskFlow, workflow, step, sleep, parallel, waitForApproval, WorkflowCtx, setWorkflowCtx, StepSuspend, runScript, runScriptAsync, runScriptByPath, runScriptByHash, runScriptByPathAsync, runScriptByHashAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, appendToResultStream, streamResult, datatable, ducklake, upsertPartition, appendPartition, getWorkspace, getStatePath, getInternalState, setInternalState, getResumeEndpoints, getResult, getResultMaybe, resolveDefaultResource, databaseUrlFromResource, base64ToUint8Array, uint8ArrayToBase64, parseS3Object, commitKafkaOffsets } from "./client";
|
|
9
9
|
import { AdminService, AuditService, FlowService, GranularAclService, GroupService, JobService, ResourceService, VariableService, ScriptService, ScheduleService, SettingsService, UserService, WorkspaceService, TeamsService } from "./services.gen";
|
|
10
10
|
declare const wmill: {
|
|
11
11
|
setClient: typeof setClient;
|
|
@@ -59,6 +59,8 @@ declare const wmill: {
|
|
|
59
59
|
streamResult: typeof streamResult;
|
|
60
60
|
datatable: typeof datatable;
|
|
61
61
|
ducklake: typeof ducklake;
|
|
62
|
+
upsertPartition: typeof upsertPartition;
|
|
63
|
+
appendPartition: typeof appendPartition;
|
|
62
64
|
SHARED_FOLDER: string;
|
|
63
65
|
getWorkspace: typeof getWorkspace;
|
|
64
66
|
getStatePath: typeof getStatePath;
|
package/dist/index.js
CHANGED
|
@@ -126,7 +126,7 @@ const OpenAPI = {
|
|
|
126
126
|
PASSWORD: void 0,
|
|
127
127
|
TOKEN: getEnv$1("WM_TOKEN"),
|
|
128
128
|
USERNAME: void 0,
|
|
129
|
-
VERSION: "1.
|
|
129
|
+
VERSION: "1.734.0",
|
|
130
130
|
WITH_CREDENTIALS: true,
|
|
131
131
|
interceptors: {
|
|
132
132
|
request: new Interceptors(),
|
|
@@ -15005,6 +15005,127 @@ function ducklake(name = "main") {
|
|
|
15005
15005
|
let { name: n, schema } = parseName(name);
|
|
15006
15006
|
return buildSqlTemplateFunction(ducklakeProvider(n, schema));
|
|
15007
15007
|
}
|
|
15008
|
+
/** Idempotently materialize `selectSql` into a ducklake table for one
|
|
15009
|
+
* partition (or the whole table when `partition` is omitted) — the client-side
|
|
15010
|
+
* equivalent of the `// materialize` engine.
|
|
15011
|
+
* With `uniqueKey` it upserts the slice (delete-by-key + insert); otherwise it
|
|
15012
|
+
* replaces it (whole table → `CREATE OR REPLACE`; partition → delete + insert).
|
|
15013
|
+
* Safe to re-run for the same partition (backfill / failure-recovery).
|
|
15014
|
+
*
|
|
15015
|
+
* Returns a lazy statement — call `.execute()` to run it:
|
|
15016
|
+
* `await wmill.upsertPartition({ table, selectSql, partition }).execute()`. */
|
|
15017
|
+
function upsertPartition(opts) {
|
|
15018
|
+
return finishMaterialize(buildUpsertStatement(opts), opts);
|
|
15019
|
+
}
|
|
15020
|
+
function buildUpsertStatement(opts) {
|
|
15021
|
+
let { name: n, schema } = parseName(opts.ducklake ?? "main");
|
|
15022
|
+
let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
|
|
15023
|
+
let pcol = sql.raw(opts.partitionCol ?? "_wm_partition");
|
|
15024
|
+
let t = sql.raw(`dl.${opts.table}`);
|
|
15025
|
+
let body = sql.raw(opts.selectSql);
|
|
15026
|
+
if (opts.partition === void 0) {
|
|
15027
|
+
if (opts.uniqueKey) {
|
|
15028
|
+
let uk = sql.raw(opts.uniqueKey);
|
|
15029
|
+
return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT * FROM (${body}) WHERE false;
|
|
15030
|
+
BEGIN TRANSACTION;
|
|
15031
|
+
DELETE FROM ${t} WHERE ${uk} IN (SELECT ${uk} FROM (${body}));
|
|
15032
|
+
INSERT INTO ${t} SELECT * FROM (${body});
|
|
15033
|
+
COMMIT;`;
|
|
15034
|
+
}
|
|
15035
|
+
return sql`CREATE OR REPLACE TABLE ${t} AS SELECT * FROM (${body});`;
|
|
15036
|
+
}
|
|
15037
|
+
if (opts.uniqueKey) {
|
|
15038
|
+
let uk = sql.raw(opts.uniqueKey);
|
|
15039
|
+
return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
|
|
15040
|
+
ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
|
|
15041
|
+
BEGIN TRANSACTION;
|
|
15042
|
+
DELETE FROM ${t} WHERE ${pcol} = ${opts.partition} AND ${uk} IN (SELECT ${uk} FROM (${body}));
|
|
15043
|
+
INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});
|
|
15044
|
+
COMMIT;`;
|
|
15045
|
+
}
|
|
15046
|
+
return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
|
|
15047
|
+
ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
|
|
15048
|
+
BEGIN TRANSACTION;
|
|
15049
|
+
DELETE FROM ${t} WHERE ${pcol} = ${opts.partition};
|
|
15050
|
+
INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});
|
|
15051
|
+
COMMIT;`;
|
|
15052
|
+
}
|
|
15053
|
+
/** INSERT-only materialization (no dedup/replace) for append-only tables.
|
|
15054
|
+
* Re-running the same partition duplicates rows — use only for immutable
|
|
15055
|
+
* event-log sources.
|
|
15056
|
+
*
|
|
15057
|
+
* Returns a lazy statement — call `.execute()` to run it:
|
|
15058
|
+
* `await wmill.appendPartition({ table, selectSql, partition }).execute()`. */
|
|
15059
|
+
function appendPartition(opts) {
|
|
15060
|
+
return finishMaterialize(buildAppendStatement(opts), opts);
|
|
15061
|
+
}
|
|
15062
|
+
function buildAppendStatement(opts) {
|
|
15063
|
+
let { name: n, schema } = parseName(opts.ducklake ?? "main");
|
|
15064
|
+
let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
|
|
15065
|
+
let pcol = sql.raw(opts.partitionCol ?? "_wm_partition");
|
|
15066
|
+
let t = sql.raw(`dl.${opts.table}`);
|
|
15067
|
+
let body = sql.raw(opts.selectSql);
|
|
15068
|
+
if (opts.partition === void 0) return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT * FROM (${body}) WHERE false;
|
|
15069
|
+
INSERT INTO ${t} SELECT * FROM (${body});`;
|
|
15070
|
+
return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
|
|
15071
|
+
ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
|
|
15072
|
+
INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});`;
|
|
15073
|
+
}
|
|
15074
|
+
function finishMaterialize(stmt, opts) {
|
|
15075
|
+
if (getEnv("WM_PIPELINE") !== "true") return stmt;
|
|
15076
|
+
let { name: n, schema } = parseName(opts.ducklake ?? "main");
|
|
15077
|
+
let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
|
|
15078
|
+
let t = sql.raw(`dl.${opts.table}`);
|
|
15079
|
+
let pcol = opts.partitionCol ?? "_wm_partition";
|
|
15080
|
+
let where = opts.partition !== void 0 ? sql.raw(`WHERE ${pcol} = '${String(opts.partition).replace(/'/g, "''")}'`) : sql.raw("");
|
|
15081
|
+
let summary = sql`SELECT (SELECT count(*) FROM ${t} ${where}) AS rows, (SELECT max(snapshot_id) FROM ducklake_snapshots('dl')) AS snapshot_id`;
|
|
15082
|
+
let assetPath = schema ? `${n}/${schema}.${opts.table}` : `${n}/${opts.table}`;
|
|
15083
|
+
let partition = opts.partition ?? "";
|
|
15084
|
+
let run = async () => {
|
|
15085
|
+
try {
|
|
15086
|
+
await stmt.execute();
|
|
15087
|
+
} catch (e) {
|
|
15088
|
+
await recordMaterialization(assetPath, partition, "failed", null, null, String(e));
|
|
15089
|
+
throw e;
|
|
15090
|
+
}
|
|
15091
|
+
let snapshot_id = null;
|
|
15092
|
+
let row_count = null;
|
|
15093
|
+
try {
|
|
15094
|
+
let s = await summary.fetchOne();
|
|
15095
|
+
snapshot_id = s?.snapshot_id ?? null;
|
|
15096
|
+
row_count = s?.rows ?? null;
|
|
15097
|
+
} catch {}
|
|
15098
|
+
await recordMaterialization(assetPath, partition, "materialized", snapshot_id, row_count, null);
|
|
15099
|
+
};
|
|
15100
|
+
return {
|
|
15101
|
+
...stmt,
|
|
15102
|
+
execute: () => run(),
|
|
15103
|
+
fetch: () => run(),
|
|
15104
|
+
fetchOne: () => run(),
|
|
15105
|
+
fetchOneScalar: () => run()
|
|
15106
|
+
};
|
|
15107
|
+
}
|
|
15108
|
+
async function recordMaterialization(assetPath, partition, status, snapshot_id, row_count, error) {
|
|
15109
|
+
try {
|
|
15110
|
+
await fetch(`${OpenAPI.BASE}/w/${getWorkspace()}/assets/record_materialization`, {
|
|
15111
|
+
method: "POST",
|
|
15112
|
+
headers: {
|
|
15113
|
+
"content-type": "application/json",
|
|
15114
|
+
authorization: `Bearer ${OpenAPI.TOKEN}`
|
|
15115
|
+
},
|
|
15116
|
+
body: JSON.stringify({
|
|
15117
|
+
asset_kind: "ducklake",
|
|
15118
|
+
asset_path: assetPath,
|
|
15119
|
+
partition,
|
|
15120
|
+
status,
|
|
15121
|
+
snapshot_id,
|
|
15122
|
+
row_count,
|
|
15123
|
+
job_id: getEnv("WM_JOB_ID") ?? null,
|
|
15124
|
+
error
|
|
15125
|
+
})
|
|
15126
|
+
});
|
|
15127
|
+
} catch {}
|
|
15128
|
+
}
|
|
15008
15129
|
function inferSqlType(value) {
|
|
15009
15130
|
if (typeof value === "bigint") return "BIGINT";
|
|
15010
15131
|
if (typeof value === "number") {
|
|
@@ -16449,6 +16570,8 @@ const wmill = {
|
|
|
16449
16570
|
streamResult,
|
|
16450
16571
|
datatable,
|
|
16451
16572
|
ducklake,
|
|
16573
|
+
upsertPartition,
|
|
16574
|
+
appendPartition,
|
|
16452
16575
|
SHARED_FOLDER,
|
|
16453
16576
|
getWorkspace,
|
|
16454
16577
|
getStatePath,
|
|
@@ -16552,6 +16675,7 @@ Object.defineProperty(exports, '_workflowCtx', {
|
|
|
16552
16675
|
return _workflowCtx;
|
|
16553
16676
|
}
|
|
16554
16677
|
});
|
|
16678
|
+
exports.appendPartition = appendPartition;
|
|
16555
16679
|
exports.appendToResultStream = appendToResultStream;
|
|
16556
16680
|
exports.commitKafkaOffsets = commitKafkaOffsets;
|
|
16557
16681
|
exports.datatable = datatable;
|
|
@@ -16597,6 +16721,7 @@ exports.streamResult = streamResult;
|
|
|
16597
16721
|
exports.task = task;
|
|
16598
16722
|
exports.taskFlow = taskFlow;
|
|
16599
16723
|
exports.taskScript = taskScript;
|
|
16724
|
+
exports.upsertPartition = upsertPartition;
|
|
16600
16725
|
exports.usernameToEmail = usernameToEmail;
|
|
16601
16726
|
exports.waitForApproval = waitForApproval;
|
|
16602
16727
|
exports.waitJob = waitJob;
|
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { ApiError } from "./core/ApiError.mjs";
|
|
|
2
2
|
import { CancelError, CancelablePromise } from "./core/CancelablePromise.mjs";
|
|
3
3
|
import { OpenAPI } from "./core/OpenAPI.mjs";
|
|
4
4
|
import { AdminService, AgentWorkersService, AppService, AssetService, AuditService, AzureTriggerService, CaptureService, ConcurrencyGroupsService, ConfigService, DocumentationService, DraftService, EmailTriggerService, FavoriteService, FlowConversationsService, FlowService, FolderService, GcpTriggerService, GitSyncService, GranularAclService, GroupService, HealthService, HelpersService, HttpTriggerService, IndexSearchService, InputService, IntegrationService, JobService, KafkaTriggerService, McpOauthService, McpService, MetricsService, MqttTriggerService, NativeTriggerService, NatsTriggerService, NpmProxyService, OauthService, OidcService, OpenapiService, PathAutocompleteService, PostgresTriggerService, RawAppService, ResourceService, ScheduleService, ScriptService, ServiceLogsService, SettingService, SettingsService, SqsTriggerService, TeamsService, TokenService, TriggerService, UserService, VariableService, VolumeService, WebsocketTriggerService, WorkerService, WorkspaceDependenciesService, WorkspaceIntegrationService, WorkspaceService } from "./services.gen.mjs";
|
|
5
|
-
import { datatable, ducklake } from "./sqlUtils.mjs";
|
|
5
|
+
import { appendPartition, datatable, ducklake, upsertPartition } from "./sqlUtils.mjs";
|
|
6
6
|
import { SHARED_FOLDER, StepSuspend, WorkflowCtx, _workflowCtx, appendToResultStream, base64ToUint8Array, commitKafkaOffsets, databaseUrlFromResource, deleteS3File, denoS3LightClientSettings, getFlowUserState, getIdToken, getInternalState, getPresignedS3PublicUrl, getPresignedS3PublicUrls, getProgress, getResource, getResult, getResultMaybe, getResumeEndpoints, getResumeUrls, getRootJobId, getState, getStatePath, getVariable, getWorkspace, loadS3File, loadS3FileStream, parallel, parseS3Object, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, resolveDefaultResource, runFlow, runFlowAsync, runScript, runScriptAsync, runScriptByHash, runScriptByHashAsync, runScriptByPath, runScriptByPathAsync, setClient, setFlowUserState, setInternalState, setProgress, setResource, setState, setVariable, setWorkflowCtx, signS3Object, signS3Objects, sleep, step, streamResult, task, taskFlow, taskScript, uint8ArrayToBase64, usernameToEmail, waitForApproval, waitJob, workflow, writeS3File } from "./client.mjs";
|
|
7
7
|
|
|
8
8
|
//#region src/index.ts
|
|
@@ -58,6 +58,8 @@ const wmill = {
|
|
|
58
58
|
streamResult,
|
|
59
59
|
datatable,
|
|
60
60
|
ducklake,
|
|
61
|
+
upsertPartition,
|
|
62
|
+
appendPartition,
|
|
61
63
|
SHARED_FOLDER,
|
|
62
64
|
getWorkspace,
|
|
63
65
|
getStatePath,
|
|
@@ -90,4 +92,4 @@ const wmill = {
|
|
|
90
92
|
var src_default = wmill;
|
|
91
93
|
|
|
92
94
|
//#endregion
|
|
93
|
-
export { AdminService, AgentWorkersService, ApiError, AppService, AssetService, AuditService, AzureTriggerService, CancelError, CancelablePromise, CaptureService, ConcurrencyGroupsService, ConfigService, DocumentationService, DraftService, EmailTriggerService, FavoriteService, FlowConversationsService, FlowService, FolderService, GcpTriggerService, GitSyncService, GranularAclService, GroupService, HealthService, HelpersService, HttpTriggerService, IndexSearchService, InputService, IntegrationService, JobService, KafkaTriggerService, McpOauthService, McpService, MetricsService, MqttTriggerService, NativeTriggerService, NatsTriggerService, NpmProxyService, OauthService, OidcService, OpenAPI, OpenapiService, PathAutocompleteService, PostgresTriggerService, RawAppService, ResourceService, ScheduleService, ScriptService, ServiceLogsService, SettingService, SettingsService, SqsTriggerService, StepSuspend, TeamsService, TokenService, TriggerService, UserService, VariableService, VolumeService, WebsocketTriggerService, WorkerService, WorkflowCtx, WorkspaceDependenciesService, WorkspaceIntegrationService, WorkspaceService, _workflowCtx, appendToResultStream, commitKafkaOffsets, datatable, src_default as default, deleteS3File, denoS3LightClientSettings, ducklake, getFlowUserState, getIdToken, getPresignedS3PublicUrl, getPresignedS3PublicUrls, getProgress, getResource, getResumeUrls, getRootJobId, getState, getVariable, loadS3File, loadS3FileStream, parallel, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, runFlow, runFlowAsync, runScript, runScriptAsync, runScriptByHash, runScriptByHashAsync, runScriptByPath, runScriptByPathAsync, setClient, setFlowUserState, setProgress, setResource, setState, setVariable, setWorkflowCtx, signS3Object, signS3Objects, sleep, step, streamResult, task, taskFlow, taskScript, usernameToEmail, waitForApproval, waitJob, workflow, writeS3File };
|
|
95
|
+
export { AdminService, AgentWorkersService, ApiError, AppService, AssetService, AuditService, AzureTriggerService, CancelError, CancelablePromise, CaptureService, ConcurrencyGroupsService, ConfigService, DocumentationService, DraftService, EmailTriggerService, FavoriteService, FlowConversationsService, FlowService, FolderService, GcpTriggerService, GitSyncService, GranularAclService, GroupService, HealthService, HelpersService, HttpTriggerService, IndexSearchService, InputService, IntegrationService, JobService, KafkaTriggerService, McpOauthService, McpService, MetricsService, MqttTriggerService, NativeTriggerService, NatsTriggerService, NpmProxyService, OauthService, OidcService, OpenAPI, OpenapiService, PathAutocompleteService, PostgresTriggerService, RawAppService, ResourceService, ScheduleService, ScriptService, ServiceLogsService, SettingService, SettingsService, SqsTriggerService, StepSuspend, TeamsService, TokenService, TriggerService, UserService, VariableService, VolumeService, WebsocketTriggerService, WorkerService, WorkflowCtx, WorkspaceDependenciesService, WorkspaceIntegrationService, WorkspaceService, _workflowCtx, appendPartition, appendToResultStream, commitKafkaOffsets, datatable, src_default as default, deleteS3File, denoS3LightClientSettings, ducklake, getFlowUserState, getIdToken, getPresignedS3PublicUrl, getPresignedS3PublicUrls, getProgress, getResource, getResumeUrls, getRootJobId, getState, getVariable, loadS3File, loadS3FileStream, parallel, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, runFlow, runFlowAsync, runScript, runScriptAsync, runScriptByHash, runScriptByHashAsync, runScriptByPath, runScriptByPathAsync, setClient, setFlowUserState, setProgress, setResource, setState, setVariable, setWorkflowCtx, signS3Object, signS3Objects, sleep, step, streamResult, task, taskFlow, taskScript, upsertPartition, usernameToEmail, waitForApproval, waitJob, workflow, writeS3File };
|
package/dist/sqlUtils.d.ts
CHANGED
|
@@ -86,4 +86,39 @@ export declare function datatable(name?: string): DatatableSqlTemplateFunction;
|
|
|
86
86
|
* let sql = wmill.ducklake("my_lake:analytics")
|
|
87
87
|
*/
|
|
88
88
|
export declare function ducklake(name?: string): SqlTemplateFunction;
|
|
89
|
+
/** Options for the ducklake materialization helpers. `partition` is bound as a
|
|
90
|
+
* DuckDB arg (never interpolated); `selectSql`, `table`, `schema`, `uniqueKey`
|
|
91
|
+
* are trusted structural SQL inlined via `raw`. */
|
|
92
|
+
export interface DucklakeMaterializeOptions {
|
|
93
|
+
/** ducklake name (default "main"), optionally "name:schema". */
|
|
94
|
+
ducklake?: string;
|
|
95
|
+
/** target table within the ducklake. */
|
|
96
|
+
table: string;
|
|
97
|
+
/** the SELECT producing the rows for this slice. */
|
|
98
|
+
selectSql: string;
|
|
99
|
+
/** the partition value (bound). Omit for a whole-table materialization — no
|
|
100
|
+
* partition column, and replace becomes a `CREATE OR REPLACE TABLE`. */
|
|
101
|
+
partition?: string;
|
|
102
|
+
/** dedup key → upsert in slice (delete-by-key + insert); omit → replace (delete partition + insert). */
|
|
103
|
+
uniqueKey?: string;
|
|
104
|
+
/** physical partition column (default "_wm_partition"). */
|
|
105
|
+
partitionCol?: string;
|
|
106
|
+
}
|
|
107
|
+
/** Idempotently materialize `selectSql` into a ducklake table for one
|
|
108
|
+
* partition (or the whole table when `partition` is omitted) — the client-side
|
|
109
|
+
* equivalent of the `// materialize` engine.
|
|
110
|
+
* With `uniqueKey` it upserts the slice (delete-by-key + insert); otherwise it
|
|
111
|
+
* replaces it (whole table → `CREATE OR REPLACE`; partition → delete + insert).
|
|
112
|
+
* Safe to re-run for the same partition (backfill / failure-recovery).
|
|
113
|
+
*
|
|
114
|
+
* Returns a lazy statement — call `.execute()` to run it:
|
|
115
|
+
* `await wmill.upsertPartition({ table, selectSql, partition }).execute()`. */
|
|
116
|
+
export declare function upsertPartition(opts: DucklakeMaterializeOptions): SqlStatement<any>;
|
|
117
|
+
/** INSERT-only materialization (no dedup/replace) for append-only tables.
|
|
118
|
+
* Re-running the same partition duplicates rows — use only for immutable
|
|
119
|
+
* event-log sources.
|
|
120
|
+
*
|
|
121
|
+
* Returns a lazy statement — call `.execute()` to run it:
|
|
122
|
+
* `await wmill.appendPartition({ table, selectSql, partition }).execute()`. */
|
|
123
|
+
export declare function appendPartition(opts: Omit<DucklakeMaterializeOptions, "uniqueKey">): SqlStatement<any>;
|
|
89
124
|
export {};
|
package/dist/sqlUtils.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { OpenAPI } from "./core/OpenAPI.mjs";
|
|
1
2
|
import { JobService } from "./services.gen.mjs";
|
|
2
|
-
import { getWorkspace, workerHasInternalServer } from "./client.mjs";
|
|
3
|
+
import { getEnv, getWorkspace, workerHasInternalServer } from "./client.mjs";
|
|
3
4
|
|
|
4
5
|
//#region src/sqlUtils.ts
|
|
5
6
|
/**
|
|
@@ -33,7 +34,7 @@ function ducklakeProvider(name, schema) {
|
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
function buildSqlStatement(provider, content, contentBody, args) {
|
|
36
|
-
async function fetch({ resultCollection } = {}) {
|
|
37
|
+
async function fetch$1({ resultCollection } = {}) {
|
|
37
38
|
let finalContent = content;
|
|
38
39
|
if (resultCollection) finalContent = `-- result_collection=${resultCollection}\n${finalContent}`;
|
|
39
40
|
try {
|
|
@@ -72,16 +73,16 @@ function buildSqlStatement(provider, content, contentBody, args) {
|
|
|
72
73
|
return {
|
|
73
74
|
content,
|
|
74
75
|
args,
|
|
75
|
-
fetch,
|
|
76
|
-
fetchOne: (params) => fetch({
|
|
76
|
+
fetch: fetch$1,
|
|
77
|
+
fetchOne: (params) => fetch$1({
|
|
77
78
|
...params,
|
|
78
79
|
resultCollection: "last_statement_first_row"
|
|
79
80
|
}),
|
|
80
|
-
fetchOneScalar: (params) => fetch({
|
|
81
|
+
fetchOneScalar: (params) => fetch$1({
|
|
81
82
|
...params,
|
|
82
83
|
resultCollection: "last_statement_first_row_scalar"
|
|
83
84
|
}),
|
|
84
|
-
execute: (params) => fetch(params)
|
|
85
|
+
execute: (params) => fetch$1(params)
|
|
85
86
|
};
|
|
86
87
|
}
|
|
87
88
|
function serializeArgValue(v) {
|
|
@@ -188,6 +189,127 @@ function ducklake(name = "main") {
|
|
|
188
189
|
let { name: n, schema } = parseName(name);
|
|
189
190
|
return buildSqlTemplateFunction(ducklakeProvider(n, schema));
|
|
190
191
|
}
|
|
192
|
+
/** Idempotently materialize `selectSql` into a ducklake table for one
|
|
193
|
+
* partition (or the whole table when `partition` is omitted) — the client-side
|
|
194
|
+
* equivalent of the `// materialize` engine.
|
|
195
|
+
* With `uniqueKey` it upserts the slice (delete-by-key + insert); otherwise it
|
|
196
|
+
* replaces it (whole table → `CREATE OR REPLACE`; partition → delete + insert).
|
|
197
|
+
* Safe to re-run for the same partition (backfill / failure-recovery).
|
|
198
|
+
*
|
|
199
|
+
* Returns a lazy statement — call `.execute()` to run it:
|
|
200
|
+
* `await wmill.upsertPartition({ table, selectSql, partition }).execute()`. */
|
|
201
|
+
function upsertPartition(opts) {
|
|
202
|
+
return finishMaterialize(buildUpsertStatement(opts), opts);
|
|
203
|
+
}
|
|
204
|
+
function buildUpsertStatement(opts) {
|
|
205
|
+
let { name: n, schema } = parseName(opts.ducklake ?? "main");
|
|
206
|
+
let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
|
|
207
|
+
let pcol = sql.raw(opts.partitionCol ?? "_wm_partition");
|
|
208
|
+
let t = sql.raw(`dl.${opts.table}`);
|
|
209
|
+
let body = sql.raw(opts.selectSql);
|
|
210
|
+
if (opts.partition === void 0) {
|
|
211
|
+
if (opts.uniqueKey) {
|
|
212
|
+
let uk = sql.raw(opts.uniqueKey);
|
|
213
|
+
return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT * FROM (${body}) WHERE false;
|
|
214
|
+
BEGIN TRANSACTION;
|
|
215
|
+
DELETE FROM ${t} WHERE ${uk} IN (SELECT ${uk} FROM (${body}));
|
|
216
|
+
INSERT INTO ${t} SELECT * FROM (${body});
|
|
217
|
+
COMMIT;`;
|
|
218
|
+
}
|
|
219
|
+
return sql`CREATE OR REPLACE TABLE ${t} AS SELECT * FROM (${body});`;
|
|
220
|
+
}
|
|
221
|
+
if (opts.uniqueKey) {
|
|
222
|
+
let uk = sql.raw(opts.uniqueKey);
|
|
223
|
+
return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
|
|
224
|
+
ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
|
|
225
|
+
BEGIN TRANSACTION;
|
|
226
|
+
DELETE FROM ${t} WHERE ${pcol} = ${opts.partition} AND ${uk} IN (SELECT ${uk} FROM (${body}));
|
|
227
|
+
INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});
|
|
228
|
+
COMMIT;`;
|
|
229
|
+
}
|
|
230
|
+
return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
|
|
231
|
+
ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
|
|
232
|
+
BEGIN TRANSACTION;
|
|
233
|
+
DELETE FROM ${t} WHERE ${pcol} = ${opts.partition};
|
|
234
|
+
INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});
|
|
235
|
+
COMMIT;`;
|
|
236
|
+
}
|
|
237
|
+
/** INSERT-only materialization (no dedup/replace) for append-only tables.
|
|
238
|
+
* Re-running the same partition duplicates rows — use only for immutable
|
|
239
|
+
* event-log sources.
|
|
240
|
+
*
|
|
241
|
+
* Returns a lazy statement — call `.execute()` to run it:
|
|
242
|
+
* `await wmill.appendPartition({ table, selectSql, partition }).execute()`. */
|
|
243
|
+
function appendPartition(opts) {
|
|
244
|
+
return finishMaterialize(buildAppendStatement(opts), opts);
|
|
245
|
+
}
|
|
246
|
+
function buildAppendStatement(opts) {
|
|
247
|
+
let { name: n, schema } = parseName(opts.ducklake ?? "main");
|
|
248
|
+
let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
|
|
249
|
+
let pcol = sql.raw(opts.partitionCol ?? "_wm_partition");
|
|
250
|
+
let t = sql.raw(`dl.${opts.table}`);
|
|
251
|
+
let body = sql.raw(opts.selectSql);
|
|
252
|
+
if (opts.partition === void 0) return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT * FROM (${body}) WHERE false;
|
|
253
|
+
INSERT INTO ${t} SELECT * FROM (${body});`;
|
|
254
|
+
return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
|
|
255
|
+
ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
|
|
256
|
+
INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});`;
|
|
257
|
+
}
|
|
258
|
+
function finishMaterialize(stmt, opts) {
|
|
259
|
+
if (getEnv("WM_PIPELINE") !== "true") return stmt;
|
|
260
|
+
let { name: n, schema } = parseName(opts.ducklake ?? "main");
|
|
261
|
+
let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
|
|
262
|
+
let t = sql.raw(`dl.${opts.table}`);
|
|
263
|
+
let pcol = opts.partitionCol ?? "_wm_partition";
|
|
264
|
+
let where = opts.partition !== void 0 ? sql.raw(`WHERE ${pcol} = '${String(opts.partition).replace(/'/g, "''")}'`) : sql.raw("");
|
|
265
|
+
let summary = sql`SELECT (SELECT count(*) FROM ${t} ${where}) AS rows, (SELECT max(snapshot_id) FROM ducklake_snapshots('dl')) AS snapshot_id`;
|
|
266
|
+
let assetPath = schema ? `${n}/${schema}.${opts.table}` : `${n}/${opts.table}`;
|
|
267
|
+
let partition = opts.partition ?? "";
|
|
268
|
+
let run = async () => {
|
|
269
|
+
try {
|
|
270
|
+
await stmt.execute();
|
|
271
|
+
} catch (e) {
|
|
272
|
+
await recordMaterialization(assetPath, partition, "failed", null, null, String(e));
|
|
273
|
+
throw e;
|
|
274
|
+
}
|
|
275
|
+
let snapshot_id = null;
|
|
276
|
+
let row_count = null;
|
|
277
|
+
try {
|
|
278
|
+
let s = await summary.fetchOne();
|
|
279
|
+
snapshot_id = s?.snapshot_id ?? null;
|
|
280
|
+
row_count = s?.rows ?? null;
|
|
281
|
+
} catch {}
|
|
282
|
+
await recordMaterialization(assetPath, partition, "materialized", snapshot_id, row_count, null);
|
|
283
|
+
};
|
|
284
|
+
return {
|
|
285
|
+
...stmt,
|
|
286
|
+
execute: () => run(),
|
|
287
|
+
fetch: () => run(),
|
|
288
|
+
fetchOne: () => run(),
|
|
289
|
+
fetchOneScalar: () => run()
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
async function recordMaterialization(assetPath, partition, status, snapshot_id, row_count, error) {
|
|
293
|
+
try {
|
|
294
|
+
await fetch(`${OpenAPI.BASE}/w/${getWorkspace()}/assets/record_materialization`, {
|
|
295
|
+
method: "POST",
|
|
296
|
+
headers: {
|
|
297
|
+
"content-type": "application/json",
|
|
298
|
+
authorization: `Bearer ${OpenAPI.TOKEN}`
|
|
299
|
+
},
|
|
300
|
+
body: JSON.stringify({
|
|
301
|
+
asset_kind: "ducklake",
|
|
302
|
+
asset_path: assetPath,
|
|
303
|
+
partition,
|
|
304
|
+
status,
|
|
305
|
+
snapshot_id,
|
|
306
|
+
row_count,
|
|
307
|
+
job_id: getEnv("WM_JOB_ID") ?? null,
|
|
308
|
+
error
|
|
309
|
+
})
|
|
310
|
+
});
|
|
311
|
+
} catch {}
|
|
312
|
+
}
|
|
191
313
|
function inferSqlType(value) {
|
|
192
314
|
if (typeof value === "bigint") return "BIGINT";
|
|
193
315
|
if (typeof value === "number") {
|
|
@@ -235,4 +357,4 @@ function parseName(name) {
|
|
|
235
357
|
}
|
|
236
358
|
|
|
237
359
|
//#endregion
|
|
238
|
-
export { datatable, ducklake };
|
|
360
|
+
export { appendPartition, datatable, ducklake, upsertPartition };
|
package/dist/types.gen.d.ts
CHANGED
|
@@ -1538,6 +1538,10 @@ export type Script = {
|
|
|
1538
1538
|
export type NewScript = {
|
|
1539
1539
|
path: string;
|
|
1540
1540
|
parent_hash?: string;
|
|
1541
|
+
/**
|
|
1542
|
+
* When true, the backend resolves the parent to the current deployed head for this path within the transaction (ignoring parent_hash), instead of failing with a "lineage must be linear" error when the supplied parent_hash is stale.
|
|
1543
|
+
*/
|
|
1544
|
+
auto_parent?: boolean;
|
|
1541
1545
|
summary: string;
|
|
1542
1546
|
description?: string;
|
|
1543
1547
|
content: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "windmill-client",
|
|
3
3
|
"description": "Windmill SDK client for browsers and Node.js",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.734.0",
|
|
5
5
|
"author": "Ruben Fiszel",
|
|
6
6
|
"license": "Apache 2.0",
|
|
7
7
|
"homepage": "https://github.com/windmill-labs/windmill/tree/main/typescript-client#readme",
|