UNPKG

@kit-data-manager/pid-component

Version:

The PID-Component is a web component that can be used to evaluate and display FAIR Digital Objects, PIDs, ORCiDs, and possibly other identifiers in a user-friendly way. It is easily extensible to support other identifier types.

181 lines (180 loc) 8.25 kB
/*! * * Copyright 2024-2026 Karlsruhe Institute of Technology. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ import { Parser } from "./Parser"; import { renderers } from "./utils"; import { openDB } from "@tempfix/idb"; const dbName = 'pid-component'; const dbVersion = 1; export class Database { constructor() { this.dbPromise = openDB(dbName, dbVersion, { upgrade(db) { const entityStore = db.createObjectStore('entities', { keyPath: 'value', }); entityStore.createIndex('by-context', 'context', { unique: false }); const relationStore = db.createObjectStore('relations', { autoIncrement: true, }); relationStore.createIndex('by-start', 'start', { unique: false }); relationStore.createIndex('by-description', 'description', { unique: false }); relationStore.createIndex('by-end', 'end', { unique: false }); }, }); } async addEntity(renderer, orderedRendererKeys) { const context = document.documentURI; const db = await this.dbPromise; const entityKey = this.normalizeKey(renderer.value); await db .add('entities', { value: entityKey, rendererKey: renderer.getSettingsKey(), orderedRendererKeys: orderedRendererKeys !== null && orderedRendererKeys !== void 0 ? orderedRendererKeys : null, context: context, lastAccess: new Date(), lastData: renderer.data, }) .catch(reason => { if (reason.name === 'ConstraintError') { console.debug('Entity already exists', reason); } else console.error('Could not add entity', reason); }); console.debug('added entity', renderer); const tx = db.transaction('relations', 'readwrite'); const promises = []; for (const item of renderer.items) { const relation = { start: renderer.value, description: item.keyTitle, end: item.value, }; const index = tx.store.index('by-start'); let cursor = await index.openCursor(); let relationExists = false; while (cursor) { if (cursor.value.start === relation.start && cursor.value.end === relation.end && cursor.value.description === relation.description) { relationExists = true; break; } cursor = await cursor.continue(); } if (!relationExists) { promises.push(tx.store.add(relation)); } } promises.push(tx.done); await Promise.all(promises); console.debug('added relations', promises); } async getEntity(value, settings, orderedRendererKeys, fallbackToAll = true) { var _a, _b; const entityKey = this.normalizeKey(value); try { const db = await this.dbPromise; const entity = await db.get('entities', entityKey); if (entity !== undefined) { const cachedOrderedKeys = entity.orderedRendererKeys; const currentOrderedKeys = orderedRendererKeys !== null && orderedRendererKeys !== void 0 ? orderedRendererKeys : null; const orderedKeysChanged = JSON.stringify(cachedOrderedKeys) !== JSON.stringify(currentOrderedKeys); if (orderedKeysChanged || (orderedRendererKeys && orderedRendererKeys.length > 0 && !orderedRendererKeys.includes(entity.rendererKey))) { console.debug('Ordered renderer keys changed or cached renderer not in ordered list, re-detecting', { cached: cachedOrderedKeys, current: currentOrderedKeys, cachedRendererKey: entity.rendererKey, currentAllowedKeys: orderedRendererKeys, }); await this.deleteEntity(value); } else { console.debug('Found entity for value in db', entity, value); const entitySettings = (_a = settings.find(value => value.type === entity.rendererKey)) === null || _a === void 0 ? void 0 : _a.values; const ttl = entitySettings === null || entitySettings === void 0 ? void 0 : entitySettings.find(value => value.name === 'ttl'); if (ttl != undefined && ttl.value != undefined && (new Date().getTime() - entity.lastAccess.getTime() > ttl.value || ttl.value === 0)) { console.log('TTL expired! Deleting entry in db', ttl.value, new Date().getTime() - entity.lastAccess.getTime()); await this.deleteEntity(value); } else { console.log('TTL not expired or undefined', new Date().getTime() - entity.lastAccess.getTime()); const renderer = new (renderers.find(renderer => renderer.key === entity.rendererKey).constructor)(value, entitySettings); renderer.settings = entitySettings; await renderer.init(entity.lastData); return renderer; } } } } catch (error) { console.error('Could not get entity from db', error); } console.debug('No valid entity found for value in db', value); const renderer = await Parser.getBestFit(value, settings, orderedRendererKeys, fallbackToAll); if (renderer === null) { console.debug('No renderer matched for value', value); return null; } renderer.settings = (_b = settings.find(value => value.type === renderer.getSettingsKey())) === null || _b === void 0 ? void 0 : _b.values; await renderer.init(); if (renderer.isResolvable()) { await this.addEntity(renderer, orderedRendererKeys); console.debug('added entity to db', value, renderer); } else { console.debug('renderer not resolvable, skipping IndexedDB cache', value, renderer.getSettingsKey()); } return renderer; } async deleteEntity(value) { const db = await this.dbPromise; const entityKey = this.normalizeKey(value); await db.delete('entities', entityKey); const tx = db.transaction('relations', 'readwrite'); const index = tx.store.index('by-start'); let cursor = await index.openCursor(); while (cursor) { if (cursor.value.start === value || cursor.value.end === value) { await tx.store.delete(cursor.primaryKey); } cursor = await cursor.continue(); } console.log('deleted entity', value); await tx.done; } async clearEntities() { const db = await this.dbPromise; await db.clear('entities'); await db.clear('relations'); console.log('cleared entities'); } normalizeKey(value) { let entityKey = value; if (typeof entityKey !== 'string' && typeof entityKey !== 'number') { try { entityKey = JSON.stringify(entityKey); } catch (_a) { entityKey = String(entityKey); } console.warn('Converted entity value to string for IndexedDB key (delete):', entityKey); } return entityKey; } } //# sourceMappingURL=IndexedDBUtil.js.map