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 Platform.OS === 'android' 43 ? { 44 sql: query.sql, 45 args: query.args.map(_escapeBlob), 46 } 47 : [query.sql, query.args]; 48} 49function _deserializeResultSet(nativeResult) { 50 const [errorMessage, insertId, rowsAffected, columns, rows] = nativeResult; 51 // TODO: send more structured error information from the native module so we can better construct 52 // a SQLException object 53 if (errorMessage !== null) { 54 return { error: new Error(errorMessage) }; 55 } 56 return { 57 insertId, 58 rowsAffected, 59 rows: rows.map((row) => zipObject(columns, row)), 60 }; 61} 62function _escapeBlob(data) { 63 if (typeof data === 'string') { 64 /* eslint-disable no-control-regex */ 65 return data 66 .replace(/\u0002/g, '\u0002\u0002') 67 .replace(/\u0001/g, '\u0001\u0002') 68 .replace(/\u0000/g, '\u0001\u0001'); 69 /* eslint-enable no-control-regex */ 70 } 71 else { 72 return data; 73 } 74} 75const _openExpoSQLiteDatabase = customOpenDatabase(SQLiteDatabase); 76// @needsAudit @docsMissing 77/** 78 * Open a database, creating it if it doesn't exist, and return a `Database` object. On disk, 79 * the database will be created under the app's [documents directory](./filesystem), i.e. 80 * `${FileSystem.documentDirectory}/SQLite/${name}`. 81 * > The `version`, `description` and `size` arguments are ignored, but are accepted by the function 82 * for compatibility with the WebSQL specification. 83 * @param name Name of the database file to open. 84 * @param version 85 * @param description 86 * @param size 87 * @param callback 88 * @return 89 */ 90export function openDatabase(name, version = '1.0', description = name, size = 1, callback) { 91 if (name === undefined) { 92 throw new TypeError(`The database name must not be undefined`); 93 } 94 const db = _openExpoSQLiteDatabase(name, version, description, size, callback); 95 db.exec = db._db.exec.bind(db._db); 96 db.closeAsync = db._db.close.bind(db._db); 97 db.deleteAsync = db._db.deleteAsync.bind(db._db); 98 return db; 99} 100//# sourceMappingURL=SQLite.js.map