dzql 0.4.1 → 0.4.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dzql",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "PostgreSQL-powered framework with zero boilerplate CRUD operations and real-time WebSocket synchronization",
5
5
  "type": "module",
6
6
  "main": "src/server/index.js",
package/src/server/db.js CHANGED
@@ -173,50 +173,14 @@ export async function setupListeners(callback) {
173
173
  }
174
174
  }
175
175
 
176
- // Cache for mode detection (null = not checked, true = compiled, false = runtime)
177
- let isCompiledMode = null;
178
-
179
- // Auto-detect if we're in compiled or runtime mode
180
- async function detectMode() {
181
- if (isCompiledMode !== null) {
182
- return isCompiledMode;
183
- }
184
-
185
- try {
186
- // Check if dzql.generic_exec exists
187
- const result = await sql`
188
- SELECT 1 FROM pg_proc
189
- WHERE proname = 'generic_exec'
190
- AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'dzql')
191
- LIMIT 1
192
- `;
193
- isCompiledMode = result.length === 0; // If no results, it's compiled mode
194
- dbLogger.trace(isCompiledMode ? 'Detected compiled mode' : 'Detected runtime mode');
195
- } catch (error) {
196
- // If there's an error checking, assume runtime mode
197
- isCompiledMode = false;
198
- dbLogger.trace('Error detecting mode, assuming runtime mode');
199
- }
200
-
201
- return isCompiledMode;
202
- }
203
-
204
- // DZQL Generic Operations
176
+ // DZQL Generic Operations - Try compiled functions first, fall back to generic_exec
205
177
  export async function callDZQLOperation(operation, entity, args, userId) {
206
178
  dbLogger.trace(`DZQL ${operation}.${entity} for user ${userId}`);
207
179
 
208
- const compiled = await detectMode();
209
-
210
- if (!compiled) {
211
- // Runtime mode - use generic_exec
212
- const result = await sql`
213
- SELECT dzql.generic_exec(${operation}, ${entity}, ${args}, ${userId}) as result
214
- `;
215
- return result[0].result;
216
- } else {
217
- // Compiled mode - call compiled function directly
218
- const compiledFunctionName = `${operation}_${entity}`;
180
+ const compiledFunctionName = `${operation}_${entity}`;
219
181
 
182
+ try {
183
+ // Try compiled function first
220
184
  // Different operations have different signatures:
221
185
  // - search: search_entity(p_user_id, p_filters, p_search, p_sort, p_page, p_limit)
222
186
  // - get: get_entity(p_user_id, p_id, p_on_date)
@@ -259,6 +223,17 @@ export async function callDZQLOperation(operation, entity, args, userId) {
259
223
  } else {
260
224
  throw new Error(`Unknown operation: ${operation}`);
261
225
  }
226
+ } catch (error) {
227
+ // If compiled function doesn't exist, fall back to generic_exec
228
+ if (error.message?.includes('does not exist') || error.code === '42883') {
229
+ dbLogger.trace(`Compiled function ${compiledFunctionName} not found, trying generic_exec`);
230
+ const result = await sql`
231
+ SELECT dzql.generic_exec(${operation}, ${entity}, ${args}, ${userId}) as result
232
+ `;
233
+ return result[0].result;
234
+ }
235
+ // Re-throw other errors
236
+ throw error;
262
237
  }
263
238
  }
264
239
 
@@ -9,9 +9,10 @@ import { sql, db } from "./db.js";
9
9
  const DEFAULT_USER_ID = 1;
10
10
 
11
11
  /**
12
- * Discover available entities from dzql.entities table
12
+ * Discover available entities from dzql.entities table or compiled functions
13
13
  */
14
14
  async function discoverEntities() {
15
+ // First try dzql.entities table (runtime mode)
15
16
  const result = await sql`
16
17
  SELECT table_name, label_field, searchable_fields
17
18
  FROM dzql.entities
@@ -19,13 +20,36 @@ async function discoverEntities() {
19
20
  `;
20
21
 
21
22
  const entities = {};
22
- for (const row of result) {
23
- const searchFields = row.searchable_fields?.join(", ") || "none";
24
- entities[row.table_name] = {
25
- label: row.label_field,
26
- searchable: row.searchable_fields || [],
27
- description: `Entity: ${row.table_name} (label: ${row.label_field}, searchable: ${searchFields})`,
28
- };
23
+
24
+ if (result.length > 0) {
25
+ // Runtime mode - use dzql.entities table
26
+ for (const row of result) {
27
+ const searchFields = row.searchable_fields?.join(", ") || "none";
28
+ entities[row.table_name] = {
29
+ label: row.label_field,
30
+ searchable: row.searchable_fields || [],
31
+ description: `Entity: ${row.table_name} (label: ${row.label_field}, searchable: ${searchFields})`,
32
+ };
33
+ }
34
+ } else {
35
+ // Compiled mode - discover from function names
36
+ const functions = await sql`
37
+ SELECT DISTINCT substring(proname from 'search_(.+)') as entity_name
38
+ FROM pg_proc
39
+ WHERE pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public')
40
+ AND proname LIKE 'search_%'
41
+ AND substring(proname from 'search_(.+)') IS NOT NULL
42
+ ORDER BY entity_name
43
+ `;
44
+
45
+ for (const row of functions) {
46
+ const entityName = row.entity_name;
47
+ entities[entityName] = {
48
+ label: 'id', // Default, since we can't know from functions alone
49
+ searchable: [],
50
+ description: `Entity: ${entityName} (compiled mode)`,
51
+ };
52
+ }
29
53
  }
30
54
 
31
55
  return entities;