Skip to content

Commit fe21269

Browse files
authored
feat: sqlite add set and minor cleanup (#4018)
* feat: sqlite add set and minor cleanup * fixup
1 parent a364e7c commit fe21269

File tree

3 files changed

+126
-71
lines changed

3 files changed

+126
-71
lines changed

lib/cache/sqlite-cache-store.js

Lines changed: 81 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,18 @@ const MAX_ENTRY_SIZE = 2 * 1000 * 1000 * 1000
1515
* @implements {CacheStore}
1616
*
1717
* @typedef {{
18-
* id: Readonly<number>
19-
* headers?: Record<string, string | string[]>
20-
* vary?: string | object
21-
* body: string
22-
* } & import('../../types/cache-interceptor.d.ts').default.CacheValue} SqliteStoreValue
18+
* id: Readonly<number>,
19+
* body?: Uint8Array
20+
* statusCode: number
21+
* statusMessage: string
22+
* headers?: string
23+
* vary?: string
24+
* etag?: string
25+
* cacheControlDirectives?: string
26+
* cachedAt: number
27+
* staleAt: number
28+
* deleteAt: number
29+
* }} SqliteStoreValue
2330
*/
2431
module.exports = class SqliteCacheStore {
2532
#maxEntrySize = MAX_ENTRY_SIZE
@@ -217,36 +224,78 @@ module.exports = class SqliteCacheStore {
217224

218225
/**
219226
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} key
220-
* @returns {import('../../types/cache-interceptor.d.ts').default.GetResult | undefined}
227+
* @returns {(import('../../types/cache-interceptor.d.ts').default.GetResult & { body?: Buffer }) | undefined}
221228
*/
222229
get (key) {
223230
assertCacheKey(key)
224231

225232
const value = this.#findValue(key)
233+
return value
234+
? {
235+
body: value.body ? Buffer.from(value.body.buffer) : undefined,
236+
statusCode: value.statusCode,
237+
statusMessage: value.statusMessage,
238+
headers: value.headers ? JSON.parse(value.headers) : undefined,
239+
etag: value.etag ? value.etag : undefined,
240+
vary: value.vary ? JSON.parse(value.vary) : undefined,
241+
cacheControlDirectives: value.cacheControlDirectives
242+
? JSON.parse(value.cacheControlDirectives)
243+
: undefined,
244+
cachedAt: value.cachedAt,
245+
staleAt: value.staleAt,
246+
deleteAt: value.deleteAt
247+
}
248+
: undefined
249+
}
226250

227-
if (!value) {
228-
return undefined
229-
}
251+
/**
252+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} key
253+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheValue & { body: null | Buffer | Array<Buffer>}} value
254+
*/
255+
set (key, value) {
256+
assertCacheKey(key)
230257

231-
/**
232-
* @type {import('../../types/cache-interceptor.d.ts').default.GetResult}
233-
*/
234-
const result = {
235-
body: Buffer.from(value.body),
236-
statusCode: value.statusCode,
237-
statusMessage: value.statusMessage,
238-
headers: value.headers ? JSON.parse(value.headers) : undefined,
239-
etag: value.etag ? value.etag : undefined,
240-
vary: value.vary ?? undefined,
241-
cacheControlDirectives: value.cacheControlDirectives
242-
? JSON.parse(value.cacheControlDirectives)
243-
: undefined,
244-
cachedAt: value.cachedAt,
245-
staleAt: value.staleAt,
246-
deleteAt: value.deleteAt
258+
const url = this.#makeValueUrl(key)
259+
const body = Array.isArray(value.body) ? Buffer.concat(value.body) : value.body
260+
const size = body?.byteLength
261+
262+
if (size && size > this.#maxEntrySize) {
263+
return
247264
}
248265

249-
return result
266+
const existingValue = this.#findValue(key, true)
267+
if (existingValue) {
268+
// Updating an existing response, let's overwrite it
269+
this.#updateValueQuery.run(
270+
body,
271+
value.deleteAt,
272+
value.statusCode,
273+
value.statusMessage,
274+
value.headers ? JSON.stringify(value.headers) : null,
275+
value.etag ? value.etag : null,
276+
value.cacheControlDirectives ? JSON.stringify(value.cacheControlDirectives) : null,
277+
value.cachedAt,
278+
value.staleAt,
279+
existingValue.id
280+
)
281+
} else {
282+
this.#prune()
283+
// New response, let's insert it
284+
this.#insertValueQuery.run(
285+
url,
286+
key.method,
287+
body,
288+
value.deleteAt,
289+
value.statusCode,
290+
value.statusMessage,
291+
value.headers ? JSON.stringify(value.headers) : null,
292+
value.etag ? value.etag : null,
293+
value.cacheControlDirectives ? JSON.stringify(value.cacheControlDirectives) : null,
294+
value.vary ? JSON.stringify(value.vary) : null,
295+
value.cachedAt,
296+
value.staleAt
297+
)
298+
}
250299
}
251300

252301
/**
@@ -258,7 +307,6 @@ module.exports = class SqliteCacheStore {
258307
assertCacheKey(key)
259308
assertCacheValue(value)
260309

261-
const url = this.#makeValueUrl(key)
262310
let size = 0
263311
/**
264312
* @type {Buffer[] | null}
@@ -267,11 +315,8 @@ module.exports = class SqliteCacheStore {
267315
const store = this
268316

269317
return new Writable({
318+
decodeStrings: true,
270319
write (chunk, encoding, callback) {
271-
if (typeof chunk === 'string') {
272-
chunk = Buffer.from(chunk, encoding)
273-
}
274-
275320
size += chunk.byteLength
276321

277322
if (size < store.#maxEntrySize) {
@@ -283,40 +328,7 @@ module.exports = class SqliteCacheStore {
283328
callback()
284329
},
285330
final (callback) {
286-
const existingValue = store.#findValue(key, true)
287-
if (existingValue) {
288-
// Updating an existing response, let's overwrite it
289-
store.#updateValueQuery.run(
290-
Buffer.concat(body),
291-
value.deleteAt,
292-
value.statusCode,
293-
value.statusMessage,
294-
value.headers ? JSON.stringify(value.headers) : null,
295-
value.etag ? value.etag : null,
296-
value.cacheControlDirectives ? JSON.stringify(value.cacheControlDirectives) : null,
297-
value.cachedAt,
298-
value.staleAt,
299-
existingValue.id
300-
)
301-
} else {
302-
store.#prune()
303-
// New response, let's insert it
304-
store.#insertValueQuery.run(
305-
url,
306-
key.method,
307-
Buffer.concat(body),
308-
value.deleteAt,
309-
value.statusCode,
310-
value.statusMessage,
311-
value.headers ? JSON.stringify(value.headers) : null,
312-
value.etag ? value.etag : null,
313-
value.cacheControlDirectives ? JSON.stringify(value.cacheControlDirectives) : null,
314-
value.vary ? JSON.stringify(value.vary) : null,
315-
value.cachedAt,
316-
value.staleAt
317-
)
318-
}
319-
331+
store.set(key, { ...value, body })
320332
callback()
321333
}
322334
})
@@ -375,7 +387,7 @@ module.exports = class SqliteCacheStore {
375387
/**
376388
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} key
377389
* @param {boolean} [canBeExpired=false]
378-
* @returns {(SqliteStoreValue & { vary?: Record<string, string[]> }) | undefined}
390+
* @returns {SqliteStoreValue | undefined}
379391
*/
380392
#findValue (key, canBeExpired = false) {
381393
const url = this.#makeValueUrl(key)
@@ -403,10 +415,10 @@ module.exports = class SqliteCacheStore {
403415
return undefined
404416
}
405417

406-
value.vary = JSON.parse(value.vary)
418+
const vary = JSON.parse(value.vary)
407419

408-
for (const header in value.vary) {
409-
if (!headerValueEquals(headers[header], value.vary[header])) {
420+
for (const header in vary) {
421+
if (!headerValueEquals(headers[header], vary[header])) {
410422
matches = false
411423
break
412424
}

test/cache-interceptor/sqlite-cache-store-tests.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict'
22

33
const { test, skip } = require('node:test')
4-
const { notEqual, strictEqual } = require('node:assert')
4+
const { notEqual, strictEqual, deepStrictEqual } = require('node:assert')
55
const { rm } = require('node:fs/promises')
66
const { cacheStoreTests, writeBody, compareGetResults } = require('./cache-store-test-utils.js')
77

@@ -179,3 +179,46 @@ test('SqliteCacheStore two writes', async (t) => {
179179
writeBody(writable, body)
180180
}
181181
})
182+
183+
test('SqliteCacheStore write & read', async (t) => {
184+
if (!hasSqlite) {
185+
t.skip()
186+
return
187+
}
188+
189+
const SqliteCacheStore = require('../../lib/cache/sqlite-cache-store.js')
190+
191+
const store = new SqliteCacheStore({
192+
maxCount: 10
193+
})
194+
195+
/**
196+
* @type {import('../../types/cache-interceptor.d.ts').default.CacheKey}
197+
*/
198+
const key = {
199+
origin: 'localhost',
200+
path: '/',
201+
method: 'GET',
202+
headers: {}
203+
}
204+
205+
/**
206+
* @type {import('../../types/cache-interceptor.d.ts').default.CacheValue & { body: Buffer }}
207+
*/
208+
const value = {
209+
statusCode: 200,
210+
statusMessage: '',
211+
headers: { foo: 'bar' },
212+
cacheControlDirectives: { 'max-stale': 0 },
213+
cachedAt: Date.now(),
214+
staleAt: Date.now() + 10000,
215+
deleteAt: Date.now() + 20000,
216+
body: Buffer.from('asd'),
217+
etag: undefined,
218+
vary: undefined
219+
}
220+
221+
store.set(key, value)
222+
223+
deepStrictEqual(store.get(key), value)
224+
})

types/cache-interceptor.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ declare namespace CacheHandler {
9090
headers: Record<string, string | string[]>
9191
vary?: Record<string, string | string[]>
9292
etag?: string
93-
body: null | Readable | Iterable<Buffer> | AsyncIterable<Buffer> | Buffer | Iterable<string> | AsyncIterable<string> | string
93+
body?: Readable | Iterable<Buffer> | AsyncIterable<Buffer> | Buffer | Iterable<string> | AsyncIterable<string> | string
9494
cacheControlDirectives: CacheControlDirectives,
9595
cachedAt: number
9696
staleAt: number

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy