dzql 0.5.0 → 0.5.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/bin/cli.js CHANGED
@@ -240,7 +240,7 @@ CREATE EXTENSION IF NOT EXISTS pgcrypto;
240
240
 
241
241
  -- Register new user
242
242
  -- p_options: optional JSON object with additional fields to set on the user record
243
- CREATE OR REPLACE FUNCTION register_user(p_email TEXT, p_password TEXT, p_options JSONB DEFAULT NULL)
243
+ CREATE OR REPLACE FUNCTION register_user(p_email TEXT, p_password TEXT, p_options JSON DEFAULT NULL)
244
244
  RETURNS JSONB
245
245
  LANGUAGE plpgsql
246
246
  SECURITY DEFINER
@@ -256,9 +256,10 @@ BEGIN
256
256
  v_hash := crypt(p_password, v_salt);
257
257
 
258
258
  -- Build insert data: options fields + email + password_hash
259
+ -- Cast p_options to JSONB for internal operations (JSON type is for API boundary convenience)
259
260
  v_insert_data := jsonb_build_object('email', p_email, 'password_hash', v_hash);
260
261
  IF p_options IS NOT NULL THEN
261
- v_insert_data := (p_options - 'id' - 'email' - 'password_hash' - 'password') || v_insert_data;
262
+ v_insert_data := (p_options::jsonb - 'id' - 'email' - 'password_hash' - 'password') || v_insert_data;
262
263
  END IF;
263
264
 
264
265
  -- Dynamic INSERT from JSONB
@@ -72,6 +72,72 @@ CREATE FUNCTION lookup_users(p_user_id INT, p_filter TEXT, ...)
72
72
  CREATE FUNCTION search_users(p_user_id INT, p_filters JSONB, ...)
73
73
  ```
74
74
 
75
+ ## JSON vs JSONB for Function Parameters
76
+
77
+ ### External API Parameters: Use JSON
78
+
79
+ When defining function parameters that accept JSON from external callers (API boundary), use `JSON` type (text-based) rather than `JSONB`. This allows callers to pass `JSON.stringify(options)` as a plain string without needing special serialization like `sql.json()`.
80
+
81
+ ```sql
82
+ -- ✅ CORRECT - JSON for external input parameters
83
+ CREATE FUNCTION register_user(
84
+ p_email TEXT,
85
+ p_password TEXT,
86
+ p_options JSON DEFAULT NULL -- Accepts plain JSON string from API
87
+ )
88
+
89
+ -- ❌ WRONG - JSONB requires special serialization from clients
90
+ CREATE FUNCTION register_user(
91
+ p_email TEXT,
92
+ p_password TEXT,
93
+ p_options JSONB DEFAULT NULL -- Harder to call from JavaScript
94
+ )
95
+ ```
96
+
97
+ ### Internal Operations: Cast to JSONB
98
+
99
+ Inside the function, cast to JSONB if you need JSONB operators (`->`, `->>`, `-`, `||`, `?`, etc.):
100
+
101
+ ```sql
102
+ CREATE FUNCTION register_user(p_email TEXT, p_password TEXT, p_options JSON DEFAULT NULL)
103
+ RETURNS JSONB AS $$
104
+ DECLARE
105
+ v_insert_data JSONB;
106
+ BEGIN
107
+ v_insert_data := jsonb_build_object('email', p_email);
108
+
109
+ IF p_options IS NOT NULL THEN
110
+ -- Cast to JSONB for internal operations
111
+ v_insert_data := (p_options::jsonb - 'id' - 'password') || v_insert_data;
112
+ END IF;
113
+
114
+ -- ...
115
+ END;
116
+ $$ LANGUAGE plpgsql;
117
+ ```
118
+
119
+ ### Table Columns: Use JSONB
120
+
121
+ Table columns should still use `JSONB` for efficient storage and indexing:
122
+
123
+ ```sql
124
+ -- ✅ CORRECT - JSONB for table columns
125
+ CREATE TABLE users (
126
+ id SERIAL PRIMARY KEY,
127
+ metadata JSONB DEFAULT '{}' -- Efficient storage & indexing
128
+ );
129
+ ```
130
+
131
+ ### Summary
132
+
133
+ | Context | Type | Reason |
134
+ |---------|------|--------|
135
+ | Function input parameters | `JSON` | Easy to pass from JavaScript (`JSON.stringify()`) |
136
+ | Internal function operations | `::jsonb` cast | Access to JSONB operators |
137
+ | Table columns | `JSONB` | Efficient storage and indexing |
138
+
139
+ This pattern - **JSON for input parameters, JSONB for storage** - eliminates serialization confusion at the API boundary.
140
+
75
141
  ## Function Categories
76
142
 
77
143
  ### Public API Functions (No underscore)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dzql",
3
- "version": "0.5.0",
3
+ "version": "0.5.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",
@@ -69,7 +69,7 @@ $$;`;
69
69
  -- p_options: optional JSON object with additional fields to set on the user record
70
70
  -- Example: register_user('test@example.com', 'password', '{"name": "Test User"}')
71
71
  -- ============================================================================
72
- CREATE OR REPLACE FUNCTION register_user(p_email TEXT, p_password TEXT, p_options JSONB DEFAULT NULL)
72
+ CREATE OR REPLACE FUNCTION register_user(p_email TEXT, p_password TEXT, p_options JSON DEFAULT NULL)
73
73
  RETURNS JSONB
74
74
  LANGUAGE plpgsql
75
75
  SECURITY DEFINER
@@ -85,9 +85,10 @@ BEGIN
85
85
  v_hash := crypt(p_password, v_salt);
86
86
 
87
87
  -- Build insert data: options fields + email + password_hash (options cannot override core fields)
88
+ -- Cast p_options to JSONB for internal operations (JSON type is for API boundary convenience)
88
89
  v_insert_data := jsonb_build_object('email', p_email, 'password_hash', v_hash);
89
90
  IF p_options IS NOT NULL THEN
90
- v_insert_data := (p_options - 'id' - 'email' - 'password_hash' - 'password') || v_insert_data;
91
+ v_insert_data := (p_options::jsonb - 'id' - 'email' - 'password_hash' - 'password') || v_insert_data;
91
92
  END IF;
92
93
 
93
94
  -- Dynamic INSERT from JSONB (same pattern as compiled save functions)