@tinybirdco/sdk 0.0.47 → 0.0.49
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 +53 -3
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +32 -0
- package/dist/cli/commands/migrate.js.map +1 -1
- package/dist/cli/commands/migrate.test.js +585 -8
- package/dist/cli/commands/migrate.test.js.map +1 -1
- package/dist/generator/connection.d.ts.map +1 -1
- package/dist/generator/connection.js +3 -0
- package/dist/generator/connection.js.map +1 -1
- package/dist/generator/connection.test.js +8 -0
- package/dist/generator/connection.test.js.map +1 -1
- package/dist/generator/datasource.d.ts.map +1 -1
- package/dist/generator/datasource.js +3 -0
- package/dist/generator/datasource.js.map +1 -1
- package/dist/generator/datasource.test.js +50 -0
- package/dist/generator/datasource.test.js.map +1 -1
- package/dist/generator/pipe.d.ts.map +1 -1
- package/dist/generator/pipe.js +31 -1
- package/dist/generator/pipe.js.map +1 -1
- package/dist/generator/pipe.test.js +50 -1
- package/dist/generator/pipe.test.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +3 -0
- package/dist/index.test.js.map +1 -1
- package/dist/migrate/emit-ts.d.ts.map +1 -1
- package/dist/migrate/emit-ts.js +159 -41
- package/dist/migrate/emit-ts.js.map +1 -1
- package/dist/migrate/parse-connection.d.ts.map +1 -1
- package/dist/migrate/parse-connection.js +13 -2
- package/dist/migrate/parse-connection.js.map +1 -1
- package/dist/migrate/parse-datasource.d.ts.map +1 -1
- package/dist/migrate/parse-datasource.js +115 -52
- package/dist/migrate/parse-datasource.js.map +1 -1
- package/dist/migrate/parse-pipe.d.ts.map +1 -1
- package/dist/migrate/parse-pipe.js +257 -46
- package/dist/migrate/parse-pipe.js.map +1 -1
- package/dist/migrate/parser-utils.d.ts +5 -0
- package/dist/migrate/parser-utils.d.ts.map +1 -1
- package/dist/migrate/parser-utils.js +22 -0
- package/dist/migrate/parser-utils.js.map +1 -1
- package/dist/migrate/types.d.ts +25 -3
- package/dist/migrate/types.d.ts.map +1 -1
- package/dist/schema/connection.d.ts +2 -0
- package/dist/schema/connection.d.ts.map +1 -1
- package/dist/schema/connection.js.map +1 -1
- package/dist/schema/datasource.d.ts +3 -1
- package/dist/schema/datasource.d.ts.map +1 -1
- package/dist/schema/datasource.js +8 -1
- package/dist/schema/datasource.js.map +1 -1
- package/dist/schema/datasource.test.js +13 -0
- package/dist/schema/datasource.test.js.map +1 -1
- package/dist/schema/engines.d.ts.map +1 -1
- package/dist/schema/engines.js +3 -0
- package/dist/schema/engines.js.map +1 -1
- package/dist/schema/engines.test.js +16 -0
- package/dist/schema/engines.test.js.map +1 -1
- package/dist/schema/pipe.d.ts +90 -3
- package/dist/schema/pipe.d.ts.map +1 -1
- package/dist/schema/pipe.js +84 -0
- package/dist/schema/pipe.js.map +1 -1
- package/dist/schema/pipe.test.js +70 -1
- package/dist/schema/pipe.test.js.map +1 -1
- package/dist/schema/secret.d.ts +6 -0
- package/dist/schema/secret.d.ts.map +1 -0
- package/dist/schema/secret.js +14 -0
- package/dist/schema/secret.js.map +1 -0
- package/dist/schema/secret.test.d.ts +2 -0
- package/dist/schema/secret.test.d.ts.map +1 -0
- package/dist/schema/secret.test.js +14 -0
- package/dist/schema/secret.test.js.map +1 -0
- package/dist/schema/types.d.ts +5 -0
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +6 -0
- package/dist/schema/types.js.map +1 -1
- package/dist/schema/types.test.js +12 -0
- package/dist/schema/types.test.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/migrate.test.ts +859 -8
- package/src/cli/commands/migrate.ts +35 -0
- package/src/generator/connection.test.ts +13 -0
- package/src/generator/connection.ts +4 -0
- package/src/generator/datasource.test.ts +60 -0
- package/src/generator/datasource.ts +3 -0
- package/src/generator/pipe.test.ts +56 -1
- package/src/generator/pipe.ts +41 -1
- package/src/index.test.ts +4 -0
- package/src/index.ts +12 -0
- package/src/migrate/emit-ts.ts +161 -48
- package/src/migrate/parse-connection.ts +15 -2
- package/src/migrate/parse-datasource.ts +134 -71
- package/src/migrate/parse-pipe.ts +364 -69
- package/src/migrate/parser-utils.ts +36 -1
- package/src/migrate/types.ts +28 -3
- package/src/schema/connection.ts +2 -0
- package/src/schema/datasource.test.ts +17 -0
- package/src/schema/datasource.ts +13 -2
- package/src/schema/engines.test.ts +18 -0
- package/src/schema/engines.ts +3 -0
- package/src/schema/pipe.test.ts +89 -0
- package/src/schema/pipe.ts +188 -4
- package/src/schema/secret.test.ts +19 -0
- package/src/schema/secret.ts +16 -0
- package/src/schema/types.test.ts +14 -0
- package/src/schema/types.ts +10 -0
package/src/migrate/emit-ts.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { toCamelCase } from "../codegen/utils.js";
|
|
|
3
3
|
import { parseLiteralFromDatafile, toTsLiteral } from "./parser-utils.js";
|
|
4
4
|
import type {
|
|
5
5
|
DatasourceModel,
|
|
6
|
+
DatasourceEngineModel,
|
|
6
7
|
KafkaConnectionModel,
|
|
7
8
|
ParsedResource,
|
|
8
9
|
PipeModel,
|
|
@@ -13,6 +14,79 @@ function escapeString(value: string): string {
|
|
|
13
14
|
return JSON.stringify(value);
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
function emitObjectKey(key: string): string {
|
|
18
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : escapeString(key);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface ParsedSecretTemplate {
|
|
22
|
+
name: string;
|
|
23
|
+
defaultValue?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseTbSecretTemplate(value: string): ParsedSecretTemplate | null {
|
|
27
|
+
const trimmed = value.trim();
|
|
28
|
+
const regex =
|
|
29
|
+
/^\{\{\s*tb_secret\(\s*["']([^"']+)["'](?:\s*,\s*["']([^"']*)["'])?\s*\)\s*\}\}$/;
|
|
30
|
+
const match = trimmed.match(regex);
|
|
31
|
+
if (!match) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
name: match[1] ?? "",
|
|
36
|
+
defaultValue: match[2],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function emitStringOrSecret(value: string): string {
|
|
41
|
+
const parsed = parseTbSecretTemplate(value);
|
|
42
|
+
if (!parsed) {
|
|
43
|
+
return escapeString(value);
|
|
44
|
+
}
|
|
45
|
+
if (parsed.defaultValue !== undefined) {
|
|
46
|
+
return `secret(${escapeString(parsed.name)}, ${escapeString(parsed.defaultValue)})`;
|
|
47
|
+
}
|
|
48
|
+
return `secret(${escapeString(parsed.name)})`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function hasSecretTemplate(resources: ParsedResource[]): boolean {
|
|
52
|
+
const values: string[] = [];
|
|
53
|
+
|
|
54
|
+
for (const resource of resources) {
|
|
55
|
+
if (resource.kind === "connection") {
|
|
56
|
+
if (resource.connectionType === "kafka") {
|
|
57
|
+
values.push(resource.bootstrapServers);
|
|
58
|
+
if (resource.key) values.push(resource.key);
|
|
59
|
+
if (resource.secret) values.push(resource.secret);
|
|
60
|
+
if (resource.sslCaPem) values.push(resource.sslCaPem);
|
|
61
|
+
if (resource.schemaRegistryUrl) values.push(resource.schemaRegistryUrl);
|
|
62
|
+
} else {
|
|
63
|
+
values.push(resource.region);
|
|
64
|
+
if (resource.arn) values.push(resource.arn);
|
|
65
|
+
if (resource.accessKey) values.push(resource.accessKey);
|
|
66
|
+
if (resource.secret) values.push(resource.secret);
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (resource.kind === "datasource") {
|
|
72
|
+
if (resource.description) values.push(resource.description);
|
|
73
|
+
if (resource.kafka) {
|
|
74
|
+
values.push(resource.kafka.topic);
|
|
75
|
+
if (resource.kafka.groupId) values.push(resource.kafka.groupId);
|
|
76
|
+
if (resource.kafka.autoOffsetReset) values.push(resource.kafka.autoOffsetReset);
|
|
77
|
+
}
|
|
78
|
+
if (resource.s3) {
|
|
79
|
+
values.push(resource.s3.bucketUri);
|
|
80
|
+
if (resource.s3.schedule) values.push(resource.s3.schedule);
|
|
81
|
+
if (resource.s3.fromTimestamp) values.push(resource.s3.fromTimestamp);
|
|
82
|
+
}
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return values.some((value) => parseTbSecretTemplate(value) !== null);
|
|
88
|
+
}
|
|
89
|
+
|
|
16
90
|
function normalizedBaseType(type: string): string {
|
|
17
91
|
let current = type.trim();
|
|
18
92
|
let updated = true;
|
|
@@ -78,7 +152,7 @@ function strictParamBaseValidator(type: string): string {
|
|
|
78
152
|
function applyParamOptional(
|
|
79
153
|
baseValidator: string,
|
|
80
154
|
required: boolean,
|
|
81
|
-
defaultValue: string | number | undefined
|
|
155
|
+
defaultValue: string | number | boolean | undefined
|
|
82
156
|
): string {
|
|
83
157
|
const withDefault = defaultValue !== undefined;
|
|
84
158
|
if (!withDefault && required) {
|
|
@@ -95,6 +169,13 @@ function applyParamOptional(
|
|
|
95
169
|
return `${baseValidator}${optionalSuffix}`;
|
|
96
170
|
}
|
|
97
171
|
|
|
172
|
+
function applyParamDescription(validator: string, description: string | undefined): string {
|
|
173
|
+
if (description === undefined) {
|
|
174
|
+
return validator;
|
|
175
|
+
}
|
|
176
|
+
return `${validator}.describe(${JSON.stringify(description)})`;
|
|
177
|
+
}
|
|
178
|
+
|
|
98
179
|
function engineFunctionName(type: string): string {
|
|
99
180
|
const map: Record<string, string> = {
|
|
100
181
|
MergeTree: "mergeTree",
|
|
@@ -111,9 +192,8 @@ function engineFunctionName(type: string): string {
|
|
|
111
192
|
return functionName;
|
|
112
193
|
}
|
|
113
194
|
|
|
114
|
-
function emitEngineOptions(
|
|
195
|
+
function emitEngineOptions(engine: DatasourceEngineModel): string {
|
|
115
196
|
const options: string[] = [];
|
|
116
|
-
const { engine } = ds;
|
|
117
197
|
|
|
118
198
|
if (engine.sortingKey.length === 1) {
|
|
119
199
|
options.push(`sortingKey: ${escapeString(engine.sortingKey[0]!)}`);
|
|
@@ -141,6 +221,9 @@ function emitEngineOptions(ds: DatasourceModel): string {
|
|
|
141
221
|
if (engine.ver) {
|
|
142
222
|
options.push(`ver: ${escapeString(engine.ver)}`);
|
|
143
223
|
}
|
|
224
|
+
if (engine.isDeleted) {
|
|
225
|
+
options.push(`isDeleted: ${escapeString(engine.isDeleted)}`);
|
|
226
|
+
}
|
|
144
227
|
if (engine.sign) {
|
|
145
228
|
options.push(`sign: ${escapeString(engine.sign)}`);
|
|
146
229
|
}
|
|
@@ -170,13 +253,6 @@ function emitDatasource(ds: DatasourceModel): string {
|
|
|
170
253
|
const variableName = toCamelCase(ds.name);
|
|
171
254
|
const lines: string[] = [];
|
|
172
255
|
const hasJsonPath = ds.columns.some((column) => column.jsonPath !== undefined);
|
|
173
|
-
const hasMissingJsonPath = ds.columns.some((column) => column.jsonPath === undefined);
|
|
174
|
-
|
|
175
|
-
if (hasJsonPath && hasMissingJsonPath) {
|
|
176
|
-
throw new Error(
|
|
177
|
-
`Datasource "${ds.name}" has mixed json path usage. This is not representable in strict mode.`
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
256
|
|
|
181
257
|
if (ds.description) {
|
|
182
258
|
lines.push("/**");
|
|
@@ -187,8 +263,8 @@ function emitDatasource(ds: DatasourceModel): string {
|
|
|
187
263
|
}
|
|
188
264
|
|
|
189
265
|
lines.push(`export const ${variableName} = defineDatasource(${escapeString(ds.name)}, {`);
|
|
190
|
-
if (ds.description) {
|
|
191
|
-
lines.push(` description: ${
|
|
266
|
+
if (ds.description !== undefined) {
|
|
267
|
+
lines.push(` description: ${emitStringOrSecret(ds.description)},`);
|
|
192
268
|
}
|
|
193
269
|
if (!hasJsonPath) {
|
|
194
270
|
lines.push(" jsonPaths: false,");
|
|
@@ -197,6 +273,7 @@ function emitDatasource(ds: DatasourceModel): string {
|
|
|
197
273
|
lines.push(" schema: {");
|
|
198
274
|
for (const column of ds.columns) {
|
|
199
275
|
let validator = strictColumnTypeToValidator(column.type);
|
|
276
|
+
const columnKey = emitObjectKey(column.name);
|
|
200
277
|
|
|
201
278
|
if (column.defaultExpression !== undefined) {
|
|
202
279
|
const parsedDefault = parseLiteralFromDatafile(column.defaultExpression);
|
|
@@ -220,26 +297,28 @@ function emitDatasource(ds: DatasourceModel): string {
|
|
|
220
297
|
}
|
|
221
298
|
|
|
222
299
|
if (column.jsonPath) {
|
|
223
|
-
|
|
224
|
-
` ${column.name}: column(${validator}, { jsonPath: ${escapeString(column.jsonPath)} }),`
|
|
225
|
-
);
|
|
226
|
-
} else {
|
|
227
|
-
lines.push(` ${column.name}: ${validator},`);
|
|
300
|
+
validator += `.jsonPath(${escapeString(column.jsonPath)})`;
|
|
228
301
|
}
|
|
302
|
+
lines.push(` ${columnKey}: ${validator},`);
|
|
229
303
|
}
|
|
230
304
|
lines.push(" },");
|
|
231
|
-
|
|
305
|
+
if (ds.engine) {
|
|
306
|
+
lines.push(` engine: ${emitEngineOptions(ds.engine)},`);
|
|
307
|
+
}
|
|
232
308
|
|
|
233
309
|
if (ds.kafka) {
|
|
234
310
|
const connectionVar = toCamelCase(ds.kafka.connectionName);
|
|
235
311
|
lines.push(" kafka: {");
|
|
236
312
|
lines.push(` connection: ${connectionVar},`);
|
|
237
|
-
lines.push(` topic: ${
|
|
313
|
+
lines.push(` topic: ${emitStringOrSecret(ds.kafka.topic)},`);
|
|
238
314
|
if (ds.kafka.groupId) {
|
|
239
|
-
lines.push(` groupId: ${
|
|
315
|
+
lines.push(` groupId: ${emitStringOrSecret(ds.kafka.groupId)},`);
|
|
240
316
|
}
|
|
241
317
|
if (ds.kafka.autoOffsetReset) {
|
|
242
|
-
lines.push(` autoOffsetReset: ${
|
|
318
|
+
lines.push(` autoOffsetReset: ${emitStringOrSecret(ds.kafka.autoOffsetReset)},`);
|
|
319
|
+
}
|
|
320
|
+
if (ds.kafka.storeRawValue !== undefined) {
|
|
321
|
+
lines.push(` storeRawValue: ${ds.kafka.storeRawValue},`);
|
|
243
322
|
}
|
|
244
323
|
lines.push(" },");
|
|
245
324
|
}
|
|
@@ -248,12 +327,12 @@ function emitDatasource(ds: DatasourceModel): string {
|
|
|
248
327
|
const connectionVar = toCamelCase(ds.s3.connectionName);
|
|
249
328
|
lines.push(" s3: {");
|
|
250
329
|
lines.push(` connection: ${connectionVar},`);
|
|
251
|
-
lines.push(` bucketUri: ${
|
|
330
|
+
lines.push(` bucketUri: ${emitStringOrSecret(ds.s3.bucketUri)},`);
|
|
252
331
|
if (ds.s3.schedule) {
|
|
253
|
-
lines.push(` schedule: ${
|
|
332
|
+
lines.push(` schedule: ${emitStringOrSecret(ds.s3.schedule)},`);
|
|
254
333
|
}
|
|
255
334
|
if (ds.s3.fromTimestamp) {
|
|
256
|
-
lines.push(` fromTimestamp: ${
|
|
335
|
+
lines.push(` fromTimestamp: ${emitStringOrSecret(ds.s3.fromTimestamp)},`);
|
|
257
336
|
}
|
|
258
337
|
lines.push(" },");
|
|
259
338
|
}
|
|
@@ -293,21 +372,24 @@ function emitConnection(connection: KafkaConnectionModel | S3ConnectionModel): s
|
|
|
293
372
|
lines.push(
|
|
294
373
|
`export const ${variableName} = defineKafkaConnection(${escapeString(connection.name)}, {`
|
|
295
374
|
);
|
|
296
|
-
lines.push(` bootstrapServers: ${
|
|
375
|
+
lines.push(` bootstrapServers: ${emitStringOrSecret(connection.bootstrapServers)},`);
|
|
297
376
|
if (connection.securityProtocol) {
|
|
298
|
-
lines.push(` securityProtocol: ${
|
|
377
|
+
lines.push(` securityProtocol: ${emitStringOrSecret(connection.securityProtocol)},`);
|
|
299
378
|
}
|
|
300
379
|
if (connection.saslMechanism) {
|
|
301
|
-
lines.push(` saslMechanism: ${
|
|
380
|
+
lines.push(` saslMechanism: ${emitStringOrSecret(connection.saslMechanism)},`);
|
|
302
381
|
}
|
|
303
382
|
if (connection.key) {
|
|
304
|
-
lines.push(` key: ${
|
|
383
|
+
lines.push(` key: ${emitStringOrSecret(connection.key)},`);
|
|
305
384
|
}
|
|
306
385
|
if (connection.secret) {
|
|
307
|
-
lines.push(` secret: ${
|
|
386
|
+
lines.push(` secret: ${emitStringOrSecret(connection.secret)},`);
|
|
387
|
+
}
|
|
388
|
+
if (connection.schemaRegistryUrl) {
|
|
389
|
+
lines.push(` schemaRegistryUrl: ${emitStringOrSecret(connection.schemaRegistryUrl)},`);
|
|
308
390
|
}
|
|
309
391
|
if (connection.sslCaPem) {
|
|
310
|
-
lines.push(` sslCaPem: ${
|
|
392
|
+
lines.push(` sslCaPem: ${emitStringOrSecret(connection.sslCaPem)},`);
|
|
311
393
|
}
|
|
312
394
|
lines.push("});");
|
|
313
395
|
lines.push("");
|
|
@@ -317,15 +399,15 @@ function emitConnection(connection: KafkaConnectionModel | S3ConnectionModel): s
|
|
|
317
399
|
lines.push(
|
|
318
400
|
`export const ${variableName} = defineS3Connection(${escapeString(connection.name)}, {`
|
|
319
401
|
);
|
|
320
|
-
lines.push(` region: ${
|
|
402
|
+
lines.push(` region: ${emitStringOrSecret(connection.region)},`);
|
|
321
403
|
if (connection.arn) {
|
|
322
|
-
lines.push(` arn: ${
|
|
404
|
+
lines.push(` arn: ${emitStringOrSecret(connection.arn)},`);
|
|
323
405
|
}
|
|
324
406
|
if (connection.accessKey) {
|
|
325
|
-
lines.push(` accessKey: ${
|
|
407
|
+
lines.push(` accessKey: ${emitStringOrSecret(connection.accessKey)},`);
|
|
326
408
|
}
|
|
327
409
|
if (connection.secret) {
|
|
328
|
-
lines.push(` secret: ${
|
|
410
|
+
lines.push(` secret: ${emitStringOrSecret(connection.secret)},`);
|
|
329
411
|
}
|
|
330
412
|
lines.push("});");
|
|
331
413
|
lines.push("");
|
|
@@ -350,25 +432,28 @@ function emitPipe(pipe: PipeModel): string {
|
|
|
350
432
|
lines.push(`export const ${variableName} = defineMaterializedView(${escapeString(pipe.name)}, {`);
|
|
351
433
|
} else if (pipe.type === "copy") {
|
|
352
434
|
lines.push(`export const ${variableName} = defineCopyPipe(${escapeString(pipe.name)}, {`);
|
|
435
|
+
} else if (pipe.type === "sink") {
|
|
436
|
+
lines.push(`export const ${variableName} = defineSinkPipe(${escapeString(pipe.name)}, {`);
|
|
353
437
|
} else {
|
|
354
438
|
lines.push(`export const ${variableName} = definePipe(${escapeString(pipe.name)}, {`);
|
|
355
439
|
}
|
|
356
440
|
|
|
357
|
-
if (pipe.description) {
|
|
441
|
+
if (pipe.description !== undefined) {
|
|
358
442
|
lines.push(` description: ${escapeString(pipe.description)},`);
|
|
359
443
|
}
|
|
360
444
|
|
|
361
|
-
if (pipe.type === "pipe" || pipe.type === "endpoint") {
|
|
445
|
+
if (pipe.type === "pipe" || pipe.type === "endpoint" || pipe.type === "sink") {
|
|
362
446
|
if (pipe.params.length > 0) {
|
|
363
447
|
lines.push(" params: {");
|
|
364
448
|
for (const param of pipe.params) {
|
|
365
449
|
const baseValidator = strictParamBaseValidator(param.type);
|
|
366
|
-
const
|
|
450
|
+
const validatorWithOptional = applyParamOptional(
|
|
367
451
|
baseValidator,
|
|
368
452
|
param.required,
|
|
369
453
|
param.defaultValue
|
|
370
454
|
);
|
|
371
|
-
|
|
455
|
+
const validator = applyParamDescription(validatorWithOptional, param.description);
|
|
456
|
+
lines.push(` ${emitObjectKey(param.name)}: ${validator},`);
|
|
372
457
|
}
|
|
373
458
|
lines.push(" },");
|
|
374
459
|
}
|
|
@@ -391,11 +476,35 @@ function emitPipe(pipe: PipeModel): string {
|
|
|
391
476
|
}
|
|
392
477
|
}
|
|
393
478
|
|
|
479
|
+
if (pipe.type === "sink") {
|
|
480
|
+
if (!pipe.sink) {
|
|
481
|
+
throw new Error(`Sink pipe "${pipe.name}" is missing sink configuration.`);
|
|
482
|
+
}
|
|
483
|
+
lines.push(" sink: {");
|
|
484
|
+
lines.push(` connection: ${toCamelCase(pipe.sink.connectionName)},`);
|
|
485
|
+
if (pipe.sink.service === "kafka") {
|
|
486
|
+
lines.push(` topic: ${escapeString(pipe.sink.topic)},`);
|
|
487
|
+
lines.push(` schedule: ${escapeString(pipe.sink.schedule)},`);
|
|
488
|
+
} else {
|
|
489
|
+
lines.push(` bucketUri: ${escapeString(pipe.sink.bucketUri)},`);
|
|
490
|
+
lines.push(` fileTemplate: ${escapeString(pipe.sink.fileTemplate)},`);
|
|
491
|
+
lines.push(` schedule: ${escapeString(pipe.sink.schedule)},`);
|
|
492
|
+
lines.push(` format: ${escapeString(pipe.sink.format)},`);
|
|
493
|
+
if (pipe.sink.strategy) {
|
|
494
|
+
lines.push(` strategy: ${escapeString(pipe.sink.strategy)},`);
|
|
495
|
+
}
|
|
496
|
+
if (pipe.sink.compression) {
|
|
497
|
+
lines.push(` compression: ${escapeString(pipe.sink.compression)},`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
lines.push(" },");
|
|
501
|
+
}
|
|
502
|
+
|
|
394
503
|
lines.push(" nodes: [");
|
|
395
504
|
for (const node of pipe.nodes) {
|
|
396
505
|
lines.push(" node({");
|
|
397
506
|
lines.push(` name: ${escapeString(node.name)},`);
|
|
398
|
-
if (node.description) {
|
|
507
|
+
if (node.description !== undefined) {
|
|
399
508
|
lines.push(` description: ${escapeString(node.description)},`);
|
|
400
509
|
}
|
|
401
510
|
lines.push(" sql: `");
|
|
@@ -413,7 +522,7 @@ function emitPipe(pipe: PipeModel): string {
|
|
|
413
522
|
}
|
|
414
523
|
lines.push(" output: {");
|
|
415
524
|
for (const columnName of endpointOutputColumns) {
|
|
416
|
-
lines.push(` ${columnName}: t.string(),`);
|
|
525
|
+
lines.push(` ${emitObjectKey(columnName)}: t.string(),`);
|
|
417
526
|
}
|
|
418
527
|
lines.push(" },");
|
|
419
528
|
}
|
|
@@ -443,10 +552,8 @@ export function emitMigrationFileContent(resources: ParsedResource[]): string {
|
|
|
443
552
|
(resource): resource is PipeModel => resource.kind === "pipe"
|
|
444
553
|
);
|
|
445
554
|
|
|
446
|
-
const needsColumn = datasources.some((ds) =>
|
|
447
|
-
ds.columns.some((column) => column.jsonPath !== undefined)
|
|
448
|
-
);
|
|
449
555
|
const needsParams = pipes.some((pipe) => pipe.params.length > 0);
|
|
556
|
+
const needsSecret = hasSecretTemplate(resources);
|
|
450
557
|
|
|
451
558
|
const imports = new Set<string>([
|
|
452
559
|
"defineDatasource",
|
|
@@ -455,7 +562,6 @@ export function emitMigrationFileContent(resources: ParsedResource[]): string {
|
|
|
455
562
|
"defineCopyPipe",
|
|
456
563
|
"node",
|
|
457
564
|
"t",
|
|
458
|
-
"engine",
|
|
459
565
|
]);
|
|
460
566
|
if (connections.some((connection) => connection.connectionType === "kafka")) {
|
|
461
567
|
imports.add("defineKafkaConnection");
|
|
@@ -463,12 +569,18 @@ export function emitMigrationFileContent(resources: ParsedResource[]): string {
|
|
|
463
569
|
if (connections.some((connection) => connection.connectionType === "s3")) {
|
|
464
570
|
imports.add("defineS3Connection");
|
|
465
571
|
}
|
|
466
|
-
if (needsColumn) {
|
|
467
|
-
imports.add("column");
|
|
468
|
-
}
|
|
469
572
|
if (needsParams) {
|
|
470
573
|
imports.add("p");
|
|
471
574
|
}
|
|
575
|
+
if (pipes.some((pipe) => pipe.type === "sink")) {
|
|
576
|
+
imports.add("defineSinkPipe");
|
|
577
|
+
}
|
|
578
|
+
if (datasources.some((datasource) => datasource.engine !== undefined)) {
|
|
579
|
+
imports.add("engine");
|
|
580
|
+
}
|
|
581
|
+
if (needsSecret) {
|
|
582
|
+
imports.add("secret");
|
|
583
|
+
}
|
|
472
584
|
|
|
473
585
|
const orderedImports = [
|
|
474
586
|
"defineKafkaConnection",
|
|
@@ -477,10 +589,11 @@ export function emitMigrationFileContent(resources: ParsedResource[]): string {
|
|
|
477
589
|
"definePipe",
|
|
478
590
|
"defineMaterializedView",
|
|
479
591
|
"defineCopyPipe",
|
|
592
|
+
"defineSinkPipe",
|
|
480
593
|
"node",
|
|
481
594
|
"t",
|
|
482
595
|
"engine",
|
|
483
|
-
"
|
|
596
|
+
"secret",
|
|
484
597
|
"p",
|
|
485
598
|
].filter((name) => imports.has(name));
|
|
486
599
|
|
|
@@ -27,6 +27,7 @@ export function parseConnectionFile(
|
|
|
27
27
|
| undefined;
|
|
28
28
|
let key: string | undefined;
|
|
29
29
|
let secret: string | undefined;
|
|
30
|
+
let schemaRegistryUrl: string | undefined;
|
|
30
31
|
let sslCaPem: string | undefined;
|
|
31
32
|
|
|
32
33
|
let region: string | undefined;
|
|
@@ -36,7 +37,7 @@ export function parseConnectionFile(
|
|
|
36
37
|
|
|
37
38
|
for (const rawLine of lines) {
|
|
38
39
|
const line = rawLine.trim();
|
|
39
|
-
if (isBlank(line)) {
|
|
40
|
+
if (isBlank(line) || line.startsWith("#")) {
|
|
40
41
|
continue;
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -81,6 +82,9 @@ export function parseConnectionFile(
|
|
|
81
82
|
case "KAFKA_SECRET":
|
|
82
83
|
secret = value;
|
|
83
84
|
break;
|
|
85
|
+
case "KAFKA_SCHEMA_REGISTRY_URL":
|
|
86
|
+
schemaRegistryUrl = value;
|
|
87
|
+
break;
|
|
84
88
|
case "KAFKA_SSL_CA_PEM":
|
|
85
89
|
sslCaPem = value;
|
|
86
90
|
break;
|
|
@@ -144,12 +148,21 @@ export function parseConnectionFile(
|
|
|
144
148
|
saslMechanism,
|
|
145
149
|
key,
|
|
146
150
|
secret,
|
|
151
|
+
schemaRegistryUrl,
|
|
147
152
|
sslCaPem,
|
|
148
153
|
};
|
|
149
154
|
}
|
|
150
155
|
|
|
151
156
|
if (connectionType === "s3") {
|
|
152
|
-
if (
|
|
157
|
+
if (
|
|
158
|
+
bootstrapServers ||
|
|
159
|
+
securityProtocol ||
|
|
160
|
+
saslMechanism ||
|
|
161
|
+
key ||
|
|
162
|
+
secret ||
|
|
163
|
+
schemaRegistryUrl ||
|
|
164
|
+
sslCaPem
|
|
165
|
+
) {
|
|
153
166
|
throw new MigrationParseError(
|
|
154
167
|
resource.filePath,
|
|
155
168
|
"connection",
|