dzql 0.5.33 → 0.6.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/.env.sample +28 -0
- package/compose.yml +28 -0
- package/dist/client/index.ts +1 -0
- package/dist/client/stores/useMyProfileStore.ts +114 -0
- package/dist/client/stores/useOrgDashboardStore.ts +131 -0
- package/dist/client/stores/useVenueDetailStore.ts +117 -0
- package/dist/client/ws.ts +716 -0
- package/dist/db/migrations/000_core.sql +92 -0
- package/dist/db/migrations/20251229T212912022Z_schema.sql +3020 -0
- package/dist/db/migrations/20251229T212912022Z_subscribables.sql +371 -0
- package/dist/runtime/manifest.json +1562 -0
- package/docs/README.md +309 -36
- package/docs/feature-requests/applyPatch-bug-report.md +85 -0
- package/docs/feature-requests/connection-ready-profile.md +57 -0
- package/docs/feature-requests/hidden-bug-report.md +111 -0
- package/docs/feature-requests/hidden-fields-subscribables.md +34 -0
- package/docs/feature-requests/subscribable-param-key-bug.md +38 -0
- package/docs/feature-requests/todo.md +146 -0
- package/docs/for_ai.md +653 -0
- package/docs/project-setup.md +456 -0
- package/examples/blog.ts +50 -0
- package/examples/invalid.ts +18 -0
- package/examples/venues.js +485 -0
- package/package.json +23 -60
- package/src/cli/codegen/client.ts +99 -0
- package/src/cli/codegen/manifest.ts +95 -0
- package/src/cli/codegen/pinia.ts +174 -0
- package/src/cli/codegen/realtime.ts +58 -0
- package/src/cli/codegen/sql.ts +698 -0
- package/src/cli/codegen/subscribable_sql.ts +547 -0
- package/src/cli/codegen/subscribable_store.ts +184 -0
- package/src/cli/codegen/types.ts +142 -0
- package/src/cli/compiler/analyzer.ts +52 -0
- package/src/cli/compiler/graph_rules.ts +251 -0
- package/src/cli/compiler/ir.ts +233 -0
- package/src/cli/compiler/loader.ts +132 -0
- package/src/cli/compiler/permissions.ts +227 -0
- package/src/cli/index.ts +166 -0
- package/src/client/index.ts +1 -0
- package/src/client/ws.ts +286 -0
- package/src/runtime/auth.ts +39 -0
- package/src/runtime/db.ts +33 -0
- package/src/runtime/errors.ts +51 -0
- package/src/runtime/index.ts +98 -0
- package/src/runtime/js_functions.ts +63 -0
- package/src/runtime/manifest_loader.ts +29 -0
- package/src/runtime/namespace.ts +483 -0
- package/src/runtime/server.ts +87 -0
- package/src/runtime/ws.ts +197 -0
- package/src/shared/ir.ts +197 -0
- package/tests/client.test.ts +38 -0
- package/tests/codegen.test.ts +71 -0
- package/tests/compiler.test.ts +45 -0
- package/tests/graph_rules.test.ts +173 -0
- package/tests/integration/db.test.ts +174 -0
- package/tests/integration/e2e.test.ts +65 -0
- package/tests/integration/features.test.ts +922 -0
- package/tests/integration/full_stack.test.ts +262 -0
- package/tests/integration/setup.ts +45 -0
- package/tests/ir.test.ts +32 -0
- package/tests/namespace.test.ts +395 -0
- package/tests/permissions.test.ts +55 -0
- package/tests/pinia.test.ts +48 -0
- package/tests/realtime.test.ts +22 -0
- package/tests/runtime.test.ts +80 -0
- package/tests/subscribable_gen.test.ts +72 -0
- package/tests/subscribable_reactivity.test.ts +258 -0
- package/tests/venues_gen.test.ts +25 -0
- package/tsconfig.json +20 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/README.md +0 -90
- package/bin/cli.js +0 -727
- package/docs/compiler/ADVANCED_FILTERS.md +0 -183
- package/docs/compiler/CODING_STANDARDS.md +0 -415
- package/docs/compiler/COMPARISON.md +0 -673
- package/docs/compiler/QUICKSTART.md +0 -326
- package/docs/compiler/README.md +0 -134
- package/docs/examples/README.md +0 -38
- package/docs/examples/blog.sql +0 -160
- package/docs/examples/venue-detail-simple.sql +0 -8
- package/docs/examples/venue-detail-subscribable.sql +0 -45
- package/docs/for-ai/claude-guide.md +0 -1210
- package/docs/getting-started/quickstart.md +0 -125
- package/docs/getting-started/subscriptions-quick-start.md +0 -203
- package/docs/getting-started/tutorial.md +0 -1104
- package/docs/guides/atomic-updates.md +0 -299
- package/docs/guides/client-stores.md +0 -730
- package/docs/guides/composite-primary-keys.md +0 -158
- package/docs/guides/custom-functions.md +0 -362
- package/docs/guides/drop-semantics.md +0 -554
- package/docs/guides/field-defaults.md +0 -240
- package/docs/guides/interpreter-vs-compiler.md +0 -237
- package/docs/guides/many-to-many.md +0 -929
- package/docs/guides/subscriptions.md +0 -537
- package/docs/reference/api.md +0 -1373
- package/docs/reference/client.md +0 -224
- package/src/client/stores/index.js +0 -8
- package/src/client/stores/useAppStore.js +0 -285
- package/src/client/stores/useWsStore.js +0 -289
- package/src/client/ws.js +0 -762
- package/src/compiler/cli/compile-example.js +0 -33
- package/src/compiler/cli/compile-subscribable.js +0 -43
- package/src/compiler/cli/debug-compile.js +0 -44
- package/src/compiler/cli/debug-parse.js +0 -26
- package/src/compiler/cli/debug-path-parser.js +0 -18
- package/src/compiler/cli/debug-subscribable-parser.js +0 -21
- package/src/compiler/cli/index.js +0 -174
- package/src/compiler/codegen/auth-codegen.js +0 -153
- package/src/compiler/codegen/drop-semantics-codegen.js +0 -553
- package/src/compiler/codegen/graph-rules-codegen.js +0 -450
- package/src/compiler/codegen/notification-codegen.js +0 -232
- package/src/compiler/codegen/operation-codegen.js +0 -1382
- package/src/compiler/codegen/permission-codegen.js +0 -318
- package/src/compiler/codegen/subscribable-codegen.js +0 -827
- package/src/compiler/compiler.js +0 -371
- package/src/compiler/index.js +0 -11
- package/src/compiler/parser/entity-parser.js +0 -440
- package/src/compiler/parser/path-parser.js +0 -290
- package/src/compiler/parser/subscribable-parser.js +0 -244
- package/src/database/dzql-core.sql +0 -161
- package/src/database/migrations/001_schema.sql +0 -60
- package/src/database/migrations/002_functions.sql +0 -890
- package/src/database/migrations/003_operations.sql +0 -1135
- package/src/database/migrations/004_search.sql +0 -581
- package/src/database/migrations/005_entities.sql +0 -730
- package/src/database/migrations/006_auth.sql +0 -94
- package/src/database/migrations/007_events.sql +0 -133
- package/src/database/migrations/008_hello.sql +0 -18
- package/src/database/migrations/008a_meta.sql +0 -172
- package/src/database/migrations/009_subscriptions.sql +0 -240
- package/src/database/migrations/010_atomic_updates.sql +0 -157
- package/src/database/migrations/010_fix_m2m_events.sql +0 -94
- package/src/index.js +0 -40
- package/src/server/api.js +0 -9
- package/src/server/db.js +0 -442
- package/src/server/index.js +0 -317
- package/src/server/logger.js +0 -259
- package/src/server/mcp.js +0 -594
- package/src/server/meta-route.js +0 -251
- package/src/server/namespace.js +0 -292
- package/src/server/subscriptions.js +0 -351
- package/src/server/ws.js +0 -573
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
-- Migration 010: Atomic Updates for Subscribables
|
|
2
|
-
-- Adds extract_scope_tables function and updates register_subscribable to auto-populate scope_tables
|
|
3
|
-
|
|
4
|
-
-- ============================================================================
|
|
5
|
-
-- Helper function to extract scope tables from relations
|
|
6
|
-
-- ============================================================================
|
|
7
|
-
|
|
8
|
-
CREATE OR REPLACE FUNCTION dzql.extract_scope_tables(
|
|
9
|
-
p_root_entity TEXT,
|
|
10
|
-
p_relations JSONB
|
|
11
|
-
) RETURNS TEXT[] AS $$
|
|
12
|
-
DECLARE
|
|
13
|
-
v_tables TEXT[];
|
|
14
|
-
v_key TEXT;
|
|
15
|
-
v_value JSONB;
|
|
16
|
-
v_entity TEXT;
|
|
17
|
-
v_nested JSONB;
|
|
18
|
-
BEGIN
|
|
19
|
-
-- Start with root entity (may be NULL for dashboard mode)
|
|
20
|
-
IF p_root_entity IS NOT NULL AND p_root_entity != '' THEN
|
|
21
|
-
v_tables := ARRAY[p_root_entity];
|
|
22
|
-
ELSE
|
|
23
|
-
v_tables := ARRAY[]::TEXT[];
|
|
24
|
-
END IF;
|
|
25
|
-
|
|
26
|
-
-- Return early if no relations
|
|
27
|
-
IF p_relations IS NULL OR p_relations = '{}'::jsonb THEN
|
|
28
|
-
RETURN v_tables;
|
|
29
|
-
END IF;
|
|
30
|
-
|
|
31
|
-
-- Iterate through relations
|
|
32
|
-
FOR v_key, v_value IN SELECT * FROM jsonb_each(p_relations)
|
|
33
|
-
LOOP
|
|
34
|
-
-- Handle string relation (simple FK expansion): "org": "organisations"
|
|
35
|
-
IF jsonb_typeof(v_value) = 'string' THEN
|
|
36
|
-
v_entity := v_value #>> '{}';
|
|
37
|
-
IF v_entity IS NOT NULL AND v_entity != '' THEN
|
|
38
|
-
v_tables := array_append(v_tables, v_entity);
|
|
39
|
-
END IF;
|
|
40
|
-
-- Handle object relation: {"entity": "sites", "filter": "..."}
|
|
41
|
-
ELSIF jsonb_typeof(v_value) = 'object' THEN
|
|
42
|
-
v_entity := v_value ->> 'entity';
|
|
43
|
-
IF v_entity IS NOT NULL AND v_entity != '' THEN
|
|
44
|
-
v_tables := array_append(v_tables, v_entity);
|
|
45
|
-
END IF;
|
|
46
|
-
|
|
47
|
-
-- Recursively handle nested relations (include or relations)
|
|
48
|
-
v_nested := v_value -> 'include';
|
|
49
|
-
IF v_nested IS NOT NULL AND jsonb_typeof(v_nested) = 'object' THEN
|
|
50
|
-
v_tables := v_tables || dzql.extract_scope_tables(NULL, v_nested);
|
|
51
|
-
END IF;
|
|
52
|
-
|
|
53
|
-
v_nested := v_value -> 'relations';
|
|
54
|
-
IF v_nested IS NOT NULL AND jsonb_typeof(v_nested) = 'object' THEN
|
|
55
|
-
v_tables := v_tables || dzql.extract_scope_tables(NULL, v_nested);
|
|
56
|
-
END IF;
|
|
57
|
-
END IF;
|
|
58
|
-
END LOOP;
|
|
59
|
-
|
|
60
|
-
-- Remove duplicates and nulls
|
|
61
|
-
SELECT array_agg(DISTINCT t) INTO v_tables
|
|
62
|
-
FROM unnest(v_tables) t
|
|
63
|
-
WHERE t IS NOT NULL;
|
|
64
|
-
|
|
65
|
-
RETURN COALESCE(v_tables, ARRAY[]::TEXT[]);
|
|
66
|
-
END;
|
|
67
|
-
$$ LANGUAGE plpgsql IMMUTABLE;
|
|
68
|
-
|
|
69
|
-
COMMENT ON FUNCTION dzql.extract_scope_tables IS
|
|
70
|
-
'Extract all table names from a subscribable definition (root entity + all relations recursively)';
|
|
71
|
-
|
|
72
|
-
-- ============================================================================
|
|
73
|
-
-- Update register_subscribable to auto-populate scope_tables
|
|
74
|
-
-- ============================================================================
|
|
75
|
-
|
|
76
|
-
CREATE OR REPLACE FUNCTION dzql.register_subscribable(
|
|
77
|
-
p_name TEXT,
|
|
78
|
-
p_permission_paths JSONB,
|
|
79
|
-
p_param_schema JSONB,
|
|
80
|
-
p_root_entity TEXT,
|
|
81
|
-
p_relations JSONB
|
|
82
|
-
) RETURNS TEXT AS $$
|
|
83
|
-
DECLARE
|
|
84
|
-
v_result TEXT;
|
|
85
|
-
v_scope_tables TEXT[];
|
|
86
|
-
BEGIN
|
|
87
|
-
-- Validate inputs
|
|
88
|
-
IF p_name IS NULL OR p_name = '' THEN
|
|
89
|
-
RAISE EXCEPTION 'Subscribable name cannot be empty';
|
|
90
|
-
END IF;
|
|
91
|
-
|
|
92
|
-
-- NULL root_entity is allowed for dashboard mode (pure collections)
|
|
93
|
-
-- But if relations is also empty, that's an error
|
|
94
|
-
IF (p_root_entity IS NULL OR p_root_entity = '') AND
|
|
95
|
-
(p_relations IS NULL OR p_relations = '{}'::jsonb) THEN
|
|
96
|
-
RAISE EXCEPTION 'Subscribable must have either a root entity or relations';
|
|
97
|
-
END IF;
|
|
98
|
-
|
|
99
|
-
-- Extract scope tables from root entity and relations
|
|
100
|
-
v_scope_tables := dzql.extract_scope_tables(p_root_entity, p_relations);
|
|
101
|
-
|
|
102
|
-
-- Insert or update subscribable
|
|
103
|
-
INSERT INTO dzql.subscribables (
|
|
104
|
-
name,
|
|
105
|
-
permission_paths,
|
|
106
|
-
param_schema,
|
|
107
|
-
root_entity,
|
|
108
|
-
relations,
|
|
109
|
-
scope_tables,
|
|
110
|
-
created_at,
|
|
111
|
-
updated_at
|
|
112
|
-
) VALUES (
|
|
113
|
-
p_name,
|
|
114
|
-
COALESCE(p_permission_paths, '{}'::jsonb),
|
|
115
|
-
COALESCE(p_param_schema, '{}'::jsonb),
|
|
116
|
-
NULLIF(p_root_entity, ''), -- Store empty string as NULL
|
|
117
|
-
COALESCE(p_relations, '{}'::jsonb),
|
|
118
|
-
v_scope_tables,
|
|
119
|
-
NOW(),
|
|
120
|
-
NOW()
|
|
121
|
-
)
|
|
122
|
-
ON CONFLICT (name) DO UPDATE SET
|
|
123
|
-
permission_paths = EXCLUDED.permission_paths,
|
|
124
|
-
param_schema = EXCLUDED.param_schema,
|
|
125
|
-
root_entity = EXCLUDED.root_entity,
|
|
126
|
-
relations = EXCLUDED.relations,
|
|
127
|
-
scope_tables = EXCLUDED.scope_tables,
|
|
128
|
-
updated_at = NOW();
|
|
129
|
-
|
|
130
|
-
v_result := format('Subscribable "%s" registered successfully with scope tables: %s',
|
|
131
|
-
p_name, array_to_string(v_scope_tables, ', '));
|
|
132
|
-
|
|
133
|
-
RAISE NOTICE '%', v_result;
|
|
134
|
-
|
|
135
|
-
RETURN v_result;
|
|
136
|
-
END;
|
|
137
|
-
$$ LANGUAGE plpgsql;
|
|
138
|
-
|
|
139
|
-
-- ============================================================================
|
|
140
|
-
-- Backfill existing subscribables with scope_tables
|
|
141
|
-
-- ============================================================================
|
|
142
|
-
|
|
143
|
-
UPDATE dzql.subscribables s
|
|
144
|
-
SET scope_tables = dzql.extract_scope_tables(s.root_entity, s.relations)
|
|
145
|
-
WHERE scope_tables = '{}' OR scope_tables IS NULL;
|
|
146
|
-
|
|
147
|
-
-- ============================================================================
|
|
148
|
-
-- Verification
|
|
149
|
-
-- ============================================================================
|
|
150
|
-
|
|
151
|
-
DO $$
|
|
152
|
-
BEGIN
|
|
153
|
-
RAISE NOTICE 'Migration 010: Atomic Updates - Complete';
|
|
154
|
-
RAISE NOTICE 'Created dzql.extract_scope_tables() function';
|
|
155
|
-
RAISE NOTICE 'Updated dzql.register_subscribable() to auto-populate scope_tables';
|
|
156
|
-
RAISE NOTICE 'Backfilled existing subscribables';
|
|
157
|
-
END $$;
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
-- ============================================================================
|
|
2
|
-
-- Migration 010: Fix M2M in Event "before" Field
|
|
3
|
-
-- ============================================================================
|
|
4
|
-
--
|
|
5
|
-
-- Issue: UPDATE events don't include M2M data in the "before" field
|
|
6
|
-
-- Root cause: l_existing_record in generic_save doesn't expand M2M relationships
|
|
7
|
-
-- Fix: Create a helper function to expand M2M, then update generic_save to use it
|
|
8
|
-
--
|
|
9
|
-
-- This ensures UPDATE events have complete before/after state including M2M data
|
|
10
|
-
-- ============================================================================
|
|
11
|
-
|
|
12
|
-
DO $$ BEGIN
|
|
13
|
-
RAISE NOTICE 'Migration 010: Fixing M2M in event before field...';
|
|
14
|
-
END $$;
|
|
15
|
-
|
|
16
|
-
-- Create helper function to expand M2M relationships for a record
|
|
17
|
-
CREATE OR REPLACE FUNCTION dzql.expand_m2m_for_record(
|
|
18
|
-
p_entity text,
|
|
19
|
-
p_record jsonb,
|
|
20
|
-
p_entity_config record,
|
|
21
|
-
p_pk_cols text[]
|
|
22
|
-
) RETURNS jsonb
|
|
23
|
-
LANGUAGE plpgsql
|
|
24
|
-
AS $$
|
|
25
|
-
DECLARE
|
|
26
|
-
l_result jsonb := p_record;
|
|
27
|
-
l_m2m_key text;
|
|
28
|
-
l_m2m_config jsonb;
|
|
29
|
-
l_id_field text;
|
|
30
|
-
l_junction_table text;
|
|
31
|
-
l_local_key text;
|
|
32
|
-
l_foreign_key text;
|
|
33
|
-
l_target_entity text;
|
|
34
|
-
l_expand boolean;
|
|
35
|
-
l_record_id text;
|
|
36
|
-
l_id_array jsonb;
|
|
37
|
-
l_expanded_objects jsonb;
|
|
38
|
-
BEGIN
|
|
39
|
-
-- Only expand if entity has M2M configuration
|
|
40
|
-
IF p_entity_config.many_to_many IS NULL OR p_entity_config.many_to_many = '{}'::jsonb THEN
|
|
41
|
-
RETURN l_result;
|
|
42
|
-
END IF;
|
|
43
|
-
|
|
44
|
-
-- Get the primary key value from the record
|
|
45
|
-
l_record_id := l_result->>p_pk_cols[1]; -- Assume single PK for now
|
|
46
|
-
|
|
47
|
-
IF l_record_id IS NULL THEN
|
|
48
|
-
RETURN l_result;
|
|
49
|
-
END IF;
|
|
50
|
-
|
|
51
|
-
-- Loop through all M2M relationships
|
|
52
|
-
FOR l_m2m_key IN SELECT jsonb_object_keys(p_entity_config.many_to_many)
|
|
53
|
-
LOOP
|
|
54
|
-
l_m2m_config := p_entity_config.many_to_many->l_m2m_key;
|
|
55
|
-
l_id_field := l_m2m_config->>'id_field';
|
|
56
|
-
l_junction_table := l_m2m_config->>'junction_table';
|
|
57
|
-
l_local_key := l_m2m_config->>'local_key';
|
|
58
|
-
l_foreign_key := l_m2m_config->>'foreign_key';
|
|
59
|
-
l_target_entity := l_m2m_config->>'target_entity';
|
|
60
|
-
l_expand := COALESCE((l_m2m_config->>'expand')::boolean, false);
|
|
61
|
-
|
|
62
|
-
-- Always include array of IDs
|
|
63
|
-
EXECUTE format('
|
|
64
|
-
SELECT COALESCE(jsonb_agg(%I ORDER BY %I), ''[]''::jsonb)
|
|
65
|
-
FROM %I
|
|
66
|
-
WHERE %I = $1::int
|
|
67
|
-
', l_foreign_key, l_foreign_key, l_junction_table, l_local_key)
|
|
68
|
-
INTO l_id_array
|
|
69
|
-
USING l_record_id;
|
|
70
|
-
|
|
71
|
-
l_result := l_result || jsonb_build_object(l_id_field, l_id_array);
|
|
72
|
-
|
|
73
|
-
-- Conditionally include expanded objects if expand: true
|
|
74
|
-
IF l_expand THEN
|
|
75
|
-
EXECUTE format('
|
|
76
|
-
SELECT COALESCE(jsonb_agg(to_jsonb(t.*) ORDER BY t.id), ''[]''::jsonb)
|
|
77
|
-
FROM %I jt
|
|
78
|
-
JOIN %I t ON t.id = jt.%I
|
|
79
|
-
WHERE jt.%I = $1::int
|
|
80
|
-
', l_junction_table, l_target_entity, l_foreign_key, l_local_key)
|
|
81
|
-
INTO l_expanded_objects
|
|
82
|
-
USING l_record_id;
|
|
83
|
-
|
|
84
|
-
l_result := l_result || jsonb_build_object(l_m2m_key, l_expanded_objects);
|
|
85
|
-
END IF;
|
|
86
|
-
END LOOP;
|
|
87
|
-
|
|
88
|
-
RETURN l_result;
|
|
89
|
-
END $$;
|
|
90
|
-
|
|
91
|
-
DO $$ BEGIN
|
|
92
|
-
RAISE NOTICE 'Migration 010: M2M expansion helper function created';
|
|
93
|
-
RAISE NOTICE 'Note: generic_save still needs updating to use this helper - will be done in next migration';
|
|
94
|
-
END $$;
|
package/src/index.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* DZQL Demo Server
|
|
4
|
-
*
|
|
5
|
-
* Minimal example server that serves demo.html and provides WebSocket functionality.
|
|
6
|
-
* Run with: bun packages/dzql/src/index.js
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { createServer } from './server/index.js';
|
|
10
|
-
import { fileURLToPath } from 'url';
|
|
11
|
-
import { dirname, join } from 'path';
|
|
12
|
-
|
|
13
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
-
const __dirname = dirname(__filename);
|
|
15
|
-
|
|
16
|
-
// Path to demo.html
|
|
17
|
-
const demoPath = join(__dirname, 'client/demo.html');
|
|
18
|
-
|
|
19
|
-
// Create DZQL server with demo route
|
|
20
|
-
const app = createServer({
|
|
21
|
-
port: 3000,
|
|
22
|
-
routes: {
|
|
23
|
-
'/': async () => {
|
|
24
|
-
const file = Bun.file(demoPath);
|
|
25
|
-
return new Response(file, {
|
|
26
|
-
headers: { 'Content-Type': 'text/html' }
|
|
27
|
-
});
|
|
28
|
-
},
|
|
29
|
-
'/demo': async () => {
|
|
30
|
-
const file = Bun.file(demoPath);
|
|
31
|
-
return new Response(file, {
|
|
32
|
-
headers: { 'Content-Type': 'text/html' }
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
console.log('🚀 DZQL Demo Server running');
|
|
39
|
-
console.log('📝 Visit http://localhost:3000 to see the demo');
|
|
40
|
-
console.log('🔌 WebSocket available at ws://localhost:3000/ws');
|