Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 52 additions & 12 deletions src/getter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,34 @@ import { log, canUseCache } from './utils.js'

var db

function openDB(config) {
function openCache(config) {
if (config.cache && typeof window !== 'undefined') {
const request = window.indexedDB.open("pokeapi-js-wrapper", 3);
const request = window.indexedDB.open("pokeapi-js-wrapper", 8);
return new Promise((resolve, reject) => {
request.onerror = (event) => {
log('IndexedDB not available')
reject()
}
request.onupgradeneeded = (event) => {
db = event.target.result;
log('db opened and cache created')
db.createObjectStore("cache", { autoIncrement: false });
resolve(db)
const db = event.target.result;
const transaction = event.target.transaction;
let objectStore;

if (!db.objectStoreNames.contains('cache')) {
objectStore = db.createObjectStore("cache", { autoIncrement: false });
log('Object store "cache" created');
} else {
objectStore = transaction.objectStore("cache");
}

if (!objectStore.indexNames.contains("deploy_date_index")) {
objectStore.createIndex("deploy_date_index", "meta.deploy_date", { unique: false });
log('Index "deploy_date_index" created');
}
}
request.onsuccess = (event) => {
log('db opened')
db = event.target.result;
log('db opened')
resolve(db)
}
request.onversionchange = (event) => {
Expand All @@ -44,7 +55,7 @@ function getFromDB(objectStore, url) {
async function loadResource(config, url) {
if (! url.includes('://')) {
url = url.replace(/^\//, '');
url = `${config.protocol}://${config.hostName}/${url}`
url = `${config.protocol}://${config.hostName}${config.versionPath}${url}`
}
if (canUseCache(config, db)) {
const transaction = db.transaction("cache", "readonly");
Expand All @@ -66,10 +77,14 @@ async function loadUrl(config, url) {
const body = await response.json()
if (response.status === 200) {
if (canUseCache(config, db)) {
const deploy_date = parseInt(response.headers.get('X-PokeAPI-Deploy-Date'))
body.meta = { deploy_date }
const transaction = db.transaction("cache", "readwrite");
const objectStore = transaction.objectStore("cache");
const request = objectStore.add(body, url)
request.onsuccess = () => log(`object cached ${url}`);
request.onsuccess = () => {
log(`object cached ${url}`);
}
request.onerror = () => {
log(request.error)
}
Expand All @@ -79,7 +94,7 @@ async function loadUrl(config, url) {
return body
}

function sizeDB(config) {
function sizeCache(config) {
if (canUseCache(config, db)) {
return new Promise((resolve, reject) => {
const transaction = db.transaction("cache", "readwrite");
Expand All @@ -93,7 +108,32 @@ function sizeDB(config) {
}
}

function clearDB(config) {
async function invalidateCache(config) {
if (canUseCache(config, db)) {
const meta = await loadResource({...config, cache: false}, 'meta')
const upstream_deploy_date = parseInt(meta.deploy_date)
const transaction = db.transaction("cache", "readwrite");
const objectStore = transaction.objectStore("cache");
const index = objectStore.index("deploy_date_index")
const range = IDBKeyRange.upperBound(upstream_deploy_date, true);
const request = index.getAllKeys(range);

request.onsuccess = () => {
const keys = request.result;
keys.forEach(pk => {
objectStore.delete(pk);
log(`invalidated ${pk}`);
});
return true
};
request.onerror = () => {throw new Error(request.error);
};
} else {
throw new Error('cache not available')
}
}

function clearCache(config) {
if (canUseCache(config, db)) {
return new Promise((resolve, reject) => {
const transaction = db.transaction("cache", "readwrite");
Expand All @@ -107,4 +147,4 @@ function clearDB(config) {
}
}

export { loadResource, openDB, sizeDB, clearDB }
export { loadResource, openCache, sizeCache, clearCache, invalidateCache }
14 changes: 9 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import endpoints from './endpoints.json' with { type: "json" }
import rootEndpoints from './rootEndpoints.json' with { type: "json" }
import { loadResource, openDB, sizeDB, clearDB } from './getter.js'
import { loadResource, openCache, sizeCache, clearCache, invalidateCache } from './getter.js'
import { Config } from './config.js'

export class Pokedex {
Expand All @@ -18,7 +18,7 @@ export class Pokedex {

// if the user has submitted a Name or an ID, return the JSON promise
if (typeof input === 'number' || typeof input === 'string') {
return loadResource(this.config, `${this.config.versionPath}${endpoint[2].replace(':id', input)}`)
return loadResource(this.config, `${endpoint[2].replace(':id', input)}`)
}

// if the user has submitted an Array
Expand All @@ -44,7 +44,7 @@ export class Pokedex {
limit = config.limit
}
}
return loadResource(this.config, `${this.config.versionPath}${rootEndpoint[1]}?limit=${limit}&offset=${offset}`)
return loadResource(this.config, `${rootEndpoint[1]}?limit=${limit}&offset=${offset}`)
}
this[rootEndpoint[0]] = this[rootEndpointFullName]
})
Expand All @@ -56,7 +56,7 @@ export class Pokedex {

static async init(config) {
config = new Config(config)
await openDB(config)
await openCache(config)
return new Pokedex(config)
}

Expand All @@ -72,6 +72,10 @@ export class Pokedex {
return clearDB(this.config)
}

invalidateCache() {
return invalidateCache(this.config)
}

resource(path) {
if (typeof path === 'string') {
return loadResource(this.config, path)
Expand All @@ -85,7 +89,7 @@ export class Pokedex {

function mapResources(config, endpoint, inputs) {
return inputs.map(input => {
return loadResource(config, `${config.versionPath}${endpoint[2].replace(':id', input)}`)
return loadResource(config, `${endpoint[2].replace(':id', input)}`)
})
}

Expand Down
5 changes: 3 additions & 2 deletions test/test.html.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,17 @@ describe("pokedex", function () {

describe(".resource(Mixed: array) not cached", function () {
it("should have property name", async function () {
const res = await customP.resource(['/api/v2/pokemon/36', 'api/v2/berry/8', 'https://pokeapi.co/api/v2/ability/9/']);
const res = await customP.resource(['pokemon/37', '/pokemon/36', '/berry/8', 'https://pokeapi.co/api/v2/ability/9/']);
expect(res[0]).to.have.property('name');
expect(res[1]).to.have.property('name');
expect(res[2]).to.have.property('name');
expect(res[3]).to.have.property('name');
});
});

describe(".resource(Path: string)", function () {
it("should have property height", async function () {
const res = await defaultP.resource('/api/v2/pokemon/34');
const res = await defaultP.resource('pokemon/34');
expect(res).to.have.property('height');
});
});
Expand Down