supatool 0.3.0 → 0.3.1

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 CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  A CLI tool that automatically generates TypeScript CRUD code from Supabase type definitions.
4
4
 
5
+
5
6
  ## Install
6
7
 
7
8
  ```
@@ -155,7 +156,7 @@ CRUD utility files for the `apps` table will be generated in `src/integrations/s
155
156
  You can import and use these functions in your application as follows:
156
157
 
157
158
  ```ts
158
- // Example: Using CRUD functions for the apps table
159
+ // Example: Using CRUD functions for the apps table (v0.3.0+)
159
160
  import {
160
161
  selectAppsRowsWithFilters,
161
162
  selectAppsSingleRowWithFilters,
@@ -165,23 +166,26 @@ import {
165
166
  deleteAppsRow,
166
167
  } from 'src/integrations/supabase/crud-autogen/apps';
167
168
 
168
- // Get multiple rows with filters
169
- const apps = await selectAppsRowsWithFilters({ status: 'active' });
169
+ // Select multiple rows with filters (NEW: destructuring parameters)
170
+ const apps = await selectAppsRowsWithFilters({ filters: { status: 'active' } });
170
171
 
171
- // Get a single row with filters
172
- const app = await selectAppsSingleRowWithFilters({ id: 'your-app-id' });
172
+ // Select a single row with filters
173
+ const app = await selectAppsSingleRowWithFilters({ filters: { id: 'your-app-id' } });
173
174
 
174
- // Get by ID
175
- const appById = await selectAppsRowById('your-app-id');
175
+ // Select by ID (NEW: destructuring parameters)
176
+ const appById = await selectAppsRowById({ id: 'your-app-id' });
176
177
 
177
- // Create new row
178
- const newApp = await insertAppsRow({ name: 'New App', status: 'active' });
178
+ // Insert new row (NEW: destructuring parameters)
179
+ const newApp = await insertAppsRow({ data: { name: 'New App', status: 'active' } });
179
180
 
180
- // Update row
181
- const updatedApp = await updateAppsRow({ id: 'your-app-id', name: 'Updated Name' });
181
+ // Update row (NEW: destructuring parameters)
182
+ const updatedApp = await updateAppsRow({
183
+ id: 'your-app-id',
184
+ data: { name: 'Updated Name' }
185
+ });
182
186
 
183
- // Delete row
184
- const deletedApp = await deleteAppsRow('your-app-id');
187
+ // Delete row (NEW: destructuring parameters)
188
+ const success = await deleteAppsRow({ id: 'your-app-id' });
185
189
  ```
186
190
 
187
191
  - All functions are async and return the corresponding row type.
@@ -318,6 +322,8 @@ Comments appear in:
318
322
  ## Changelog
319
323
 
320
324
  ### v0.3.0
325
+
326
+ **NEW Features:**
321
327
  - **NEW**: `extract` command for database schema extraction
322
328
  - **NEW**: Full compliance with Supabase declarative database schemas workflow
323
329
  - **NEW**: AI-friendly index.md and llms.txt generation for better schema understanding
@@ -327,6 +333,20 @@ Comments appear in:
327
333
  - **ENHANCED**: Support for all database object types (RLS, functions, triggers, cron jobs, custom types)
328
334
  - **ENHANCED**: Flexible output options with --no-separate compatibility
329
335
 
336
+ **Enhanced Error Handling:**
337
+ - Comprehensive try-catch blocks for all CRUD operations
338
+ - Enhanced null/undefined checks with proper fallbacks
339
+ - Detailed error messages with contextual information
340
+ - Special handling for PGRST116 errors (record not found)
341
+ - Parameter validation for required fields
342
+ - Proper error logging and debugging support
343
+
344
+ **Breaking Changes:**
345
+ - **Function Parameter Format**: All CRUD functions now use destructuring assignment
346
+ - Before: `selectTableRowById(id: string)`
347
+ - After: `selectTableRowById({ id }: { id: string })`
348
+ - **Type Safety**: Enhanced TypeScript type annotations for all functions
349
+
330
350
  ### v0.2.0
331
351
  - Added `gen:` commands for code and schema generation
332
352
  - Enhanced `create` command
@@ -34,21 +34,158 @@ function generateCrudFromModel(model, outDir) {
34
34
  if (tableObj.skipCreate)
35
35
  continue;
36
36
  const tableName = tableObj.tableName;
37
+ const capitalizedName = capitalize(tableName);
37
38
  let code = `// 自動生成: ${tableName}用CRUD関数\n\n`;
38
39
  code += `import { supabase } from '../client';\n`;
39
40
  code += `import type { ${tableName} } from '../types';\n\n`;
41
+ // 型定義
42
+ code += `// フィルター型定義\n`;
43
+ code += `type FilterValue = string | number | boolean | null;\n`;
44
+ code += `type Filters = Record<string, FilterValue | FilterValue[]>;\n\n`;
45
+ // 全件取得関数(改良版)
40
46
  code += `/** 全件取得 */\n`;
41
- code += `export async function getAll${capitalize(tableName)}(): Promise<${tableName}[]> {\n`;
42
- code += ` const { data, error } = await supabase.from('${tableName}').select('*');\n`;
43
- code += ` if (error) throw error;\n`;
44
- code += ` return data as ${tableName}[];\n`;
47
+ code += `export async function select${capitalizedName}Rows(): Promise<${tableName}[]> {\n`;
48
+ code += ` try {\n`;
49
+ code += ` const { data, error } = await supabase.from('${tableName}').select('*');\n`;
50
+ code += ` if (error) {\n`;
51
+ code += ` console.error('Error fetching all ${tableName}:', error);\n`;
52
+ code += ` throw new Error(\`Failed to fetch ${tableName}: \${error.message}\`);\n`;
53
+ code += ` }\n`;
54
+ code += ` if (!data) {\n`;
55
+ code += ` return [];\n`;
56
+ code += ` }\n`;
57
+ code += ` return data as ${tableName}[];\n`;
58
+ code += ` } catch (error) {\n`;
59
+ code += ` console.error('Unexpected error in select${capitalizedName}Rows:', error);\n`;
60
+ code += ` throw error;\n`;
61
+ code += ` }\n`;
45
62
  code += `}\n\n`;
63
+ // IDで1件取得関数(改良版)
46
64
  code += `/** IDで1件取得 */\n`;
47
- code += `export async function get${capitalize(tableName)}ById(id: string): Promise<${tableName} | null> {\n`;
48
- code += ` const { data, error } = await supabase.from('${tableName}').select('*').eq('id', id).single();\n`;
49
- code += ` if (error) throw error;\n`;
50
- code += ` return data as ${tableName} | null;\n`;
51
- code += `}\n`;
65
+ code += `export async function select${capitalizedName}RowById({ id }: { id: string }): Promise<${tableName} | null> {\n`;
66
+ code += ` if (!id) {\n`;
67
+ code += ` throw new Error('ID is required');\n`;
68
+ code += ` }\n`;
69
+ code += ` try {\n`;
70
+ code += ` const { data, error } = await supabase.from('${tableName}').select('*').eq('id', id).single();\n`;
71
+ code += ` if (error) {\n`;
72
+ code += ` // レコードが見つからない場合(PGRST116)は null を返す\n`;
73
+ code += ` if (error.code === 'PGRST116') {\n`;
74
+ code += ` return null;\n`;
75
+ code += ` }\n`;
76
+ code += ` console.error('Error fetching ${tableName} by ID:', error);\n`;
77
+ code += ` throw new Error(\`Failed to fetch ${tableName} with ID \${id}: \${error.message}\`);\n`;
78
+ code += ` }\n`;
79
+ code += ` return data as ${tableName} | null;\n`;
80
+ code += ` } catch (error) {\n`;
81
+ code += ` console.error('Unexpected error in select${capitalizedName}RowById:', error);\n`;
82
+ code += ` throw error;\n`;
83
+ code += ` }\n`;
84
+ code += `}\n\n`;
85
+ // フィルターで検索関数
86
+ code += `/** フィルターで複数件取得 */\n`;
87
+ code += `export async function select${capitalizedName}RowsWithFilters({ filters }: { filters: Filters }): Promise<${tableName}[]> {\n`;
88
+ code += ` try {\n`;
89
+ code += ` let query = supabase.from('${tableName}').select('*');\n`;
90
+ code += ` \n`;
91
+ code += ` // フィルターを適用\n`;
92
+ code += ` for (const [key, value] of Object.entries(filters)) {\n`;
93
+ code += ` if (Array.isArray(value)) {\n`;
94
+ code += ` query = query.in(key, value);\n`;
95
+ code += ` } else {\n`;
96
+ code += ` query = query.eq(key, value);\n`;
97
+ code += ` }\n`;
98
+ code += ` }\n`;
99
+ code += ` \n`;
100
+ code += ` const { data, error } = await query;\n`;
101
+ code += ` if (error) {\n`;
102
+ code += ` console.error('Error fetching ${tableName} by filters:', error);\n`;
103
+ code += ` throw new Error(\`Failed to fetch ${tableName}: \${error.message}\`);\n`;
104
+ code += ` }\n`;
105
+ code += ` return (data as unknown as ${tableName}[]) || [];\n`;
106
+ code += ` } catch (error) {\n`;
107
+ code += ` console.error('Unexpected error in select${capitalizedName}RowsWithFilters:', error);\n`;
108
+ code += ` throw error;\n`;
109
+ code += ` }\n`;
110
+ code += `}\n\n`;
111
+ // 作成関数
112
+ code += `/** 新規作成 */\n`;
113
+ code += `export async function insert${capitalizedName}Row({ data }: { data: Omit<${tableName}, 'id' | 'created_at' | 'updated_at'> }): Promise<${tableName}> {\n`;
114
+ code += ` if (!data) {\n`;
115
+ code += ` throw new Error('Data is required for creation');\n`;
116
+ code += ` }\n`;
117
+ code += ` try {\n`;
118
+ code += ` const { data: createdData, error } = await supabase\n`;
119
+ code += ` .from('${tableName}')\n`;
120
+ code += ` .insert([data])\n`;
121
+ code += ` .select()\n`;
122
+ code += ` .single();\n`;
123
+ code += ` if (error) {\n`;
124
+ code += ` console.error('Error creating ${tableName}:', error);\n`;
125
+ code += ` throw new Error(\`Failed to create ${tableName}: \${error.message}\`);\n`;
126
+ code += ` }\n`;
127
+ code += ` if (!createdData) {\n`;
128
+ code += ` throw new Error('No data returned after creation');\n`;
129
+ code += ` }\n`;
130
+ code += ` return createdData as ${tableName};\n`;
131
+ code += ` } catch (error) {\n`;
132
+ code += ` console.error('Unexpected error in insert${capitalizedName}Row:', error);\n`;
133
+ code += ` throw error;\n`;
134
+ code += ` }\n`;
135
+ code += `}\n\n`;
136
+ // 更新関数
137
+ code += `/** 更新 */\n`;
138
+ code += `export async function update${capitalizedName}Row({ id, data }: { id: string; data: Partial<Omit<${tableName}, 'id' | 'created_at'>> }): Promise<${tableName}> {\n`;
139
+ code += ` if (!id) {\n`;
140
+ code += ` throw new Error('ID is required for update');\n`;
141
+ code += ` }\n`;
142
+ code += ` if (!data || Object.keys(data).length === 0) {\n`;
143
+ code += ` throw new Error('Update data is required');\n`;
144
+ code += ` }\n`;
145
+ code += ` try {\n`;
146
+ code += ` const { data: updatedData, error } = await supabase\n`;
147
+ code += ` .from('${tableName}')\n`;
148
+ code += ` .update(data)\n`;
149
+ code += ` .eq('id', id)\n`;
150
+ code += ` .select()\n`;
151
+ code += ` .single();\n`;
152
+ code += ` if (error) {\n`;
153
+ code += ` if (error.code === 'PGRST116') {\n`;
154
+ code += ` throw new Error(\`${tableName} with ID \${id} not found\`);\n`;
155
+ code += ` }\n`;
156
+ code += ` console.error('Error updating ${tableName}:', error);\n`;
157
+ code += ` throw new Error(\`Failed to update ${tableName} with ID \${id}: \${error.message}\`);\n`;
158
+ code += ` }\n`;
159
+ code += ` if (!updatedData) {\n`;
160
+ code += ` throw new Error(\`${tableName} with ID \${id} not found\`);\n`;
161
+ code += ` }\n`;
162
+ code += ` return updatedData as ${tableName};\n`;
163
+ code += ` } catch (error) {\n`;
164
+ code += ` console.error('Unexpected error in update${capitalizedName}Row:', error);\n`;
165
+ code += ` throw error;\n`;
166
+ code += ` }\n`;
167
+ code += `}\n\n`;
168
+ // 削除関数
169
+ code += `/** 削除 */\n`;
170
+ code += `export async function delete${capitalizedName}Row({ id }: { id: string }): Promise<boolean> {\n`;
171
+ code += ` if (!id) {\n`;
172
+ code += ` throw new Error('ID is required for deletion');\n`;
173
+ code += ` }\n`;
174
+ code += ` try {\n`;
175
+ code += ` const { error } = await supabase\n`;
176
+ code += ` .from('${tableName}')\n`;
177
+ code += ` .delete()\n`;
178
+ code += ` .eq('id', id);\n`;
179
+ code += ` if (error) {\n`;
180
+ code += ` console.error('Error deleting ${tableName}:', error);\n`;
181
+ code += ` throw new Error(\`Failed to delete ${tableName} with ID \${id}: \${error.message}\`);\n`;
182
+ code += ` }\n`;
183
+ code += ` return true;\n`;
184
+ code += ` } catch (error) {\n`;
185
+ code += ` console.error('Unexpected error in delete${capitalizedName}Row:', error);\n`;
186
+ code += ` throw error;\n`;
187
+ code += ` }\n`;
188
+ code += `}\n\n`;
52
189
  fs_1.default.writeFileSync(path_1.default.join(outDir, `${tableName}.ts`), code);
53
190
  }
54
191
  }
package/dist/index.js CHANGED
@@ -161,13 +161,13 @@ const toUpperCamelCase = (str) => {
161
161
  // CRUD template
162
162
  const crudTemplate = (typeName, fields, isView) => {
163
163
  const upperCamelTypeName = toUpperCamelCase(typeName);
164
- const selectByIdFunctionName = 'select' + upperCamelTypeName + 'RowById';
165
- const selectFilteredRowsFunctionName = 'select' + upperCamelTypeName + 'RowsWithFilters';
166
- const selectFilteredSingleRowFunctionName = 'select' + upperCamelTypeName + 'SingleRowWithFilters';
167
- const insertFunctionName = 'insert' + upperCamelTypeName + 'Row';
164
+ const getByIdFunctionName = 'select' + upperCamelTypeName + 'RowById';
165
+ const getByFiltersFunctionName = 'select' + upperCamelTypeName + 'RowsWithFilters';
166
+ const getSingleByFiltersFunctionName = 'select' + upperCamelTypeName + 'SingleRowWithFilters';
167
+ const createFunctionName = 'insert' + upperCamelTypeName + 'Row';
168
168
  const updateFunctionName = 'update' + upperCamelTypeName + 'Row';
169
169
  const deleteFunctionName = 'delete' + upperCamelTypeName + 'Row';
170
- const idType = fields.find((field) => field.name === 'id')?.type;
170
+ const idType = fields.find((field) => field.name === 'id')?.type || 'string';
171
171
  const hasIdColumn = idType !== undefined; // Check if 'id' column exists
172
172
  const exportHeaders = `// Supabase CRUD operations for ${typeName}
173
173
  // This file is automatically generated. Do not edit it directly.
@@ -180,17 +180,29 @@ type Filters = Record<string, FilterTypesValue | FilterTypesValue[]>;
180
180
  `;
181
181
  const exportSelectById = `
182
182
  // Read single row using id
183
- async function ${selectByIdFunctionName}(id: ${idType}): Promise<${typeName} | ${typeName}[]> {
184
- if (id !== undefined) {
183
+ export async function ${getByIdFunctionName}({ id }: { id: ${idType} }): Promise<${typeName} | null> {
184
+ if (!id) {
185
+ throw new Error('ID is required');
186
+ }
187
+ try {
185
188
  const result = await supabase
186
189
  .from('${typeName.toLowerCase()}')
187
190
  .select('*')
188
191
  .eq('id', id)
189
192
  .single();
193
+
194
+ if (result.error) {
195
+ if (result.error.code === 'PGRST116') {
196
+ return null;
197
+ }
198
+ throw new Error(\`Failed to fetch ${typeName}: \${result.error.message}\`);
199
+ }
200
+
190
201
  return result.data as ${typeName};
202
+ } catch (error) {
203
+ console.error('Error in ${getByIdFunctionName}:', error);
204
+ throw error;
191
205
  }
192
- const result = await supabase.from('${typeName.toLowerCase()}').select('*');
193
- return result.data as ${typeName}[];
194
206
  }
195
207
  `;
196
208
  const exportSelectQueries = `
@@ -248,64 +260,138 @@ function applyFilters(query: any, filters: Filters): any {
248
260
  }
249
261
 
250
262
  // Read multiple rows with dynamic filters
251
- async function ${selectFilteredRowsFunctionName}(filters: Filters = {}): Promise<${typeName}[]> {
252
- let query = supabase.from('${typeName.toLowerCase()}').select('*');
253
- query = applyFilters(query, filters);
263
+ export async function ${getByFiltersFunctionName}({ filters }: { filters: Filters }): Promise<${typeName}[]> {
264
+ try {
265
+ let query = supabase.from('${typeName.toLowerCase()}').select('*');
266
+ query = applyFilters(query, filters);
254
267
 
255
- const result = await query;
256
- return result.data as ${typeName}[];
268
+ const result = await query;
269
+
270
+ if (result.error) {
271
+ throw new Error(\`Failed to fetch ${typeName}: \${result.error.message}\`);
272
+ }
273
+
274
+ return (result.data as unknown as ${typeName}[]) || [];
275
+ } catch (error) {
276
+ console.error('Error in ${getByFiltersFunctionName}:', error);
277
+ throw error;
278
+ }
257
279
  }
258
280
 
259
281
  // Read a single row with dynamic filters
260
- async function ${selectFilteredSingleRowFunctionName}(filters: Filters = {}): Promise<${typeName}> {
261
- let query = supabase.from('${typeName.toLowerCase()}').select('*');
262
- query = applyFilters(query, filters).single();
282
+ export async function ${getSingleByFiltersFunctionName}({ filters }: { filters: Filters }): Promise<${typeName} | null> {
283
+ try {
284
+ let query = supabase.from('${typeName.toLowerCase()}').select('*');
285
+ query = applyFilters(query, filters).single();
263
286
 
264
- const result = await query;
265
- return result.data as unknown as ${typeName};
287
+ const result = await query;
288
+
289
+ if (result.error) {
290
+ if (result.error.code === 'PGRST116') {
291
+ return null;
292
+ }
293
+ throw new Error(\`Failed to fetch ${typeName}: \${result.error.message}\`);
294
+ }
295
+
296
+ return result.data as unknown as ${typeName};
297
+ } catch (error) {
298
+ console.error('Error in ${getSingleByFiltersFunctionName}:', error);
299
+ throw error;
300
+ }
266
301
  }
267
302
  `;
268
303
  const exportInsertOperation = isView ? '' :
269
304
  `
270
305
  // Create Function
271
- async function ${insertFunctionName}(data: TablesInsert<'${typeName}'>): Promise<${typeName}> {
272
- const result = await supabase
273
- .from('${typeName}')
274
- .insert([data])
275
- .select()
276
- .single();
306
+ export async function ${createFunctionName}({ data }: { data: TablesInsert<'${typeName}'> }): Promise<${typeName}> {
307
+ if (!data) {
308
+ throw new Error('Data is required for creation');
309
+ }
310
+ try {
311
+ const result = await supabase
312
+ .from('${typeName}')
313
+ .insert([data])
314
+ .select()
315
+ .single();
277
316
 
278
- if (result.data) {
317
+ if (result.error) {
318
+ throw new Error(\`Failed to create ${typeName}: \${result.error.message}\`);
319
+ }
320
+
321
+ if (!result.data) {
322
+ throw new Error('No data returned after creation');
323
+ }
324
+
279
325
  return result.data as ${typeName};
326
+ } catch (error) {
327
+ console.error('Error in ${createFunctionName}:', error);
328
+ throw error;
280
329
  }
281
- throw new Error('Failed to insert data');
282
330
  }
283
331
  `;
284
332
  const exportUpdateOperation = isView ? '' :
285
333
  `
286
334
  // Update Function
287
- async function ${updateFunctionName}(data: TablesUpdate<'${typeName}'> & { id: ${idType} }): Promise<${typeName}> {
288
- const result = await supabase.from('${typeName.toLowerCase()}').update(data).eq('id', data.id).select().single();
289
- if (result.data) {
335
+ export async function ${updateFunctionName}({ id, data }: { id: ${idType}; data: TablesUpdate<'${typeName}'> }): Promise<${typeName}> {
336
+ if (!id) {
337
+ throw new Error('ID is required for update');
338
+ }
339
+ if (!data || Object.keys(data).length === 0) {
340
+ throw new Error('Update data is required');
341
+ }
342
+ try {
343
+ const result = await supabase
344
+ .from('${typeName.toLowerCase()}')
345
+ .update(data)
346
+ .eq('id', id)
347
+ .select()
348
+ .single();
349
+
350
+ if (result.error) {
351
+ if (result.error.code === 'PGRST116') {
352
+ throw new Error(\`${typeName} with ID \${id} not found\`);
353
+ }
354
+ throw new Error(\`Failed to update ${typeName}: \${result.error.message}\`);
355
+ }
356
+
357
+ if (!result.data) {
358
+ throw new Error(\`${typeName} with ID \${id} not found\`);
359
+ }
360
+
290
361
  return result.data as ${typeName};
362
+ } catch (error) {
363
+ console.error('Error in ${updateFunctionName}:', error);
364
+ throw error;
291
365
  }
292
- throw new Error('Failed to update data');
293
366
  }
294
367
  `;
295
368
  const exportDeleteOperation = isView ? '' :
296
369
  `
297
370
  // Delete Function
298
- async function ${deleteFunctionName}(id: ${idType}): Promise<${typeName}> {
299
- const result = await supabase.from('${typeName.toLowerCase()}').delete().eq('id', id).select().single();
300
- if (result.data) {
301
- return result.data as ${typeName};
371
+ export async function ${deleteFunctionName}({ id }: { id: ${idType} }): Promise<boolean> {
372
+ if (!id) {
373
+ throw new Error('ID is required for deletion');
374
+ }
375
+ try {
376
+ const result = await supabase
377
+ .from('${typeName.toLowerCase()}')
378
+ .delete()
379
+ .eq('id', id);
380
+
381
+ if (result.error) {
382
+ throw new Error(\`Failed to delete ${typeName}: \${result.error.message}\`);
383
+ }
384
+
385
+ return true;
386
+ } catch (error) {
387
+ console.error('Error in ${deleteFunctionName}:', error);
388
+ throw error;
302
389
  }
303
- throw new Error('Failed to delete data');
304
390
  }
305
391
  `;
306
392
  // Export all functions
307
393
  const exportAll = `
308
- export { ${selectFilteredRowsFunctionName}, ${selectFilteredSingleRowFunctionName}${hasIdColumn ? ', ' + selectByIdFunctionName : ''}${isView ? '' : ', ' + insertFunctionName + ', ' + updateFunctionName + ', ' + deleteFunctionName} };
394
+ // All functions are exported individually above
309
395
  `;
310
396
  // Return all the code
311
397
  return exportHeaders + exportSelectQueries + (hasIdColumn ? exportSelectById : '') + exportInsertOperation + exportUpdateOperation + exportDeleteOperation + exportAll;
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTasksByFilters = getTasksByFilters;
4
+ exports.getTasksSingleByFilters = getTasksSingleByFilters;
5
+ exports.getTasksById = getTasksById;
6
+ exports.createTasks = createTasks;
7
+ exports.updateTasks = updateTasks;
8
+ exports.deleteTasks = deleteTasks;
9
+ exports.queryTasks = queryTasks;
10
+ // Supabase CRUD operations for tasks
11
+ // This file is automatically generated. Do not edit it directly.
12
+ const client_1 = require("../client");
13
+ // Function to apply filters to a query
14
+ function applyFilters(query, filters) {
15
+ for (const [key, value] of Object.entries(filters)) {
16
+ if (Array.isArray(value)) {
17
+ query = query.in(key, value); // Use 'in' for array values
18
+ }
19
+ else if (typeof value === 'object' && value !== null) {
20
+ for (const [operator, val] of Object.entries(value)) {
21
+ switch (operator) {
22
+ case 'eq':
23
+ query = query.eq(key, val);
24
+ break;
25
+ case 'neq':
26
+ query = query.neq(key, val);
27
+ break;
28
+ case 'like':
29
+ query = query.like(key, val);
30
+ break;
31
+ case 'ilike':
32
+ query = query.ilike(key, val);
33
+ break;
34
+ case 'lt':
35
+ query = query.lt(key, val);
36
+ break;
37
+ case 'lte':
38
+ query = query.lte(key, val);
39
+ break;
40
+ case 'gte':
41
+ query = query.gte(key, val);
42
+ break;
43
+ case 'gt':
44
+ query = query.gt(key, val);
45
+ break;
46
+ case 'contains':
47
+ query = query.contains(key, val);
48
+ break;
49
+ case 'contains_any':
50
+ query = query.contains_any(key, val);
51
+ break;
52
+ case 'contains_all':
53
+ query = query.contains_all(key, val);
54
+ break;
55
+ // Add more operators as needed
56
+ default:
57
+ throw new Error('Unsupported operator: ' + operator);
58
+ }
59
+ }
60
+ }
61
+ else {
62
+ query = query.eq(key, value); // Default to 'eq' for simple values
63
+ }
64
+ }
65
+ return query;
66
+ }
67
+ // Read multiple rows with dynamic filters
68
+ async function getTasksByFilters({ filters }) {
69
+ try {
70
+ let query = client_1.supabase.from('tasks').select('*');
71
+ query = applyFilters(query, filters);
72
+ const result = await query;
73
+ if (result.error) {
74
+ throw new Error(`Failed to fetch tasks: ${result.error.message}`);
75
+ }
76
+ return result.data || [];
77
+ }
78
+ catch (error) {
79
+ console.error('Error in getTasksByFilters:', error);
80
+ throw error;
81
+ }
82
+ }
83
+ // Read a single row with dynamic filters
84
+ async function getTasksSingleByFilters({ filters }) {
85
+ try {
86
+ let query = client_1.supabase.from('tasks').select('*');
87
+ query = applyFilters(query, filters).single();
88
+ const result = await query;
89
+ if (result.error) {
90
+ if (result.error.code === 'PGRST116') {
91
+ return null;
92
+ }
93
+ throw new Error(`Failed to fetch tasks: ${result.error.message}`);
94
+ }
95
+ return result.data;
96
+ }
97
+ catch (error) {
98
+ console.error('Error in getTasksSingleByFilters:', error);
99
+ throw error;
100
+ }
101
+ }
102
+ // Read single row using id
103
+ async function getTasksById({ id }) {
104
+ if (!id) {
105
+ throw new Error('ID is required');
106
+ }
107
+ try {
108
+ const result = await client_1.supabase
109
+ .from('tasks')
110
+ .select('*')
111
+ .eq('id', id)
112
+ .single();
113
+ if (result.error) {
114
+ if (result.error.code === 'PGRST116') {
115
+ return null;
116
+ }
117
+ throw new Error(`Failed to fetch tasks: ${result.error.message}`);
118
+ }
119
+ return result.data;
120
+ }
121
+ catch (error) {
122
+ console.error('Error in getTasksById:', error);
123
+ throw error;
124
+ }
125
+ }
126
+ // Create Function
127
+ async function createTasks({ data }) {
128
+ if (!data) {
129
+ throw new Error('Data is required for creation');
130
+ }
131
+ try {
132
+ const result = await client_1.supabase
133
+ .from('tasks')
134
+ .insert([data])
135
+ .select()
136
+ .single();
137
+ if (result.error) {
138
+ throw new Error(`Failed to create tasks: ${result.error.message}`);
139
+ }
140
+ if (!result.data) {
141
+ throw new Error('No data returned after creation');
142
+ }
143
+ return result.data;
144
+ }
145
+ catch (error) {
146
+ console.error('Error in createTasks:', error);
147
+ throw error;
148
+ }
149
+ }
150
+ // Update Function
151
+ async function updateTasks({ id, data }) {
152
+ if (!id) {
153
+ throw new Error('ID is required for update');
154
+ }
155
+ if (!data || Object.keys(data).length === 0) {
156
+ throw new Error('Update data is required');
157
+ }
158
+ try {
159
+ const result = await client_1.supabase
160
+ .from('tasks')
161
+ .update(data)
162
+ .eq('id', id)
163
+ .select()
164
+ .single();
165
+ if (result.error) {
166
+ if (result.error.code === 'PGRST116') {
167
+ throw new Error(`tasks with ID ${id} not found`);
168
+ }
169
+ throw new Error(`Failed to update tasks: ${result.error.message}`);
170
+ }
171
+ if (!result.data) {
172
+ throw new Error(`tasks with ID ${id} not found`);
173
+ }
174
+ return result.data;
175
+ }
176
+ catch (error) {
177
+ console.error('Error in updateTasks:', error);
178
+ throw error;
179
+ }
180
+ }
181
+ // Delete Function
182
+ async function deleteTasks({ id }) {
183
+ if (!id) {
184
+ throw new Error('ID is required for deletion');
185
+ }
186
+ try {
187
+ const result = await client_1.supabase
188
+ .from('tasks')
189
+ .delete()
190
+ .eq('id', id);
191
+ if (result.error) {
192
+ throw new Error(`Failed to delete tasks: ${result.error.message}`);
193
+ }
194
+ return true;
195
+ }
196
+ catch (error) {
197
+ console.error('Error in deleteTasks:', error);
198
+ throw error;
199
+ }
200
+ }
201
+ // Custom query function
202
+ async function queryTasks({ query }) {
203
+ if (!query) {
204
+ throw new Error('Query is required');
205
+ }
206
+ try {
207
+ const result = await client_1.supabase
208
+ .from('tasks')
209
+ .select(query);
210
+ if (result.error) {
211
+ throw new Error(`Failed to execute query: ${result.error.message}`);
212
+ }
213
+ return result.data || [];
214
+ }
215
+ catch (error) {
216
+ console.error('Error in queryTasks:', error);
217
+ throw error;
218
+ }
219
+ }
220
+ // All functions are exported individually above
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWorkflowsByFilters = getWorkflowsByFilters;
4
+ exports.getWorkflowsSingleByFilters = getWorkflowsSingleByFilters;
5
+ exports.getWorkflowsById = getWorkflowsById;
6
+ exports.createWorkflows = createWorkflows;
7
+ exports.updateWorkflows = updateWorkflows;
8
+ exports.deleteWorkflows = deleteWorkflows;
9
+ exports.queryWorkflows = queryWorkflows;
10
+ // Supabase CRUD operations for workflows
11
+ // This file is automatically generated. Do not edit it directly.
12
+ const client_1 = require("../client");
13
+ // Function to apply filters to a query
14
+ function applyFilters(query, filters) {
15
+ for (const [key, value] of Object.entries(filters)) {
16
+ if (Array.isArray(value)) {
17
+ query = query.in(key, value); // Use 'in' for array values
18
+ }
19
+ else if (typeof value === 'object' && value !== null) {
20
+ for (const [operator, val] of Object.entries(value)) {
21
+ switch (operator) {
22
+ case 'eq':
23
+ query = query.eq(key, val);
24
+ break;
25
+ case 'neq':
26
+ query = query.neq(key, val);
27
+ break;
28
+ case 'like':
29
+ query = query.like(key, val);
30
+ break;
31
+ case 'ilike':
32
+ query = query.ilike(key, val);
33
+ break;
34
+ case 'lt':
35
+ query = query.lt(key, val);
36
+ break;
37
+ case 'lte':
38
+ query = query.lte(key, val);
39
+ break;
40
+ case 'gte':
41
+ query = query.gte(key, val);
42
+ break;
43
+ case 'gt':
44
+ query = query.gt(key, val);
45
+ break;
46
+ case 'contains':
47
+ query = query.contains(key, val);
48
+ break;
49
+ case 'contains_any':
50
+ query = query.contains_any(key, val);
51
+ break;
52
+ case 'contains_all':
53
+ query = query.contains_all(key, val);
54
+ break;
55
+ // Add more operators as needed
56
+ default:
57
+ throw new Error('Unsupported operator: ' + operator);
58
+ }
59
+ }
60
+ }
61
+ else {
62
+ query = query.eq(key, value); // Default to 'eq' for simple values
63
+ }
64
+ }
65
+ return query;
66
+ }
67
+ // Read multiple rows with dynamic filters
68
+ async function getWorkflowsByFilters({ filters }) {
69
+ try {
70
+ let query = client_1.supabase.from('workflows').select('*');
71
+ query = applyFilters(query, filters);
72
+ const result = await query;
73
+ if (result.error) {
74
+ throw new Error(`Failed to fetch workflows: ${result.error.message}`);
75
+ }
76
+ return result.data || [];
77
+ }
78
+ catch (error) {
79
+ console.error('Error in getWorkflowsByFilters:', error);
80
+ throw error;
81
+ }
82
+ }
83
+ // Read a single row with dynamic filters
84
+ async function getWorkflowsSingleByFilters({ filters }) {
85
+ try {
86
+ let query = client_1.supabase.from('workflows').select('*');
87
+ query = applyFilters(query, filters).single();
88
+ const result = await query;
89
+ if (result.error) {
90
+ if (result.error.code === 'PGRST116') {
91
+ return null;
92
+ }
93
+ throw new Error(`Failed to fetch workflows: ${result.error.message}`);
94
+ }
95
+ return result.data;
96
+ }
97
+ catch (error) {
98
+ console.error('Error in getWorkflowsSingleByFilters:', error);
99
+ throw error;
100
+ }
101
+ }
102
+ // Read single row using id
103
+ async function getWorkflowsById({ id }) {
104
+ if (!id) {
105
+ throw new Error('ID is required');
106
+ }
107
+ try {
108
+ const result = await client_1.supabase
109
+ .from('workflows')
110
+ .select('*')
111
+ .eq('id', id)
112
+ .single();
113
+ if (result.error) {
114
+ if (result.error.code === 'PGRST116') {
115
+ return null;
116
+ }
117
+ throw new Error(`Failed to fetch workflows: ${result.error.message}`);
118
+ }
119
+ return result.data;
120
+ }
121
+ catch (error) {
122
+ console.error('Error in getWorkflowsById:', error);
123
+ throw error;
124
+ }
125
+ }
126
+ // Create Function
127
+ async function createWorkflows({ data }) {
128
+ if (!data) {
129
+ throw new Error('Data is required for creation');
130
+ }
131
+ try {
132
+ const result = await client_1.supabase
133
+ .from('workflows')
134
+ .insert([data])
135
+ .select()
136
+ .single();
137
+ if (result.error) {
138
+ throw new Error(`Failed to create workflows: ${result.error.message}`);
139
+ }
140
+ if (!result.data) {
141
+ throw new Error('No data returned after creation');
142
+ }
143
+ return result.data;
144
+ }
145
+ catch (error) {
146
+ console.error('Error in createWorkflows:', error);
147
+ throw error;
148
+ }
149
+ }
150
+ // Update Function
151
+ async function updateWorkflows({ id, data }) {
152
+ if (!id) {
153
+ throw new Error('ID is required for update');
154
+ }
155
+ if (!data || Object.keys(data).length === 0) {
156
+ throw new Error('Update data is required');
157
+ }
158
+ try {
159
+ const result = await client_1.supabase
160
+ .from('workflows')
161
+ .update(data)
162
+ .eq('id', id)
163
+ .select()
164
+ .single();
165
+ if (result.error) {
166
+ if (result.error.code === 'PGRST116') {
167
+ throw new Error(`workflows with ID ${id} not found`);
168
+ }
169
+ throw new Error(`Failed to update workflows: ${result.error.message}`);
170
+ }
171
+ if (!result.data) {
172
+ throw new Error(`workflows with ID ${id} not found`);
173
+ }
174
+ return result.data;
175
+ }
176
+ catch (error) {
177
+ console.error('Error in updateWorkflows:', error);
178
+ throw error;
179
+ }
180
+ }
181
+ // Delete Function
182
+ async function deleteWorkflows({ id }) {
183
+ if (!id) {
184
+ throw new Error('ID is required for deletion');
185
+ }
186
+ try {
187
+ const result = await client_1.supabase
188
+ .from('workflows')
189
+ .delete()
190
+ .eq('id', id);
191
+ if (result.error) {
192
+ throw new Error(`Failed to delete workflows: ${result.error.message}`);
193
+ }
194
+ return true;
195
+ }
196
+ catch (error) {
197
+ console.error('Error in deleteWorkflows:', error);
198
+ throw error;
199
+ }
200
+ }
201
+ // Custom query function
202
+ async function queryWorkflows({ query }) {
203
+ if (!query) {
204
+ throw new Error('Query is required');
205
+ }
206
+ try {
207
+ const result = await client_1.supabase
208
+ .from('workflows')
209
+ .select(query);
210
+ if (result.error) {
211
+ throw new Error(`Failed to execute query: ${result.error.message}`);
212
+ }
213
+ return result.data || [];
214
+ }
215
+ catch (error) {
216
+ console.error('Error in queryWorkflows:', error);
217
+ throw error;
218
+ }
219
+ }
220
+ // All functions are exported individually above
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supatool",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "A CLI tool for Supabase schema extraction and TypeScript CRUD generation with declarative database schema support.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",