dzql 0.1.5 → 0.2.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.
- package/README.md +8 -1
- package/docs/CLIENT-QUICK-START.md +183 -0
- package/docs/CLIENT-STORES.md +730 -0
- package/docs/REFERENCE.md +139 -0
- package/package.json +5 -2
- package/src/client/stores/README.md +95 -0
- package/src/client/stores/index.js +8 -0
- package/src/client/stores/useAppStore.js +285 -0
- package/src/client/stores/useWsStore.js +289 -0
- package/src/client/ws.js +87 -2
- package/src/compiler/codegen/operation-codegen.js +28 -3
- package/src/compiler/codegen/subscribable-codegen.js +396 -0
- package/src/compiler/compiler.js +115 -0
- package/src/compiler/parser/subscribable-parser.js +242 -0
- package/src/database/migrations/009_subscriptions.sql +230 -0
- package/src/index.js +35 -14
- package/src/server/index.js +90 -1
- package/src/server/subscriptions.js +209 -0
- package/src/server/ws.js +78 -2
- package/src/client/ui-configs/sample-2.js +0 -207
- package/src/client/ui-loader.js +0 -618
- package/src/client/ui.js +0 -990
- package/src/client.js +0 -9
package/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# DZQL
|
|
2
2
|
|
|
3
|
-
PostgreSQL-powered framework with automatic CRUD operations and real-time WebSocket synchronization.
|
|
3
|
+
PostgreSQL-powered framework with automatic CRUD operations, live query subscriptions, and real-time WebSocket synchronization.
|
|
4
4
|
|
|
5
5
|
## Documentation
|
|
6
6
|
|
|
7
7
|
- **[Getting Started Guide](docs/GETTING_STARTED.md)** - Complete tutorial with working todo app
|
|
8
8
|
- **[API Reference](docs/REFERENCE.md)** - Complete API documentation
|
|
9
|
+
- **[Live Query Subscriptions](../../docs/SUBSCRIPTIONS_QUICK_START.md)** - Real-time denormalized documents (NEW in v0.2.0)
|
|
9
10
|
- **[Compiler Documentation](docs/compiler/)** - Entity compilation guide and coding standards
|
|
10
11
|
- **[Claude Guide](docs/CLAUDE.md)** - Development guide for AI assistants
|
|
11
12
|
- **[Venues Example](../venues/)** - Full working application
|
|
@@ -29,6 +30,12 @@ await ws.connect();
|
|
|
29
30
|
// All 5 operations work automatically
|
|
30
31
|
const user = await ws.api.save.users({ name: 'Alice' });
|
|
31
32
|
const results = await ws.api.search.users({ filters: { name: 'alice' } });
|
|
33
|
+
|
|
34
|
+
// NEW in v0.2.0: Live query subscriptions
|
|
35
|
+
const { data, unsubscribe } = await ws.api.subscribe_venue_detail(
|
|
36
|
+
{ venue_id: 123 },
|
|
37
|
+
(updated) => console.log('Venue changed!', updated)
|
|
38
|
+
);
|
|
32
39
|
```
|
|
33
40
|
|
|
34
41
|
## DZQL Compiler
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# DZQL Client Quick Start
|
|
2
|
+
|
|
3
|
+
**TL;DR:** Copy-paste guide to get a DZQL Vue.js app running in minutes.
|
|
4
|
+
|
|
5
|
+
## 1. Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install dzql pinia vue-router
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 2. Copy Template
|
|
12
|
+
|
|
13
|
+
Copy the canonical App.vue template:
|
|
14
|
+
```bash
|
|
15
|
+
cp node_modules/dzql/src/client/templates/App.vue src/App.vue
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or create it manually:
|
|
19
|
+
|
|
20
|
+
**src/App.vue:**
|
|
21
|
+
```vue
|
|
22
|
+
<script setup>
|
|
23
|
+
import { computed, onMounted } from 'vue'
|
|
24
|
+
import { useWsStore, useAppStore } from 'dzql/client/stores'
|
|
25
|
+
import LoginView from './components/LoginView.vue'
|
|
26
|
+
|
|
27
|
+
const wsStore = useWsStore()
|
|
28
|
+
const appStore = useAppStore()
|
|
29
|
+
const state = computed(() => wsStore.appState)
|
|
30
|
+
const profile = computed(() => wsStore.profile)
|
|
31
|
+
|
|
32
|
+
onMounted(() => {
|
|
33
|
+
appStore.initialize({ title: 'My App' })
|
|
34
|
+
})
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<!-- CONNECTING -->
|
|
39
|
+
<div v-if="state === 'connecting'">Connecting...</div>
|
|
40
|
+
|
|
41
|
+
<!-- LOGIN -->
|
|
42
|
+
<LoginView v-else-if="state === 'login'" />
|
|
43
|
+
|
|
44
|
+
<!-- READY -->
|
|
45
|
+
<div v-else>
|
|
46
|
+
<nav>
|
|
47
|
+
<h1>{{ appStore.title }}</h1>
|
|
48
|
+
<button @click="wsStore.logout()">Logout</button>
|
|
49
|
+
</nav>
|
|
50
|
+
<router-view />
|
|
51
|
+
</div>
|
|
52
|
+
</template>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 3. Create LoginView
|
|
56
|
+
|
|
57
|
+
**src/components/LoginView.vue:**
|
|
58
|
+
```vue
|
|
59
|
+
<script setup>
|
|
60
|
+
import { ref } from 'vue'
|
|
61
|
+
import { useWsStore } from 'dzql/client/stores'
|
|
62
|
+
|
|
63
|
+
const wsStore = useWsStore()
|
|
64
|
+
const email = ref('')
|
|
65
|
+
const password = ref('')
|
|
66
|
+
|
|
67
|
+
async function login() {
|
|
68
|
+
try {
|
|
69
|
+
await wsStore.login({ email: email.value, password: password.value })
|
|
70
|
+
} catch (err) {
|
|
71
|
+
alert(err.message)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<template>
|
|
77
|
+
<form @submit.prevent="login">
|
|
78
|
+
<input v-model="email" type="email" placeholder="Email" required />
|
|
79
|
+
<input v-model="password" type="password" placeholder="Password" required />
|
|
80
|
+
<button type="submit">Login</button>
|
|
81
|
+
</form>
|
|
82
|
+
</template>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 4. Setup main.js
|
|
86
|
+
|
|
87
|
+
**src/main.js:**
|
|
88
|
+
```javascript
|
|
89
|
+
import { createApp } from 'vue'
|
|
90
|
+
import { createRouter, createWebHashHistory } from 'vue-router'
|
|
91
|
+
import { createPinia } from 'pinia'
|
|
92
|
+
import { useAppStore } from 'dzql/client/stores'
|
|
93
|
+
import App from './App.vue'
|
|
94
|
+
|
|
95
|
+
const pinia = createPinia()
|
|
96
|
+
|
|
97
|
+
const router = createRouter({
|
|
98
|
+
history: createWebHashHistory(),
|
|
99
|
+
routes: [
|
|
100
|
+
{ path: '/', name: 'home', component: () => import('./views/Home.vue') },
|
|
101
|
+
{ path: '/:entity', name: 'entity-list', component: () => import('./views/EntityList.vue') },
|
|
102
|
+
{ path: '/:entity/:id', name: 'entity-detail', component: () => import('./views/EntityDetail.vue') }
|
|
103
|
+
]
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const app = createApp(App)
|
|
107
|
+
app.use(pinia)
|
|
108
|
+
app.use(router)
|
|
109
|
+
|
|
110
|
+
const appStore = useAppStore()
|
|
111
|
+
appStore.setRouter(router)
|
|
112
|
+
|
|
113
|
+
app.mount('#app')
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 5. Use DZQL API
|
|
117
|
+
|
|
118
|
+
**Any component:**
|
|
119
|
+
```vue
|
|
120
|
+
<script setup>
|
|
121
|
+
import { ref, onMounted } from 'vue'
|
|
122
|
+
import { useWsStore } from 'dzql/client/stores'
|
|
123
|
+
|
|
124
|
+
const wsStore = useWsStore()
|
|
125
|
+
const ws = wsStore.getWs()
|
|
126
|
+
const venues = ref([])
|
|
127
|
+
|
|
128
|
+
onMounted(async () => {
|
|
129
|
+
const result = await ws.api.search.venues({ limit: 50 })
|
|
130
|
+
venues.value = result.data
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
async function createVenue() {
|
|
134
|
+
await ws.api.save.venues({ name: 'New Venue' })
|
|
135
|
+
}
|
|
136
|
+
</script>
|
|
137
|
+
|
|
138
|
+
<template>
|
|
139
|
+
<div v-for="venue in venues" :key="venue.id">
|
|
140
|
+
{{ venue.name }}
|
|
141
|
+
</div>
|
|
142
|
+
<button @click="createVenue">Create</button>
|
|
143
|
+
</template>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## That's It! 🎉
|
|
147
|
+
|
|
148
|
+
You now have:
|
|
149
|
+
- ✅ WebSocket connection with auto-reconnect
|
|
150
|
+
- ✅ Three-phase lifecycle (connecting → login → ready)
|
|
151
|
+
- ✅ Authentication (login/logout)
|
|
152
|
+
- ✅ Router integration
|
|
153
|
+
- ✅ DZQL API access
|
|
154
|
+
|
|
155
|
+
## Next Steps
|
|
156
|
+
|
|
157
|
+
- Read [CLIENT-STORES.md](./CLIENT-STORES.md) for complete API reference
|
|
158
|
+
- Customize the App.vue template
|
|
159
|
+
- Add your own components
|
|
160
|
+
- Style with Tailwind/DaisyUI
|
|
161
|
+
|
|
162
|
+
## Common Issues
|
|
163
|
+
|
|
164
|
+
**"Cannot find module 'dzql/client/stores'"**
|
|
165
|
+
- Make sure you're using dzql v0.1.6 or later
|
|
166
|
+
- Run `npm install dzql@latest`
|
|
167
|
+
|
|
168
|
+
**Connection fails**
|
|
169
|
+
- Check server is running
|
|
170
|
+
- For dev, use explicit URL: `appStore.initialize({ wsUrl: 'ws://localhost:3000/ws' })`
|
|
171
|
+
|
|
172
|
+
**Router not working**
|
|
173
|
+
- Make sure you call `appStore.setRouter(router)` in main.js
|
|
174
|
+
|
|
175
|
+
## Example Projects
|
|
176
|
+
|
|
177
|
+
Check `packages/client` for a complete working example.
|
|
178
|
+
|
|
179
|
+
## Help
|
|
180
|
+
|
|
181
|
+
For more help, see:
|
|
182
|
+
- [CLIENT-STORES.md](./CLIENT-STORES.md) - Complete documentation
|
|
183
|
+
- [GitHub Issues](https://github.com/blueshed/dzql/issues)
|