Skip to content

Commit 9f0b0c2

Browse files
authored
[Electric]: Use numbers for txid (#245)
1 parent 329107e commit 9f0b0c2

File tree

14 files changed

+134
-209
lines changed

14 files changed

+134
-209
lines changed

.changeset/poor-beds-push.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@tanstack/db-collections": patch
3+
"@tanstack/db-example-react-todo": patch
4+
"@tanstack/db": patch
5+
---
6+
7+
- [Breaking change for the Electric Collection]: Use numbers for txid
8+
- misc type fixes

docs/overview.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,6 @@ insert([
575575
{ text: "Buy groceries", completed: false },
576576
{ text: "Walk dog", completed: false },
577577
])
578-
579-
// Insert with custom key
580-
insert({ text: "Buy groceries" }, { key: "grocery-task" })
581578
```
582579

583580
##### `update`

examples/react/todo/src/App.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -158,31 +158,31 @@ const createTodoCollection = (type: CollectionType) => {
158158
} = transaction.mutations[0].modified
159159
const response = await api.todos.create(modified)
160160

161-
return { txid: String(response.txid) }
161+
return { txid: response.txid }
162162
},
163163
onUpdate: async ({ transaction }) => {
164164
const txids = await Promise.all(
165165
transaction.mutations.map(async (mutation) => {
166166
const { original, changes } = mutation
167167
const response = await api.todos.update(original.id, changes)
168168

169-
return { txid: String(response.txid) }
169+
return response.txid
170170
})
171171
)
172172

173-
return { txid: String(txids[0]!.txid) }
173+
return { txid: txids }
174174
},
175175
onDelete: async ({ transaction }) => {
176176
const txids = await Promise.all(
177177
transaction.mutations.map(async (mutation) => {
178178
const { original } = mutation
179179
const response = await api.todos.delete(original.id)
180180

181-
return { txid: String(response.txid) }
181+
return response.txid
182182
})
183183
)
184184

185-
return { txid: String(txids[0]!.txid) }
185+
return { txid: txids }
186186
},
187187
})
188188
)
@@ -265,18 +265,18 @@ const createConfigCollection = (type: CollectionType) => {
265265
onInsert: async ({ transaction }) => {
266266
const modified = transaction.mutations[0].modified
267267
const response = await api.config.create(modified)
268-
return { txid: String(response.txid) }
268+
return { txid: response.txid }
269269
},
270270
onUpdate: async ({ transaction }) => {
271271
const txids = await Promise.all(
272272
transaction.mutations.map(async (mutation) => {
273273
const { original, changes } = mutation
274274
const response = await api.config.update(original.id, changes)
275-
return { txid: String(response.txid) }
275+
return response.txid
276276
})
277277
)
278278

279-
return { txid: String(txids[0]) }
279+
return { txid: txids }
280280
},
281281
})
282282
)
@@ -302,18 +302,18 @@ const createConfigCollection = (type: CollectionType) => {
302302
onInsert: async ({ transaction }) => {
303303
const modified = transaction.mutations[0].modified
304304
const response = await api.config.create(modified)
305-
return { txid: String(response.txid) }
305+
return { txid: response.txid }
306306
},
307307
onUpdate: async ({ transaction }) => {
308308
const txids = await Promise.all(
309309
transaction.mutations.map(async (mutation) => {
310310
const { original, changes } = mutation
311311
const response = await api.config.update(original.id, changes)
312-
return { txid: String(response.txid) }
312+
return response.txid
313313
})
314314
)
315315

316-
return { txid: String(txids[0]) }
316+
return { txid: txids }
317317
},
318318
})
319319
)

examples/react/todo/src/api/server.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
validateUpdateTodo,
99
} from "../db/validation"
1010
import type { Express } from "express"
11+
import type { Txid } from "@tanstack/db-collections"
1112

1213
// Create Express app
1314
const app: Express = express()
@@ -23,15 +24,19 @@ app.get(`/api/health`, (req, res) => {
2324
})
2425

2526
// Generate a transaction ID
26-
async function generateTxId(tx: any): Promise<string> {
27-
const result = await tx`SELECT txid_current() as txid`
27+
async function generateTxId(tx: any): Promise<Txid> {
28+
// The ::xid cast strips off the epoch, giving you the raw 32-bit value
29+
// that matches what PostgreSQL sends in logical replication streams
30+
// (and then exposed through Electric which we'll match against
31+
// in the client).
32+
const result = await tx`SELECT pg_current_xact_id()::xid::text as txid`
2833
const txid = result[0]?.txid
2934

3035
if (txid === undefined) {
3136
throw new Error(`Failed to get transaction ID`)
3237
}
3338

34-
return String(txid)
39+
return parseInt(txid, 10)
3540
}
3641

3742
// ===== TODOS API =====
@@ -75,7 +80,7 @@ app.post(`/api/todos`, async (req, res) => {
7580
try {
7681
const todoData = validateInsertTodo(req.body)
7782

78-
let txid!: string
83+
let txid!: Txid
7984
const newTodo = await sql.begin(async (tx) => {
8085
txid = await generateTxId(tx)
8186

@@ -102,7 +107,7 @@ app.put(`/api/todos/:id`, async (req, res) => {
102107
const { id } = req.params
103108
const todoData = validateUpdateTodo(req.body)
104109

105-
let txid!: string
110+
let txid!: Txid
106111
const updatedTodo = await sql.begin(async (tx) => {
107112
txid = await generateTxId(tx)
108113

@@ -139,7 +144,7 @@ app.delete(`/api/todos/:id`, async (req, res) => {
139144
try {
140145
const { id } = req.params
141146

142-
let txid!: string
147+
let txid!: Txid
143148
await sql.begin(async (tx) => {
144149
txid = await generateTxId(tx)
145150

@@ -210,7 +215,7 @@ app.post(`/api/config`, async (req, res) => {
210215
console.log(`POST /api/config`, req.body)
211216
const configData = validateInsertConfig(req.body)
212217

213-
let txid!: string
218+
let txid!: Txid
214219
const newConfig = await sql.begin(async (tx) => {
215220
txid = await generateTxId(tx)
216221

@@ -237,7 +242,7 @@ app.put(`/api/config/:id`, async (req, res) => {
237242
const { id } = req.params
238243
const configData = validateUpdateConfig(req.body)
239244

240-
let txid!: string
245+
let txid!: Txid
241246
const updatedConfig = await sql.begin(async (tx) => {
242247
txid = await generateTxId(tx)
243248

@@ -274,7 +279,7 @@ app.delete(`/api/config/:id`, async (req, res) => {
274279
try {
275280
const { id } = req.params
276281

277-
let txid!: string
282+
let txid!: Txid
278283
await sql.begin(async (tx) => {
279284
txid = await generateTxId(tx)
280285

examples/react/todo/src/api/write-to-pg.ts

Lines changed: 0 additions & 115 deletions
This file was deleted.

packages/db-collections/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
"description": "A collection for (aspirationally) every way of loading your data",
44
"version": "0.0.22",
55
"dependencies": {
6+
"@standard-schema/spec": "^1.0.0",
67
"@tanstack/db": "workspace:*",
78
"@tanstack/query-core": "^5.75.7",
8-
"@standard-schema/spec": "^1.0.0",
9-
"@tanstack/store": "^0.7.0"
9+
"@tanstack/store": "^0.7.0",
10+
"debug": "^4.4.1"
1011
},
1112
"devDependencies": {
1213
"@electric-sql/client": "1.0.0",
14+
"@types/debug": "^4.1.12",
1315
"@vitest/coverage-istanbul": "^3.0.9"
1416
},
1517
"exports": {

0 commit comments

Comments
 (0)