Skip to content

Commit 120022b

Browse files
committed
drop better-sqlite3 dependency
1 parent 58d6fdd commit 120022b

File tree

3 files changed

+53
-393
lines changed

3 files changed

+53
-393
lines changed

app/utils/cache.server.ts

Lines changed: 49 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,17 @@ import {
1111
type CreateReporter,
1212
} from '@epic-web/cachified'
1313
import { remember } from '@epic-web/remember'
14-
import Database from 'better-sqlite3'
1514
import { LRUCache } from 'lru-cache'
15+
import { DatabaseSync } from 'node:sqlite'
1616
import { z } from 'zod'
17-
import { updatePrimaryCacheValue } from '#app/routes/admin+/cache_.sqlite.server.ts'
18-
import { getInstanceInfo, getInstanceInfoSync } from './litefs.server.ts'
1917
import { cachifiedTimingReporter, type Timings } from './timing.server.ts'
2018

2119
const CACHE_DATABASE_PATH = process.env.CACHE_DATABASE_PATH
2220

2321
const cacheDb = remember('cacheDb', createDatabase)
2422

25-
function createDatabase(tryAgain = true): Database.Database {
26-
const db = new Database(CACHE_DATABASE_PATH)
27-
const { currentIsPrimary } = getInstanceInfoSync()
28-
if (!currentIsPrimary) return db
23+
function createDatabase(tryAgain = true): DatabaseSync {
24+
const db = new DatabaseSync(CACHE_DATABASE_PATH)
2925

3026
try {
3127
// create cache table with metadata JSON column and value JSON column if it does not exist already
@@ -46,6 +42,7 @@ function createDatabase(tryAgain = true): Database.Database {
4642
}
4743
throw error
4844
}
45+
4946
return db
5047
}
5148

@@ -68,6 +65,31 @@ export const lruCache = {
6865
delete: (key) => lru.delete(key),
6966
} satisfies Cache
7067

68+
const isBuffer = (obj: unknown): obj is Buffer =>
69+
Buffer.isBuffer(obj) || obj instanceof Uint8Array
70+
71+
function bufferReplacer(_key: string, value: unknown) {
72+
if (isBuffer(value)) {
73+
return {
74+
__isBuffer: true,
75+
data: value.toString('base64'),
76+
}
77+
}
78+
return value
79+
}
80+
81+
function bufferReviver(_key: string, value: unknown) {
82+
if (
83+
value &&
84+
typeof value === 'object' &&
85+
'__isBuffer' in value &&
86+
(value as any).data
87+
) {
88+
return Buffer.from((value as any).data, 'base64')
89+
}
90+
return value
91+
}
92+
7193
const cacheEntrySchema = z.object({
7294
metadata: z.object({
7395
createdTime: z.number(),
@@ -81,75 +103,46 @@ const cacheQueryResultSchema = z.object({
81103
value: z.string(),
82104
})
83105

106+
const getStatement = cacheDb.prepare(
107+
'SELECT value, metadata FROM cache WHERE key = ?',
108+
)
109+
const setStatement = cacheDb.prepare(
110+
'INSERT OR REPLACE INTO cache (key, value, metadata) VALUES (?, ?, ?)',
111+
)
112+
const deleteStatement = cacheDb.prepare('DELETE FROM cache WHERE key = ?')
113+
const getAllKeysStatement = cacheDb.prepare('SELECT key FROM cache LIMIT ?')
114+
const searchKeysStatement = cacheDb.prepare(
115+
'SELECT key FROM cache WHERE key LIKE ? LIMIT ?',
116+
)
117+
84118
export const cache: CachifiedCache = {
85119
name: 'SQLite cache',
86-
get(key) {
87-
const result = cacheDb
88-
.prepare('SELECT value, metadata FROM cache WHERE key = ?')
89-
.get(key)
120+
async get(key) {
121+
const result = getStatement.get(key)
90122
const parseResult = cacheQueryResultSchema.safeParse(result)
91123
if (!parseResult.success) return null
92124

93125
const parsedEntry = cacheEntrySchema.safeParse({
94126
metadata: JSON.parse(parseResult.data.metadata),
95-
value: JSON.parse(parseResult.data.value),
127+
value: JSON.parse(parseResult.data.value, bufferReviver),
96128
})
97129
if (!parsedEntry.success) return null
98130
const { metadata, value } = parsedEntry.data
99131
if (!value) return null
100132
return { metadata, value }
101133
},
102134
async set(key, entry) {
103-
const { currentIsPrimary, primaryInstance } = await getInstanceInfo()
104-
if (currentIsPrimary) {
105-
cacheDb
106-
.prepare(
107-
'INSERT OR REPLACE INTO cache (key, value, metadata) VALUES (@key, @value, @metadata)',
108-
)
109-
.run({
110-
key,
111-
value: JSON.stringify(entry.value),
112-
metadata: JSON.stringify(entry.metadata),
113-
})
114-
} else {
115-
// fire-and-forget cache update
116-
void updatePrimaryCacheValue({
117-
key,
118-
cacheValue: entry,
119-
}).then((response) => {
120-
if (!response.ok) {
121-
console.error(
122-
`Error updating cache value for key "${key}" on primary instance (${primaryInstance}): ${response.status} ${response.statusText}`,
123-
{ entry },
124-
)
125-
}
126-
})
127-
}
135+
const value = JSON.stringify(entry.value, bufferReplacer)
136+
setStatement.run(key, value, JSON.stringify(entry.metadata))
128137
},
129138
async delete(key) {
130-
const { currentIsPrimary, primaryInstance } = await getInstanceInfo()
131-
if (currentIsPrimary) {
132-
cacheDb.prepare('DELETE FROM cache WHERE key = ?').run(key)
133-
} else {
134-
// fire-and-forget cache update
135-
void updatePrimaryCacheValue({
136-
key,
137-
cacheValue: undefined,
138-
}).then((response) => {
139-
if (!response.ok) {
140-
console.error(
141-
`Error deleting cache value for key "${key}" on primary instance (${primaryInstance}): ${response.status} ${response.statusText}`,
142-
)
143-
}
144-
})
145-
}
139+
deleteStatement.run(key)
146140
},
147141
}
148142

149143
export async function getAllCacheKeys(limit: number) {
150144
return {
151-
sqlite: cacheDb
152-
.prepare('SELECT key FROM cache LIMIT ?')
145+
sqlite: getAllKeysStatement
153146
.all(limit)
154147
.map((row) => (row as { key: string }).key),
155148
lru: [...lru.keys()],
@@ -158,8 +151,7 @@ export async function getAllCacheKeys(limit: number) {
158151

159152
export async function searchCacheKeys(search: string, limit: number) {
160153
return {
161-
sqlite: cacheDb
162-
.prepare('SELECT key FROM cache WHERE key LIKE ? LIMIT ?')
154+
sqlite: searchKeysStatement
163155
.all(`%${search}%`, limit)
164156
.map((row) => (row as { key: string }).key),
165157
lru: [...lru.keys()].filter((key) => key.includes(search)),

0 commit comments

Comments
 (0)