UNPKG

angular-indexed-db-helper

Version:

A powerful and flexible Angular library for managing client-side storage using IndexedDB with support for cache expiration and CRUD operations.

293 lines (286 loc) 12.5 kB
import * as i0 from '@angular/core'; import { InjectionToken, Injectable, Inject } from '@angular/core'; // Define InjectionTokens for dbName and storeName const DB_NAME = new InjectionToken('DB_NAME'); const STORE_NAME = new InjectionToken('STORE_NAME'); const CACHED_TIME = new InjectionToken('CACHED_TIME'); // Add new token for cached time class DataToStore { id; value; savedTime; cachedTime = null; constructor(id, value) { this.id = id; this.value = value; this.savedTime = new Date().toISOString(); // Generate the current timestamp } } class IndexedDbHandler { dbName; storeName; cachedTime; dbInitialized; constructor(dbName, storeName, cachedTime) { this.dbName = dbName; this.storeName = storeName; this.cachedTime = cachedTime; this.dbInitialized = this.initDB(); } /** * Ensures that the database is fully set up before performing any operations. * @returns A promise that resolves when the IndexedDB is initialized. */ async whenInitialized() { return this.dbInitialized; } /** * Initializes the IndexedDB and creates the object store if it doesn't exist. * @returns A promise that resolves to the IndexedDB instance. */ initDB() { return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName); request.onupgradeneeded = (event) => { const db = event.target.result; if (!db.objectStoreNames.contains(this.storeName)) { db.createObjectStore(this.storeName, { keyPath: 'id' }); console.info(`Object store '${this.storeName}' created.`); } }; request.onsuccess = (event) => { const db = event.target.result; resolve(db); }; request.onerror = (event) => { console.error('Error opening IndexedDB:', event); reject(event.target.error); }; }); } /** * Saves data to the IndexedDB. * @param key The key used to store the data. * @param value The data to be saved. * @param cacheTime Optional parameter to specify the cache time for the data. * @returns A promise that resolves when the data is saved. */ async saveData(key, value, cacheTime = null) { await this.whenInitialized(); // Ensure DB is initialized const db = await this.whenInitialized(); const transaction = db.transaction(this.storeName, 'readwrite'); const store = transaction.objectStore(this.storeName); // Create a new instance of the DataToStore class const dataToStore = new DataToStore(key, value); dataToStore.cachedTime = cacheTime; // Set the cacheTime (null if not provided) return new Promise((resolve, reject) => { const request = store.put(dataToStore); // Save the object request.onsuccess = () => { resolve(); }; request.onerror = (event) => { reject(`Error saving data: ${event}`); }; }); } /** * Retrieves data from the IndexedDB by key. * @param key The key of the data to retrieve. * @returns A promise that resolves to the data or null if not found or expired. */ async getData(key) { await this.whenInitialized(); // Ensure DB is initialized const db = await this.whenInitialized(); const transaction = db.transaction(this.storeName, 'readonly'); const store = transaction.objectStore(this.storeName); return new Promise((resolve, reject) => { const request = store.get(key); // Retrieve data by key request.onsuccess = async () => { if (request.result === undefined) { resolve(null); // Return null if no data found } else { // Check expiration based on cachedTime or CACHED_TIME const cachedTime = request.result.cachedTime; let isExpired = false; if (cachedTime === null) { // If cachedTime is null, use the default CACHED_TIME for expiration check isExpired = await this.checkIfExpired(request.result.savedTime, this.cachedTime); } else { // If cachedTime exists, check against it isExpired = await this.checkIfExpired(request.result.savedTime, cachedTime); } if (isExpired) { resolve(null); // Return null if data is expired } else { resolve(request.result.value); // Return the value if not expired } } }; request.onerror = (event) => { reject(`Error retrieving data: ${event}`); }; }); } /** * Removes data from the IndexedDB by key. * @param key The key of the data to remove. * @returns A promise that resolves when the data is removed. */ async removeData(key) { await this.whenInitialized(); // Ensure DB is initialized const db = await this.whenInitialized(); const transaction = db.transaction(this.storeName, 'readwrite'); const store = transaction.objectStore(this.storeName); return new Promise((resolve, reject) => { const request = store.delete(key); // Delete data by key request.onsuccess = () => { resolve(); // Resolve when the data is removed }; request.onerror = (event) => { reject(`Error removing data: ${event}`); }; }); } /** * Updates data in the IndexedDB by key. * @param key The key of the data to update. * @param value The new data to update. * @returns A promise that resolves when the data is updated. */ async updateData(key, value) { await this.whenInitialized(); // Ensure DB is initialized const db = await this.whenInitialized(); const transaction = db.transaction(this.storeName, 'readwrite'); const store = transaction.objectStore(this.storeName); // Create a new instance of the DataToStore class const dataToStore = new DataToStore(key, value); return new Promise((resolve, reject) => { const request = store.put(dataToStore); // Save the object request.onsuccess = () => { resolve(); }; request.onerror = (event) => { reject(`Error saving data: ${event}`); }; }); } /** * Retrieves all data from the IndexedDB store. * Filters out expired data based on the cache time or default expiration time. * @returns A promise that resolves to an array of all valid data items. */ async getAll() { await this.whenInitialized(); // Ensure DB is initialized const db = await this.whenInitialized(); const transaction = db.transaction(this.storeName, 'readonly'); const store = transaction.objectStore(this.storeName); return new Promise((resolve, reject) => { const getRequest = store.getAll(); // Get all records from the store // Handle success getRequest.onsuccess = async () => { const result = getRequest.result; if (result === undefined || result.length === 0) { resolve([]); // Return an empty array if no data found } else { // Filter out expired items using cachedTime or CACHED_TIME const filteredResults = await Promise.all(result.map(async (item) => { let isExpired = false; const cachedTime = item.cachedTime; if (cachedTime === null) { // If cachedTime is null, compare against CACHED_TIME isExpired = await this.checkIfExpired(item.savedTime, this.cachedTime); } else { // Compare against cachedTime isExpired = await this.checkIfExpired(item.savedTime, cachedTime); } return isExpired ? null : item.value; // Exclude expired items })); // Filter out null values (expired data) resolve(filteredResults.filter(item => item !== null)); } }; // Handle error getRequest.onerror = (event) => { reject(`Error retrieving all data from IndexedDB: ${event}`); }; }); } /** * Clears all data in the IndexedDB store. * @returns A promise that resolves when the store is cleared. */ async clearStore() { await this.whenInitialized(); // Ensure DB is initialized const db = await this.whenInitialized(); const transaction = db.transaction(this.storeName, 'readwrite'); // Open a transaction in 'readwrite' mode const store = transaction.objectStore(this.storeName); return new Promise((resolve, reject) => { const request = store.clear(); // Clear all records in the store request.onsuccess = () => { resolve(); // Resolve if the store is cleared successfully }; request.onerror = (event) => { reject(`Error clearing the store: ${event}`); // Reject if there's an error }; }); } /** * Getter for the cached time value. * @returns The current cached time value. */ getCachedTime() { return this.cachedTime; } /** * Setter for the cached time value. * @param newCachedTime The new cached time value to set. */ setCachedTime(newCachedTime) { this.cachedTime = newCachedTime; // Update the cachedTime value } /** * Checks if the data has expired based on the saved time and comparison time. * @param savedTime The saved time of the data. * @param comparisonTimeInMs The comparison time in milliseconds. * @returns A promise that resolves to a boolean indicating if the data is expired. */ async checkIfExpired(savedTime, comparisonTimeInMs) { if (comparisonTimeInMs === 0) { return false; // If comparisonTime is 0, data never expires } const currentTime = new Date().getTime(); // Get current time in milliseconds const savedTimeStamp = new Date(savedTime).getTime(); // Convert savedTime to milliseconds const difference = currentTime - savedTimeStamp; // Calculate time difference // Check if the time difference exceeds the comparisonTime (in milliseconds) return difference > comparisonTimeInMs; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: IndexedDbHandler, deps: [{ token: DB_NAME }, { token: STORE_NAME }, { token: CACHED_TIME }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: IndexedDbHandler, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: IndexedDbHandler, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: () => [{ type: undefined, decorators: [{ type: Inject, args: [DB_NAME] }] }, { type: undefined, decorators: [{ type: Inject, args: [STORE_NAME] }] }, { type: undefined, decorators: [{ type: Inject, args: [CACHED_TIME] }] }] }); /* * Public API Surface of indexed-db */ /** * Generated bundle index. Do not edit. */ export { CACHED_TIME, DB_NAME, IndexedDbHandler, STORE_NAME }; //# sourceMappingURL=angular-indexed-db-helper.mjs.map