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