UNPKG

2.64 kBJavaScriptView Raw
1// @flow
2
3import './timer/polyfillNextTick';
4
5import map from 'lodash.map';
6import zipObject from 'lodash.zipobject';
7import { NativeModules, Platform } from 'react-native';
8import customOpenDatabase from 'websql/custom';
9
10const { ExponentSQLite } = NativeModules;
11
12function SQLiteResult(error, insertId, rowsAffected, rows) {
13 this.error = error;
14 this.insertId = insertId;
15 this.rowsAffected = rowsAffected;
16 this.rows = rows;
17}
18
19function massageError(err) {
20 return typeof err === 'string' ? new Error(err) : err;
21}
22
23function SQLiteDatabase(name) {
24 this._name = name;
25}
26
27function dearrayifyRow(res) {
28 // use a compressed array format to send minimal data between native and web layers
29 var rawError = res[0];
30 if (rawError) {
31 return new SQLiteResult(massageError(res[0]));
32 }
33 var insertId = res[1];
34 if (insertId === null) {
35 insertId = undefined;
36 }
37 var rowsAffected = res[2];
38 var columns = res[3];
39 var rows = res[4];
40 var zippedRows = [];
41 for (var i = 0, len = rows.length; i < len; i++) {
42 zippedRows.push(zipObject(columns, rows[i]));
43 }
44
45 // v8 likes predictable objects
46 return new SQLiteResult(null, insertId, rowsAffected, zippedRows);
47}
48
49// send less data over the wire, use an array
50function arrayifyQuery(query) {
51 return [query.sql, escapeForAndroid(query.args || [])];
52}
53
54// for avoiding strings truncated with '\u0000'
55function escapeForAndroid(args) {
56 if (Platform.OS === 'android') {
57 return map(args, escapeBlob);
58 } else {
59 return args;
60 }
61}
62
63function escapeBlob(data) {
64 if (typeof data === 'string') {
65 return data
66 .replace(/\u0002/g, '\u0002\u0002')
67 .replace(/\u0001/g, '\u0001\u0002')
68 .replace(/\u0000/g, '\u0001\u0001');
69 } else {
70 return data;
71 }
72}
73
74SQLiteDatabase.prototype.exec = function exec(queries, readOnly, callback) {
75 function onSuccess(rawResults) {
76 var results = map(rawResults, dearrayifyRow);
77 callback(null, results);
78 }
79
80 function onError(err) {
81 callback(massageError(err));
82 }
83
84 ExponentSQLite.exec(this._name, map(queries, arrayifyQuery), readOnly).then(onSuccess, onError);
85};
86
87const openDB = customOpenDatabase(SQLiteDatabase);
88
89function openDatabase(
90 name: string,
91 version: string,
92 description: string,
93 size: number,
94 callback: ?(db: *) => void
95) {
96 if (!size) {
97 size = 1;
98 }
99 if (!description) {
100 description = name;
101 }
102 if (!version) {
103 version = '1.0';
104 }
105 if (typeof name === 'undefined') {
106 throw new Error('please be sure to call: openDatabase("myname.db")');
107 }
108 return openDB(name, version, description, size, callback);
109}
110
111export default {
112 openDatabase,
113};