Skip to content

Commit 6ea23bb

Browse files
feat: add Vue support (#83)
Co-authored-by: Kyle Mathews <mathews.kyle@gmail.com>
1 parent 1d4747e commit 6ea23bb

11 files changed

Lines changed: 1168 additions & 1 deletion

File tree

.changeset/purple-kings-breathe.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tanstack/vue-db": patch
3+
---
4+
5+
Add Vue support

packages/db/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"url": "https://github.com/TanStack/db.git",
4141
"directory": "packages/db"
4242
},
43-
"homepage": "https://tanstack.com/optimistic",
43+
"homepage": "https://tanstack.com/db",
4444
"keywords": [
4545
"optimistic",
4646
"typescript"

packages/vue-db/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# @tanstack/vue-db
2+
3+
Vue composables for TanStack DB. See [TanStack/db](https://github.com/TanStack/db) for more details.

packages/vue-db/package.json

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"name": "@tanstack/vue-db",
3+
"description": "Vue integration for @tanstack/db",
4+
"version": "0.0.0",
5+
"author": "Kyle Mathews",
6+
"license": "MIT",
7+
"repository": {
8+
"type": "git",
9+
"url": "https://github.com/TanStack/db.git",
10+
"directory": "packages/vue-db"
11+
},
12+
"homepage": "https://tanstack.com/db",
13+
"keywords": [
14+
"optimistic",
15+
"vue",
16+
"typescript"
17+
],
18+
"packageManager": "pnpm@10.5.2",
19+
"dependencies": {
20+
"@tanstack/db": "workspace:*",
21+
"@tanstack/vue-store": "^0.7.0"
22+
},
23+
"devDependencies": {
24+
"@electric-sql/client": "1.0.0",
25+
"@vitest/coverage-istanbul": "^3.0.9",
26+
"@vitejs/plugin-vue": "^5.2.4",
27+
"vue": "^3.5.13"
28+
},
29+
"exports": {
30+
".": {
31+
"import": {
32+
"types": "./dist/esm/index.d.ts",
33+
"default": "./dist/esm/index.js"
34+
},
35+
"require": {
36+
"types": "./dist/cjs/index.d.cts",
37+
"default": "./dist/cjs/index.cjs"
38+
}
39+
},
40+
"./package.json": "./package.json"
41+
},
42+
"files": [
43+
"dist",
44+
"src"
45+
],
46+
"main": "dist/cjs/index.cjs",
47+
"module": "dist/esm/index.js",
48+
"peerDependencies": {
49+
"vue": ">=3.3.0"
50+
},
51+
"scripts": {
52+
"build": "vite build",
53+
"dev": "vite build --watch",
54+
"test": "npx vitest --run",
55+
"lint": "eslint . --fix"
56+
},
57+
"sideEffects": false,
58+
"type": "module",
59+
"types": "dist/esm/index.d.ts"
60+
}

packages/vue-db/src/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Re-export all public APIs
2+
export * from "./useOptimisticMutation"
3+
export * from "./useLiveQuery"
4+
5+
// Re-export everything from @tanstack/db
6+
export * from "@tanstack/db"
7+
8+
// Re-export some stuff explicitly to ensure the type & value is exported
9+
export { Collection } from "@tanstack/db"
10+
export { createTransaction } from "@tanstack/db"
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { computed, toValue, watch } from "vue"
2+
import { useStore } from "@tanstack/vue-store"
3+
import { compileQuery, queryBuilder } from "@tanstack/db"
4+
import type {
5+
Collection,
6+
Context,
7+
InitialQueryBuilder,
8+
QueryBuilder,
9+
ResultsFromContext,
10+
Schema,
11+
} from "@tanstack/db"
12+
import type { ComputedRef, MaybeRefOrGetter } from "vue"
13+
14+
export interface UseLiveQueryReturn<T extends object> {
15+
state: ComputedRef<Map<string, T>>
16+
data: ComputedRef<Array<T>>
17+
collection: ComputedRef<Collection<T>>
18+
}
19+
20+
export function useLiveQuery<
21+
TResultContext extends Context<Schema> = Context<Schema>,
22+
>(
23+
queryFn: (
24+
q: InitialQueryBuilder<Context<Schema>>
25+
) => QueryBuilder<TResultContext>,
26+
deps: Array<MaybeRefOrGetter<unknown>> = []
27+
): UseLiveQueryReturn<ResultsFromContext<TResultContext>> {
28+
const compiledQuery = computed(() => {
29+
// Just reference deps to make computed reactive to them
30+
deps.forEach((dep) => toValue(dep))
31+
32+
const query = queryFn(queryBuilder())
33+
const compiled = compileQuery(query)
34+
compiled.start()
35+
return compiled
36+
})
37+
38+
const state = computed(() => {
39+
return useStore(compiledQuery.value.results.derivedState).value
40+
})
41+
const data = computed(() => {
42+
return useStore(compiledQuery.value.results.derivedArray).value
43+
})
44+
45+
watch(compiledQuery, (newQuery, oldQuery, onInvalidate) => {
46+
if (newQuery.state === `stopped`) {
47+
newQuery.start()
48+
}
49+
50+
onInvalidate(() => {
51+
oldQuery.stop()
52+
})
53+
})
54+
55+
return {
56+
state,
57+
data,
58+
collection: computed(() => compiledQuery.value.results),
59+
}
60+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { createTransaction } from "@tanstack/db"
2+
import type { Transaction, TransactionConfig } from "@tanstack/db"
3+
4+
export function useOptimisticMutation(config: TransactionConfig) {
5+
return {
6+
mutate: (callback: () => void): Transaction => {
7+
const transaction = createTransaction(config)
8+
transaction.mutate(callback)
9+
return transaction
10+
},
11+
createTransaction: (): Transaction => {
12+
return createTransaction({ ...config, autoCommit: false })
13+
},
14+
}
15+
}

0 commit comments

Comments
 (0)