diff --git a/lib/ops/integrity-store-ops.js b/lib/ops/integrity-store-ops.js new file mode 100644 --- /dev/null +++ b/lib/ops/integrity-store-ops.js @@ -0,0 +1,118 @@ +// @flow + +import { type BaseStoreOpsHandlers } from './base-ops.js'; +import type { ThreadHashes, IntegrityStore } from '../types/integrity-types.js'; +import { entries } from '../utils/objects.js'; + +// client types +export type ReplaceIntegrityThreadHashesOperation = { + +type: 'replace_integrity_thread_hashes', + +payload: { +threadHashes: ThreadHashes }, +}; + +export type RemoveIntegrityThreadHashesOperation = { + +type: 'remove_integrity_thread_hashes', + +payload: { +ids: $ReadOnlyArray }, +}; + +export type RemoveAllIntegrityThreadHashesOperation = { + +type: 'remove_all_integrity_thread_hashes', +}; + +export type IntegrityStoreOperation = + | ReplaceIntegrityThreadHashesOperation + | RemoveIntegrityThreadHashesOperation + | RemoveAllIntegrityThreadHashesOperation; + +// SQLite types +export type ClientDBIntegrityThreadHash = { + +id: string, + +threadHash: string, +}; + +export type ClientDBReplaceIntegrityThreadHashOperation = { + +type: 'replace_integrity_thread_hashes', + +payload: { +threadHashes: $ReadOnlyArray }, +}; + +export type ClientDBIntegrityStoreOperation = + | ClientDBReplaceIntegrityThreadHashOperation + | RemoveIntegrityThreadHashesOperation + | RemoveAllIntegrityThreadHashesOperation; + +const integrityStoreOpsHandlers: BaseStoreOpsHandlers< + IntegrityStore, + IntegrityStoreOperation, + ClientDBIntegrityStoreOperation, + ThreadHashes, + ClientDBIntegrityThreadHash, +> = { + processStoreOperations( + integrityStore: IntegrityStore, + ops: $ReadOnlyArray, + ): IntegrityStore { + if (ops.length === 0) { + return integrityStore; + } + + let processedThreadHashes = { ...integrityStore.threadHashes }; + for (const operation: IntegrityStoreOperation of ops) { + if (operation.type === 'replace_integrity_thread_hashes') { + for (const id in operation.payload.threadHashes) { + processedThreadHashes[id] = operation.payload.threadHashes[id]; + } + } else if (operation.type === 'remove_integrity_thread_hashes') { + for (const id of operation.payload.ids) { + delete processedThreadHashes[id]; + } + } else if (operation.type === 'remove_all_integrity_thread_hashes') { + processedThreadHashes = {}; + } + } + return { ...integrityStore, threadHashes: processedThreadHashes }; + }, + + convertOpsToClientDBOps( + ops: $ReadOnlyArray, + ): $ReadOnlyArray { + const convertedOperations = ops.map(integrityStoreOperation => { + if ( + integrityStoreOperation.type === 'remove_all_integrity_thread_hashes' || + integrityStoreOperation.type === 'remove_integrity_thread_hashes' + ) { + return integrityStoreOperation; + } + + const { threadHashes } = integrityStoreOperation.payload; + const dbIntegrityThreadHashes: ClientDBIntegrityThreadHash[] = entries( + threadHashes, + ).map(([id, threadHash]) => ({ + id: id, + threadHash: threadHash.toString(), + })); + + if (dbIntegrityThreadHashes.length === 0) { + return undefined; + } + return { + type: 'replace_integrity_thread_hashes', + payload: { threadHashes: dbIntegrityThreadHashes }, + }; + }); + + return convertedOperations.filter(Boolean); + }, + + translateClientDBData( + data: $ReadOnlyArray, + ): ThreadHashes { + return Object.fromEntries( + data.map((dbThreadHash: ClientDBIntegrityThreadHash) => [ + dbThreadHash.id, + Number(dbThreadHash.threadHash), + ]), + ); + }, +}; + +export { integrityStoreOpsHandlers }; diff --git a/lib/types/integrity-types.js b/lib/types/integrity-types.js --- a/lib/types/integrity-types.js +++ b/lib/types/integrity-types.js @@ -1,10 +1,14 @@ // @flow export type IntegrityStore = { - +threadHashes: { +[string]: number }, - +threadHashingStatus: - | 'data_not_loaded' - | 'starting' - | 'running' - | 'completed', + +threadHashes: ThreadHashes, + +threadHashingStatus: ThreadHashingStatus, }; + +export type ThreadHashes = { +[string]: number }; + +export type ThreadHashingStatus = + | 'data_not_loaded' + | 'starting' + | 'running' + | 'completed';