// 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 = ""; let version = 1; interface IDBRequestEvent extends Event { target: IDBRequest; } // IndexedDB uses DOMException, so let's use it for error typing type DBError = Event & { target: { errorCode: DOMException }; }; function upgrade_0to1(db:IDBDatabase) { let store = db.createObjectStore(postStoreName, { keyPath: "id", autoIncrement: true }); store.createIndex("datetimeIndex", "post_timestamp", { unique: false }); store.createIndex("postIDIndex", "data.post_id", { unique: true }); } export function openDatabase(userID: string): Promise { const dbName = `user_${userID}` return new Promise((resolve, reject) => { const request: IDBOpenDBRequest = indexedDB.open(dbName, version); request.onerror = (event: 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; upgrade_0to1(db); }; request.onsuccess = (event: Event) => { const db: IDBDatabase = (event.target as IDBOpenDBRequest).result; resolve(db); }; }); } async function getDBTransactionStore(userID:string) { const db = await openDatabase(userID); const transaction = db.transaction(postStoreName, "readwrite"); const store = transaction.objectStore(postStoreName); return {db, transaction, store} } export async function addData(userID: string, data: any): Promise { try { const {db, transaction, store} = await getDBTransactionStore(userID); 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, transaction, store} = await getDBTransactionStore(userID); 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, transaction, store} = await getDBTransactionStore(userID); 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, transaction, store} = await getDBTransactionStore(userID); 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 checkPostIds(userID: string, post_ids: string[]) { try { const {db, transaction, store} = await getDBTransactionStore(userID); 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 postIdsNeeded: any = []; for (let id of post_ids) { try { let havePost = await new Promise((resolve, reject) => { const getRequest = index.getKey(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) { postIdsNeeded.push(id); } } catch (error) { console.error("Error processing post:", error); } } console.log(`checkPostIds need ${postIdsNeeded.length} posts`); return postIdsNeeded; } catch (error) { console.error("Error in opening database:", error); } } export async function mergeDataArray(userID: string, array: any[]): Promise { try { const {db, transaction, store} = await getDBTransactionStore(userID); 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 getPostForUser(userID: string, postID: string): Promise { } export async function getData(userID: string, lowerID: Date, upperID: Date): Promise { const { store } = await getDBTransactionStore(userID); const keyRangeValue = IDBKeyRange.bound(lowerID, upperID); const index = store.index("datetimeIndex"); return new Promise((resolve, reject) => { const getAllRequest = index.getAll(keyRangeValue); getAllRequest.onsuccess = () => { const records = getAllRequest.result.map((item: any) => item.data); resolve(records); }; getAllRequest.onerror = () => { console.error('Transaction failed:', getAllRequest.error?.message); reject(getAllRequest.error); }; }); } export async function getAllData(userID: string): Promise { const {store} = await getDBTransactionStore(userID); 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 }; }); } export async function getAllIds(userID: string): Promise { const {store} = await getDBTransactionStore(userID); const index = store.index("postIDIndex"); let keys: string[] = []; return new Promise((resolve, reject) => { let request = index.openKeyCursor(); request.onsuccess = (event:any) => { let cursor = event.target.result; if (cursor) { keys.push(cursor.key); cursor.continue(); } else { resolve(keys); } }; request.onerror = (event: any) => { reject(event); }; }); } export async function getPostsByIds(userID:string, postIDs:string[]) { const {store} = await getDBTransactionStore(userID); const index = store.index("postIDIndex"); let posts = []; for (const postID of postIDs) { const post = await new Promise((resolve, reject) => { let request = index.get(postID); request.onsuccess = (event:any) => { resolve(event.target.result); // Resolve with the post }; request.onerror = (event) => { reject(event); // Reject if any error occurs }; }); if (post) { posts.push(post); // Add the post to the result array if found } } return posts; // Return the array of posts }