@tinybirdco/sdk 0.0.4 → 0.0.7

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 (165) hide show
  1. package/README.md +52 -13
  2. package/dist/api/branches.d.ts.map +1 -1
  3. package/dist/api/branches.js +6 -5
  4. package/dist/api/branches.js.map +1 -1
  5. package/dist/api/branches.test.js +32 -6
  6. package/dist/api/branches.test.js.map +1 -1
  7. package/dist/api/build.d.ts.map +1 -1
  8. package/dist/api/build.js +2 -1
  9. package/dist/api/build.js.map +1 -1
  10. package/dist/api/deploy.d.ts +42 -3
  11. package/dist/api/deploy.d.ts.map +1 -1
  12. package/dist/api/deploy.js +162 -19
  13. package/dist/api/deploy.js.map +1 -1
  14. package/dist/api/deploy.test.js +83 -31
  15. package/dist/api/deploy.test.js.map +1 -1
  16. package/dist/api/fetcher.d.ts +6 -0
  17. package/dist/api/fetcher.d.ts.map +1 -0
  18. package/dist/api/fetcher.js +13 -0
  19. package/dist/api/fetcher.js.map +1 -0
  20. package/dist/api/local.d.ts.map +1 -1
  21. package/dist/api/local.js +5 -4
  22. package/dist/api/local.js.map +1 -1
  23. package/dist/api/local.test.js.map +1 -1
  24. package/dist/api/resources.d.ts +178 -0
  25. package/dist/api/resources.d.ts.map +1 -0
  26. package/dist/api/resources.js +245 -0
  27. package/dist/api/resources.js.map +1 -0
  28. package/dist/api/resources.test.d.ts +2 -0
  29. package/dist/api/resources.test.d.ts.map +1 -0
  30. package/dist/api/resources.test.js +255 -0
  31. package/dist/api/resources.test.js.map +1 -0
  32. package/dist/api/workspaces.d.ts.map +1 -1
  33. package/dist/api/workspaces.js +2 -1
  34. package/dist/api/workspaces.js.map +1 -1
  35. package/dist/api/workspaces.test.js +9 -1
  36. package/dist/api/workspaces.test.js.map +1 -1
  37. package/dist/cli/auth.d.ts.map +1 -1
  38. package/dist/cli/auth.js +2 -1
  39. package/dist/cli/auth.js.map +1 -1
  40. package/dist/cli/commands/build.d.ts +3 -4
  41. package/dist/cli/commands/build.d.ts.map +1 -1
  42. package/dist/cli/commands/build.js +23 -25
  43. package/dist/cli/commands/build.js.map +1 -1
  44. package/dist/cli/commands/deploy.d.ts +41 -0
  45. package/dist/cli/commands/deploy.d.ts.map +1 -0
  46. package/dist/cli/commands/deploy.js +92 -0
  47. package/dist/cli/commands/deploy.js.map +1 -0
  48. package/dist/cli/commands/dev.d.ts.map +1 -1
  49. package/dist/cli/commands/dev.js +7 -3
  50. package/dist/cli/commands/dev.js.map +1 -1
  51. package/dist/cli/commands/init.d.ts +38 -1
  52. package/dist/cli/commands/init.d.ts.map +1 -1
  53. package/dist/cli/commands/init.js +434 -23
  54. package/dist/cli/commands/init.js.map +1 -1
  55. package/dist/cli/commands/init.test.js +190 -30
  56. package/dist/cli/commands/init.test.js.map +1 -1
  57. package/dist/cli/index.js +80 -15
  58. package/dist/cli/index.js.map +1 -1
  59. package/dist/cli/utils/package-manager.d.ts +8 -0
  60. package/dist/cli/utils/package-manager.d.ts.map +1 -0
  61. package/dist/cli/utils/package-manager.js +45 -0
  62. package/dist/cli/utils/package-manager.js.map +1 -0
  63. package/dist/cli/utils/package-manager.test.d.ts +2 -0
  64. package/dist/cli/utils/package-manager.test.d.ts.map +1 -0
  65. package/dist/cli/utils/package-manager.test.js +85 -0
  66. package/dist/cli/utils/package-manager.test.js.map +1 -0
  67. package/dist/client/base.d.ts.map +1 -1
  68. package/dist/client/base.js +2 -1
  69. package/dist/client/base.js.map +1 -1
  70. package/dist/codegen/index.d.ts +39 -0
  71. package/dist/codegen/index.d.ts.map +1 -0
  72. package/dist/codegen/index.js +300 -0
  73. package/dist/codegen/index.js.map +1 -0
  74. package/dist/codegen/index.test.d.ts +2 -0
  75. package/dist/codegen/index.test.d.ts.map +1 -0
  76. package/dist/codegen/index.test.js +310 -0
  77. package/dist/codegen/index.test.js.map +1 -0
  78. package/dist/codegen/type-mapper.d.ts +20 -0
  79. package/dist/codegen/type-mapper.d.ts.map +1 -0
  80. package/dist/codegen/type-mapper.js +238 -0
  81. package/dist/codegen/type-mapper.js.map +1 -0
  82. package/dist/codegen/type-mapper.test.d.ts +2 -0
  83. package/dist/codegen/type-mapper.test.d.ts.map +1 -0
  84. package/dist/codegen/type-mapper.test.js +167 -0
  85. package/dist/codegen/type-mapper.test.js.map +1 -0
  86. package/dist/codegen/utils.d.ts +46 -0
  87. package/dist/codegen/utils.d.ts.map +1 -0
  88. package/dist/codegen/utils.js +141 -0
  89. package/dist/codegen/utils.js.map +1 -0
  90. package/dist/codegen/utils.test.d.ts +2 -0
  91. package/dist/codegen/utils.test.d.ts.map +1 -0
  92. package/dist/codegen/utils.test.js +178 -0
  93. package/dist/codegen/utils.test.js.map +1 -0
  94. package/dist/generator/index.d.ts +3 -0
  95. package/dist/generator/index.d.ts.map +1 -1
  96. package/dist/generator/index.js +17 -1
  97. package/dist/generator/index.js.map +1 -1
  98. package/dist/generator/index.test.js +104 -1
  99. package/dist/generator/index.test.js.map +1 -1
  100. package/dist/generator/loader.d.ts +15 -0
  101. package/dist/generator/loader.d.ts.map +1 -1
  102. package/dist/generator/loader.js +24 -0
  103. package/dist/generator/loader.js.map +1 -1
  104. package/dist/schema/connection.d.ts.map +1 -1
  105. package/dist/schema/connection.js +3 -2
  106. package/dist/schema/connection.js.map +1 -1
  107. package/dist/schema/datasource.d.ts.map +1 -1
  108. package/dist/schema/datasource.js +3 -2
  109. package/dist/schema/datasource.js.map +1 -1
  110. package/dist/schema/params.d.ts.map +1 -1
  111. package/dist/schema/params.js +3 -2
  112. package/dist/schema/params.js.map +1 -1
  113. package/dist/schema/pipe.d.ts +2 -2
  114. package/dist/schema/pipe.d.ts.map +1 -1
  115. package/dist/schema/pipe.js +4 -4
  116. package/dist/schema/pipe.js.map +1 -1
  117. package/dist/schema/project.d.ts.map +1 -1
  118. package/dist/schema/project.js +3 -2
  119. package/dist/schema/project.js.map +1 -1
  120. package/dist/schema/types.d.ts.map +1 -1
  121. package/dist/schema/types.js +3 -2
  122. package/dist/schema/types.js.map +1 -1
  123. package/dist/test/handlers.d.ts +49 -0
  124. package/dist/test/handlers.d.ts.map +1 -1
  125. package/dist/test/handlers.js +45 -0
  126. package/dist/test/handlers.js.map +1 -1
  127. package/package.json +4 -2
  128. package/src/api/branches.test.ts +65 -57
  129. package/src/api/branches.ts +7 -5
  130. package/src/api/build.ts +2 -1
  131. package/src/api/deploy.test.ts +141 -36
  132. package/src/api/deploy.ts +231 -23
  133. package/src/api/fetcher.ts +17 -0
  134. package/src/api/local.test.ts +43 -31
  135. package/src/api/local.ts +5 -4
  136. package/src/api/resources.test.ts +332 -0
  137. package/src/api/resources.ts +555 -0
  138. package/src/api/workspaces.test.ts +15 -9
  139. package/src/api/workspaces.ts +3 -1
  140. package/src/cli/auth.ts +2 -1
  141. package/src/cli/commands/build.ts +29 -33
  142. package/src/cli/commands/deploy.ts +131 -0
  143. package/src/cli/commands/dev.ts +10 -3
  144. package/src/cli/commands/init.test.ts +239 -30
  145. package/src/cli/commands/init.ts +548 -26
  146. package/src/cli/index.ts +117 -20
  147. package/src/cli/utils/package-manager.test.ts +118 -0
  148. package/src/cli/utils/package-manager.ts +44 -0
  149. package/src/client/base.ts +3 -2
  150. package/src/codegen/index.test.ts +367 -0
  151. package/src/codegen/index.ts +379 -0
  152. package/src/codegen/type-mapper.test.ts +224 -0
  153. package/src/codegen/type-mapper.ts +265 -0
  154. package/src/codegen/utils.test.ts +221 -0
  155. package/src/codegen/utils.ts +174 -0
  156. package/src/generator/index.test.ts +121 -1
  157. package/src/generator/index.ts +19 -1
  158. package/src/generator/loader.ts +43 -0
  159. package/src/schema/connection.ts +3 -2
  160. package/src/schema/datasource.ts +3 -2
  161. package/src/schema/params.ts +3 -2
  162. package/src/schema/pipe.ts +4 -4
  163. package/src/schema/project.ts +3 -2
  164. package/src/schema/types.ts +3 -2
  165. package/src/test/handlers.ts +58 -0
@@ -0,0 +1,367 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import {
3
+ generateDatasourceCode,
4
+ generatePipeCode,
5
+ generateDatasourcesFile,
6
+ generatePipesFile,
7
+ generateClientFile,
8
+ generateAllFiles,
9
+ } from "./index.js";
10
+ import type { DatasourceInfo, PipeInfo } from "../api/resources.js";
11
+
12
+ describe("generateDatasourceCode", () => {
13
+ it("generates valid datasource code", () => {
14
+ const ds: DatasourceInfo = {
15
+ name: "page_views",
16
+ description: "Page view tracking data",
17
+ columns: [
18
+ { name: "timestamp", type: "DateTime" },
19
+ { name: "pathname", type: "String" },
20
+ { name: "session_id", type: "String" },
21
+ ],
22
+ engine: {
23
+ type: "MergeTree",
24
+ sorting_key: "pathname, timestamp",
25
+ },
26
+ };
27
+
28
+ const code = generateDatasourceCode(ds);
29
+
30
+ expect(code).toContain('export const pageViews = defineDatasource("page_views"');
31
+ expect(code).toContain("timestamp: t.dateTime()");
32
+ expect(code).toContain("pathname: t.string()");
33
+ expect(code).toContain("session_id: t.string()");
34
+ expect(code).toContain("engine.mergeTree");
35
+ expect(code).toContain("export type PageViewsRow = InferRow<typeof pageViews>");
36
+ });
37
+
38
+ it("handles nullable columns", () => {
39
+ const ds: DatasourceInfo = {
40
+ name: "events",
41
+ columns: [
42
+ { name: "user_id", type: "Nullable(String)" },
43
+ ],
44
+ engine: { type: "MergeTree", sorting_key: "user_id" },
45
+ };
46
+
47
+ const code = generateDatasourceCode(ds);
48
+ expect(code).toContain("user_id: t.string().nullable()");
49
+ });
50
+
51
+ it("handles LowCardinality columns", () => {
52
+ const ds: DatasourceInfo = {
53
+ name: "events",
54
+ columns: [
55
+ { name: "country", type: "LowCardinality(String)" },
56
+ ],
57
+ engine: { type: "MergeTree", sorting_key: "country" },
58
+ };
59
+
60
+ const code = generateDatasourceCode(ds);
61
+ expect(code).toContain("country: t.string().lowCardinality()");
62
+ });
63
+
64
+ it("includes description in JSDoc", () => {
65
+ const ds: DatasourceInfo = {
66
+ name: "events",
67
+ description: "Event tracking data",
68
+ columns: [{ name: "id", type: "String" }],
69
+ engine: { type: "MergeTree", sorting_key: "id" },
70
+ };
71
+
72
+ const code = generateDatasourceCode(ds);
73
+ expect(code).toContain("/**");
74
+ expect(code).toContain(" * Event tracking data");
75
+ expect(code).toContain(" */");
76
+ });
77
+ });
78
+
79
+ describe("generatePipeCode", () => {
80
+ it("generates endpoint code", () => {
81
+ const pipe: PipeInfo = {
82
+ name: "top_pages",
83
+ description: "Get the most visited pages",
84
+ nodes: [
85
+ {
86
+ name: "aggregated",
87
+ sql: "SELECT pathname, count() AS views FROM page_views GROUP BY pathname",
88
+ },
89
+ ],
90
+ params: [
91
+ { name: "limit", type: "Int32", default: 10, required: false },
92
+ ],
93
+ type: "endpoint",
94
+ endpoint: { enabled: true },
95
+ output_columns: [
96
+ { name: "pathname", type: "String" },
97
+ { name: "views", type: "UInt64" },
98
+ ],
99
+ };
100
+
101
+ const code = generatePipeCode(pipe);
102
+
103
+ expect(code).toContain('export const topPages = defineEndpoint("top_pages"');
104
+ expect(code).toContain("limit: p.int32().optional(10)");
105
+ expect(code).toContain('name: "aggregated"');
106
+ expect(code).toContain("pathname: t.string()");
107
+ expect(code).toContain("views: t.uint64()");
108
+ expect(code).toContain("export type TopPagesParams = InferParams<typeof topPages>");
109
+ expect(code).toContain("export type TopPagesOutput = InferOutputRow<typeof topPages>");
110
+ });
111
+
112
+ it("generates materialized view code", () => {
113
+ const pipe: PipeInfo = {
114
+ name: "daily_stats_mv",
115
+ nodes: [
116
+ { name: "aggregate", sql: "SELECT toDate(timestamp) AS date, count() AS cnt FROM events GROUP BY date" },
117
+ ],
118
+ params: [],
119
+ type: "materialized",
120
+ materialized: { datasource: "daily_stats" },
121
+ output_columns: [],
122
+ };
123
+
124
+ const code = generatePipeCode(pipe);
125
+
126
+ expect(code).toContain('export const dailyStatsMv = defineMaterializedView("daily_stats_mv"');
127
+ expect(code).toContain("datasource: dailyStats");
128
+ });
129
+
130
+ it("generates copy pipe code", () => {
131
+ const pipe: PipeInfo = {
132
+ name: "daily_snapshot",
133
+ nodes: [
134
+ { name: "snapshot", sql: "SELECT * FROM events WHERE date = today()" },
135
+ ],
136
+ params: [],
137
+ type: "copy",
138
+ copy: {
139
+ target_datasource: "snapshots",
140
+ copy_schedule: "0 0 * * *",
141
+ copy_mode: "append",
142
+ },
143
+ output_columns: [],
144
+ };
145
+
146
+ const code = generatePipeCode(pipe);
147
+
148
+ expect(code).toContain('export const dailySnapshot = defineCopyPipe("daily_snapshot"');
149
+ expect(code).toContain("datasource: snapshots");
150
+ expect(code).toContain('copy_schedule: "0 0 * * *"');
151
+ expect(code).toContain('copy_mode: "append"');
152
+ });
153
+
154
+ it("generates regular pipe code", () => {
155
+ const pipe: PipeInfo = {
156
+ name: "filtered_events",
157
+ nodes: [
158
+ { name: "filtered", sql: "SELECT * FROM events WHERE status = 'active'" },
159
+ ],
160
+ params: [],
161
+ type: "pipe",
162
+ output_columns: [],
163
+ };
164
+
165
+ const code = generatePipeCode(pipe);
166
+
167
+ expect(code).toContain('export const filteredEvents = definePipe("filtered_events"');
168
+ });
169
+
170
+ it("handles params with descriptions", () => {
171
+ const pipe: PipeInfo = {
172
+ name: "search",
173
+ nodes: [{ name: "search", sql: "SELECT * FROM events" }],
174
+ params: [
175
+ { name: "query", type: "String", required: true, description: "Search query" },
176
+ ],
177
+ type: "endpoint",
178
+ endpoint: { enabled: true },
179
+ output_columns: [],
180
+ };
181
+
182
+ const code = generatePipeCode(pipe);
183
+ expect(code).toContain('query: p.string().describe("Search query")');
184
+ });
185
+ });
186
+
187
+ describe("generateDatasourcesFile", () => {
188
+ it("generates file with imports and all datasources", () => {
189
+ const datasources: DatasourceInfo[] = [
190
+ {
191
+ name: "events",
192
+ columns: [{ name: "id", type: "String" }],
193
+ engine: { type: "MergeTree", sorting_key: "id" },
194
+ },
195
+ {
196
+ name: "users",
197
+ columns: [{ name: "user_id", type: "String" }],
198
+ engine: { type: "MergeTree", sorting_key: "user_id" },
199
+ },
200
+ ];
201
+
202
+ const file = generateDatasourcesFile(datasources);
203
+
204
+ expect(file).toContain('import { defineDatasource, t, engine, type InferRow } from "@tinybirdco/sdk"');
205
+ expect(file).toContain('export const events = defineDatasource("events"');
206
+ expect(file).toContain('export const users = defineDatasource("users"');
207
+ });
208
+
209
+ it("generates placeholder for empty datasources", () => {
210
+ const file = generateDatasourcesFile([]);
211
+
212
+ expect(file).toContain("// No datasources found in workspace");
213
+ });
214
+ });
215
+
216
+ describe("generatePipesFile", () => {
217
+ it("generates file with appropriate imports", () => {
218
+ const pipes: PipeInfo[] = [
219
+ {
220
+ name: "top_pages",
221
+ nodes: [{ name: "agg", sql: "SELECT 1" }],
222
+ params: [{ name: "limit", type: "Int32", required: false }],
223
+ type: "endpoint",
224
+ endpoint: { enabled: true },
225
+ output_columns: [{ name: "count", type: "UInt64" }],
226
+ },
227
+ ];
228
+
229
+ const file = generatePipesFile(pipes, []);
230
+
231
+ expect(file).toContain("defineEndpoint");
232
+ expect(file).toContain("node");
233
+ expect(file).toContain("t");
234
+ expect(file).toContain("p");
235
+ expect(file).toContain("type InferParams");
236
+ expect(file).toContain("type InferOutputRow");
237
+ });
238
+
239
+ it("imports datasources for materialized views", () => {
240
+ const datasources: DatasourceInfo[] = [
241
+ {
242
+ name: "daily_stats",
243
+ columns: [{ name: "date", type: "Date" }],
244
+ engine: { type: "MergeTree", sorting_key: "date" },
245
+ },
246
+ ];
247
+
248
+ const pipes: PipeInfo[] = [
249
+ {
250
+ name: "daily_stats_mv",
251
+ nodes: [{ name: "agg", sql: "SELECT 1" }],
252
+ params: [],
253
+ type: "materialized",
254
+ materialized: { datasource: "daily_stats" },
255
+ output_columns: [],
256
+ },
257
+ ];
258
+
259
+ const file = generatePipesFile(pipes, datasources);
260
+
261
+ expect(file).toContain('import { dailyStats } from "./datasources.js"');
262
+ expect(file).toContain("defineMaterializedView");
263
+ });
264
+
265
+ it("generates placeholder for empty pipes", () => {
266
+ const file = generatePipesFile([], []);
267
+
268
+ expect(file).toContain("// No pipes found in workspace");
269
+ });
270
+ });
271
+
272
+ describe("generateClientFile", () => {
273
+ it("generates client with datasources and pipes", () => {
274
+ const datasources: DatasourceInfo[] = [
275
+ {
276
+ name: "events",
277
+ columns: [{ name: "id", type: "String" }],
278
+ engine: { type: "MergeTree", sorting_key: "id" },
279
+ },
280
+ ];
281
+
282
+ const pipes: PipeInfo[] = [
283
+ {
284
+ name: "top_events",
285
+ nodes: [{ name: "agg", sql: "SELECT 1" }],
286
+ params: [],
287
+ type: "endpoint",
288
+ endpoint: { enabled: true },
289
+ output_columns: [],
290
+ },
291
+ ];
292
+
293
+ const file = generateClientFile(datasources, pipes);
294
+
295
+ expect(file).toContain('import { createTinybirdClient } from "@tinybirdco/sdk"');
296
+ expect(file).toContain('import { events, type EventsRow } from "./datasources.js"');
297
+ expect(file).toContain('import { topEvents, type TopEventsParams, type TopEventsOutput } from "./pipes.js"');
298
+ expect(file).toContain("datasources: { events }");
299
+ expect(file).toContain("pipes: { topEvents }");
300
+ expect(file).toContain("export type { EventsRow, TopEventsParams, TopEventsOutput }");
301
+ expect(file).toContain("export { events, topEvents }");
302
+ });
303
+
304
+ it("handles empty datasources and pipes", () => {
305
+ const file = generateClientFile([], []);
306
+
307
+ expect(file).toContain("datasources: {}");
308
+ expect(file).toContain("pipes: {}");
309
+ });
310
+
311
+ it("only includes endpoints in client pipes", () => {
312
+ const pipes: PipeInfo[] = [
313
+ {
314
+ name: "endpoint_pipe",
315
+ nodes: [{ name: "n", sql: "SELECT 1" }],
316
+ params: [],
317
+ type: "endpoint",
318
+ endpoint: { enabled: true },
319
+ output_columns: [],
320
+ },
321
+ {
322
+ name: "materialized_pipe",
323
+ nodes: [{ name: "n", sql: "SELECT 1" }],
324
+ params: [],
325
+ type: "materialized",
326
+ materialized: { datasource: "target" },
327
+ output_columns: [],
328
+ },
329
+ ];
330
+
331
+ const file = generateClientFile([], pipes);
332
+
333
+ expect(file).toContain("endpointPipe");
334
+ expect(file).not.toContain("materializedPipe");
335
+ });
336
+ });
337
+
338
+ describe("generateAllFiles", () => {
339
+ it("returns all generated content with counts", () => {
340
+ const datasources: DatasourceInfo[] = [
341
+ {
342
+ name: "events",
343
+ columns: [{ name: "id", type: "String" }],
344
+ engine: { type: "MergeTree", sorting_key: "id" },
345
+ },
346
+ ];
347
+
348
+ const pipes: PipeInfo[] = [
349
+ {
350
+ name: "top_events",
351
+ nodes: [{ name: "agg", sql: "SELECT 1" }],
352
+ params: [],
353
+ type: "endpoint",
354
+ endpoint: { enabled: true },
355
+ output_columns: [],
356
+ },
357
+ ];
358
+
359
+ const result = generateAllFiles(datasources, pipes);
360
+
361
+ expect(result.datasourceCount).toBe(1);
362
+ expect(result.pipeCount).toBe(1);
363
+ expect(result.datasourcesContent).toContain("defineDatasource");
364
+ expect(result.pipesContent).toContain("defineEndpoint");
365
+ expect(result.clientContent).toContain("createTinybirdClient");
366
+ });
367
+ });