Skip to content

Commit

Permalink
Fix caching id for /v2/characters
Browse files Browse the repository at this point in the history
  • Loading branch information
queicherius committed Jan 28, 2024
1 parent f9cedf9 commit 2631f8e
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 5 deletions.
11 changes: 6 additions & 5 deletions src/endpoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module.exports = class AbstractEndpoint {
this.isPaginated = false
this.maxPageSize = 200
this.isBulk = false
this.bulkId = 'id'
this.supportsBulkAll = true
this.isLocalized = false
this.isAuthenticated = false
Expand Down Expand Up @@ -202,7 +203,7 @@ module.exports = class AbstractEndpoint {
this.debugMessage(`many(${this.url}) resolving partially from cache (${cached.length} ids)`)
const missingIds = getMissingIds(ids, cached)
return this._many(missingIds, cached.length > 0).then(content => {
const cacheContent = content.map(value => [this._cacheHash(value.id), value])
const cacheContent = content.map(value => [this._cacheHash(value[this.bulkId]), value])
this._cacheSetMany(cacheContent)

// Merge the new content with the cached content and guarantee element order
Expand All @@ -215,7 +216,7 @@ module.exports = class AbstractEndpoint {
const getMissingIds = (ids, cached) => {
const cachedIds = {}
cached.map(x => {
cachedIds[x.id] = 1
cachedIds[x[this.bulkId]] = 1
})

return ids.filter(x => cachedIds[x] !== 1)
Expand Down Expand Up @@ -288,7 +289,7 @@ module.exports = class AbstractEndpoint {
let cacheContent = [[hash, content]]

if (this.isBulk) {
cacheContent = cacheContent.concat(content.map(value => [this._cacheHash(value.id), value]))
cacheContent = cacheContent.concat(content.map(value => [this._cacheHash(value[this.bulkId]), value]))
}

this._cacheSetMany(cacheContent)
Expand Down Expand Up @@ -335,7 +336,7 @@ module.exports = class AbstractEndpoint {
let cacheContent = [[hash, content]]

if (this.isBulk) {
cacheContent = cacheContent.concat(content.map(value => [this._cacheHash(value.id), value]))
cacheContent = cacheContent.concat(content.map(value => [this._cacheHash(value[this.bulkId]), value]))
}

this._cacheSetMany(cacheContent)
Expand Down Expand Up @@ -521,7 +522,7 @@ module.exports = class AbstractEndpoint {
})

// Sort by the indexes
entries.sort((a, b) => indexMap[a.id] - indexMap[b.id])
entries.sort((a, b) => indexMap[a[this.bulkId]] - indexMap[b[this.bulkId]])
return entries
}

Expand Down
1 change: 1 addition & 0 deletions src/endpoints/characters.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = class CharactersEndpoint extends AbstractEndpoint {
this.url = '/v2/characters'
this.isPaginated = true
this.isBulk = true
this.bulkId = 'name'
this.supportsBulkAll = false
this.isAuthenticated = true
this.cacheTime = 5 * 60
Expand Down
123 changes: 123 additions & 0 deletions tests/endpoint.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,34 @@ describe('abstract endpoint', () => {
expect(bulkEntriesInCache).toEqual(content)
})

it('caching with custom bulk id', async () => {
let content = [
{ name: 1, profession: 'foo' },
{ name: 2, profession: 'bar' },
{ name: 3, profession: 'fooo' }
]
endpoint.isBulk = true
endpoint.bulkId = 'name'
endpoint.url = '/v2/test'
endpoint.cacheTime = 60
fetchMock.addResponse(content)

let entry = await endpoint.many([1, 2, 3])
await wait(50)
let entryShouldCache = await endpoint.many([2, 3, 2])
let bulkEntriesInCache = await endpoint._cacheGetMany([
'hash[https://api.guildwars2.com/v2/test:schema]:1',
'hash[https://api.guildwars2.com/v2/test:schema]:2',
'hash[https://api.guildwars2.com/v2/test:schema]:3'
])

expect(fetchMock.lastUrl()).toEqual('https://api.guildwars2.com/v2/test?v=schema&ids=1,2,3')
expect(fetchMock.urls().length).toEqual(1)
expect(entry).toEqual(content)
expect(entryShouldCache).toEqual(content.slice(1))
expect(bulkEntriesInCache).toEqual(content)
})

it('partial caching', async () => {
let content = [
{ id: 1, name: 'foo' },
Expand Down Expand Up @@ -345,6 +373,40 @@ describe('abstract endpoint', () => {
expect(bulkEntriesInCache).toEqual(content)
})

it('partial caching with custom bulk id', async () => {
let content = [
{ name: 1, profession: 'foo' },
{ name: 2, profession: 'bar' },
{ name: 3, profession: 'fooo' },
{ name: 4, profession: 'xd' }
]
endpoint.isBulk = true
endpoint.bulkId = 'name'
endpoint.url = '/v2/test'
endpoint.cacheTime = 60
fetchMock.addResponse(content.slice(1, 3))
fetchMock.addResponse(content.slice(0, 1).concat(content.slice(3, 4)))

let entry = await endpoint.many([2, 3])
await wait(50)
let entryShouldCache = await endpoint.many([1, 2, 3, 4])
await wait(50)
let bulkEntriesInCache = await endpoint._cacheGetMany([
'hash[https://api.guildwars2.com/v2/test:schema]:1',
'hash[https://api.guildwars2.com/v2/test:schema]:2',
'hash[https://api.guildwars2.com/v2/test:schema]:3',
'hash[https://api.guildwars2.com/v2/test:schema]:4'
])

expect(fetchMock.urls()).toEqual([
'https://api.guildwars2.com/v2/test?v=schema&ids=2,3',
'https://api.guildwars2.com/v2/test?v=schema&ids=1,4'
])
expect(entry).toEqual(content.slice(1, 3))
expect(entryShouldCache).toEqual(content)
expect(bulkEntriesInCache).toEqual(content)
})

it('cant mutate cache data', async () => {
endpoint.isBulk = true
endpoint.url = '/v2/test'
Expand Down Expand Up @@ -513,6 +575,37 @@ describe('abstract endpoint', () => {
expect(bulkEntriesInCache).toEqual(content)
})

it('caching for bulk endpoints with custom bulk id', async () => {
let content = [
{ name: 1, profession: 'foo' },
{ name: 2, profession: 'bar' },
{ name: 3, profession: 'fooo' }
]
endpoint.isPaginated = true
endpoint.isBulk = true
endpoint.bulkId = 'name'
endpoint.url = '/v2/test'
endpoint.cacheTime = 60
fetchMock.addResponse(content)

let entry = await endpoint.page(0, 3)
await wait(50)
let entryShouldCache = await endpoint.page(0, 3)
let entryInCache = await endpoint._cacheGetSingle('hash[https://api.guildwars2.com/v2/test:schema]:page-0/3')
let bulkEntriesInCache = await endpoint._cacheGetMany([
'hash[https://api.guildwars2.com/v2/test:schema]:1',
'hash[https://api.guildwars2.com/v2/test:schema]:2',
'hash[https://api.guildwars2.com/v2/test:schema]:3'
])

expect(fetchMock.lastUrl()).toEqual('https://api.guildwars2.com/v2/test?v=schema&page=0&page_size=3')
expect(fetchMock.urls().length).toEqual(1)
expect(entry).toEqual(content)
expect(entryShouldCache).toEqual(content)
expect(entryInCache).toEqual(content)
expect(bulkEntriesInCache).toEqual(content)
})

it('cant mutate cache data', async () => {
endpoint.isPaginated = true
endpoint.url = '/v2/test'
Expand Down Expand Up @@ -714,6 +807,36 @@ describe('abstract endpoint', () => {
expect(cacheEntries).toEqual(content)
})

it('caching for bulk endpoints with custom bulk id', async () => {
let content = [
{ name: 1, profession: 'foo' },
{ name: 2, profession: 'bar' },
{ name: 3, profession: 'fooo' }
]
endpoint.isBulk = true
endpoint.bulkId = 'name'
endpoint.url = '/v2/test'
endpoint.cacheTime = 60
fetchMock.addResponse(content)

let entry = await endpoint.all()
await wait(50)
let entryShouldCache = await endpoint.all()
let entryInCache = await endpoint._cacheGetSingle('hash[https://api.guildwars2.com/v2/test:schema]:all')
let cacheEntries = await endpoint._cacheGetMany([
'hash[https://api.guildwars2.com/v2/test:schema]:1',
'hash[https://api.guildwars2.com/v2/test:schema]:2',
'hash[https://api.guildwars2.com/v2/test:schema]:3'
])

expect(fetchMock.lastUrl()).toEqual('https://api.guildwars2.com/v2/test?v=schema&ids=all')
expect(fetchMock.urls().length).toEqual(1)
expect(entry).toEqual(content)
expect(entryShouldCache).toEqual(content)
expect(entryInCache).toEqual(content)
expect(cacheEntries).toEqual(content)
})

it('cant mutate cache data', async () => {
endpoint.isPaginated = true
endpoint.url = '/v2/test'
Expand Down
1 change: 1 addition & 0 deletions tests/endpoints/characters.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe('endpoints > characters', () => {
it('test /v2/characters', async () => {
expect(endpoint.isPaginated).toEqual(true)
expect(endpoint.isBulk).toEqual(true)
expect(endpoint.bulkId).toEqual('name')
expect(endpoint.supportsBulkAll).toEqual(false)
expect(endpoint.isLocalized).toEqual(false)
expect(endpoint.isAuthenticated).toEqual(true)
Expand Down

0 comments on commit 2631f8e

Please sign in to comment.