// interface MyJsonObject { // id: string; // name: string; // email: string; // } // Efficiently storing data in indexdb: https://stackoverflow.com/a/62975917 const postStoreName: string = "posts"; let keyBase = "dandelion_posts_v1_" let key = ""; interface IDBRequestEvent extends Event { target: IDBRequest; } // IndexedDB uses DOMException, so let's use it for error typing type DBError = Event & { target: { errorCode: DOMException }; }; export function openDatabase(userID: string): Promise { const dbName = `user_${userID}` return new Promise((resolve, reject) => { const request: IDBOpenDBRequest = indexedDB.open(dbName, 1); request.onerror = (event: Event) => { // Use a type assertion to access the specific properties of IDBRequest error event const errorEvent = event as IDBRequestEvent; reject(`Database error: ${errorEvent.target.error?.message}`); }; request.onupgradeneeded = (event: IDBVersionChangeEvent) => { const db: IDBDatabase = (event.target as IDBOpenDBRequest).result; if (!db.objectStoreNames.contains(postStoreName)) { let store = db.createObjectStore(postStoreName, { keyPath: "id", autoIncrement: true }); store.createIndex("datetimeIndex", "post_timestamp", { unique: false }); store.createIndex("postIDIndex", "data.post_id", { unique: true }); } }; request.onsuccess = (event: Event) => { const db: IDBDatabase = (event.target as IDBOpenDBRequest).result; resolve(db); }; }); } export async function addData(userID: string, data: any): Promise { try { const db = await openDatabase(userID); const transaction = db.transaction(postStoreName, "readwrite"); const store = transaction.objectStore(postStoreName); const addRequest = store.add({ post_timestamp: data.post_timestamp, data: data }); addRequest.onsuccess = (e: Event) => { // console.log('Data has been added:', (e.target as IDBRequest).result); }; addRequest.onerror = (event: Event) => { // Use a type assertion to access the specific properties of IDBRequest error event const errorEvent = event as IDBRequestEvent; console.error('Error in adding data:', errorEvent.target.error?.message); }; } catch (error) { console.error('Error in opening database:', error); } } export async function deleteData(userID: string, postID: string) { try { const db = await openDatabase(userID); const transaction = db.transaction(postStoreName, "readwrite"); const store = transaction.objectStore(postStoreName); const index = store.index("postIDIndex"); const getRequest = index.getKey(postID); getRequest.onerror = e => console.log((e.target as IDBRequest).error) getRequest.onsuccess = e => { const key = (e.target as IDBRequest).result; if (key === undefined) { console.error("Post not found"); return null; } const deleteRequest = store.delete(key); deleteRequest.onerror = e => { console.error((e.target as IDBRequest).error); return false }; deleteRequest.onsuccess = () => true; } } catch (error) { console.error('Error in opening database:', error); } } export async function clearData(userID: string) { try { const db = await openDatabase(userID); const transaction = db.transaction(postStoreName, "readwrite"); const store = transaction.objectStore(postStoreName); const clearRequest = store.clear(); clearRequest.onsuccess = (e: Event) => { // console.log('Data has been added:', (e.target as IDBRequest).result); }; clearRequest.onerror = (event: Event) => { // Use a type assertion to access the specific properties of IDBRequest error event const errorEvent = event as IDBRequestEvent; console.error('Error in clearing data:', errorEvent.target.error?.message); }; } catch (error) { console.error('Error in opening database:', error); } } export async function addDataArray(userID: string, array: any[]): Promise { try { const db = await openDatabase(userID); const transaction = db.transaction(postStoreName, "readwrite"); const store = transaction.objectStore(postStoreName); let count = 0; array.reverse(); for (let data of array) { const addRequest = store.add({ post_timestamp: data.post_timestamp, data: data }); addRequest.onsuccess = (e: Event) => { // console.log('Data has been added:', (e.target as IDBRequest).result); }; addRequest.onerror = (event: Event) => { // Use a type assertion to access the specific properties of IDBRequest error event const errorEvent = event as IDBRequestEvent; console.error('Error in adding data:', errorEvent.target.error?.message); }; count++; // if (count % 100 === 0) { // console.log(`Added ${count} posts...`); // } } } catch (error) { console.error('Error in opening database:', error); } } export async function mergeDataArray(userID: string, array:any[]): Promise { try { const db = await openDatabase(userID); const transaction = db.transaction(postStoreName, "readwrite"); const store = transaction.objectStore(postStoreName); const index = store.index("postIDIndex"); transaction.oncomplete = () => { console.log("Transaction completed successfully"); db.close(); }; transaction.onerror = (event) => { console.error("Transaction error:", (event.target as any).error); db.close(); }; let postsToWrite:any = []; for (let post of array) { try { let havePost = await new Promise((resolve, reject) => { const getRequest = index.getKey(post.post_id); getRequest.onerror = (e) => { console.log((e.target as IDBRequest).error); reject(e); }; getRequest.onsuccess = async (e) => { const key = (e.target as IDBRequest).result; resolve(key !== undefined) }; }); // console.log(post.post_id, havePost); if (!havePost ) { postsToWrite.push(post); } } catch (error) { console.error("Error processing post:", error); } } console.log(`Writing ${postsToWrite.length} posts`); await addDataArray(userID, postsToWrite); } catch (error) { console.error("Error in opening database:", error); } } export async function getData(userID: string, lowerID: Date, upperID: Date): Promise { const db = await openDatabase(userID); const transaction = db.transaction(postStoreName, "readonly"); const store = transaction.objectStore(postStoreName); return new Promise((resolve, reject) => { const keyRangeValue = IDBKeyRange.bound(lowerID, upperID); const records: any[] = []; const index = store.index("datetimeIndex"); const cursorRequest = index.openCursor(keyRangeValue); cursorRequest.onsuccess = (event: Event) => { const cursor = (event.target as IDBRequest).result as IDBCursorWithValue; if (cursor) { records.push(cursor.value.data); // Collect the record cursor.continue(); // Move to the next item in the range } else { // No more entries in the range resolve(records); } }; cursorRequest.onerror = (event: Event) => { // Use a type assertion to access the specific properties of IDBRequest error event const errorEvent = event as IDBRequestEvent; console.error('Transaction failed:', errorEvent.target.error?.message); reject(errorEvent.target.error); // Reject the promise if there's an error }; }); } export async function getAllData(userID: string): Promise { const db = await openDatabase(userID); const transaction = db.transaction(postStoreName, "readonly"); const store = transaction.objectStore(postStoreName); return new Promise((resolve, reject) => { const getRequest = store.getAll(); getRequest.onsuccess = () => { if (getRequest.result) { // console.log('Retrieved data:', getRequest.result.jsonData); // resolve(getRequest.result.jsonData as any); resolve(getRequest.result); } else { console.log('No data record found for key', key); resolve(undefined); // explicitly resolve with undefined when no data is found } }; getRequest.onerror = (event: Event) => { // Use a type assertion to access the specific properties of IDBRequest error event const errorEvent = event as IDBRequestEvent; console.error('Transaction failed:', errorEvent.target.error?.message); reject(errorEvent.target.error); // reject the promise if there's an error }; }); }