Skip to content

Commit 5d43ae0

Browse files
authored
feat!: upgrade to zero v0.12 and expose query status (#24)
BREAKING CHANGES: query details are now exposed via `data` and `status` properties returned from `useQuery`
1 parent 3ec1e0b commit 5d43ae0

File tree

8 files changed

+172
-117
lines changed

8 files changed

+172
-117
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const z = new Zero({
3131
kvStore: 'mem',
3232
})
3333

34-
const users = useQuery(z.query.user)
34+
const { data: users } = useQuery(z.query.user)
3535
```
3636

3737
> [!TIP]

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"vue": "^3.5.13"
3636
},
3737
"dependencies": {
38-
"@rocicorp/zero": "^0.11.0"
38+
"@rocicorp/zero": "^0.12.2025012600"
3939
},
4040
"devDependencies": {
4141
"@antfu/eslint-config": "latest",

playground/src/app.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ const z = new Zero({
2525
kvStore: 'mem',
2626
})
2727
28-
const users = useQuery(z.query.user)
29-
const mediums = useQuery(z.query.medium)
30-
const allMessages = useQuery(z.query.message)
28+
const { data: users } = useQuery(z.query.user)
29+
const { data: mediums } = useQuery(z.query.medium)
30+
const { data: allMessages } = useQuery(z.query.message)
3131
3232
const filterUser = ref('')
3333
const filterText = ref('')
3434
const action = ref<'add' | 'remove' | undefined>(undefined)
3535
36-
const filteredMessages = useQuery(() => {
36+
const { data: filteredMessages } = useQuery(() => {
3737
let filtered = z.query.message
3838
.related('medium', medium => medium.one())
3939
.related('sender', sender => sender.one())

playground/src/db/schema.ts

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,64 +5,65 @@
55
// See https://github.com/rocicorp/mono/blob/main/apps/zbugs/src/domain/schema.ts
66
// for more complex examples, including many-to-many.
77

8-
import type { ExpressionBuilder, Row, TableSchema } from '@rocicorp/zero'
9-
import { ANYONE_CAN, createSchema, createTableSchema, definePermissions, NOBODY_CAN } from '@rocicorp/zero'
8+
import type { ExpressionBuilder, Row } from '@rocicorp/zero'
9+
import {
10+
ANYONE_CAN,
11+
boolean,
12+
createSchema,
13+
definePermissions,
14+
NOBODY_CAN,
15+
number,
16+
relationships,
17+
string,
18+
table,
19+
} from '@rocicorp/zero'
1020

11-
const userSchema = createTableSchema({
12-
tableName: 'user',
13-
columns: {
14-
id: 'string',
15-
name: 'string',
16-
partner: 'boolean',
17-
},
18-
primaryKey: 'id',
19-
})
21+
const user = table('user')
22+
.columns({
23+
id: string(),
24+
name: string(),
25+
partner: boolean(),
26+
})
27+
.primaryKey('id')
2028

21-
const mediumSchema = createTableSchema({
22-
tableName: 'medium',
23-
columns: {
24-
id: 'string',
25-
name: 'string',
26-
},
27-
primaryKey: 'id',
28-
})
29+
const medium = table('medium')
30+
.columns({
31+
id: string(),
32+
name: string(),
33+
})
34+
.primaryKey('id')
2935

30-
const messageSchema = createTableSchema({
31-
tableName: 'message',
32-
columns: {
33-
id: 'string',
34-
senderID: 'string',
35-
mediumID: 'string',
36-
body: 'string',
37-
timestamp: 'number',
38-
},
39-
primaryKey: 'id',
40-
relationships: {
41-
sender: {
42-
sourceField: 'senderID',
43-
destSchema: userSchema,
44-
destField: 'id',
45-
},
46-
medium: {
47-
sourceField: 'mediumID',
48-
destSchema: mediumSchema,
49-
destField: 'id',
50-
},
51-
},
52-
})
36+
const message = table('message')
37+
.columns({
38+
id: string(),
39+
senderID: string(),
40+
mediumID: string(),
41+
body: string(),
42+
timestamp: number(),
43+
})
44+
.primaryKey('id')
45+
46+
const messageRelationships = relationships(message, ({ one }) => ({
47+
sender: one({
48+
sourceField: ['senderID'],
49+
destField: ['id'],
50+
destSchema: user,
51+
}),
52+
medium: one({
53+
sourceField: ['mediumID'],
54+
destField: ['id'],
55+
destSchema: medium,
56+
}),
57+
}))
5358

54-
export const schema = createSchema({
55-
version: 1,
56-
tables: {
57-
user: userSchema,
58-
medium: mediumSchema,
59-
message: messageSchema,
60-
},
59+
export const schema = createSchema(1, {
60+
tables: [user, medium, message],
61+
relationships: [messageRelationships],
6162
})
6263

6364
export type Schema = typeof schema
64-
export type Message = Row<typeof messageSchema>
65-
export type Medium = Row<typeof mediumSchema>
65+
export type Message = Row<typeof schema.tables.message>
66+
export type Medium = Row<typeof schema.tables.medium>
6667
export type User = Row<typeof schema.tables.user>
6768

6869
// The contents of your decoded JWT.
@@ -73,12 +74,12 @@ interface AuthData {
7374
export const permissions = definePermissions<AuthData, Schema>(schema, () => {
7475
const allowIfLoggedIn = (
7576
authData: AuthData,
76-
{ cmpLit }: ExpressionBuilder<TableSchema>,
77+
{ cmpLit }: ExpressionBuilder<Schema, keyof Schema['tables']>,
7778
) => cmpLit(authData.sub, 'IS NOT', null)
7879

7980
const allowIfMessageSender = (
8081
authData: AuthData,
81-
{ cmp }: ExpressionBuilder<typeof messageSchema>,
82+
{ cmp }: ExpressionBuilder<Schema, 'message'>,
8283
) => cmp('senderID', '=', authData.sub ?? '')
8384

8485
return {

pnpm-lock.yaml

Lines changed: 11 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/query.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,38 @@
11
// based on https://github.com/rocicorp/mono/tree/main/packages/zero-solid
22

3-
import type { AdvancedQuery, Query, QueryType, Smash, TableSchema } from '@rocicorp/zero/advanced'
3+
import type { ResultType, Schema } from '@rocicorp/zero'
4+
import type { AdvancedQuery, HumanReadable, Query } from '@rocicorp/zero/advanced'
45
import type { ComputedRef, MaybeRefOrGetter } from 'vue'
5-
import { computed, getCurrentInstance, isRef, onUnmounted, shallowRef, toValue, watch } from 'vue'
66

7+
import { computed, getCurrentInstance, isRef, onUnmounted, shallowRef, toValue, watch } from 'vue'
78
import { vueViewFactory } from './view'
89

10+
interface QueryResult<TReturn> {
11+
data: ComputedRef<HumanReadable<TReturn>>
12+
status: ComputedRef<ResultType>
13+
}
14+
915
export function useQuery<
10-
TSchema extends TableSchema,
11-
TReturn extends QueryType,
12-
>(_query: MaybeRefOrGetter<Query<TSchema, TReturn>>): ComputedRef<Smash<TReturn>> {
13-
const query = toValue(_query) as AdvancedQuery<TSchema, TReturn>
16+
TSchema extends Schema,
17+
TTable extends keyof TSchema['tables'] & string,
18+
TReturn,
19+
>(_query: MaybeRefOrGetter<Query<TSchema, TTable, TReturn>>): QueryResult<TReturn> {
20+
const query = toValue(_query) as AdvancedQuery<TSchema, TTable, TReturn>
1421
const view = shallowRef(query.materialize(vueViewFactory))
1522

1623
if (isRef(_query) || _query instanceof Function) {
1724
watch(_query, (query) => {
1825
view.value.destroy()
19-
view.value = (query as AdvancedQuery<TSchema, TReturn>).materialize(vueViewFactory)
26+
view.value = (query as AdvancedQuery<TSchema, TTable, TReturn>).materialize(vueViewFactory)
2027
})
2128
}
2229

2330
if (getCurrentInstance()) {
2431
onUnmounted(() => view.value.destroy())
2532
}
2633

27-
return computed(() => view.value.data)
34+
return {
35+
data: computed(() => view.value.data),
36+
status: computed(() => view.value.status),
37+
}
2838
}

0 commit comments

Comments
 (0)