UNPKG

@nozbe/watermelondb

Version:

Build powerful React Native and React web apps that scale from hundreds to tens of thousands of records and remain fast

228 lines (198 loc) 6.01 kB
// @flow import DatabaseDriver from './DatabaseDriver' type Connection = { driver: DatabaseDriver, queue: any[], status: string, } class DatabaseBridge { connections: { [key: number]: Connection } = {} // MARK: - Asynchronous connections connected(tag: number, driver: DatabaseDriver): void { this.connections[tag] = { driver, queue: [], status: 'connected' } } waiting(tag: number, driver: DatabaseDriver): void { this.connections[tag] = { driver, queue: [], status: 'waiting' } } initialize( tag: number, databaseName: string, schemaVersion: number, resolve: (status: { code: string, databaseVersion?: number }) => void, reject: () => void, ): void { let driver try { this.assertNoConnection(tag) driver = new DatabaseDriver() driver.initialize(databaseName, schemaVersion) this.connected(tag, driver) resolve({ code: 'ok' }) } catch (error) { if (driver && error.type === 'SchemaNeededError') { this.waiting(tag, driver) resolve({ code: 'schema_needed' }) } else if (driver && error.type === 'MigrationNeededError') { this.waiting(tag, driver) resolve({ code: 'migrations_needed', databaseVersion: error.databaseVersion }) } else { this.sendReject(reject, error, 'initialize') } } } setUpWithSchema( tag: number, databaseName: string, schema: string, schemaVersion: number, resolve: (boolean) => void, _reject: () => void, ): void { const driver = new DatabaseDriver() driver.setUpWithSchema(databaseName, schema, schemaVersion) this.connectDriverAsync(tag, driver) resolve(true) } setUpWithMigrations( tag: number, databaseName: string, migrations: string, fromVersion: number, toVersion: number, resolve: (boolean) => void, reject: () => void, ): void { try { const driver = new DatabaseDriver() driver.setUpWithMigrations(databaseName, { from: fromVersion, to: toVersion, sql: migrations, }) this.connectDriverAsync(tag, driver) resolve(true) } catch (error) { this.disconnectDriver(tag) this.sendReject(reject, error, 'setUpWithMigrations') } } // MARK: - Asynchronous actions find( tag: number, table: string, id: string, resolve: (any) => void, reject: (string) => void, ): void { this.withDriver(tag, resolve, reject, 'find', (driver) => driver.find(table, id)) } query( tag: number, table: string, query: string, args: any[], resolve: (any) => void, reject: (string) => void, ): void { this.withDriver(tag, resolve, reject, 'query', (driver) => driver.cachedQuery(table, query, args), ) } queryIds( tag: number, query: string, args: any[], resolve: (any) => void, reject: (string) => void, ): void { this.withDriver(tag, resolve, reject, 'queryIds', (driver) => driver.queryIds(query, args)) } unsafeQueryRaw( tag: number, query: string, args: any[], resolve: (any) => void, reject: (string) => void, ): void { this.withDriver(tag, resolve, reject, 'unsafeQueryRaw', (driver) => driver.unsafeQueryRaw(query, args), ) } count( tag: number, query: string, args: any[], resolve: (any) => void, reject: (string) => void, ): void { this.withDriver(tag, resolve, reject, 'count', (driver) => driver.count(query, args)) } batch(tag: number, operations: any[], resolve: (any) => void, reject: (string) => void): void { this.withDriver(tag, resolve, reject, 'batch', (driver) => driver.batch(operations)) } unsafeResetDatabase( tag: number, schema: string, schemaVersion: number, resolve: (any) => void, reject: (string) => void, ): void { this.withDriver(tag, resolve, reject, 'unsafeResetDatabase', (driver) => driver.unsafeResetDatabase({ version: schemaVersion, sql: schema }), ) } getLocal(tag: number, key: string, resolve: (any) => void, reject: (string) => void): void { this.withDriver(tag, resolve, reject, 'getLocal', (driver) => driver.getLocal(key)) } // MARK: - Helpers withDriver( tag: number, resolve: (any) => void, reject: (any) => void, functionName: string, action: (driver: DatabaseDriver) => any, ): void { try { const connection = this.connections[tag] if (!connection) { throw new Error(`No driver for with tag ${tag} available`) } if (connection.status === 'connected') { const result = action(connection.driver) resolve(result) } else if (connection.status === 'waiting') { // consoleLog('Operation for driver (tagID) enqueued') // try again when driver is ready connection.queue.push(() => { this.withDriver(tag, resolve, reject, functionName, action) }) } } catch (error) { this.sendReject(reject, error, functionName) } } connectDriverAsync(tag: number, driver: DatabaseDriver): void { const { queue = [] } = this.connections[tag] this.connections[tag] = { driver, queue: [], status: 'connected' } queue.forEach((operation) => operation()) } disconnectDriver(tag: number): void { const { queue = [] } = this.connections[tag] delete this.connections[tag] queue.forEach((operation) => operation()) } assertNoConnection(tag: number): void { if (this.connections[tag]) { throw new Error(`A driver with tag ${tag} already set up`) } } sendReject(reject: (string, string, Error) => void, error: Error, functionName: string): void { if (reject) { reject(`db.${functionName}.error`, error.message, error) } else { throw new Error(`db.${functionName} missing reject (${error.message})`) } } } const databaseBridge: DatabaseBridge = new DatabaseBridge() export default databaseBridge