@tinybirdco/sdk 0.0.48 → 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.
Files changed (52) hide show
  1. package/README.md +53 -3
  2. package/dist/cli/commands/migrate.d.ts.map +1 -1
  3. package/dist/cli/commands/migrate.js +32 -0
  4. package/dist/cli/commands/migrate.js.map +1 -1
  5. package/dist/cli/commands/migrate.test.js +398 -1
  6. package/dist/cli/commands/migrate.test.js.map +1 -1
  7. package/dist/generator/pipe.d.ts.map +1 -1
  8. package/dist/generator/pipe.js +31 -1
  9. package/dist/generator/pipe.js.map +1 -1
  10. package/dist/generator/pipe.test.js +50 -1
  11. package/dist/generator/pipe.test.js.map +1 -1
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/migrate/emit-ts.d.ts.map +1 -1
  17. package/dist/migrate/emit-ts.js +50 -9
  18. package/dist/migrate/emit-ts.js.map +1 -1
  19. package/dist/migrate/parse-datasource.d.ts.map +1 -1
  20. package/dist/migrate/parse-datasource.js +77 -49
  21. package/dist/migrate/parse-datasource.js.map +1 -1
  22. package/dist/migrate/parse-pipe.d.ts.map +1 -1
  23. package/dist/migrate/parse-pipe.js +254 -44
  24. package/dist/migrate/parse-pipe.js.map +1 -1
  25. package/dist/migrate/parser-utils.d.ts +5 -0
  26. package/dist/migrate/parser-utils.d.ts.map +1 -1
  27. package/dist/migrate/parser-utils.js +22 -0
  28. package/dist/migrate/parser-utils.js.map +1 -1
  29. package/dist/migrate/types.d.ts +22 -3
  30. package/dist/migrate/types.d.ts.map +1 -1
  31. package/dist/schema/datasource.test.js +1 -0
  32. package/dist/schema/datasource.test.js.map +1 -1
  33. package/dist/schema/pipe.d.ts +90 -3
  34. package/dist/schema/pipe.d.ts.map +1 -1
  35. package/dist/schema/pipe.js +84 -0
  36. package/dist/schema/pipe.js.map +1 -1
  37. package/dist/schema/pipe.test.js +70 -1
  38. package/dist/schema/pipe.test.js.map +1 -1
  39. package/package.json +1 -1
  40. package/src/cli/commands/migrate.test.ts +580 -1
  41. package/src/cli/commands/migrate.ts +35 -0
  42. package/src/generator/pipe.test.ts +56 -1
  43. package/src/generator/pipe.ts +41 -1
  44. package/src/index.ts +9 -0
  45. package/src/migrate/emit-ts.ts +52 -10
  46. package/src/migrate/parse-datasource.ts +82 -68
  47. package/src/migrate/parse-pipe.ts +359 -66
  48. package/src/migrate/parser-utils.ts +36 -1
  49. package/src/migrate/types.ts +25 -3
  50. package/src/schema/datasource.test.ts +1 -0
  51. package/src/schema/pipe.test.ts +89 -0
  52. package/src/schema/pipe.ts +188 -4
package/README.md CHANGED
@@ -358,6 +358,7 @@ Behavior:
358
358
  - Processes files, directories, and glob patterns.
359
359
  - Continues through all matches and reports migratable resources plus per-file errors.
360
360
  - In strict mode (default), exits with non-zero status if any errors are found.
361
+ - Infers parameter defaults from scalar SQL placeholders (for example `{{String(env, 'prod')}}`) while treating `{{Array(ids, 'String')}}` second arguments as element types, not defaults.
361
362
  - Writes one output file by default: `./tinybird.migration.ts`.
362
363
 
363
364
  ### `tinybird dev`
@@ -529,14 +530,14 @@ In local mode:
529
530
  ### Connections
530
531
 
531
532
  ```typescript
532
- import { defineKafkaConnection, defineS3Connection } from "@tinybirdco/sdk";
533
+ import { defineKafkaConnection, defineS3Connection, secret } from "@tinybirdco/sdk";
533
534
 
534
535
  export const eventsKafka = defineKafkaConnection("events_kafka", {
535
536
  bootstrapServers: "kafka.example.com:9092",
536
537
  securityProtocol: "SASL_SSL",
537
538
  saslMechanism: "PLAIN",
538
- key: '{{ tb_secret("KAFKA_KEY") }}',
539
- secret: '{{ tb_secret("KAFKA_SECRET") }}',
539
+ key: secret("KAFKA_KEY"),
540
+ secret: secret("KAFKA_SECRET"),
540
541
  });
541
542
 
542
543
  export const landingS3 = defineS3Connection("landing_s3", {
@@ -741,6 +742,55 @@ export const manualReport = defineCopyPipe("manual_report", {
741
742
  });
742
743
  ```
743
744
 
745
+ ### Sink Pipes
746
+
747
+ Use sink pipes to publish query results to external systems. The SDK supports only Kafka and S3 sinks.
748
+
749
+ ```typescript
750
+ import { defineSinkPipe, node } from "@tinybirdco/sdk";
751
+ import { eventsKafka, landingS3 } from "./connections";
752
+
753
+ // Kafka sink
754
+ export const kafkaEventsSink = defineSinkPipe("kafka_events_sink", {
755
+ sink: {
756
+ connection: eventsKafka,
757
+ topic: "events_export",
758
+ schedule: "@on-demand",
759
+ },
760
+ nodes: [
761
+ node({
762
+ name: "publish",
763
+ sql: `
764
+ SELECT timestamp, payload
765
+ FROM kafka_events
766
+ `,
767
+ }),
768
+ ],
769
+ });
770
+
771
+ // S3 sink
772
+ export const s3EventsSink = defineSinkPipe("s3_events_sink", {
773
+ sink: {
774
+ connection: landingS3,
775
+ bucketUri: "s3://my-bucket/exports/",
776
+ fileTemplate: "events_{date}",
777
+ format: "csv",
778
+ schedule: "@once",
779
+ strategy: "create_new",
780
+ compression: "gzip",
781
+ },
782
+ nodes: [
783
+ node({
784
+ name: "export",
785
+ sql: `
786
+ SELECT timestamp, session_id
787
+ FROM s3_landing
788
+ `,
789
+ }),
790
+ ],
791
+ });
792
+ ```
793
+
744
794
  ### Static Tokens
745
795
 
746
796
  Define reusable tokens for resource access control:
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/migrate.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,eAAe,EAGhB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA2BD,wBAAsB,UAAU,CAC9B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAgM1B"}
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/migrate.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,eAAe,EAGhB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA2BD,wBAAsB,UAAU,CAC9B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAmO1B"}
@@ -79,6 +79,7 @@ export async function runMigrate(options) {
79
79
  const migrated = [];
80
80
  const migratedConnectionNames = new Set();
81
81
  const migratedDatasourceNames = new Set();
82
+ const parsedConnectionTypeByName = new Map(parsedConnections.map((connection) => [connection.name, connection.connectionType]));
82
83
  for (const connection of parsedConnections) {
83
84
  try {
84
85
  validateResourceForEmission(connection);
@@ -121,6 +122,37 @@ export async function runMigrate(options) {
121
122
  }
122
123
  }
123
124
  for (const pipe of parsedPipes) {
125
+ if (pipe.type === "sink") {
126
+ const sinkConnectionName = pipe.sink?.connectionName;
127
+ if (!sinkConnectionName || !migratedConnectionNames.has(sinkConnectionName)) {
128
+ errors.push({
129
+ filePath: pipe.filePath,
130
+ resourceName: pipe.name,
131
+ resourceKind: pipe.kind,
132
+ message: `Sink pipe references missing/unmigrated connection "${sinkConnectionName ?? "(none)"}".`,
133
+ });
134
+ continue;
135
+ }
136
+ const sinkConnectionType = parsedConnectionTypeByName.get(sinkConnectionName);
137
+ if (!sinkConnectionType) {
138
+ errors.push({
139
+ filePath: pipe.filePath,
140
+ resourceName: pipe.name,
141
+ resourceKind: pipe.kind,
142
+ message: `Sink pipe connection "${sinkConnectionName}" could not be resolved.`,
143
+ });
144
+ continue;
145
+ }
146
+ if (sinkConnectionType !== pipe.sink?.service) {
147
+ errors.push({
148
+ filePath: pipe.filePath,
149
+ resourceName: pipe.name,
150
+ resourceKind: pipe.kind,
151
+ message: `Sink pipe service "${pipe.sink?.service}" is incompatible with connection "${sinkConnectionName}" type "${sinkConnectionType}".`,
152
+ });
153
+ continue;
154
+ }
155
+ }
124
156
  if (pipe.type === "materialized" &&
125
157
  (!pipe.materializedDatasource ||
126
158
  !migratedDatasourceNames.has(pipe.materializedDatasource))) {
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../src/cli/commands/migrate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../src/cli/commands/migrate.ts"],"names":[],"mappings":"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"}
@@ -105,7 +105,7 @@ export const eventsEndpoint = definePipe("events_endpoint", {
105
105
  SELECT event_id, user_id, payload
106
106
  FROM events
107
107
  WHERE user_id = {{UInt64(user_id)}}
108
- AND env = {{String(env, 'prod')}}
108
+ AND env = {{String(env, 'prod')}}
109
109
  \`,
110
110
  }),
111
111
  node({
@@ -586,6 +586,260 @@ DATASOURCE events_state
586
586
  expect(output).toContain("storeRawValue: true");
587
587
  expect(output).toContain('engine: engine.replacingMergeTree({ sortingKey: "event_id", ver: "version_ts", isDeleted: "_is_deleted" })');
588
588
  });
589
+ it("migrates TYPE copy in lowercase", async () => {
590
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
591
+ tempDirs.push(tempDir);
592
+ writeFile(tempDir, "copy_target.datasource", `SCHEMA >
593
+ id String
594
+
595
+ ENGINE "MergeTree"
596
+ ENGINE_SORTING_KEY "id"
597
+ `);
598
+ writeFile(tempDir, "copy_lower.pipe", `NODE copy_node
599
+ SQL >
600
+ SELECT id
601
+ FROM copy_target
602
+ TYPE copy
603
+ TARGET_DATASOURCE copy_target
604
+ `);
605
+ const result = await runMigrate({
606
+ cwd: tempDir,
607
+ patterns: ["."],
608
+ strict: true,
609
+ });
610
+ expect(result.success).toBe(true);
611
+ expect(result.errors).toHaveLength(0);
612
+ const output = fs.readFileSync(result.outputPath, "utf-8");
613
+ expect(output).toContain('export const copyLower = defineCopyPipe("copy_lower", {');
614
+ expect(output).toContain("datasource: copyTarget,");
615
+ });
616
+ it("migrates TYPE ENDPOINT in uppercase", async () => {
617
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
618
+ tempDirs.push(tempDir);
619
+ writeFile(tempDir, "endpoint_upper.pipe", `NODE endpoint
620
+ SQL >
621
+ SELECT 1 AS id
622
+ FROM system.numbers
623
+ LIMIT 1
624
+ TYPE ENDPOINT
625
+ `);
626
+ const result = await runMigrate({
627
+ cwd: tempDir,
628
+ patterns: ["."],
629
+ strict: true,
630
+ });
631
+ expect(result.success).toBe(true);
632
+ expect(result.errors).toHaveLength(0);
633
+ const output = fs.readFileSync(result.outputPath, "utf-8");
634
+ expect(output).toContain('export const endpointUpper = definePipe("endpoint_upper", {');
635
+ expect(output).toContain("endpoint: true,");
636
+ });
637
+ it("parses multiline datasource blocks with flexible indentation", async () => {
638
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
639
+ tempDirs.push(tempDir);
640
+ writeFile(tempDir, "flex.datasource", `DESCRIPTION >
641
+ Flexible indentation description
642
+
643
+ SCHEMA >
644
+ id String,
645
+ env String
646
+
647
+ ENGINE "MergeTree"
648
+ ENGINE_SORTING_KEY "id"
649
+ FORWARD_QUERY >
650
+ SELECT id, env
651
+ FROM upstream_ds
652
+ SHARED_WITH >
653
+ workspace_a,
654
+ workspace_b
655
+ `);
656
+ const result = await runMigrate({
657
+ cwd: tempDir,
658
+ patterns: ["."],
659
+ strict: true,
660
+ });
661
+ expect(result.success).toBe(true);
662
+ expect(result.errors).toHaveLength(0);
663
+ const output = fs.readFileSync(result.outputPath, "utf-8");
664
+ expect(output).toContain('description: "Flexible indentation description"');
665
+ expect(output).toContain("forwardQuery: `");
666
+ expect(output).toContain("SELECT id, env");
667
+ expect(output).toContain("FROM upstream_ds");
668
+ expect(output).toContain('sharedWith: ["workspace_a", "workspace_b"],');
669
+ });
670
+ it("parses node SQL blocks with flexible indentation", async () => {
671
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
672
+ tempDirs.push(tempDir);
673
+ writeFile(tempDir, "flex_pipe.pipe", `NODE endpoint_node
674
+ DESCRIPTION >
675
+ Endpoint node description
676
+ SQL >
677
+ %
678
+ SELECT 1 AS id
679
+ FROM system.numbers
680
+ TYPE endpoint
681
+ `);
682
+ const result = await runMigrate({
683
+ cwd: tempDir,
684
+ patterns: ["."],
685
+ strict: true,
686
+ });
687
+ expect(result.success).toBe(true);
688
+ expect(result.errors).toHaveLength(0);
689
+ const output = fs.readFileSync(result.outputPath, "utf-8");
690
+ expect(output).toContain('description: "Endpoint node description"');
691
+ expect(output).toContain("SELECT 1 AS id");
692
+ expect(output).toContain("FROM system.numbers");
693
+ expect(output).toContain("endpoint: true,");
694
+ });
695
+ it("migrates datasource without engine directives", async () => {
696
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
697
+ tempDirs.push(tempDir);
698
+ writeFile(tempDir, "no_engine.datasource", `SCHEMA >
699
+ id String,
700
+ name String
701
+ `);
702
+ const result = await runMigrate({
703
+ cwd: tempDir,
704
+ patterns: ["."],
705
+ strict: true,
706
+ });
707
+ expect(result.success).toBe(true);
708
+ expect(result.errors).toHaveLength(0);
709
+ const output = fs.readFileSync(result.outputPath, "utf-8");
710
+ expect(output).toContain('export const noEngine = defineDatasource("no_engine", {');
711
+ expect(output).not.toContain("engine:");
712
+ expect(output).not.toContain(", engine,");
713
+ });
714
+ it("infers MergeTree when engine options exist without ENGINE directive", async () => {
715
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
716
+ tempDirs.push(tempDir);
717
+ writeFile(tempDir, "implicit_engine.datasource", `SCHEMA >
718
+ id String,
719
+ event_date Date
720
+
721
+ ENGINE_SORTING_KEY "id"
722
+ ENGINE_PARTITION_KEY "toYYYYMM(event_date)"
723
+ `);
724
+ const result = await runMigrate({
725
+ cwd: tempDir,
726
+ patterns: ["."],
727
+ strict: true,
728
+ });
729
+ expect(result.success).toBe(true);
730
+ expect(result.errors).toHaveLength(0);
731
+ const output = fs.readFileSync(result.outputPath, "utf-8");
732
+ expect(output).toContain('export const implicitEngine = defineDatasource("implicit_engine", {');
733
+ expect(output).toContain('engine: engine.mergeTree({ sortingKey: "id", partitionKey: "toYYYYMM(event_date)" }),');
734
+ });
735
+ it("supports quoted datasource token names with spaces", async () => {
736
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
737
+ tempDirs.push(tempDir);
738
+ writeFile(tempDir, "token_spaces.datasource", `TOKEN "ingestion (Data Source append)" APPEND
739
+
740
+ SCHEMA >
741
+ id String
742
+
743
+ ENGINE "MergeTree"
744
+ ENGINE_SORTING_KEY "id"
745
+ `);
746
+ const result = await runMigrate({
747
+ cwd: tempDir,
748
+ patterns: ["."],
749
+ strict: true,
750
+ });
751
+ expect(result.success).toBe(true);
752
+ expect(result.errors).toHaveLength(0);
753
+ const output = fs.readFileSync(result.outputPath, "utf-8");
754
+ expect(output).toContain('{ name: "ingestion (Data Source append)", permissions: ["APPEND"] },');
755
+ });
756
+ it("rejects unquoted datasource token names with spaces", async () => {
757
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
758
+ tempDirs.push(tempDir);
759
+ writeFile(tempDir, "bad_token.datasource", `TOKEN ingestion data APPEND
760
+
761
+ SCHEMA >
762
+ id String
763
+
764
+ ENGINE "MergeTree"
765
+ ENGINE_SORTING_KEY "id"
766
+ `);
767
+ const result = await runMigrate({
768
+ cwd: tempDir,
769
+ patterns: ["."],
770
+ strict: true,
771
+ });
772
+ expect(result.success).toBe(false);
773
+ expect(result.errors).toHaveLength(1);
774
+ expect(result.errors[0]?.message).toContain("Unsupported TOKEN syntax in strict mode");
775
+ });
776
+ it("allows empty datasource DESCRIPTION block", async () => {
777
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
778
+ tempDirs.push(tempDir);
779
+ writeFile(tempDir, "empty_ds_desc.datasource", `DESCRIPTION >
780
+
781
+ SCHEMA >
782
+ id String
783
+
784
+ ENGINE "MergeTree"
785
+ ENGINE_SORTING_KEY "id"
786
+ `);
787
+ const result = await runMigrate({
788
+ cwd: tempDir,
789
+ patterns: ["."],
790
+ strict: true,
791
+ });
792
+ expect(result.success).toBe(true);
793
+ expect(result.errors).toHaveLength(0);
794
+ const output = fs.readFileSync(result.outputPath, "utf-8");
795
+ expect(output).toContain('export const emptyDsDesc = defineDatasource("empty_ds_desc", {');
796
+ expect(output).toContain('description: "",');
797
+ });
798
+ it("allows empty node DESCRIPTION block", async () => {
799
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
800
+ tempDirs.push(tempDir);
801
+ writeFile(tempDir, "empty_node_desc.pipe", `NODE helper
802
+ DESCRIPTION >
803
+
804
+ SQL >
805
+ SELECT 1 AS id
806
+ TYPE endpoint
807
+ `);
808
+ const result = await runMigrate({
809
+ cwd: tempDir,
810
+ patterns: ["."],
811
+ strict: true,
812
+ });
813
+ expect(result.success).toBe(true);
814
+ expect(result.errors).toHaveLength(0);
815
+ const output = fs.readFileSync(result.outputPath, "utf-8");
816
+ expect(output).toContain('export const emptyNodeDesc = definePipe("empty_node_desc", {');
817
+ expect(output).toContain('description: "",');
818
+ });
819
+ it("supports keyword-style pipe param arguments", async () => {
820
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
821
+ tempDirs.push(tempDir);
822
+ writeFile(tempDir, "keyword_params.pipe", `NODE endpoint
823
+ SQL >
824
+ SELECT 1 AS id
825
+ WHERE tenant_id = {{ String(tenant_id, description="Tenant ID to filter", default="") }}
826
+ AND event_date >= {{ Date(from_date, description="Starting date", required=False) }}
827
+ AND days >= {{ Int32(days, 1, description="Days to include", required=True) }}
828
+ TYPE endpoint
829
+ `);
830
+ const result = await runMigrate({
831
+ cwd: tempDir,
832
+ patterns: ["."],
833
+ strict: true,
834
+ });
835
+ expect(result.success).toBe(true);
836
+ expect(result.errors).toHaveLength(0);
837
+ const output = fs.readFileSync(result.outputPath, "utf-8");
838
+ expect(output).toContain('export const keywordParams = definePipe("keyword_params", {');
839
+ expect(output).toContain('tenant_id: p.string().optional("").describe("Tenant ID to filter"),');
840
+ expect(output).toContain('from_date: p.date().optional().describe("Starting date"),');
841
+ expect(output).toContain('days: p.int32().optional(1).describe("Days to include"),');
842
+ });
589
843
  it("migrates datasource with mixed explicit and default json paths", async () => {
590
844
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
591
845
  tempDirs.push(tempDir);
@@ -687,5 +941,148 @@ KAFKA_GROUP_ID events-group
687
941
  expect(output).not.toContain("const secret = (name: string, defaultValue?: string) =>");
688
942
  expect(output).toContain('groupId: "events-group",');
689
943
  });
944
+ it("migrates Kafka sink pipes and emits sink config in TypeScript", async () => {
945
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
946
+ tempDirs.push(tempDir);
947
+ writeFile(tempDir, "events_kafka.connection", `TYPE kafka
948
+ KAFKA_BOOTSTRAP_SERVERS localhost:9092
949
+ `);
950
+ writeFile(tempDir, "events_sink.pipe", `NODE publish
951
+ SQL >
952
+ SELECT *
953
+ FROM events
954
+ WHERE env = {{String(env, 'prod')}}
955
+ TYPE sink
956
+ EXPORT_CONNECTION_NAME events_kafka
957
+ EXPORT_KAFKA_TOPIC events_out
958
+ EXPORT_SCHEDULE @on-demand
959
+ `);
960
+ const result = await runMigrate({
961
+ cwd: tempDir,
962
+ patterns: ["."],
963
+ strict: true,
964
+ });
965
+ expect(result.success).toBe(true);
966
+ expect(result.errors).toHaveLength(0);
967
+ expect(result.migrated.filter((resource) => resource.kind === "connection")).toHaveLength(1);
968
+ expect(result.migrated.filter((resource) => resource.kind === "pipe")).toHaveLength(1);
969
+ const output = fs.readFileSync(result.outputPath, "utf-8");
970
+ expect(output).toContain('export const eventsSink = defineSinkPipe("events_sink", {');
971
+ expect(output).toContain("params: {");
972
+ expect(output).toContain('env: p.string().optional("prod"),');
973
+ expect(output).toContain("sink: {");
974
+ expect(output).toContain("connection: eventsKafka");
975
+ expect(output).toContain('topic: "events_out"');
976
+ expect(output).toContain('schedule: "@on-demand"');
977
+ expect(output).not.toContain('strategy:');
978
+ });
979
+ it("migrates S3 sink pipes and emits compression/strategy config in TypeScript", async () => {
980
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
981
+ tempDirs.push(tempDir);
982
+ writeFile(tempDir, "exports_s3.connection", `TYPE s3
983
+ S3_REGION "us-east-1"
984
+ S3_ARN "arn:aws:iam::123456789012:role/tinybird-s3-access"
985
+ `);
986
+ writeFile(tempDir, "events_s3_sink.pipe", `NODE export
987
+ SQL >
988
+ SELECT * FROM events
989
+ TYPE sink
990
+ EXPORT_CONNECTION_NAME exports_s3
991
+ EXPORT_BUCKET_URI s3://exports/events/
992
+ EXPORT_FILE_TEMPLATE events_{date}
993
+ EXPORT_SCHEDULE @once
994
+ EXPORT_FORMAT ndjson
995
+ EXPORT_STRATEGY create_new
996
+ EXPORT_COMPRESSION gzip
997
+ `);
998
+ const result = await runMigrate({
999
+ cwd: tempDir,
1000
+ patterns: ["."],
1001
+ strict: true,
1002
+ });
1003
+ expect(result.success).toBe(true);
1004
+ expect(result.errors).toHaveLength(0);
1005
+ const output = fs.readFileSync(result.outputPath, "utf-8");
1006
+ expect(output).toContain('export const eventsS3Sink = defineSinkPipe("events_s3_sink", {');
1007
+ expect(output).toContain("sink: {");
1008
+ expect(output).toContain("connection: exportsS3");
1009
+ expect(output).toContain('bucketUri: "s3://exports/events/"');
1010
+ expect(output).toContain('fileTemplate: "events_{date}"');
1011
+ expect(output).toContain('schedule: "@once"');
1012
+ expect(output).toContain('format: "ndjson"');
1013
+ expect(output).toContain('strategy: "create_new"');
1014
+ expect(output).toContain('compression: "gzip"');
1015
+ });
1016
+ it("reports an error when sink pipe references a missing connection", async () => {
1017
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
1018
+ tempDirs.push(tempDir);
1019
+ writeFile(tempDir, "events_sink.pipe", `NODE publish
1020
+ SQL >
1021
+ SELECT * FROM events
1022
+ TYPE sink
1023
+ EXPORT_CONNECTION_NAME missing_connection
1024
+ EXPORT_KAFKA_TOPIC events_out
1025
+ EXPORT_SCHEDULE @on-demand
1026
+ `);
1027
+ const result = await runMigrate({
1028
+ cwd: tempDir,
1029
+ patterns: ["."],
1030
+ strict: true,
1031
+ });
1032
+ expect(result.success).toBe(false);
1033
+ expect(result.errors.map((error) => error.message)).toEqual(expect.arrayContaining([
1034
+ 'Sink pipe references missing/unmigrated connection "missing_connection".',
1035
+ ]));
1036
+ });
1037
+ it("reports an error when sink connection type does not match sink service", async () => {
1038
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
1039
+ tempDirs.push(tempDir);
1040
+ writeFile(tempDir, "events_kafka.connection", `TYPE kafka
1041
+ KAFKA_BOOTSTRAP_SERVERS localhost:9092
1042
+ `);
1043
+ writeFile(tempDir, "events_s3_sink.pipe", `NODE export
1044
+ SQL >
1045
+ SELECT * FROM events
1046
+ TYPE sink
1047
+ EXPORT_CONNECTION_NAME events_kafka
1048
+ EXPORT_BUCKET_URI s3://exports/events/
1049
+ EXPORT_FILE_TEMPLATE events_{date}
1050
+ EXPORT_SCHEDULE @once
1051
+ EXPORT_FORMAT csv
1052
+ `);
1053
+ const result = await runMigrate({
1054
+ cwd: tempDir,
1055
+ patterns: ["."],
1056
+ strict: true,
1057
+ });
1058
+ expect(result.success).toBe(false);
1059
+ expect(result.errors.map((error) => error.message)).toEqual(expect.arrayContaining([
1060
+ 'Sink pipe service "s3" is incompatible with connection "events_kafka" type "kafka".',
1061
+ ]));
1062
+ });
1063
+ it("supports comments in sink pipe files", async () => {
1064
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "tinybird-migrate-"));
1065
+ tempDirs.push(tempDir);
1066
+ writeFile(tempDir, "events_kafka.connection", `TYPE kafka
1067
+ KAFKA_BOOTSTRAP_SERVERS localhost:9092
1068
+ `);
1069
+ writeFile(tempDir, "events_sink.pipe", `# this pipe publishes records
1070
+ NODE publish
1071
+ SQL >
1072
+ SELECT * FROM events
1073
+ TYPE sink
1074
+ # Kafka target
1075
+ EXPORT_CONNECTION_NAME events_kafka
1076
+ EXPORT_KAFKA_TOPIC events_out
1077
+ EXPORT_SCHEDULE @on-demand
1078
+ `);
1079
+ const result = await runMigrate({
1080
+ cwd: tempDir,
1081
+ patterns: ["."],
1082
+ strict: true,
1083
+ });
1084
+ expect(result.success).toBe(true);
1085
+ expect(result.errors).toHaveLength(0);
1086
+ });
690
1087
  });
691
1088
  //# sourceMappingURL=migrate.test.js.map