1import './polyfillNextTick'; 2import customOpenDatabase from '@expo/websql/custom'; 3import { requireNativeModule } from 'expo-modules-core'; 4import { Platform } from 'react-native'; 5const ExpoSQLite = requireNativeModule('ExpoSQLite'); 6function zipObject(keys, values) { 7 const result = {}; 8 for (let i = 0; i < keys.length; i++) { 9 result[keys[i]] = values[i]; 10 } 11 return result; 12} 13class SQLiteDatabase { 14 _name; 15 _closed = false; 16 constructor(name) { 17 this._name = name; 18 } 19 exec(queries, readOnly, callback) { 20 if (this._closed) { 21 throw new Error(`The SQLite database is closed`); 22 } 23 ExpoSQLite.exec(this._name, queries.map(_serializeQuery), readOnly).then((nativeResultSets) => { 24 callback(null, nativeResultSets.map(_deserializeResultSet)); 25 }, (error) => { 26 // TODO: make the native API consistently reject with an error, not a string or other type 27 callback(error instanceof Error ? error : new Error(error)); 28 }); 29 } 30 close() { 31 this._closed = true; 32 return ExpoSQLite.close(this._name); 33 } 34 deleteAsync() { 35 if (!this._closed) { 36 throw new Error(`Unable to delete '${this._name}' database that is currently open. Close it prior to deletion.`); 37 } 38 return ExpoSQLite.deleteAsync(this._name); 39 } 40} 41function _serializeQuery(query) { 42 return [query.sql, Platform.OS === 'android' ? query.args.map(_escapeBlob) : query.args]; 43} 44function _deserializeResultSet(nativeResult) { 45 const [errorMessage, insertId, rowsAffected, columns, rows] = nativeResult; 46 // TODO: send more structured error information from the native module so we can better construct 47 // a SQLException object 48 if (errorMessage !== null) { 49 return { error: new Error(errorMessage) }; 50 } 51 return { 52 insertId, 53 rowsAffected, 54 rows: rows.map((row) => zipObject(columns, row)), 55 }; 56} 57function _escapeBlob(data) { 58 if (typeof data === 'string') { 59 /* eslint-disable no-control-regex */ 60 return data 61 .replace(/\u0002/g, '\u0002\u0002') 62 .replace(/\u0001/g, '\u0001\u0002') 63 .replace(/\u0000/g, '\u0001\u0001'); 64 /* eslint-enable no-control-regex */ 65 } 66 else { 67 return data; 68 } 69} 70const _openExpoSQLiteDatabase = customOpenDatabase(SQLiteDatabase); 71// @needsAudit @docsMissing 72/** 73 * Open a database, creating it if it doesn't exist, and return a `Database` object. On disk, 74 * the database will be created under the app's [documents directory](./filesystem), i.e. 75 * `${FileSystem.documentDirectory}/SQLite/${name}`. 76 * > The `version`, `description` and `size` arguments are ignored, but are accepted by the function 77 * for compatibility with the WebSQL specification. 78 * @param name Name of the database file to open. 79 * @param version 80 * @param description 81 * @param size 82 * @param callback 83 * @return 84 */ 85export function openDatabase(name, version = '1.0', description = name, size = 1, callback) { 86 if (name === undefined) { 87 throw new TypeError(`The database name must not be undefined`); 88 } 89 const db = _openExpoSQLiteDatabase(name, version, description, size, callback); 90 db.exec = db._db.exec.bind(db._db); 91 db.closeAsync = db._db.close.bind(db._db); 92 db.deleteAsync = db._db.deleteAsync.bind(db._db); 93 return db; 94} 95//# sourceMappingURL=SQLite.js.map