dzql 0.5.32 → 0.6.0

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.
Files changed (150) hide show
  1. package/.env.sample +28 -0
  2. package/compose.yml +28 -0
  3. package/dist/client/index.ts +1 -0
  4. package/dist/client/stores/useMyProfileStore.ts +114 -0
  5. package/dist/client/stores/useOrgDashboardStore.ts +131 -0
  6. package/dist/client/stores/useVenueDetailStore.ts +117 -0
  7. package/dist/client/ws.ts +716 -0
  8. package/dist/db/migrations/000_core.sql +92 -0
  9. package/dist/db/migrations/20251229T212912022Z_schema.sql +3020 -0
  10. package/dist/db/migrations/20251229T212912022Z_subscribables.sql +371 -0
  11. package/dist/runtime/manifest.json +1562 -0
  12. package/docs/README.md +293 -36
  13. package/docs/feature-requests/applyPatch-bug-report.md +85 -0
  14. package/docs/feature-requests/connection-ready-profile.md +57 -0
  15. package/docs/feature-requests/hidden-bug-report.md +111 -0
  16. package/docs/feature-requests/hidden-fields-subscribables.md +34 -0
  17. package/docs/feature-requests/subscribable-param-key-bug.md +38 -0
  18. package/docs/feature-requests/todo.md +146 -0
  19. package/docs/for_ai.md +641 -0
  20. package/docs/project-setup.md +432 -0
  21. package/examples/blog.ts +50 -0
  22. package/examples/invalid.ts +18 -0
  23. package/examples/venues.js +485 -0
  24. package/package.json +23 -60
  25. package/src/cli/codegen/client.ts +99 -0
  26. package/src/cli/codegen/manifest.ts +95 -0
  27. package/src/cli/codegen/pinia.ts +174 -0
  28. package/src/cli/codegen/realtime.ts +58 -0
  29. package/src/cli/codegen/sql.ts +698 -0
  30. package/src/cli/codegen/subscribable_sql.ts +547 -0
  31. package/src/cli/codegen/subscribable_store.ts +184 -0
  32. package/src/cli/codegen/types.ts +142 -0
  33. package/src/cli/compiler/analyzer.ts +52 -0
  34. package/src/cli/compiler/graph_rules.ts +251 -0
  35. package/src/cli/compiler/ir.ts +233 -0
  36. package/src/cli/compiler/loader.ts +132 -0
  37. package/src/cli/compiler/permissions.ts +227 -0
  38. package/src/cli/index.ts +164 -0
  39. package/src/client/index.ts +1 -0
  40. package/src/client/ws.ts +286 -0
  41. package/src/create/.env.example +8 -0
  42. package/src/create/README.md +101 -0
  43. package/src/create/compose.yml +14 -0
  44. package/src/create/domain.ts +153 -0
  45. package/src/create/package.json +24 -0
  46. package/src/create/server.ts +18 -0
  47. package/src/create/setup.sh +11 -0
  48. package/src/create/tsconfig.json +15 -0
  49. package/src/runtime/auth.ts +39 -0
  50. package/src/runtime/db.ts +33 -0
  51. package/src/runtime/errors.ts +51 -0
  52. package/src/runtime/index.ts +98 -0
  53. package/src/runtime/js_functions.ts +63 -0
  54. package/src/runtime/manifest_loader.ts +29 -0
  55. package/src/runtime/namespace.ts +483 -0
  56. package/src/runtime/server.ts +87 -0
  57. package/src/runtime/ws.ts +197 -0
  58. package/src/shared/ir.ts +197 -0
  59. package/tests/client.test.ts +38 -0
  60. package/tests/codegen.test.ts +71 -0
  61. package/tests/compiler.test.ts +45 -0
  62. package/tests/graph_rules.test.ts +173 -0
  63. package/tests/integration/db.test.ts +174 -0
  64. package/tests/integration/e2e.test.ts +65 -0
  65. package/tests/integration/features.test.ts +922 -0
  66. package/tests/integration/full_stack.test.ts +262 -0
  67. package/tests/integration/setup.ts +45 -0
  68. package/tests/ir.test.ts +32 -0
  69. package/tests/namespace.test.ts +395 -0
  70. package/tests/permissions.test.ts +55 -0
  71. package/tests/pinia.test.ts +48 -0
  72. package/tests/realtime.test.ts +22 -0
  73. package/tests/runtime.test.ts +80 -0
  74. package/tests/subscribable_gen.test.ts +72 -0
  75. package/tests/subscribable_reactivity.test.ts +258 -0
  76. package/tests/venues_gen.test.ts +25 -0
  77. package/tsconfig.json +20 -0
  78. package/tsconfig.tsbuildinfo +1 -0
  79. package/README.md +0 -90
  80. package/bin/cli.js +0 -727
  81. package/docs/compiler/ADVANCED_FILTERS.md +0 -183
  82. package/docs/compiler/CODING_STANDARDS.md +0 -415
  83. package/docs/compiler/COMPARISON.md +0 -673
  84. package/docs/compiler/QUICKSTART.md +0 -326
  85. package/docs/compiler/README.md +0 -134
  86. package/docs/examples/README.md +0 -38
  87. package/docs/examples/blog.sql +0 -160
  88. package/docs/examples/venue-detail-simple.sql +0 -8
  89. package/docs/examples/venue-detail-subscribable.sql +0 -45
  90. package/docs/for-ai/claude-guide.md +0 -1210
  91. package/docs/getting-started/quickstart.md +0 -125
  92. package/docs/getting-started/subscriptions-quick-start.md +0 -203
  93. package/docs/getting-started/tutorial.md +0 -1104
  94. package/docs/guides/atomic-updates.md +0 -299
  95. package/docs/guides/client-stores.md +0 -730
  96. package/docs/guides/composite-primary-keys.md +0 -158
  97. package/docs/guides/custom-functions.md +0 -362
  98. package/docs/guides/drop-semantics.md +0 -554
  99. package/docs/guides/field-defaults.md +0 -240
  100. package/docs/guides/interpreter-vs-compiler.md +0 -237
  101. package/docs/guides/many-to-many.md +0 -929
  102. package/docs/guides/subscriptions.md +0 -537
  103. package/docs/reference/api.md +0 -1373
  104. package/docs/reference/client.md +0 -224
  105. package/src/client/stores/index.js +0 -8
  106. package/src/client/stores/useAppStore.js +0 -285
  107. package/src/client/stores/useWsStore.js +0 -289
  108. package/src/client/ws.js +0 -762
  109. package/src/compiler/cli/compile-example.js +0 -33
  110. package/src/compiler/cli/compile-subscribable.js +0 -43
  111. package/src/compiler/cli/debug-compile.js +0 -44
  112. package/src/compiler/cli/debug-parse.js +0 -26
  113. package/src/compiler/cli/debug-path-parser.js +0 -18
  114. package/src/compiler/cli/debug-subscribable-parser.js +0 -21
  115. package/src/compiler/cli/index.js +0 -174
  116. package/src/compiler/codegen/auth-codegen.js +0 -153
  117. package/src/compiler/codegen/drop-semantics-codegen.js +0 -553
  118. package/src/compiler/codegen/graph-rules-codegen.js +0 -450
  119. package/src/compiler/codegen/notification-codegen.js +0 -232
  120. package/src/compiler/codegen/operation-codegen.js +0 -1382
  121. package/src/compiler/codegen/permission-codegen.js +0 -318
  122. package/src/compiler/codegen/subscribable-codegen.js +0 -827
  123. package/src/compiler/compiler.js +0 -371
  124. package/src/compiler/index.js +0 -11
  125. package/src/compiler/parser/entity-parser.js +0 -440
  126. package/src/compiler/parser/path-parser.js +0 -290
  127. package/src/compiler/parser/subscribable-parser.js +0 -244
  128. package/src/database/dzql-core.sql +0 -161
  129. package/src/database/migrations/001_schema.sql +0 -60
  130. package/src/database/migrations/002_functions.sql +0 -890
  131. package/src/database/migrations/003_operations.sql +0 -1135
  132. package/src/database/migrations/004_search.sql +0 -581
  133. package/src/database/migrations/005_entities.sql +0 -730
  134. package/src/database/migrations/006_auth.sql +0 -94
  135. package/src/database/migrations/007_events.sql +0 -133
  136. package/src/database/migrations/008_hello.sql +0 -18
  137. package/src/database/migrations/008a_meta.sql +0 -172
  138. package/src/database/migrations/009_subscriptions.sql +0 -240
  139. package/src/database/migrations/010_atomic_updates.sql +0 -157
  140. package/src/database/migrations/010_fix_m2m_events.sql +0 -94
  141. package/src/index.js +0 -40
  142. package/src/server/api.js +0 -9
  143. package/src/server/db.js +0 -442
  144. package/src/server/index.js +0 -317
  145. package/src/server/logger.js +0 -259
  146. package/src/server/mcp.js +0 -594
  147. package/src/server/meta-route.js +0 -251
  148. package/src/server/namespace.js +0 -292
  149. package/src/server/subscriptions.js +0 -351
  150. package/src/server/ws.js +0 -573
@@ -1,125 +0,0 @@
1
- # DZQL Quick Start
2
-
3
- Get a real-time API with automatic CRUD in 5 minutes.
4
-
5
- ## Prerequisites
6
-
7
- - PostgreSQL (local or Docker)
8
- - Bun or Node.js 18+
9
-
10
- ## 1. Install
11
-
12
- ```bash
13
- mkdir my-app && cd my-app
14
- bun init -y
15
- bun add dzql
16
- ```
17
-
18
- ## 2. Start PostgreSQL
19
-
20
- ```bash
21
- docker run -d --name dzql-db \
22
- -e POSTGRES_USER=dzql \
23
- -e POSTGRES_PASSWORD=dzql \
24
- -e POSTGRES_DB=dzql \
25
- -p 5432:5432 \
26
- postgres:latest
27
-
28
- export DATABASE_URL="postgresql://dzql:dzql@localhost:5432/dzql"
29
- ```
30
-
31
- ## 3. Initialize Database
32
-
33
- ```bash
34
- bunx dzql db:init
35
- ```
36
-
37
- ## 4. Define Entities
38
-
39
- Create `entities.sql`:
40
-
41
- ```sql
42
- -- Schema
43
- CREATE TABLE users (
44
- id SERIAL PRIMARY KEY,
45
- email TEXT UNIQUE NOT NULL,
46
- name TEXT,
47
- created_at TIMESTAMPTZ DEFAULT now()
48
- );
49
-
50
- CREATE TABLE todos (
51
- id SERIAL PRIMARY KEY,
52
- title TEXT NOT NULL,
53
- completed BOOLEAN DEFAULT false,
54
- user_id INT REFERENCES users(id),
55
- created_at TIMESTAMPTZ DEFAULT now()
56
- );
57
-
58
- -- Register with DZQL
59
- SELECT dzql.register_entity('users', 'name', ARRAY['name', 'email']);
60
- SELECT dzql.register_entity('todos', 'title', ARRAY['title']);
61
- ```
62
-
63
- ## 5. Compile
64
-
65
- ```bash
66
- bunx dzql compile entities.sql -o init_db/
67
- ```
68
-
69
- ## 6. Apply
70
-
71
- ```bash
72
- psql $DATABASE_URL -f init_db/001_schema.sql
73
- psql $DATABASE_URL -f init_db/users.sql
74
- psql $DATABASE_URL -f init_db/todos.sql
75
- ```
76
-
77
- ## 7. Create Server
78
-
79
- Create `index.js`:
80
-
81
- ```javascript
82
- import { createServer } from 'dzql/server';
83
-
84
- createServer({ port: 3000 });
85
- console.log('Server running at http://localhost:3000');
86
- ```
87
-
88
- ## 8. Use
89
-
90
- ```javascript
91
- import { WebSocketManager } from 'dzql/client';
92
-
93
- const ws = new WebSocketManager();
94
- await ws.connect();
95
-
96
- // Auto-generated CRUD
97
- const todo = await ws.api.save.todos({ title: 'Buy milk' });
98
- const todos = await ws.api.search.todos({});
99
- await ws.api.save.todos({ id: todo.id, completed: true });
100
- await ws.api.delete.todos({ id: todo.id });
101
-
102
- // Real-time updates
103
- ws.onBroadcast((method, params) => {
104
- console.log('Change:', method, params);
105
- });
106
- ```
107
-
108
- ## What You Get
109
-
110
- For each entity:
111
- - `get_<entity>(user_id, id)` - Get by ID
112
- - `save_<entity>(user_id, data)` - Create or update
113
- - `delete_<entity>(user_id, id)` - Delete
114
- - `search_<entity>(user_id, filters, search, sort, page, limit)` - Search
115
-
116
- Plus:
117
- - Real-time updates via WebSocket
118
- - Permission checks in SQL
119
- - Audit trail in `dzql.events`
120
-
121
- ## Next Steps
122
-
123
- - [Full Tutorial](./tutorial.md) - Complete walkthrough
124
- - [Subscriptions](./subscriptions-quick-start.md) - Real-time denormalized documents
125
- - [API Reference](../reference/api.md) - All operations
@@ -1,203 +0,0 @@
1
- # Live Query Subscriptions - Quick Start
2
-
3
- Get up and running with live query subscriptions in 5 minutes.
4
-
5
- ## Step 1: Create a Subscribable (2 min)
6
-
7
- Create `my_subscribable.sql`:
8
-
9
- ```sql
10
- SELECT dzql.register_subscribable(
11
- 'venue_detail', -- Name (use in API)
12
- '{"subscribe": ["@org_id->acts_for[org_id=$]{active}.user_id"]}'::jsonb, -- Who can subscribe
13
- '{"venue_id": "int"}'::jsonb, -- Subscription parameters
14
- 'venues', -- Root table
15
- '{"org": "organisations", "sites": {"entity": "sites", "filter": "venue_id=$venue_id"}}'::jsonb -- Related data
16
- );
17
- ```
18
-
19
- ## Step 2: Compile and Deploy (1 min)
20
-
21
- ```bash
22
- # Compile to PostgreSQL functions
23
- bun packages/dzql/src/compiler/cli/compile-subscribable.js my_subscribable.sql | psql $DATABASE_URL
24
- ```
25
-
26
- This creates 3 functions:
27
- - `venue_detail_can_subscribe(user_id, params)` - permission check
28
- - `get_venue_detail(params, user_id)` - query builder
29
- - `venue_detail_affected_documents(table, op, old, new)` - change detector
30
-
31
- ## Step 3: Subscribe from Client (2 min)
32
-
33
- ```javascript
34
- import { WebSocketManager } from '@dzql/client';
35
-
36
- const ws = new WebSocketManager('ws://localhost:3000/ws');
37
- await ws.connect();
38
-
39
- // Subscribe - get initial data + live updates
40
- const { data, unsubscribe } = await ws.api.subscribe_venue_detail(
41
- { venue_id: 123 },
42
- (updatedData) => {
43
- console.log('Venue changed!', updatedData);
44
- }
45
- );
46
-
47
- console.log('Initial data:', data);
48
-
49
- // Later: cleanup
50
- await unsubscribe();
51
- ```
52
-
53
- ## That's It!
54
-
55
- Your client now receives real-time updates whenever:
56
- - The venue record changes
57
- - Related organisation changes
58
- - Related sites change
59
-
60
- All change detection happens in PostgreSQL - zero configuration needed on the server!
61
-
62
- ## Next Steps
63
-
64
- - [Full Documentation](../guides/subscriptions.md)
65
- - [Permission Paths Guide](../../../../docs/architecture/PERMISSIONS.md)
66
- - [API Reference](../reference/api.md)
67
-
68
- ## Common Patterns
69
-
70
- ### Simple Document (Single Table)
71
-
72
- ```sql
73
- SELECT dzql.register_subscribable(
74
- 'user_settings',
75
- '{"subscribe": ["@user_id"]}'::jsonb, -- Only owner
76
- '{"user_id": "int"}'::jsonb,
77
- 'user_settings',
78
- '{}'::jsonb -- No relations
79
- );
80
- ```
81
-
82
- ### With One Relation
83
-
84
- ```sql
85
- SELECT dzql.register_subscribable(
86
- 'booking_summary',
87
- '{"subscribe": ["@user_id"]}'::jsonb,
88
- '{"booking_id": "int"}'::jsonb,
89
- 'bookings',
90
- '{"venue": "venues"}'::jsonb -- Include venue
91
- );
92
- ```
93
-
94
- ### With Filtered Relations
95
-
96
- ```sql
97
- SELECT dzql.register_subscribable(
98
- 'organisation_dashboard',
99
- '{"subscribe": ["@id->acts_for[org_id=$]{active}.user_id"]}'::jsonb,
100
- '{"org_id": "int"}'::jsonb,
101
- 'organisations',
102
- '{
103
- "members": {
104
- "entity": "acts_for",
105
- "filter": "org_id=$org_id AND valid_to IS NULL"
106
- },
107
- "venues": {
108
- "entity": "venues",
109
- "filter": "org_id=$org_id"
110
- }
111
- }'::jsonb
112
- );
113
- ```
114
-
115
- ### Multiple Permission Paths (OR logic)
116
-
117
- ```sql
118
- SELECT dzql.register_subscribable(
119
- 'venue_admin',
120
- '{
121
- "subscribe": [
122
- "@owner_id", -- Direct owner
123
- "@org_id->acts_for[org_id=$]{active}.user_id" -- OR org member
124
- ]
125
- }'::jsonb,
126
- '{"venue_id": "int"}'::jsonb,
127
- 'venues',
128
- '{"sites": {"entity": "sites", "filter": "venue_id=$venue_id"}}'::jsonb
129
- );
130
- ```
131
-
132
- ## Debugging Tips
133
-
134
- ### Test the functions manually:
135
-
136
- ```sql
137
- -- Check permission
138
- SELECT venue_detail_can_subscribe(1, '{"venue_id": 123}'::jsonb);
139
-
140
- -- Get data
141
- SELECT get_venue_detail('{"venue_id": 123}'::jsonb, 1);
142
-
143
- -- Test change detection
144
- SELECT venue_detail_affected_documents(
145
- 'venues',
146
- 'update',
147
- '{"id": 123}'::jsonb,
148
- '{"id": 123, "name": "New"}'::jsonb
149
- );
150
- ```
151
-
152
- ### Check active subscriptions:
153
-
154
- ```javascript
155
- // Client-side
156
- console.log('My subscriptions:', ws.subscriptions.size);
157
- ```
158
-
159
- ## FAQ
160
-
161
- **Q: When should I use subscriptions vs. simple queries?**
162
- A: Use subscriptions when data changes frequently and client needs to stay in sync. Use simple queries for one-time lookups.
163
-
164
- **Q: What happens when client disconnects?**
165
- A: Server automatically cleans up all subscriptions for that connection.
166
-
167
- **Q: Can multiple clients subscribe to the same data?**
168
- A: Yes! Each subscription is independent. All will receive updates.
169
-
170
- **Q: How do I update the subscribable definition?**
171
- A: Re-compile and deploy. The `register_subscribable()` call uses `ON CONFLICT UPDATE`, so it's safe to run repeatedly.
172
-
173
- **Q: What if the underlying data is deleted?**
174
- A: The `get_<name>()` function returns `null`. Handle this in your callback:
175
- ```javascript
176
- (data) => {
177
- if (!data) {
178
- console.log('Record was deleted');
179
- return;
180
- }
181
- updateUI(data);
182
- }
183
- ```
184
-
185
- **Q: How do I subscribe to a list of items?**
186
- A: Create a subscribable with array parameters or use multiple subscriptions. For dashboard-style views, consider a single subscribable that returns an array.
187
-
188
- ## Performance Tips
189
-
190
- 1. **Index your joins**: Make sure foreign keys are indexed
191
- 2. **Keep _affected_documents() simple**: Early return for unrelated tables
192
- 3. **Limit relation depth**: Avoid deeply nested relations (max 2-3 levels)
193
- 4. **Use specific subscription keys**: `venue_id` is better than `org_id` (fewer false positives)
194
- 5. **Unsubscribe when done**: Always cleanup to free server resources
195
-
196
- ## Architecture Benefits
197
-
198
- - ✅ **PostgreSQL-First**: All logic in database, not application code
199
- - ✅ **Zero Configuration**: No server changes needed for new subscribables
200
- - ✅ **Type Safe**: Compiled functions validated at deploy time
201
- - ✅ **Efficient**: In-memory registry, PostgreSQL does matching
202
- - ✅ **Secure**: Permission paths enforced at database level
203
- - ✅ **Scalable**: Stateless server, can add instances freely