dzql 0.4.3 โ†’ 0.4.4

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
@@ -7,7 +7,7 @@ PostgreSQL-powered framework with automatic CRUD operations, live query subscrip
7
7
  - **[Documentation Hub](docs/)** - Complete documentation index
8
8
  - **[Getting Started Tutorial](docs/getting-started/tutorial.md)** - Complete tutorial with working todo app
9
9
  - **[API Reference](docs/reference/api.md)** - Complete API documentation
10
- - **[Live Query Subscriptions](docs/getting-started/subscriptions-quick-start.md)** - Real-time denormalized documents (NEW in v0.2.0)
10
+ - **[Live Query Subscriptions](docs/getting-started/subscriptions-quick-start.md)** - Real-time denormalized documents
11
11
  - **[Compiler Documentation](docs/compiler/)** - Entity compilation guide and coding standards
12
12
  - **[Claude Guide](docs/for-ai/claude-guide.md)** - Development guide for AI assistants
13
13
  - **[Venues Example](../venues/)** - Full working application
@@ -32,7 +32,7 @@ await ws.connect();
32
32
  const user = await ws.api.save.users({ name: 'Alice' });
33
33
  const results = await ws.api.search.users({ filters: { name: 'alice' } });
34
34
 
35
- // NEW in v0.2.0: Live query subscriptions
35
+ // Live query subscriptions
36
36
  const { data, unsubscribe } = await ws.api.subscribe_venue_detail(
37
37
  { venue_id: 123 },
38
38
  (updated) => console.log('Venue changed!', updated)
@@ -59,17 +59,20 @@ See **[Compiler Documentation](docs/compiler/)** for complete usage guide, codin
59
59
  ## Testing
60
60
 
61
61
  ```bash
62
- # Start test database
63
- cd tests/test-utils && docker compose up -d
62
+ # From repository root - start test database
63
+ docker compose up -d
64
+
65
+ # Initialize test database
66
+ bun run test:init
64
67
 
65
68
  # Run tests
66
69
  bun test
67
70
 
68
71
  # Stop database
69
- cd tests/test-utils && docker compose down
72
+ docker compose down
70
73
  ```
71
74
 
72
- All tests use `bun:test` framework with automatic database setup/teardown. See **[tests/test-utils/README.md](tests/test-utils/README.md)** for details.
75
+ All tests use `bun:test` framework. See **[tests/README.md](../../tests/README.md)** for details.
73
76
 
74
77
  ## License
75
78
 
package/docs/README.md CHANGED
@@ -7,6 +7,7 @@ Complete documentation for the DZQL PostgreSQL-powered framework.
7
7
  New to DZQL? Start here:
8
8
 
9
9
  - **[Tutorial](getting-started/tutorial.md)** - Complete step-by-step guide with a working todo app
10
+ - **[Interpreter vs Compiler](guides/interpreter-vs-compiler.md)** - Understand the two execution modes
10
11
  - **[Subscriptions Quick Start](getting-started/subscriptions-quick-start.md)** - Get real-time subscriptions working in 5 minutes
11
12
 
12
13
  ## ๐Ÿ“– Guides
@@ -14,6 +15,9 @@ New to DZQL? Start here:
14
15
  Feature-specific guides and how-tos:
15
16
 
16
17
  - **[Live Query Subscriptions](guides/subscriptions.md)** - Real-time denormalized documents
18
+ - **[Many-to-Many Relationships](guides/many-to-many.md)** - Junction table management
19
+ - **[Field Defaults](guides/field-defaults.md)** - Auto-populate fields on create
20
+ - **[Custom Functions](guides/custom-functions.md)** - Extend with PostgreSQL or Bun functions
17
21
  - **[Client Stores](guides/client-stores.md)** - Pinia store patterns for Vue.js
18
22
 
19
23
  ## ๐Ÿ“˜ Reference
@@ -29,7 +33,7 @@ Complete API documentation:
29
33
  - [Quickstart](compiler/QUICKSTART.md) - Get started with the DZQL compiler
30
34
  - [Advanced Filters](compiler/ADVANCED_FILTERS.md) - Complex search operators
31
35
  - [Coding Standards](compiler/CODING_STANDARDS.md) - Best practices for DZQL code
32
- - [Comparison](compiler/COMPARISON.md) - DZQL vs other approaches
36
+ - [Comparison](compiler/COMPARISON.md) - Runtime vs compiled side-by-side
33
37
 
34
38
  ## ๐Ÿค– For AI Assistants
35
39
 
@@ -40,28 +44,6 @@ Complete API documentation:
40
44
  - [npm Package](https://www.npmjs.com/package/dzql)
41
45
  - [GitHub Repository](https://github.com/blueshed/dzql)
42
46
  - [Issue Tracker](https://github.com/blueshed/dzql/issues)
43
- - [Changelog](../../../CHANGELOG.md)
44
- - [Contributing](../../../CONTRIBUTING.md)
45
-
46
- ## ๐Ÿ—๏ธ Architecture
47
-
48
- Looking for architecture and design docs? See the [repository docs](../../../docs/):
49
-
50
- - [Permissions System](../../../docs/architecture/PERMISSIONS.md)
51
- - [Project Roadmap](../../../docs/architecture/ROADMAP.md)
52
- - [Subscription Architecture](../../../docs/architecture/SUBSCRIPTIONS_STRATEGY.md)
53
-
54
- ## ๐Ÿงช Development
55
-
56
- Contributing to DZQL? See development documentation:
57
-
58
- - [TDD Workflow](../../../docs/development/TDD_WORKFLOW.md)
59
- - [WebSocket Testing](../../../docs/development/WEBSOCKET_TESTING.md)
60
- - [Claude Web Setup](../../../docs/development/CLAUDE-WEB.md)
61
-
62
- ## ๐Ÿ“ฆ Package Contents
63
-
64
- This documentation is published with the npm package. For repository-wide documentation (contributors, development workflow, architecture), see [`/docs/`](../../../docs/) in the repository root.
65
47
 
66
48
  ## Need Help?
67
49
 
@@ -2,6 +2,38 @@
2
2
 
3
3
  This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
4
 
5
+ ## Quick Reference Card
6
+
7
+ ```
8
+ DZQL QUICK REFERENCE
9
+ ====================
10
+
11
+ 5 Operations: get, save, delete, lookup, search
12
+ 2 Modes: Interpreter (runtime) | Compiler (static SQL)
13
+ Client API: ws.api.{operation}.{entity}(params)
14
+ Server API: db.api.{operation}.{entity}(params, userId)
15
+
16
+ Entity Registration:
17
+ dzql.register_entity(
18
+ table_name, -- 'todos'
19
+ label_field, -- 'title' (for lookups)
20
+ searchable_fields, -- ARRAY['title', 'description']
21
+ fk_includes, -- '{"org": "organisations"}'
22
+ soft_delete, -- false
23
+ temporal_fields, -- '{}'
24
+ notification_paths, -- '{"ownership": ["@org_id->acts_for..."]}'
25
+ permission_paths, -- '{"view": [], "create": [...]}'
26
+ graph_rules, -- '{"on_create": {...}, "many_to_many": {...}}'
27
+ field_defaults -- '{"owner_id": "@user_id"}'
28
+ )
29
+
30
+ M2M id_field naming: tag_ids (singular + _ids), NOT tags_ids
31
+ Permission [] = public, omitted = denied
32
+ Path syntax: @field->table[filter]{temporal}.target_field
33
+
34
+ Compile: dzql compile entities.sql -o compiled/
35
+ ```
36
+
5
37
  ## Project Overview
6
38
 
7
39
  DZQL is a PostgreSQL-powered framework that eliminates CRUD boilerplate by providing automatic database operations, real-time WebSocket synchronization, and graph-based relationship management. The core concept: register an entity in PostgreSQL and instantly get 5 standard operations (get, save, delete, lookup, search) plus real-time notifications with zero code.
@@ -0,0 +1,237 @@
1
+ # Interpreter vs Compiler Mode
2
+
3
+ DZQL offers two execution modes for your entities. Understanding when to use each is fundamental to getting the best out of the framework.
4
+
5
+ ## Quick Summary
6
+
7
+ | Aspect | Interpreter | Compiler |
8
+ |--------|-------------|----------|
9
+ | **Setup** | Register entity, use immediately | Register entity, compile, deploy SQL |
10
+ | **Performance** | ~8-12ms per operation | ~2-4ms per operation |
11
+ | **Debugging** | Opaque (dynamic SQL) | Transparent (static SQL) |
12
+ | **Best For** | Development, prototyping | Production, performance-critical |
13
+
14
+ ## How It Works
15
+
16
+ ### Interpreter Mode (Runtime)
17
+
18
+ Entity configuration is stored as JSON in `dzql.entities` table and parsed at runtime:
19
+
20
+ ```
21
+ Client Request โ†’ generic_exec() โ†’ Parse JSON config โ†’ Build SQL โ†’ Execute
22
+ ```
23
+
24
+ **Characteristics:**
25
+ - Zero build step - changes take effect immediately
26
+ - JSON config parsed on every request
27
+ - Dynamic SQL generated at runtime
28
+ - Generic query plans (harder to optimize)
29
+
30
+ **Usage:**
31
+ ```sql
32
+ -- Register entity
33
+ SELECT dzql.register_entity('todos', 'title', ARRAY['title'], ...);
34
+
35
+ -- Use immediately via generic executor
36
+ SELECT dzql.generic_exec('save', 'todos', '{"title": "Buy milk"}'::jsonb, 1);
37
+ ```
38
+
39
+ ### Compiler Mode (Static)
40
+
41
+ Entity configuration is compiled into dedicated PostgreSQL functions:
42
+
43
+ ```
44
+ Entity Definition โ†’ dzql compile โ†’ Static SQL Functions โ†’ Deploy โ†’ Execute
45
+ ```
46
+
47
+ **Characteristics:**
48
+ - Build step required
49
+ - No JSON parsing at runtime
50
+ - Static SQL with specific query plans
51
+ - PostgreSQL can optimize and cache plans
52
+
53
+ **Usage:**
54
+ ```bash
55
+ # Compile entities to SQL
56
+ dzql compile entities.sql -o compiled/
57
+
58
+ # Deploy to database
59
+ psql < compiled/entities.sql
60
+ ```
61
+
62
+ ```sql
63
+ -- Use compiled functions directly
64
+ SELECT save_todos('{"title": "Buy milk"}'::jsonb, 1);
65
+ ```
66
+
67
+ ## The Server Automatically Chooses
68
+
69
+ The DZQL server (`db.js`) automatically tries compiled functions first:
70
+
71
+ ```javascript
72
+ // In callDZQLOperation()
73
+ try {
74
+ // Try compiled function: save_todos()
75
+ const result = await sql.unsafe(`SELECT save_todos($1, $2)`, [data, userId]);
76
+ return result[0].result;
77
+ } catch (error) {
78
+ // If compiled function doesn't exist, fall back to interpreter
79
+ if (error.message.includes('save_todos') && error.code === '42883') {
80
+ return await sql`SELECT dzql.generic_exec('save', 'todos', ${data}, ${userId})`;
81
+ }
82
+ throw error;
83
+ }
84
+ ```
85
+
86
+ This means you can:
87
+ 1. Start with interpreter mode during development
88
+ 2. Compile and deploy when ready for production
89
+ 3. Mix and match - some entities compiled, others interpreted
90
+
91
+ ## Performance Comparison
92
+
93
+ ### Interpreter (Runtime Parsing)
94
+
95
+ ```sql
96
+ SELECT dzql.generic_exec('save', 'venues', '{"name": "MSG"}'::jsonb, 42);
97
+ ```
98
+
99
+ **Execution steps:**
100
+ 1. Fetch entity config from `dzql.entities` (table lookup)
101
+ 2. Parse `permission_paths` JSONB
102
+ 3. Build permission query dynamically
103
+ 4. Parse `graph_rules` JSONB
104
+ 5. Execute rules via dynamic SQL
105
+ 6. Parse `notification_paths` JSONB
106
+ 7. Resolve paths dynamically
107
+ 8. Execute the actual save
108
+
109
+ **Cost:** ~8-12ms, 3-5 JSONB parses, unpredictable query plans
110
+
111
+ ### Compiler (Pre-built Functions)
112
+
113
+ ```sql
114
+ SELECT save_venues('{"name": "MSG"}'::jsonb, 42);
115
+ ```
116
+
117
+ **Execution steps:**
118
+ 1. Call `can_update_venues()` - pre-compiled permission check
119
+ 2. Execute INSERT/UPDATE - direct SQL
120
+ 3. Call `graph_venues_on_create()` - pre-compiled graph rules
121
+ 4. Call `resolve_notification_paths_venues()` - pre-compiled
122
+ 5. Done
123
+
124
+ **Cost:** ~2-4ms, 0 JSONB parses, optimized query plans
125
+
126
+ ## When to Use Each
127
+
128
+ ### Use Interpreter When:
129
+ - Rapid prototyping and development
130
+ - Schema changes frequently
131
+ - Learning DZQL concepts
132
+ - Small applications with low traffic
133
+ - Need maximum flexibility
134
+
135
+ ### Use Compiler When:
136
+ - Production deployments
137
+ - Performance is critical
138
+ - Need predictable query performance
139
+ - Want reviewable/auditable SQL
140
+ - Large teams (generated SQL is easy to review)
141
+ - Complex permission or graph rules
142
+
143
+ ### Recommended Workflow:
144
+ 1. **Development:** Use interpreter for fast iteration
145
+ 2. **Staging:** Compile and test performance
146
+ 3. **Production:** Deploy compiled functions
147
+
148
+ ## Compiling Entities
149
+
150
+ ### Via CLI
151
+
152
+ ```bash
153
+ # Single file
154
+ dzql compile database/entities.sql -o compiled/
155
+
156
+ # Multiple files
157
+ dzql compile database/*.sql -o compiled/
158
+ ```
159
+
160
+ ### Programmatically
161
+
162
+ ```javascript
163
+ import { DZQLCompiler } from 'dzql/compiler';
164
+
165
+ const compiler = new DZQLCompiler();
166
+ const result = compiler.compileFromSQL(sqlContent);
167
+
168
+ console.log(result.sql); // Generated PostgreSQL functions
169
+ ```
170
+
171
+ ### What Gets Generated
172
+
173
+ For each entity, the compiler generates:
174
+
175
+ | Function | Purpose |
176
+ |----------|---------|
177
+ | `get_{entity}(id, user_id)` | Retrieve single record |
178
+ | `save_{entity}(data, user_id)` | Create or update |
179
+ | `delete_{entity}(id, user_id)` | Delete record |
180
+ | `lookup_{entity}(term, user_id)` | Autocomplete search |
181
+ | `search_{entity}(filters, user_id)` | Paginated search |
182
+ | `can_view_{entity}(user_id, record)` | Permission check |
183
+ | `can_create_{entity}(user_id, record)` | Permission check |
184
+ | `can_update_{entity}(user_id, record)` | Permission check |
185
+ | `can_delete_{entity}(user_id, record)` | Permission check |
186
+
187
+ ## Debugging
188
+
189
+ ### Interpreter Mode
190
+
191
+ Debugging is harder because SQL is generated dynamically:
192
+
193
+ ```sql
194
+ -- You see this
195
+ EXPLAIN ANALYZE SELECT dzql.generic_exec('save', 'venues', '...');
196
+
197
+ -- But the actual query is hidden inside
198
+ ```
199
+
200
+ ### Compiler Mode
201
+
202
+ Standard PostgreSQL tools work:
203
+
204
+ ```sql
205
+ -- See the actual function
206
+ \sf save_venues
207
+
208
+ -- Analyze performance
209
+ EXPLAIN ANALYZE SELECT save_venues('{"name": "MSG"}'::jsonb, 42);
210
+
211
+ -- Check slow queries
212
+ SELECT * FROM pg_stat_statements WHERE query LIKE '%save_venues%';
213
+ ```
214
+
215
+ ## Feature Parity
216
+
217
+ Both modes support the same features:
218
+
219
+ | Feature | Interpreter | Compiler |
220
+ |---------|-------------|----------|
221
+ | CRUD operations | โœ… | โœ… |
222
+ | Permission paths | โœ… | โœ… |
223
+ | Graph rules | โœ… | โœ… |
224
+ | Notification paths | โœ… | โœ… |
225
+ | FK includes | โœ… | โœ… |
226
+ | Many-to-many | โœ… | โœ… |
227
+ | Field defaults | โœ… | โœ… |
228
+ | Soft delete | โœ… | โœ… |
229
+ | Temporal fields | โœ… | โœ… |
230
+
231
+ The difference is purely in execution speed and debuggability, not functionality.
232
+
233
+ ## See Also
234
+
235
+ - [Compiler Quickstart](../compiler/QUICKSTART.md) - Get started with compilation
236
+ - [Compiler Comparison](../compiler/COMPARISON.md) - Detailed side-by-side analysis
237
+ - [API Reference](../reference/api.md) - The 5 operations
@@ -161,6 +161,23 @@ SELECT dzql.register_entity(
161
161
  | `id_field` | Yes | Field name for ID array in API | `"tag_ids"` |
162
162
  | `expand` | No | Include full objects (default: false) | `false` or `true` |
163
163
 
164
+ ### Naming Convention for `id_field`
165
+
166
+ **Important:** The `id_field` should use the **singular** form of the target entity, not plural:
167
+
168
+ | Target Entity | Correct `id_field` | Wrong |
169
+ |---------------|-------------------|-------|
170
+ | `tags` | `tag_ids` | `tags_ids` |
171
+ | `roles` | `role_ids` | `roles_ids` |
172
+ | `categories` | `category_ids` | `categories_ids` |
173
+ | `users` | `user_ids` | `users_ids` |
174
+
175
+ This convention matches common ORM patterns and is more readable:
176
+ - `tag_ids: [1, 2, 3]` reads as "tag IDs"
177
+ - `tags_ids: [1, 2, 3]` reads awkwardly as "tags IDs"
178
+
179
+ Using the wrong naming will cause the M2M sync to fail because the generated code looks for a field name that doesn't match what clients send.
180
+
164
181
  ### The `expand` Flag
165
182
 
166
183
  Controls whether full related objects are included in responses:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dzql",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
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",
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "scripts": {
26
26
  "test": "bun test ../../tests/core/*.test.js",
27
- "prepublishOnly": "echo 'โœ… Publishing DZQL v0.3.5...'"
27
+ "prepublishOnly": "echo 'โœ… Publishing DZQL...' "
28
28
  },
29
29
  "dependencies": {
30
30
  "jose": "^6.1.0",