-
Notifications
You must be signed in to change notification settings - Fork 428
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core): use indexedDB POC for editState
- Loading branch information
1 parent
c98ed5e
commit 7f95804
Showing
2 changed files
with
247 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
194 changes: 194 additions & 0 deletions
194
packages/sanity/src/core/store/_legacy/document/document-pair/utils/indexedDbPOC.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
/* eslint-disable no-console */ | ||
import {isSanityDocument, type SanityDocument} from '@sanity/types' | ||
|
||
import {type IdPair} from '../../types' | ||
|
||
const DB_NAME = 'sanityDocumentsDB' | ||
const DB_VERSION = 1 | ||
const STORE_NAME = 'documents' | ||
|
||
let idb: IDBDatabase | null = null | ||
|
||
function openDatabase() { | ||
if (idb) { | ||
return Promise.resolve(idb) | ||
} | ||
return new Promise<IDBDatabase>((resolve, reject) => { | ||
const request = indexedDB.open(DB_NAME, DB_VERSION) | ||
|
||
request.onupgradeneeded = () => { | ||
const db = request.result | ||
if (!db.objectStoreNames.contains(STORE_NAME)) { | ||
db.createObjectStore(STORE_NAME, {keyPath: '_id'}) | ||
} | ||
} | ||
|
||
request.onsuccess = () => { | ||
idb = request.result | ||
resolve(request.result) | ||
} | ||
|
||
request.onerror = () => { | ||
reject(request.error) | ||
} | ||
}) | ||
} | ||
|
||
async function getDocumentFromIndexedDB(id: string): Promise<SanityDocument | null> { | ||
try { | ||
const db = await openDatabase() | ||
return new Promise<SanityDocument | null>((resolve, reject) => { | ||
const transaction = db.transaction(STORE_NAME, 'readonly') | ||
const store = transaction.objectStore(STORE_NAME) | ||
const request = store.get(id) | ||
|
||
request.onsuccess = () => { | ||
const result = request.result | ||
resolve(isSanityDocument(result) ? result : null) | ||
} | ||
|
||
transaction.onerror = () => { | ||
console.error(`Error retrieving document with ID ${id} from IndexedDB:`, request.error) | ||
reject(transaction.error) | ||
} | ||
}) | ||
} catch (error) { | ||
console.error(`Error opening IndexedDB:`, error) | ||
return null | ||
} | ||
} | ||
|
||
async function saveDocumentToIndexedDB(document: SanityDocument): Promise<void> { | ||
const db = await openDatabase() | ||
return new Promise<void>((resolve, reject) => { | ||
const transaction = db.transaction(STORE_NAME, 'readwrite') | ||
const store = transaction.objectStore(STORE_NAME) | ||
const request = store.put(document) | ||
|
||
request.onsuccess = () => { | ||
resolve() | ||
} | ||
|
||
transaction.onerror = () => { | ||
console.error(`Error saving document with ID ${document._id} to IndexedDB:`, request.error) | ||
reject(transaction.error) | ||
} | ||
}) | ||
} | ||
|
||
interface DocumentPair { | ||
draft: SanityDocument | null | ||
published: SanityDocument | null | ||
} | ||
|
||
/** | ||
* returns the pair in one transaction | ||
*/ | ||
async function getDocumentPairIndexedDB(idPair: IdPair): Promise<DocumentPair | null> { | ||
try { | ||
const db = await openDatabase() | ||
return new Promise<DocumentPair>((resolve, reject) => { | ||
const transaction = db.transaction(STORE_NAME, 'readonly') | ||
const store = transaction.objectStore(STORE_NAME) | ||
|
||
let draft: SanityDocument | null = null | ||
let published: SanityDocument | null = null | ||
|
||
transaction.oncomplete = () => { | ||
resolve({draft, published}) | ||
} | ||
|
||
// Handle transaction errors | ||
transaction.onerror = () => { | ||
console.error('Transaction error:', transaction.error) | ||
reject(transaction.error) | ||
} | ||
|
||
// Initiate the get request for the draft document | ||
const draftRequest = store.get(idPair.draftId) | ||
draftRequest.onsuccess = () => { | ||
const result = draftRequest.result | ||
draft = isSanityDocument(result) ? result : null | ||
} | ||
// Initiate the get request for the published document | ||
const publishedRequest = store.get(idPair.publishedId) | ||
publishedRequest.onsuccess = () => { | ||
const result = publishedRequest.result | ||
published = isSanityDocument(result) ? result : null | ||
} | ||
}) | ||
} catch (error) { | ||
console.error(`Error opening IndexedDB:`, error) | ||
return null | ||
} | ||
} | ||
|
||
async function saveDocumentPairIndexedDB(documentPair: DocumentPair): Promise<void> { | ||
try { | ||
const db = await openDatabase() | ||
return new Promise<void>((resolve, reject) => { | ||
const transaction = db.transaction(STORE_NAME, 'readwrite') | ||
const store = transaction.objectStore(STORE_NAME) | ||
|
||
transaction.oncomplete = () => { | ||
resolve() | ||
} | ||
|
||
transaction.onerror = () => { | ||
console.error('Transaction error:', transaction.error) | ||
reject(transaction.error) | ||
} | ||
|
||
// Save the draft document if it exists | ||
if (documentPair.draft) { | ||
store.put(documentPair.draft) | ||
} | ||
|
||
// Save the published document if it exists | ||
if (documentPair.published) { | ||
store.put(documentPair.published) | ||
} | ||
}) | ||
} catch (error) { | ||
console.error(`Error opening IndexedDB:`, error) | ||
// Optionally, rethrow the error or handle it | ||
throw error | ||
} | ||
} | ||
|
||
export const supportsIndexedDB = (() => { | ||
try { | ||
return 'indexedDB' in window && window.indexedDB !== null | ||
} catch (e) { | ||
return false | ||
} | ||
})() | ||
|
||
export async function getPairFromIndexedDB(idPair: IdPair): Promise<DocumentPair> { | ||
console.log('Getting idbPair', idPair) | ||
if (!supportsIndexedDB) { | ||
console.info("IndexedDB isn't supported, returning null") | ||
return { | ||
draft: null, | ||
published: null, | ||
} | ||
} | ||
console.time('getPairFromIndexedDB') | ||
const pair = await getDocumentPairIndexedDB(idPair) | ||
console.timeEnd('getPairFromIndexedDB') | ||
if (!pair) { | ||
return { | ||
draft: null, | ||
published: null, | ||
} | ||
} | ||
return pair | ||
} | ||
|
||
export async function savePairToIndexedDB(documentPair: DocumentPair | null) { | ||
console.log('Saving pair to indexedDB', documentPair?.published?._id || documentPair?.draft?._id) | ||
if (!supportsIndexedDB || !documentPair) return | ||
console.time('savePairToIndexedDB') | ||
await saveDocumentPairIndexedDB(documentPair) | ||
console.timeEnd('savePairToIndexedDB') | ||
} |