@dossierhq/sqlite-core
Version:
A library used by concrete SQLite adapters for Dossier.
177 lines • 13.2 kB
JavaScript
/// <reference types="./SqliteDatabaseAdapter.d.ts" />
import { notOk, ok } from '@dossierhq/core';
import { adminEntityArchivingGetEntityInfo } from './admin-entity/archivingGetEntityInfo.js';
import { adminCreateEntity } from './admin-entity/createEntity.js';
import { adminEntityCreateEntityEvent } from './admin-entity/createEntityEvent.js';
import { adminEntityDeleteEntities } from './admin-entity/deleteEntity.js';
import { adminEntityDeleteGetEntityInfo } from './admin-entity/deleteGetEntityInfo.js';
import { adminEntityGetMultiple } from './admin-entity/getEntities.js';
import { adminGetEntity } from './admin-entity/getEntity.js';
import { adminEntityGetEntityName } from './admin-entity/getEntityName.js';
import { adminEntityGetReferenceEntitiesInfo } from './admin-entity/getReferenceEntitiesInfo.js';
import { adminEntitySearchTotalCount } from './admin-entity/getTotalCount.js';
import { adminEntityIndexesUpdateLatest } from './admin-entity/indexesUpdateLatest.js';
import { adminEntityIndexesUpdatePublished } from './admin-entity/indexesUpdatePublished.js';
import { adminEntityPublishGetVersionInfo, adminEntityPublishUpdateEntity, } from './admin-entity/publishEntities.js';
import { adminEntitySampleEntities } from './admin-entity/sampleEntities.js';
import { adminEntitySearchEntities } from './admin-entity/searchEntities.js';
import { adminEntityUniqueIndexGetValues } from './admin-entity/uniqueIndexGetValues.js';
import { adminEntityUniqueIndexUpdateValues } from './admin-entity/uniqueIndexUpdateValues.js';
import { adminEntityUnpublishEntities, adminEntityUnpublishGetEntitiesInfo, adminEntityUnpublishGetPublishedReferencedEntities, } from './admin-entity/unpublishEntities.js';
import { adminEntityUpdateEntity, adminEntityUpdateGetEntityInfo, } from './admin-entity/updateEntity.js';
import { adminEntityUpdateStatus } from './admin-entity/updateStatus.js';
import { advisoryLockAcquire } from './advisory-lock/advisoryLockAcquire.js';
import { advisoryLockDeleteExpired } from './advisory-lock/advisoryLockDeleteExpired.js';
import { advisoryLockRelease } from './advisory-lock/advisoryLockRelease.js';
import { advisoryLockRenew } from './advisory-lock/advisoryLockRenew.js';
import { authCreateSession, authCreateSyncSessionForSubject } from './auth/createSession.js';
import { authGetPrincipals } from './auth/getPrincipals.js';
import { authGetPrincipalsTotalCount } from './auth/getPrincipalsTotalCount.js';
import { eventGetChangelogEvents } from './event/getChangelogEvents.js';
import { eventGetChangelogEventsEntityInfo } from './event/getChangelogEventsEntityInfo.js';
import { eventGetChangelogEventsTotalCount } from './event/getChangelogEventsTotalCount.js';
import { createInitializationContext } from './InitializationContext.js';
import { managementDirtyGetNextEntity } from './management/dirtyGetNextEntity.js';
import { managementDirtyMarkEntities } from './management/dirtyMarkEntities.js';
import { managementDirtyUpdateEntity } from './management/dirtyUpdateEntity.js';
import { managementOptimize } from './management/optimize.js';
import { managementSyncGetEvents } from './management/syncGetEvents.js';
import { managementSyncGetHeadEventId } from './management/syncGetHeadEventId.js';
import { publishedEntityGetEntities } from './published-entity/getEntities.js';
import { publishedEntityGetOne } from './published-entity/getEntity.js';
import { publishedEntitySearchTotalCount } from './published-entity/getTotalCount.js';
import { publishedEntitySampleEntities } from './published-entity/sampleEntities.js';
import { publishedEntitySearchEntities } from './published-entity/searchEntities.js';
import { queryNoneOrOne, queryOne, queryRun } from './QueryFunctions.js';
import { schemaGetSpecification } from './schema/getSpecification.js';
import { schemaUpdateCountEntitiesWithTypes } from './schema/updateCountEntitiesWithTypes.js';
import { schemaUpdateDeleteComponentTypesFromIndexes } from './schema/updateDeleteComponentTypesFromIndexes.js';
import { schemaUpdateModifyIndexes } from './schema/updateModifyIndexes.js';
import { schemaUpdateRenameTypes } from './schema/updateRenameTypes.js';
import { schemaUpdateSpecification } from './schema/updateSpecification.js';
import { checkMigrationStatus, migrateDatabaseIfNecessary } from './SchemaDefinition.js';
import { isSemVerEqualOrGreaterThan, parseSemVer } from './SemVer.js';
import { withNestedTransaction, withRootTransaction, } from './SqliteTransaction.js';
import { Mutex } from './utils/MutexUtils.js';
// For https://www.sqlite.org/stricttables.html
const minimumSupportedVersion = { major: 3, minor: 37, patch: 0 };
const supportedJournalModes = ['wal', 'delete', 'memory'];
export async function createSqliteDatabaseAdapterAdapter(context, sqliteAdapter, options) {
const database = { mutex: new Mutex(), adapter: sqliteAdapter };
const outerAdapter = createOuterAdapter(database);
const initializationContext = createInitializationContext(outerAdapter, context.logger, null);
const validityResult = await checkAdapterValidity(database, initializationContext);
if (validityResult.isError())
return validityResult;
const enableForeignKeysResult = await enableForeignKeys(database, initializationContext);
if (enableForeignKeysResult.isError())
return enableForeignKeysResult;
if (options.migrate) {
const migrationResult = await migrateDatabaseIfNecessary(database, initializationContext, options);
if (migrationResult.isError())
return migrationResult;
}
else {
const migrationResult = await checkMigrationStatus(database, initializationContext);
if (migrationResult.isError())
return migrationResult;
}
if (options.journalMode) {
const journalModeResult = await setJournalMode(database, initializationContext, options.journalMode);
if (journalModeResult.isError())
return journalModeResult;
}
return ok(outerAdapter);
}
async function setJournalMode(database, context, journalMode) {
if (!supportedJournalModes.includes(journalMode)) {
return notOk.Generic(`Unsupported journal mode (${journalMode})`);
}
// journalMode is safe to use here because we check it above
const result = await queryRun(database, context, `PRAGMA journal_mode = ${journalMode}`, undefined);
return result.isOk() ? ok(undefined) : result;
}
function createOuterAdapter(database) {
return {
adminEntityArchivingGetEntityInfo: (...args) => adminEntityArchivingGetEntityInfo(database, ...args),
adminEntityCreate: (...args) => adminCreateEntity(database, ...args),
adminEntityCreateEntityEvent: (...args) => adminEntityCreateEntityEvent(database, ...args),
adminEntityDeleteEntities: (...args) => adminEntityDeleteEntities(database, ...args),
adminEntityDeleteGetEntityInfo: (...args) => adminEntityDeleteGetEntityInfo(database, ...args),
adminEntityGetOne: (...args) => adminGetEntity(database, ...args),
adminEntityGetMultiple: (...args) => adminEntityGetMultiple(database, ...args),
adminEntityGetEntityName: (...args) => adminEntityGetEntityName(database, ...args),
adminEntityGetReferenceEntitiesInfo: (...args) => adminEntityGetReferenceEntitiesInfo(database, ...args),
adminEntityIndexesUpdateLatest: (...args) => adminEntityIndexesUpdateLatest(database, ...args),
adminEntityIndexesUpdatePublished: (...args) => adminEntityIndexesUpdatePublished(database, ...args),
adminEntityPublishGetVersionInfo: (...args) => adminEntityPublishGetVersionInfo(database, ...args),
adminEntityPublishUpdateEntity: (...args) => adminEntityPublishUpdateEntity(database, ...args),
adminEntitySampleEntities: (...args) => adminEntitySampleEntities(database, ...args),
adminEntitySearchEntities: (...args) => adminEntitySearchEntities(database, ...args),
adminEntitySearchTotalCount: (...args) => adminEntitySearchTotalCount(database, ...args),
adminEntityUniqueIndexGetValues: (...args) => adminEntityUniqueIndexGetValues(database, ...args),
adminEntityUniqueIndexUpdateValues: (...args) => adminEntityUniqueIndexUpdateValues(database, ...args),
adminEntityUpdateEntity: (...args) => adminEntityUpdateEntity(database, ...args),
adminEntityUpdateGetEntityInfo: (...args) => adminEntityUpdateGetEntityInfo(database, ...args),
adminEntityUpdateStatus: (...args) => adminEntityUpdateStatus(database, ...args),
adminEntityUnpublishGetEntitiesInfo: (...args) => adminEntityUnpublishGetEntitiesInfo(database, ...args),
adminEntityUnpublishEntities: (...args) => adminEntityUnpublishEntities(database, ...args),
adminEntityUnpublishGetPublishedReferencedEntities: (...args) => adminEntityUnpublishGetPublishedReferencedEntities(database, ...args),
advisoryLockAcquire: (...args) => advisoryLockAcquire(database, ...args),
advisoryLockDeleteExpired: (...args) => advisoryLockDeleteExpired(database, ...args),
advisoryLockRelease: (...args) => advisoryLockRelease(database, ...args),
advisoryLockRenew: (...args) => advisoryLockRenew(database, ...args),
authCreateSession: (...args) => authCreateSession(database, ...args),
authCreateSyncSessionForSubject: (...args) => authCreateSyncSessionForSubject(database, ...args),
authGetPrincipals: (...args) => authGetPrincipals(database, ...args),
authGetPrincipalsTotalCount: (...args) => authGetPrincipalsTotalCount(database, ...args),
eventGetChangelogEvents: (...args) => eventGetChangelogEvents(database, ...args),
eventGetChangelogEventsEntityInfo: (...args) => eventGetChangelogEventsEntityInfo(database, ...args),
eventGetChangelogEventsTotalCount: (...args) => eventGetChangelogEventsTotalCount(database, ...args),
disconnect: () => database.adapter.disconnect(),
managementDirtyMarkEntities: (...args) => managementDirtyMarkEntities(database, ...args),
managementOptimize: (...args) => managementOptimize(database, ...args),
managementDirtyGetNextEntity: (...args) => managementDirtyGetNextEntity(database, ...args),
managementDirtyUpdateEntity: (...args) => managementDirtyUpdateEntity(database, ...args),
managementSyncGetEvents: (...args) => managementSyncGetEvents(database, ...args),
managementSyncGetHeadEventId: (...args) => managementSyncGetHeadEventId(database, ...args),
publishedEntityGetOne: (...args) => publishedEntityGetOne(database, ...args),
publishedEntityGetEntities: (...args) => publishedEntityGetEntities(database, ...args),
publishedEntitySampleEntities: (...args) => publishedEntitySampleEntities(database, ...args),
publishedEntitySearchEntities: (...args) => publishedEntitySearchEntities(database, ...args),
publishedEntitySearchTotalCount: (...args) => publishedEntitySearchTotalCount(database, ...args),
schemaGetSpecification: (...args) => schemaGetSpecification(database, ...args),
schemaUpdateCountEntitiesWithTypes: (...args) => schemaUpdateCountEntitiesWithTypes(database, ...args),
schemaUpdateDeleteComponentTypesFromIndexes: (...args) => schemaUpdateDeleteComponentTypesFromIndexes(database, ...args),
schemaUpdateModifyIndexes: (...args) => schemaUpdateModifyIndexes(database, ...args),
schemaUpdateRenameTypes: (...args) => schemaUpdateRenameTypes(database, ...args),
schemaUpdateSpecification: (...args) => schemaUpdateSpecification(database, ...args),
withNestedTransaction: (...args) => withNestedTransaction(database, ...args),
withRootTransaction: (...args) => withRootTransaction(database, ...args),
};
}
async function checkAdapterValidity(database, context) {
// Check the SQLite version
const versionResult = await queryOne(database, context, 'SELECT sqlite_version() AS version', undefined);
if (versionResult.isError())
return versionResult;
const { version } = versionResult.value;
const isSupported = isSemVerEqualOrGreaterThan(parseSemVer(version), minimumSupportedVersion);
if (!isSupported) {
return notOk.BadRequest(`Database is using sqlite ${version}, (${minimumSupportedVersion.major}.${minimumSupportedVersion.minor}.${minimumSupportedVersion.patch}+ required)`);
}
// Check that foreign keys are supported (enabling them is done later)
const foreignKeysResult = await queryNoneOrOne(database, context, 'PRAGMA foreign_keys');
if (foreignKeysResult.isError())
return foreignKeysResult;
if (!foreignKeysResult.value) {
return notOk.BadRequest('Foreign keys are not supported, PRAGMA foreign_keys returned no rows');
}
return ok(undefined);
}
async function enableForeignKeys(database, context) {
// Foreign keys need to be enabled for each connection: https://www.sqlite.org/foreignkeys.html#fk_enable
const result = await queryRun(database, context, 'PRAGMA foreign_keys = ON', undefined);
return result.isOk() ? ok(undefined) : result;
}
//# sourceMappingURL=SqliteDatabaseAdapter.js.map