@tinybirdco/sdk 0.0.40 → 0.0.42
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 +42 -1
- package/dist/api/api.d.ts +2 -0
- package/dist/api/api.d.ts.map +1 -1
- package/dist/api/api.js +1 -1
- package/dist/api/api.js.map +1 -1
- package/dist/api/api.test.js +14 -0
- package/dist/api/api.test.js.map +1 -1
- package/dist/api/resources.d.ts +72 -1
- package/dist/api/resources.d.ts.map +1 -1
- package/dist/api/resources.js +197 -1
- package/dist/api/resources.js.map +1 -1
- package/dist/api/resources.test.js +82 -1
- package/dist/api/resources.test.js.map +1 -1
- package/dist/cli/commands/migrate.d.ts +11 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -0
- package/dist/cli/commands/migrate.js +196 -0
- package/dist/cli/commands/migrate.js.map +1 -0
- package/dist/cli/commands/migrate.test.d.ts +2 -0
- package/dist/cli/commands/migrate.test.d.ts.map +1 -0
- package/dist/cli/commands/migrate.test.js +473 -0
- package/dist/cli/commands/migrate.test.js.map +1 -0
- package/dist/cli/commands/pull.d.ts +59 -0
- package/dist/cli/commands/pull.d.ts.map +1 -0
- package/dist/cli/commands/pull.js +104 -0
- package/dist/cli/commands/pull.js.map +1 -0
- package/dist/cli/commands/pull.test.d.ts +2 -0
- package/dist/cli/commands/pull.test.d.ts.map +1 -0
- package/dist/cli/commands/pull.test.js +140 -0
- package/dist/cli/commands/pull.test.js.map +1 -0
- package/dist/cli/index.js +77 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/client/base.d.ts +18 -1
- package/dist/client/base.d.ts.map +1 -1
- package/dist/client/base.js +43 -2
- package/dist/client/base.js.map +1 -1
- package/dist/client/base.test.js +5 -1
- package/dist/client/base.test.js.map +1 -1
- package/dist/client/types.d.ts +4 -0
- package/dist/client/types.d.ts.map +1 -1
- package/dist/migrate/discovery.d.ts +7 -0
- package/dist/migrate/discovery.d.ts.map +1 -0
- package/dist/migrate/discovery.js +125 -0
- package/dist/migrate/discovery.js.map +1 -0
- package/dist/migrate/emit-ts.d.ts +4 -0
- package/dist/migrate/emit-ts.d.ts.map +1 -0
- package/dist/migrate/emit-ts.js +387 -0
- package/dist/migrate/emit-ts.js.map +1 -0
- package/dist/migrate/parse-connection.d.ts +3 -0
- package/dist/migrate/parse-connection.d.ts.map +1 -0
- package/dist/migrate/parse-connection.js +74 -0
- package/dist/migrate/parse-connection.js.map +1 -0
- package/dist/migrate/parse-datasource.d.ts +3 -0
- package/dist/migrate/parse-datasource.d.ts.map +1 -0
- package/dist/migrate/parse-datasource.js +324 -0
- package/dist/migrate/parse-datasource.js.map +1 -0
- package/dist/migrate/parse-pipe.d.ts +3 -0
- package/dist/migrate/parse-pipe.d.ts.map +1 -0
- package/dist/migrate/parse-pipe.js +332 -0
- package/dist/migrate/parse-pipe.js.map +1 -0
- package/dist/migrate/parse.d.ts +3 -0
- package/dist/migrate/parse.d.ts.map +1 -0
- package/dist/migrate/parse.js +18 -0
- package/dist/migrate/parse.js.map +1 -0
- package/dist/migrate/parser-utils.d.ts +20 -0
- package/dist/migrate/parser-utils.d.ts.map +1 -0
- package/dist/migrate/parser-utils.js +130 -0
- package/dist/migrate/parser-utils.js.map +1 -0
- package/dist/migrate/types.d.ts +110 -0
- package/dist/migrate/types.d.ts.map +1 -0
- package/dist/migrate/types.js +2 -0
- package/dist/migrate/types.js.map +1 -0
- package/dist/schema/project.d.ts +13 -27
- package/dist/schema/project.d.ts.map +1 -1
- package/dist/schema/project.js +14 -24
- package/dist/schema/project.js.map +1 -1
- package/dist/schema/project.test.js +25 -13
- package/dist/schema/project.test.js.map +1 -1
- package/package.json +1 -1
- package/src/api/api.test.ts +25 -0
- package/src/api/api.ts +3 -1
- package/src/api/resources.test.ts +121 -0
- package/src/api/resources.ts +292 -1
- package/src/cli/commands/migrate.test.ts +564 -0
- package/src/cli/commands/migrate.ts +240 -0
- package/src/cli/commands/pull.test.ts +173 -0
- package/src/cli/commands/pull.ts +177 -0
- package/src/cli/index.ts +112 -0
- package/src/client/base.test.ts +5 -1
- package/src/client/base.ts +56 -2
- package/src/client/types.ts +8 -0
- package/src/migrate/discovery.ts +151 -0
- package/src/migrate/emit-ts.ts +469 -0
- package/src/migrate/parse-connection.ts +128 -0
- package/src/migrate/parse-datasource.ts +453 -0
- package/src/migrate/parse-pipe.ts +518 -0
- package/src/migrate/parse.ts +20 -0
- package/src/migrate/parser-utils.ts +160 -0
- package/src/migrate/types.ts +125 -0
- package/src/schema/project.test.ts +25 -13
- package/src/schema/project.ts +33 -57
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { runMigrate } from "./migrate.js";
|
|
6
|
+
function writeFile(dir, relativePath, content) {
|
|
7
|
+
const fullPath = path.join(dir, relativePath);
|
|
8
|
+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
9
|
+
fs.writeFileSync(fullPath, content);
|
|
10
|
+
}
|
|
11
|
+
const EXPECTED_COMPLEX_OUTPUT = `/**
|
|
12
|
+
* Generated by tinybird migrate.
|
|
13
|
+
* Review endpoint output schemas and any defaults before production use.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createKafkaConnection, defineDatasource, definePipe, defineMaterializedView, defineCopyPipe, node, t, engine, column, p } from "@tinybirdco/sdk";
|
|
17
|
+
|
|
18
|
+
// Connections
|
|
19
|
+
|
|
20
|
+
export const stream = createKafkaConnection("stream", {
|
|
21
|
+
bootstrapServers: "localhost:9092",
|
|
22
|
+
securityProtocol: "SASL_SSL",
|
|
23
|
+
saslMechanism: "PLAIN",
|
|
24
|
+
key: "api-key",
|
|
25
|
+
secret: "api-secret",
|
|
26
|
+
sslCaPem: "ca-pem-content",
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Datasources
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Events from Kafka stream
|
|
33
|
+
*/
|
|
34
|
+
export const events = defineDatasource("events", {
|
|
35
|
+
description: "Events from Kafka stream",
|
|
36
|
+
schema: {
|
|
37
|
+
event_id: column(t.string(), { jsonPath: "$.event_id" }),
|
|
38
|
+
user_id: column(t.uint64(), { jsonPath: "$.user.id" }),
|
|
39
|
+
env: column(t.string().default("prod"), { jsonPath: "$.env" }),
|
|
40
|
+
is_test: column(t.bool().default(false), { jsonPath: "$.meta.is_test" }),
|
|
41
|
+
updated_at: column(t.dateTime(), { jsonPath: "$.updated_at" }),
|
|
42
|
+
payload: column(t.string().default("{}").codec("ZSTD(1)"), { jsonPath: "$.payload" }),
|
|
43
|
+
},
|
|
44
|
+
engine: engine.replacingMergeTree({ sortingKey: ["event_id", "user_id"], partitionKey: "toYYYYMM(updated_at)", primaryKey: "event_id", ttl: "updated_at + toIntervalDay(30)", ver: "updated_at", settings: { "index_granularity": 8192, "enable_mixed_granularity_parts": true } }),
|
|
45
|
+
kafka: {
|
|
46
|
+
connection: stream,
|
|
47
|
+
topic: "events_topic",
|
|
48
|
+
groupId: "events-consumer",
|
|
49
|
+
autoOffsetReset: "earliest",
|
|
50
|
+
},
|
|
51
|
+
forwardQuery: \`
|
|
52
|
+
SELECT *
|
|
53
|
+
FROM events_mv
|
|
54
|
+
\`,
|
|
55
|
+
tokens: [
|
|
56
|
+
{ name: "events_read", permissions: ["READ"] },
|
|
57
|
+
{ name: "events_append", permissions: ["APPEND"] },
|
|
58
|
+
],
|
|
59
|
+
sharedWith: ["workspace_a", "workspace_b"],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export const eventsRollup = defineDatasource("events_rollup", {
|
|
63
|
+
jsonPaths: false,
|
|
64
|
+
schema: {
|
|
65
|
+
user_id: t.uint64(),
|
|
66
|
+
total: t.uint64(),
|
|
67
|
+
},
|
|
68
|
+
engine: engine.summingMergeTree({ sortingKey: "user_id", columns: ["total"] }),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Pipes
|
|
72
|
+
|
|
73
|
+
export const copyEvents = defineCopyPipe("copy_events", {
|
|
74
|
+
datasource: eventsRollup,
|
|
75
|
+
copy_mode: "replace",
|
|
76
|
+
copy_schedule: "@on-demand",
|
|
77
|
+
nodes: [
|
|
78
|
+
node({
|
|
79
|
+
name: "copy_node",
|
|
80
|
+
sql: \`
|
|
81
|
+
SELECT event_id, user_id
|
|
82
|
+
FROM events
|
|
83
|
+
\`,
|
|
84
|
+
}),
|
|
85
|
+
],
|
|
86
|
+
tokens: [
|
|
87
|
+
{ name: "copy_token" },
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Endpoint for filtered events
|
|
93
|
+
*/
|
|
94
|
+
export const eventsEndpoint = definePipe("events_endpoint", {
|
|
95
|
+
description: "Endpoint for filtered events",
|
|
96
|
+
params: {
|
|
97
|
+
env: p.string().optional("prod"),
|
|
98
|
+
user_id: p.uint64(),
|
|
99
|
+
},
|
|
100
|
+
nodes: [
|
|
101
|
+
node({
|
|
102
|
+
name: "base",
|
|
103
|
+
description: "Base filter",
|
|
104
|
+
sql: \`
|
|
105
|
+
SELECT event_id, user_id, payload
|
|
106
|
+
FROM events
|
|
107
|
+
WHERE user_id = {{UInt64(user_id)}}
|
|
108
|
+
AND env = {{String(env, 'prod')}}
|
|
109
|
+
\`,
|
|
110
|
+
}),
|
|
111
|
+
node({
|
|
112
|
+
name: "endpoint",
|
|
113
|
+
sql: \`
|
|
114
|
+
SELECT event_id AS event_id, user_id AS user_id
|
|
115
|
+
FROM base
|
|
116
|
+
\`,
|
|
117
|
+
}),
|
|
118
|
+
],
|
|
119
|
+
endpoint: { enabled: true, cache: { enabled: true, ttl: 120 } },
|
|
120
|
+
output: {
|
|
121
|
+
event_id: t.string(),
|
|
122
|
+
user_id: t.string(),
|
|
123
|
+
},
|
|
124
|
+
tokens: [
|
|
125
|
+
{ name: "endpoint_token" },
|
|
126
|
+
],
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Materialized rollup
|
|
131
|
+
*/
|
|
132
|
+
export const eventsMv = defineMaterializedView("events_mv", {
|
|
133
|
+
description: "Materialized rollup",
|
|
134
|
+
datasource: eventsRollup,
|
|
135
|
+
deploymentMethod: "alter",
|
|
136
|
+
nodes: [
|
|
137
|
+
node({
|
|
138
|
+
name: "rollup",
|
|
139
|
+
sql: \`
|
|
140
|
+
SELECT user_id, count() AS total
|
|
141
|
+
FROM events
|
|
142
|
+
GROUP BY user_id
|
|
143
|
+
\`,
|
|
144
|
+
}),
|
|
145
|
+
],
|
|
146
|
+
tokens: [
|
|
147
|
+
{ name: "mv_token" },
|
|
148
|
+
],
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
export const statsPipe = definePipe("stats_pipe", {
|
|
152
|
+
params: {
|
|
153
|
+
min_total: p.uint32().optional(10),
|
|
154
|
+
},
|
|
155
|
+
nodes: [
|
|
156
|
+
node({
|
|
157
|
+
name: "agg",
|
|
158
|
+
sql: \`
|
|
159
|
+
SELECT user_id, count() AS total
|
|
160
|
+
FROM events
|
|
161
|
+
GROUP BY user_id
|
|
162
|
+
\`,
|
|
163
|
+
}),
|
|
164
|
+
node({
|
|
165
|
+
name: "final",
|
|
166
|
+
sql: \`
|
|
167
|
+
SELECT user_id, total
|
|
168
|
+
FROM agg
|
|
169
|
+
WHERE total > {{UInt32(min_total, 10)}}
|
|
170
|
+
\`,
|
|
171
|
+
}),
|
|
172
|
+
],
|
|
173
|
+
tokens: [
|
|
174
|
+
{ name: "stats_token" },
|
|
175
|
+
],
|
|
176
|
+
});
|
|
177
|
+
`;
|
|
178
|
+
const EXPECTED_PARTIAL_OUTPUT = `/**
|
|
179
|
+
* Generated by tinybird migrate.
|
|
180
|
+
* Review endpoint output schemas and any defaults before production use.
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
import { createKafkaConnection, defineDatasource, definePipe, defineMaterializedView, defineCopyPipe, node, t, engine, p } from "@tinybirdco/sdk";
|
|
184
|
+
|
|
185
|
+
// Connections
|
|
186
|
+
|
|
187
|
+
export const stream = createKafkaConnection("stream", {
|
|
188
|
+
bootstrapServers: "localhost:9092",
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Datasources
|
|
192
|
+
|
|
193
|
+
export const events = defineDatasource("events", {
|
|
194
|
+
jsonPaths: false,
|
|
195
|
+
schema: {
|
|
196
|
+
event_id: t.string(),
|
|
197
|
+
user_id: t.uint64(),
|
|
198
|
+
created_at: t.dateTime(),
|
|
199
|
+
},
|
|
200
|
+
engine: engine.mergeTree({ sortingKey: "event_id" }),
|
|
201
|
+
kafka: {
|
|
202
|
+
connection: stream,
|
|
203
|
+
topic: "events_topic",
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Pipes
|
|
208
|
+
|
|
209
|
+
export const eventsEndpoint = definePipe("events_endpoint", {
|
|
210
|
+
params: {
|
|
211
|
+
user_id: p.uint64(),
|
|
212
|
+
},
|
|
213
|
+
nodes: [
|
|
214
|
+
node({
|
|
215
|
+
name: "source",
|
|
216
|
+
sql: \`
|
|
217
|
+
SELECT event_id, user_id
|
|
218
|
+
FROM events
|
|
219
|
+
\`,
|
|
220
|
+
}),
|
|
221
|
+
node({
|
|
222
|
+
name: "endpoint",
|
|
223
|
+
sql: \`
|
|
224
|
+
SELECT event_id AS event_id, user_id AS user_id
|
|
225
|
+
FROM source
|
|
226
|
+
WHERE user_id = {{UInt64(user_id)}}
|
|
227
|
+
\`,
|
|
228
|
+
}),
|
|
229
|
+
],
|
|
230
|
+
endpoint: true,
|
|
231
|
+
output: {
|
|
232
|
+
event_id: t.string(),
|
|
233
|
+
user_id: t.string(),
|
|
234
|
+
},
|
|
235
|
+
tokens: [
|
|
236
|
+
{ name: "endpoint_token" },
|
|
237
|
+
],
|
|
238
|
+
});
|
|
239
|
+
`;
|
|
240
|
+
describe("runMigrate", () => {
|
|
241
|
+
const tempDirs = [];
|
|
242
|
+
afterEach(() => {
|
|
243
|
+
for (const dir of tempDirs) {
|
|
244
|
+
try {
|
|
245
|
+
fs.rmSync(dir, { recursive: true });
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
// Ignore cleanup failures
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
tempDirs.length = 0;
|
|
252
|
+
});
|
|
253
|
+
it("migrates complex resources including endpoint, materialized, and copy pipes", async () => {
|
|
254
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
|
|
255
|
+
tempDirs.push(tempDir);
|
|
256
|
+
writeFile(tempDir, "stream.connection", `TYPE kafka
|
|
257
|
+
KAFKA_BOOTSTRAP_SERVERS localhost:9092
|
|
258
|
+
KAFKA_SECURITY_PROTOCOL SASL_SSL
|
|
259
|
+
KAFKA_SASL_MECHANISM PLAIN
|
|
260
|
+
KAFKA_KEY api-key
|
|
261
|
+
KAFKA_SECRET api-secret
|
|
262
|
+
KAFKA_SSL_CA_PEM ca-pem-content
|
|
263
|
+
`);
|
|
264
|
+
writeFile(tempDir, "events.datasource", `DESCRIPTION >
|
|
265
|
+
Events from Kafka stream
|
|
266
|
+
SCHEMA >
|
|
267
|
+
event_id String \`json:$.event_id\`,
|
|
268
|
+
user_id UInt64 \`json:$.user.id\`,
|
|
269
|
+
env String \`json:$.env\` DEFAULT 'prod',
|
|
270
|
+
is_test Bool \`json:$.meta.is_test\` DEFAULT 0,
|
|
271
|
+
updated_at DateTime \`json:$.updated_at\`,
|
|
272
|
+
payload String \`json:$.payload\` DEFAULT '{}' CODEC(ZSTD(1))
|
|
273
|
+
|
|
274
|
+
ENGINE "ReplacingMergeTree"
|
|
275
|
+
ENGINE_SORTING_KEY "event_id, user_id"
|
|
276
|
+
ENGINE_PARTITION_KEY "toYYYYMM(updated_at)"
|
|
277
|
+
ENGINE_PRIMARY_KEY "event_id"
|
|
278
|
+
ENGINE_TTL "updated_at + toIntervalDay(30)"
|
|
279
|
+
ENGINE_VER "updated_at"
|
|
280
|
+
ENGINE_SETTINGS "index_granularity=8192, enable_mixed_granularity_parts=true"
|
|
281
|
+
KAFKA_CONNECTION_NAME stream
|
|
282
|
+
KAFKA_TOPIC events_topic
|
|
283
|
+
KAFKA_GROUP_ID events-consumer
|
|
284
|
+
KAFKA_AUTO_OFFSET_RESET earliest
|
|
285
|
+
TOKEN events_read READ
|
|
286
|
+
TOKEN events_append APPEND
|
|
287
|
+
SHARED_WITH >
|
|
288
|
+
workspace_a,
|
|
289
|
+
workspace_b
|
|
290
|
+
FORWARD_QUERY >
|
|
291
|
+
SELECT *
|
|
292
|
+
FROM events_mv
|
|
293
|
+
`);
|
|
294
|
+
writeFile(tempDir, "events_rollup.datasource", `SCHEMA >
|
|
295
|
+
user_id UInt64,
|
|
296
|
+
total UInt64
|
|
297
|
+
|
|
298
|
+
ENGINE "SummingMergeTree"
|
|
299
|
+
ENGINE_SORTING_KEY "user_id"
|
|
300
|
+
ENGINE_SUMMING_COLUMNS "total"
|
|
301
|
+
`);
|
|
302
|
+
writeFile(tempDir, "events_endpoint.pipe", `DESCRIPTION >
|
|
303
|
+
Endpoint for filtered events
|
|
304
|
+
NODE base
|
|
305
|
+
DESCRIPTION >
|
|
306
|
+
Base filter
|
|
307
|
+
SQL >
|
|
308
|
+
%
|
|
309
|
+
SELECT event_id, user_id, payload
|
|
310
|
+
FROM events
|
|
311
|
+
WHERE user_id = {{UInt64(user_id)}}
|
|
312
|
+
AND env = {{String(env, 'prod')}}
|
|
313
|
+
NODE endpoint
|
|
314
|
+
SQL >
|
|
315
|
+
SELECT event_id AS event_id, user_id AS user_id
|
|
316
|
+
FROM base
|
|
317
|
+
TYPE endpoint
|
|
318
|
+
CACHE 120
|
|
319
|
+
TOKEN endpoint_token READ
|
|
320
|
+
`);
|
|
321
|
+
writeFile(tempDir, "events_mv.pipe", `DESCRIPTION >
|
|
322
|
+
Materialized rollup
|
|
323
|
+
NODE rollup
|
|
324
|
+
SQL >
|
|
325
|
+
SELECT user_id, count() AS total
|
|
326
|
+
FROM events
|
|
327
|
+
GROUP BY user_id
|
|
328
|
+
TYPE MATERIALIZED
|
|
329
|
+
DATASOURCE events_rollup
|
|
330
|
+
DEPLOYMENT_METHOD alter
|
|
331
|
+
TOKEN mv_token READ
|
|
332
|
+
`);
|
|
333
|
+
writeFile(tempDir, "copy_events.pipe", `NODE copy_node
|
|
334
|
+
SQL >
|
|
335
|
+
SELECT event_id, user_id
|
|
336
|
+
FROM events
|
|
337
|
+
TYPE COPY
|
|
338
|
+
TARGET_DATASOURCE events_rollup
|
|
339
|
+
COPY_SCHEDULE @on-demand
|
|
340
|
+
COPY_MODE replace
|
|
341
|
+
TOKEN copy_token READ
|
|
342
|
+
`);
|
|
343
|
+
writeFile(tempDir, "stats_pipe.pipe", `NODE agg
|
|
344
|
+
SQL >
|
|
345
|
+
SELECT user_id, count() AS total
|
|
346
|
+
FROM events
|
|
347
|
+
GROUP BY user_id
|
|
348
|
+
NODE final
|
|
349
|
+
SQL >
|
|
350
|
+
SELECT user_id, total
|
|
351
|
+
FROM agg
|
|
352
|
+
WHERE total > {{UInt32(min_total, 10)}}
|
|
353
|
+
TOKEN stats_token READ
|
|
354
|
+
`);
|
|
355
|
+
const result = await runMigrate({
|
|
356
|
+
cwd: tempDir,
|
|
357
|
+
patterns: ["."],
|
|
358
|
+
strict: true,
|
|
359
|
+
});
|
|
360
|
+
expect(result.success).toBe(true);
|
|
361
|
+
expect(result.errors).toHaveLength(0);
|
|
362
|
+
expect(result.migrated).toHaveLength(7);
|
|
363
|
+
expect(result.migrated.filter((resource) => resource.kind === "connection")).toHaveLength(1);
|
|
364
|
+
expect(result.migrated.filter((resource) => resource.kind === "datasource")).toHaveLength(2);
|
|
365
|
+
expect(result.migrated.filter((resource) => resource.kind === "pipe")).toHaveLength(4);
|
|
366
|
+
expect(path.basename(result.outputPath)).toBe("tinybird.migration.ts");
|
|
367
|
+
expect(fs.existsSync(result.outputPath)).toBe(true);
|
|
368
|
+
const output = fs.readFileSync(result.outputPath, "utf-8");
|
|
369
|
+
expect(output).toBe(EXPECTED_COMPLEX_OUTPUT);
|
|
370
|
+
});
|
|
371
|
+
it("continues processing and reports all errors while writing complex migratable resources", async () => {
|
|
372
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
|
|
373
|
+
tempDirs.push(tempDir);
|
|
374
|
+
writeFile(tempDir, "stream.connection", `TYPE kafka
|
|
375
|
+
KAFKA_BOOTSTRAP_SERVERS localhost:9092
|
|
376
|
+
`);
|
|
377
|
+
writeFile(tempDir, "events.datasource", `SCHEMA >
|
|
378
|
+
event_id String,
|
|
379
|
+
user_id UInt64,
|
|
380
|
+
created_at DateTime
|
|
381
|
+
|
|
382
|
+
ENGINE "MergeTree"
|
|
383
|
+
ENGINE_SORTING_KEY "event_id"
|
|
384
|
+
KAFKA_CONNECTION_NAME stream
|
|
385
|
+
KAFKA_TOPIC events_topic
|
|
386
|
+
`);
|
|
387
|
+
writeFile(tempDir, "events_endpoint.pipe", `NODE source
|
|
388
|
+
SQL >
|
|
389
|
+
SELECT event_id, user_id
|
|
390
|
+
FROM events
|
|
391
|
+
NODE endpoint
|
|
392
|
+
SQL >
|
|
393
|
+
SELECT event_id AS event_id, user_id AS user_id
|
|
394
|
+
FROM source
|
|
395
|
+
WHERE user_id = {{UInt64(user_id)}}
|
|
396
|
+
TYPE endpoint
|
|
397
|
+
TOKEN endpoint_token READ
|
|
398
|
+
`);
|
|
399
|
+
writeFile(tempDir, "events_mv.pipe", `NODE rollup
|
|
400
|
+
SQL >
|
|
401
|
+
SELECT user_id, count() AS total
|
|
402
|
+
FROM events
|
|
403
|
+
GROUP BY user_id
|
|
404
|
+
TYPE MATERIALIZED
|
|
405
|
+
DATASOURCE missing_ds
|
|
406
|
+
`);
|
|
407
|
+
writeFile(tempDir, "broken.pipe", `NODE broken
|
|
408
|
+
SQL >
|
|
409
|
+
SELECT *
|
|
410
|
+
FROM events
|
|
411
|
+
TYPE endpoint
|
|
412
|
+
UNSUPPORTED_DIRECTIVE true
|
|
413
|
+
`);
|
|
414
|
+
const result = await runMigrate({
|
|
415
|
+
cwd: tempDir,
|
|
416
|
+
patterns: ["."],
|
|
417
|
+
strict: true,
|
|
418
|
+
});
|
|
419
|
+
expect(result.success).toBe(false);
|
|
420
|
+
expect(result.errors).toHaveLength(2);
|
|
421
|
+
expect(result.errors.map((error) => error.message)).toEqual(expect.arrayContaining([
|
|
422
|
+
'Unsupported pipe directive in strict mode: "UNSUPPORTED_DIRECTIVE true"',
|
|
423
|
+
'Materialized pipe references missing/unmigrated datasource "missing_ds".',
|
|
424
|
+
]));
|
|
425
|
+
expect(result.migrated.filter((resource) => resource.kind === "connection")).toHaveLength(1);
|
|
426
|
+
expect(result.migrated.filter((resource) => resource.kind === "datasource")).toHaveLength(1);
|
|
427
|
+
expect(result.migrated.filter((resource) => resource.kind === "pipe")).toHaveLength(1);
|
|
428
|
+
expect(fs.existsSync(result.outputPath)).toBe(true);
|
|
429
|
+
const output = fs.readFileSync(result.outputPath, "utf-8");
|
|
430
|
+
expect(output).toBe(EXPECTED_PARTIAL_OUTPUT);
|
|
431
|
+
});
|
|
432
|
+
it("returns exact output content in dry-run mode for complex migratable resources", async () => {
|
|
433
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
|
|
434
|
+
tempDirs.push(tempDir);
|
|
435
|
+
writeFile(tempDir, "stream.connection", `TYPE kafka
|
|
436
|
+
KAFKA_BOOTSTRAP_SERVERS localhost:9092
|
|
437
|
+
`);
|
|
438
|
+
writeFile(tempDir, "events.datasource", `SCHEMA >
|
|
439
|
+
event_id String,
|
|
440
|
+
user_id UInt64,
|
|
441
|
+
created_at DateTime
|
|
442
|
+
|
|
443
|
+
ENGINE "MergeTree"
|
|
444
|
+
ENGINE_SORTING_KEY "event_id"
|
|
445
|
+
KAFKA_CONNECTION_NAME stream
|
|
446
|
+
KAFKA_TOPIC events_topic
|
|
447
|
+
`);
|
|
448
|
+
writeFile(tempDir, "events_endpoint.pipe", `NODE source
|
|
449
|
+
SQL >
|
|
450
|
+
SELECT event_id, user_id
|
|
451
|
+
FROM events
|
|
452
|
+
NODE endpoint
|
|
453
|
+
SQL >
|
|
454
|
+
SELECT event_id AS event_id, user_id AS user_id
|
|
455
|
+
FROM source
|
|
456
|
+
WHERE user_id = {{UInt64(user_id)}}
|
|
457
|
+
TYPE endpoint
|
|
458
|
+
TOKEN endpoint_token READ
|
|
459
|
+
`);
|
|
460
|
+
const result = await runMigrate({
|
|
461
|
+
cwd: tempDir,
|
|
462
|
+
patterns: ["."],
|
|
463
|
+
strict: true,
|
|
464
|
+
dryRun: true,
|
|
465
|
+
});
|
|
466
|
+
expect(result.success).toBe(true);
|
|
467
|
+
expect(result.errors).toHaveLength(0);
|
|
468
|
+
expect(result.migrated).toHaveLength(3);
|
|
469
|
+
expect(result.outputContent).toBe(EXPECTED_PARTIAL_OUTPUT);
|
|
470
|
+
expect(fs.existsSync(result.outputPath)).toBe(false);
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
//# sourceMappingURL=migrate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.test.js","sourceRoot":"","sources":["../../../src/cli/commands/migrate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pull command - downloads all cloud resources as Tinybird datafiles
|
|
3
|
+
*/
|
|
4
|
+
import { type ResourceFileType } from "../../api/resources.js";
|
|
5
|
+
/**
|
|
6
|
+
* Pull command options
|
|
7
|
+
*/
|
|
8
|
+
export interface PullCommandOptions {
|
|
9
|
+
/** Working directory (defaults to cwd) */
|
|
10
|
+
cwd?: string;
|
|
11
|
+
/** Output directory for pulled files (defaults to current directory) */
|
|
12
|
+
outputDir?: string;
|
|
13
|
+
/** Whether to overwrite existing files (defaults to false) */
|
|
14
|
+
overwrite?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Single file written by pull
|
|
18
|
+
*/
|
|
19
|
+
export interface PulledFileResult {
|
|
20
|
+
/** Resource name */
|
|
21
|
+
name: string;
|
|
22
|
+
/** Resource type */
|
|
23
|
+
type: ResourceFileType;
|
|
24
|
+
/** Filename written */
|
|
25
|
+
filename: string;
|
|
26
|
+
/** Absolute path written */
|
|
27
|
+
path: string;
|
|
28
|
+
/** Path relative to cwd */
|
|
29
|
+
relativePath: string;
|
|
30
|
+
/** Whether this file was newly created or overwritten */
|
|
31
|
+
status: "created" | "overwritten";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Pull command result
|
|
35
|
+
*/
|
|
36
|
+
export interface PullCommandResult {
|
|
37
|
+
/** Whether pull was successful */
|
|
38
|
+
success: boolean;
|
|
39
|
+
/** Output directory used */
|
|
40
|
+
outputDir?: string;
|
|
41
|
+
/** Files written */
|
|
42
|
+
files?: PulledFileResult[];
|
|
43
|
+
/** Pull statistics */
|
|
44
|
+
stats?: {
|
|
45
|
+
datasources: number;
|
|
46
|
+
pipes: number;
|
|
47
|
+
connections: number;
|
|
48
|
+
total: number;
|
|
49
|
+
};
|
|
50
|
+
/** Error message if failed */
|
|
51
|
+
error?: string;
|
|
52
|
+
/** Duration in milliseconds */
|
|
53
|
+
durationMs: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Pull all resources from Tinybird and write them as datafiles
|
|
57
|
+
*/
|
|
58
|
+
export declare function runPull(options?: PullCommandOptions): Promise<PullCommandResult>;
|
|
59
|
+
//# sourceMappingURL=pull.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pull.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAC;AAEhC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,IAAI,EAAE,gBAAgB,CAAC;IACvB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,sBAAsB;IACtB,KAAK,CAAC,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AASD;;GAEG;AACH,wBAAsB,OAAO,CAC3B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAiG5B"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pull command - downloads all cloud resources as Tinybird datafiles
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from "node:fs/promises";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { loadConfigAsync } from "../config.js";
|
|
7
|
+
import { pullAllResourceFiles, } from "../../api/resources.js";
|
|
8
|
+
/**
|
|
9
|
+
* Convert grouped resources to a flat file list
|
|
10
|
+
*/
|
|
11
|
+
function flattenResources(resources) {
|
|
12
|
+
return [...resources.datasources, ...resources.pipes, ...resources.connections];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Pull all resources from Tinybird and write them as datafiles
|
|
16
|
+
*/
|
|
17
|
+
export async function runPull(options = {}) {
|
|
18
|
+
const startTime = Date.now();
|
|
19
|
+
const cwd = options.cwd ?? process.cwd();
|
|
20
|
+
const outputDir = path.resolve(cwd, options.outputDir ?? ".");
|
|
21
|
+
const overwrite = options.overwrite ?? false;
|
|
22
|
+
let config;
|
|
23
|
+
try {
|
|
24
|
+
config = await loadConfigAsync(cwd);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
return {
|
|
28
|
+
success: false,
|
|
29
|
+
error: error.message,
|
|
30
|
+
durationMs: Date.now() - startTime,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
let pulled;
|
|
34
|
+
try {
|
|
35
|
+
pulled = await pullAllResourceFiles({
|
|
36
|
+
baseUrl: config.baseUrl,
|
|
37
|
+
token: config.token,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
return {
|
|
42
|
+
success: false,
|
|
43
|
+
error: `Pull failed: ${error.message}`,
|
|
44
|
+
durationMs: Date.now() - startTime,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const allFiles = flattenResources(pulled).sort((a, b) => a.filename.localeCompare(b.filename));
|
|
48
|
+
try {
|
|
49
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
50
|
+
const writtenFiles = [];
|
|
51
|
+
for (const file of allFiles) {
|
|
52
|
+
const absolutePath = path.join(outputDir, file.filename);
|
|
53
|
+
let existed = false;
|
|
54
|
+
try {
|
|
55
|
+
await fs.access(absolutePath);
|
|
56
|
+
existed = true;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
existed = false;
|
|
60
|
+
}
|
|
61
|
+
await fs.writeFile(absolutePath, file.content, {
|
|
62
|
+
encoding: "utf-8",
|
|
63
|
+
flag: overwrite ? "w" : "wx",
|
|
64
|
+
});
|
|
65
|
+
writtenFiles.push({
|
|
66
|
+
name: file.name,
|
|
67
|
+
type: file.type,
|
|
68
|
+
filename: file.filename,
|
|
69
|
+
path: absolutePath,
|
|
70
|
+
relativePath: path.relative(cwd, absolutePath),
|
|
71
|
+
status: existed ? "overwritten" : "created",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
success: true,
|
|
76
|
+
outputDir,
|
|
77
|
+
files: writtenFiles,
|
|
78
|
+
stats: {
|
|
79
|
+
datasources: pulled.datasources.length,
|
|
80
|
+
pipes: pulled.pipes.length,
|
|
81
|
+
connections: pulled.connections.length,
|
|
82
|
+
total: writtenFiles.length,
|
|
83
|
+
},
|
|
84
|
+
durationMs: Date.now() - startTime,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
const err = error;
|
|
89
|
+
if (err.code === "EEXIST") {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: `File already exists: ${err.path ?? "unknown"}. ` +
|
|
93
|
+
"Use --force to overwrite existing files.",
|
|
94
|
+
durationMs: Date.now() - startTime,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
error: `Failed to write files: ${error.message}`,
|
|
100
|
+
durationMs: Date.now() - startTime,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../../src/cli/commands/pull.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pull.test.ts"],"names":[],"mappings":""}
|