@tinybirdco/sdk 0.0.38 → 0.0.39

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/src/api/api.ts CHANGED
@@ -2,10 +2,14 @@ import { createTinybirdFetcher, type TinybirdFetch } from "./fetcher.js";
2
2
  import type {
3
3
  AppendOptions,
4
4
  AppendResult,
5
+ DeleteOptions,
6
+ DeleteResult,
5
7
  IngestOptions,
6
8
  IngestResult,
7
9
  QueryOptions,
8
10
  QueryResult,
11
+ TruncateOptions,
12
+ TruncateResult,
9
13
  TinybirdErrorResponse,
10
14
  } from "../client/types.js";
11
15
 
@@ -48,6 +52,16 @@ export interface TinybirdApiAppendOptions extends Omit<AppendOptions, 'url' | 'f
48
52
  token?: string;
49
53
  }
50
54
 
55
+ export interface TinybirdApiDeleteOptions extends Omit<DeleteOptions, 'deleteCondition'> {
56
+ /** Optional token override for this request */
57
+ token?: string;
58
+ }
59
+
60
+ export interface TinybirdApiTruncateOptions extends TruncateOptions {
61
+ /** Optional token override for this request */
62
+ token?: string;
63
+ }
64
+
51
65
  /**
52
66
  * Scope definition for token creation APIs
53
67
  */
@@ -369,6 +383,82 @@ export class TinybirdApi {
369
383
  return (await response.json()) as AppendResult;
370
384
  }
371
385
 
386
+ /**
387
+ * Delete rows from a datasource using a SQL condition
388
+ */
389
+ async deleteDatasource(
390
+ datasourceName: string,
391
+ options: DeleteOptions,
392
+ apiOptions: TinybirdApiDeleteOptions = {}
393
+ ): Promise<DeleteResult> {
394
+ const deleteCondition = options.deleteCondition?.trim();
395
+
396
+ if (!deleteCondition) {
397
+ throw new Error("'deleteCondition' must be provided in options");
398
+ }
399
+
400
+ const url = new URL(
401
+ `/v0/datasources/${encodeURIComponent(datasourceName)}/delete`,
402
+ `${this.baseUrl}/`
403
+ );
404
+
405
+ const requestBody = new URLSearchParams();
406
+ requestBody.set("delete_condition", deleteCondition);
407
+
408
+ const dryRun = options.dryRun ?? apiOptions.dryRun;
409
+ if (dryRun !== undefined) {
410
+ requestBody.set("dry_run", String(dryRun));
411
+ }
412
+
413
+ const response = await this.request(url.toString(), {
414
+ method: "POST",
415
+ token: apiOptions.token,
416
+ headers: {
417
+ "Content-Type": "application/x-www-form-urlencoded",
418
+ },
419
+ body: requestBody.toString(),
420
+ signal: this.createAbortSignal(
421
+ options.timeout ?? apiOptions.timeout,
422
+ options.signal ?? apiOptions.signal
423
+ ),
424
+ });
425
+
426
+ if (!response.ok) {
427
+ await this.handleErrorResponse(response);
428
+ }
429
+
430
+ return (await response.json()) as DeleteResult;
431
+ }
432
+
433
+ /**
434
+ * Truncate all rows from a datasource
435
+ */
436
+ async truncateDatasource(
437
+ datasourceName: string,
438
+ options: TruncateOptions = {},
439
+ apiOptions: TinybirdApiTruncateOptions = {}
440
+ ): Promise<TruncateResult> {
441
+ const url = new URL(
442
+ `/v0/datasources/${encodeURIComponent(datasourceName)}/truncate`,
443
+ `${this.baseUrl}/`
444
+ );
445
+
446
+ const response = await this.request(url.toString(), {
447
+ method: "POST",
448
+ token: apiOptions.token,
449
+ signal: this.createAbortSignal(
450
+ options.timeout ?? apiOptions.timeout,
451
+ options.signal ?? apiOptions.signal
452
+ ),
453
+ });
454
+
455
+ if (!response.ok) {
456
+ await this.handleErrorResponse(response);
457
+ }
458
+
459
+ return this.parseOptionalJson(response);
460
+ }
461
+
372
462
  /**
373
463
  * Create a token using Tinybird Token API.
374
464
  * Supports both static and JWT token payloads.
@@ -438,6 +528,20 @@ export class TinybirdApi {
438
528
  return formData;
439
529
  }
440
530
 
531
+ private async parseOptionalJson<T extends object>(response: Response): Promise<T> {
532
+ const rawBody = await response.text();
533
+
534
+ if (!rawBody.trim()) {
535
+ return {} as T;
536
+ }
537
+
538
+ try {
539
+ return JSON.parse(rawBody) as T;
540
+ } catch {
541
+ return {} as T;
542
+ }
543
+ }
544
+
441
545
  private createAbortSignal(
442
546
  timeout?: number,
443
547
  existingSignal?: AbortSignal
@@ -156,6 +156,8 @@ describe("TinybirdClient", () => {
156
156
  });
157
157
 
158
158
  expect(typeof client.datasources.append).toBe("function");
159
+ expect(typeof client.datasources.delete).toBe("function");
160
+ expect(typeof client.datasources.truncate).toBe("function");
159
161
  });
160
162
 
161
163
  it("datasources conforms to DatasourcesNamespace interface", () => {
@@ -167,6 +169,8 @@ describe("TinybirdClient", () => {
167
169
  const datasources: DatasourcesNamespace = client.datasources;
168
170
  expect(datasources).toBeDefined();
169
171
  expect(typeof datasources.append).toBe("function");
172
+ expect(typeof datasources.delete).toBe("function");
173
+ expect(typeof datasources.truncate).toBe("function");
170
174
  });
171
175
  });
172
176
  });
@@ -8,10 +8,14 @@ import type {
8
8
  ClientConfig,
9
9
  ClientContext,
10
10
  DatasourcesNamespace,
11
+ DeleteOptions,
12
+ DeleteResult,
11
13
  QueryResult,
12
14
  IngestResult,
13
15
  QueryOptions,
14
16
  IngestOptions,
17
+ TruncateOptions,
18
+ TruncateResult,
15
19
  } from "./types.js";
16
20
  import { TinybirdError } from "./types.js";
17
21
  import { TinybirdApi, TinybirdApiError } from "../api/api.js";
@@ -89,6 +93,15 @@ export class TinybirdClient {
89
93
  append: (datasourceName: string, options: AppendOptions): Promise<AppendResult> => {
90
94
  return this.appendDatasource(datasourceName, options);
91
95
  },
96
+ delete: (datasourceName: string, options: DeleteOptions): Promise<DeleteResult> => {
97
+ return this.deleteDatasource(datasourceName, options);
98
+ },
99
+ truncate: (
100
+ datasourceName: string,
101
+ options: TruncateOptions = {}
102
+ ): Promise<TruncateResult> => {
103
+ return this.truncateDatasource(datasourceName, options);
104
+ },
92
105
  };
93
106
 
94
107
  // Initialize tokens namespace
@@ -133,6 +146,46 @@ export class TinybirdClient {
133
146
  }
134
147
  }
135
148
 
149
+ /**
150
+ * Delete rows from a datasource using a SQL condition
151
+ *
152
+ * @param datasourceName - Name of the datasource
153
+ * @param options - Delete options including deleteCondition
154
+ * @returns Delete job result
155
+ */
156
+ private async deleteDatasource(
157
+ datasourceName: string,
158
+ options: DeleteOptions
159
+ ): Promise<DeleteResult> {
160
+ const token = await this.getToken();
161
+
162
+ try {
163
+ return await this.getApi(token).deleteDatasource(datasourceName, options);
164
+ } catch (error) {
165
+ this.rethrowApiError(error);
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Truncate all rows from a datasource
171
+ *
172
+ * @param datasourceName - Name of the datasource
173
+ * @param options - Truncate options
174
+ * @returns Truncate result
175
+ */
176
+ private async truncateDatasource(
177
+ datasourceName: string,
178
+ options: TruncateOptions = {}
179
+ ): Promise<TruncateResult> {
180
+ const token = await this.getToken();
181
+
182
+ try {
183
+ return await this.getApi(token).truncateDatasource(datasourceName, options);
184
+ } catch (error) {
185
+ this.rethrowApiError(error);
186
+ }
187
+ }
188
+
136
189
  /**
137
190
  * Get the effective token, resolving branch token in dev mode if needed
138
191
  */
@@ -236,10 +236,64 @@ export interface AppendResult {
236
236
  import_id?: string;
237
237
  }
238
238
 
239
+ /**
240
+ * Options for deleting rows from a datasource
241
+ */
242
+ export interface DeleteOptions {
243
+ /** SQL WHERE clause condition used to select rows to delete */
244
+ deleteCondition: string;
245
+ /** Validate and return matched rows without executing deletion */
246
+ dryRun?: boolean;
247
+ /** Request timeout in milliseconds */
248
+ timeout?: number;
249
+ /** AbortController signal for cancellation */
250
+ signal?: AbortSignal;
251
+ }
252
+
253
+ /**
254
+ * Result of deleting rows from a datasource
255
+ */
256
+ export interface DeleteResult {
257
+ /** Delete job ID */
258
+ id?: string;
259
+ /** Same value as id */
260
+ job_id?: string;
261
+ /** Job status URL */
262
+ job_url?: string;
263
+ /** Job status */
264
+ status?: string;
265
+ /** Same value as id */
266
+ delete_id?: string;
267
+ /** Number of rows matched in dry run mode */
268
+ rows_to_be_deleted?: number;
269
+ }
270
+
271
+ /**
272
+ * Options for truncating a datasource
273
+ */
274
+ export interface TruncateOptions {
275
+ /** Request timeout in milliseconds */
276
+ timeout?: number;
277
+ /** AbortController signal for cancellation */
278
+ signal?: AbortSignal;
279
+ }
280
+
281
+ /**
282
+ * Result of truncating a datasource
283
+ */
284
+ export interface TruncateResult {
285
+ /** Optional status returned by the API */
286
+ status?: string;
287
+ }
288
+
239
289
  /**
240
290
  * Datasources namespace interface for raw client
241
291
  */
242
292
  export interface DatasourcesNamespace {
243
293
  /** Append data to a datasource from a URL or file */
244
294
  append(datasourceName: string, options: AppendOptions): Promise<AppendResult>;
295
+ /** Delete rows from a datasource using a SQL condition */
296
+ delete(datasourceName: string, options: DeleteOptions): Promise<DeleteResult>;
297
+ /** Truncate all rows from a datasource */
298
+ truncate(datasourceName: string, options?: TruncateOptions): Promise<TruncateResult>;
245
299
  }
package/src/index.ts CHANGED
@@ -208,10 +208,14 @@ export type {
208
208
  ClientContext,
209
209
  CsvDialectOptions,
210
210
  DatasourcesNamespace,
211
+ DeleteOptions,
212
+ DeleteResult,
211
213
  QueryResult,
212
214
  IngestResult,
213
215
  QueryOptions,
214
216
  IngestOptions,
217
+ TruncateOptions,
218
+ TruncateResult,
215
219
  ColumnMeta,
216
220
  QueryStatistics,
217
221
  TinybirdErrorResponse,
@@ -231,6 +235,8 @@ export type {
231
235
  TinybirdApiQueryOptions,
232
236
  TinybirdApiIngestOptions,
233
237
  TinybirdApiAppendOptions,
238
+ TinybirdApiDeleteOptions,
239
+ TinybirdApiTruncateOptions,
234
240
  TinybirdApiRequestInit,
235
241
  TinybirdApiTokenScope,
236
242
  TinybirdApiCreateTokenRequest,
@@ -94,7 +94,7 @@ describe("Project Schema", () => {
94
94
  expect((project.tinybird as unknown as Record<string, unknown>).pipes).toBeUndefined();
95
95
  });
96
96
 
97
- it("creates datasource accessors with append method", () => {
97
+ it("creates datasource accessors with append/delete/truncate methods", () => {
98
98
  const events = defineDatasource("events", {
99
99
  schema: { timestamp: t.dateTime() },
100
100
  });
@@ -105,6 +105,8 @@ describe("Project Schema", () => {
105
105
 
106
106
  expect(project.tinybird.events).toBeDefined();
107
107
  expect(typeof project.tinybird.events.append).toBe("function");
108
+ expect(typeof project.tinybird.events.delete).toBe("function");
109
+ expect(typeof project.tinybird.events.truncate).toBe("function");
108
110
  });
109
111
 
110
112
  it("creates multiple datasource accessors", () => {
@@ -123,6 +125,10 @@ describe("Project Schema", () => {
123
125
  expect(project.tinybird.pageViews).toBeDefined();
124
126
  expect(typeof project.tinybird.events.append).toBe("function");
125
127
  expect(typeof project.tinybird.pageViews.append).toBe("function");
128
+ expect(typeof project.tinybird.events.delete).toBe("function");
129
+ expect(typeof project.tinybird.pageViews.delete).toBe("function");
130
+ expect(typeof project.tinybird.events.truncate).toBe("function");
131
+ expect(typeof project.tinybird.pageViews.truncate).toBe("function");
126
132
  });
127
133
 
128
134
  it("throws error when accessing client before initialization", () => {
@@ -304,7 +310,7 @@ describe("Project Schema", () => {
304
310
  expect((client as unknown as Record<string, unknown>).pipes).toBeUndefined();
305
311
  });
306
312
 
307
- it("creates datasource accessors with append method", () => {
313
+ it("creates datasource accessors with append/delete/truncate methods", () => {
308
314
  const events = defineDatasource("events", {
309
315
  schema: { id: t.string() },
310
316
  });
@@ -316,6 +322,8 @@ describe("Project Schema", () => {
316
322
 
317
323
  expect(client.events).toBeDefined();
318
324
  expect(typeof client.events.append).toBe("function");
325
+ expect(typeof client.events.delete).toBe("function");
326
+ expect(typeof client.events.truncate).toBe("function");
319
327
  });
320
328
 
321
329
  it("creates multiple datasource accessors", () => {
@@ -335,6 +343,10 @@ describe("Project Schema", () => {
335
343
  expect(client.pageViews).toBeDefined();
336
344
  expect(typeof client.events.append).toBe("function");
337
345
  expect(typeof client.pageViews.append).toBe("function");
346
+ expect(typeof client.events.delete).toBe("function");
347
+ expect(typeof client.pageViews.delete).toBe("function");
348
+ expect(typeof client.events.truncate).toBe("function");
349
+ expect(typeof client.pageViews.truncate).toBe("function");
338
350
  });
339
351
 
340
352
  it("accepts devMode option", () => {
@@ -12,8 +12,12 @@ import type {
12
12
  AppendOptions,
13
13
  AppendResult,
14
14
  DatasourcesNamespace,
15
+ DeleteOptions,
16
+ DeleteResult,
15
17
  QueryOptions,
16
18
  QueryResult,
19
+ TruncateOptions,
20
+ TruncateResult,
17
21
  } from "../client/types.js";
18
22
  import type { InferRow, InferParams, InferOutputRow } from "../infer/index.js";
19
23
  import type { TokensNamespace } from "../client/tokens.js";
@@ -82,16 +86,20 @@ type IngestMethods<T extends DatasourcesDefinition> = {
82
86
  };
83
87
 
84
88
  /**
85
- * Type for a datasource accessor with append method
89
+ * Type for a datasource accessor with import/mutation methods
86
90
  */
87
91
  type DatasourceAccessor = {
88
92
  /** Append data from a URL or file */
89
93
  append(options: AppendOptions): Promise<AppendResult>;
94
+ /** Delete rows using a SQL condition */
95
+ delete(options: DeleteOptions): Promise<DeleteResult>;
96
+ /** Truncate all rows */
97
+ truncate(options?: TruncateOptions): Promise<TruncateResult>;
90
98
  };
91
99
 
92
100
  /**
93
101
  * Type for datasource accessors object
94
- * Maps each datasource to an accessor with append method
102
+ * Maps each datasource to an accessor with import/mutation methods
95
103
  */
96
104
  type DatasourceAccessors<T extends DatasourcesDefinition> = {
97
105
  [K in keyof T]: DatasourceAccessor;
@@ -105,7 +113,7 @@ interface ProjectClientBase<TDatasources extends DatasourcesDefinition> {
105
113
  ingest: IngestMethods<TDatasources>;
106
114
  /** Token operations (JWT creation, etc.) */
107
115
  readonly tokens: TokensNamespace;
108
- /** Datasource operations (append from URL/file) */
116
+ /** Datasource operations (append/delete/truncate) */
109
117
  readonly datasources: DatasourcesNamespace;
110
118
  /** Execute raw SQL queries */
111
119
  sql<T = unknown>(sql: string, options?: QueryOptions): Promise<QueryResult<T>>;
@@ -374,6 +382,14 @@ function buildProjectClient<
374
382
  const client = await getClient();
375
383
  return client.datasources.append(tinybirdName, options);
376
384
  },
385
+ delete: async (options: DeleteOptions) => {
386
+ const client = await getClient();
387
+ return client.datasources.delete(tinybirdName, options);
388
+ },
389
+ truncate: async (options: TruncateOptions = {}) => {
390
+ const client = await getClient();
391
+ return client.datasources.truncate(tinybirdName, options);
392
+ },
377
393
  };
378
394
  }
379
395