文件
mynode/packages/app-mobile/utils/database-driver-react-native.ts
chen 301194963b
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
feat: Initial clean release of CHM
2026-11-04 11:29:39 +08:00

95 行
3.2 KiB
TypeScript

import * as SQLite from 'expo-sqlite';
import DatabaseDriver, { DatabaseCloseOptions, DatabaseOpenOptions, SqlSelectParams } from '@joplin/lib/database-driver';
import * as RNFS from '@dr.pogodin/react-native-fs';
import { NativeModules, Platform } from 'react-native';
import shim from '@joplin/lib/shim';
import { join } from 'path';
// cspell:ignore NSURLI
const getDatabaseDirectory = async () => {
let databaseDirectory;
if (Platform.OS === 'ios') {
databaseDirectory = `${RNFS.LibraryDirectoryPath}/LocalDatabase/`;
} else if (Platform.OS === 'android') {
databaseDirectory = NativeModules.SystemInformationPackage?.getConstants()?.databaseDirectory;
}
if (!databaseDirectory) throw new Error('Unable to determine database path.');
if (!await shim.fsDriver().exists(databaseDirectory)) {
// For compatibility with react-native-sqlite-storage, exclude the database
// directory from iCloud backups:
await RNFS.mkdir(databaseDirectory, { NSURLIsExcludedFromBackupKey: true });
}
return databaseDirectory;
};
export default class DatabaseDriverReactNative implements DatabaseDriver {
private lastInsertId_: string;
private db_: SQLite.SQLiteDatabase;
public constructor() {
this.lastInsertId_ = null;
}
public async open(options: DatabaseOpenOptions) {
const database = await SQLite.openDatabaseAsync(
options.name,
{
// Work around an FTS-related crash when closing the database (see https://github.com/expo/expo/38168)
finalizeUnusedStatementsBeforeClosing: false,
},
await getDatabaseDirectory(),
);
// Write-ahead logging (https://sqlite.org/wal.html) helps avoid "database locked" errors
// on Android (and, on iOS, seems to match the behavior of react-native-sqlite-storage
// before migrating to expo-sqlite):
await database.execAsync('PRAGMA journal_mode=WAL;');
this.db_ = database;
}
public async deleteDatabase(options: DatabaseCloseOptions) {
const databaseDirectory = await getDatabaseDirectory();
await SQLite.deleteDatabaseAsync(options.name, databaseDirectory);
// Workaround: Expo < SDK 56 does not delete database -wal, -shm, and -journal files.
// Remove after upgrading Expo.
// See https://github.com/expo/expo/pull/49125
const databasePath = join(databaseDirectory, options.name);
const toDelete = [`${databasePath}-wal`, `${databasePath}-shm`, `${databasePath}-journal`];
for (const path of toDelete) {
if (await shim.fsDriver().exists(path)) {
await shim.fsDriver().remove(path);
}
}
}
public sqliteErrorToJsError(error: Error) {
return error;
}
public async selectOne(sql: string, params: SqlSelectParams = []) {
return await this.db_.getFirstAsync(sql, params);
}
public async selectAll(sql: string, params: SqlSelectParams = []) {
return await this.db_.getAllAsync(sql, params);
}
public loadExtension(path: string) {
// Extensions need to be enabled via options when opening the database
throw new Error(`No extension support for ${path} in expo-sqlite`);
}
public async exec(sql: string, params: SqlSelectParams = []) {
const result = await this.db_.runAsync(sql, params);
if (result.lastInsertRowId) {
this.lastInsertId_ = String(result.lastInsertRowId);
}
}
public lastInsertId() {
return this.lastInsertId_;
}
}