From 4a7bfa1d2926acb8a3ed6fada08100b6038a0960 Mon Sep 17 00:00:00 2001 From: Kudo Chien Date: Wed, 28 Jun 2023 01:32:58 +0800 Subject: [PATCH] [sqlite] add experimental promise support (#23109) # Why fixes #13357 close ENG-8685 # How - originally, the callbacks for websql doesn't support Promise. when people using either 'async/async` or '.then` inside the callback, the statement will be executed after the "transaction end" statement. - we should we low level control without websql at all. - introduce low-level `execAsync` - introduce `transactionAsync` usage ```tsx const db = SQLite.openDatabase('dbName', version); const readOnly = true; await db.transactionAsync(async tx => { const result = await tx.executeSqlAsync('SELECT COUNT(*) FROM USERS', []); console.log('Count:', result.rows[0]['COUNT(*)']); }, readOnly); ``` note that the result is the [`ResultSet` type](https://github.com/expo/expo/blob/065419647694cf9341261bc7ac614d05e4bac27d/packages/expo-sqlite/src/SQLite.types.ts#L167-L177) but not the [`SQLResultSet` type](https://github.com/expo/expo/blob/065419647694cf9341261bc7ac614d05e4bac27d/packages/expo-sqlite/src/SQLite.types.ts#L93C18-L121). people can access the result items by `rows[0]` rather than `rows.item(0)`. i was thinking to deprecate websql somehow and it doesn't make sense to wrap the result by the [`WebSQLResultSet` again](https://github.com/nolanlawson/node-websql/blob/b3e48284572108feff1cd019dc7f13c1d8aa34b2/lib/websql/WebSQLTransaction.js#L12-L36) # Test Plan add some SQLite Async unit tests and test suite ci should be passed --- apps/test-suite/tests/SQLite.js | 155 ++++++++++++++++++ .../pages/versions/unversioned/sdk/sqlite.mdx | 17 +- .../static/data/unversioned/expo-sqlite.json | 2 +- packages/expo-sqlite/CHANGELOG.md | 1 + packages/expo-sqlite/build/SQLite.d.ts | 47 +++++- packages/expo-sqlite/build/SQLite.d.ts.map | 2 +- packages/expo-sqlite/build/SQLite.js | 66 +++++++- packages/expo-sqlite/build/SQLite.js.map | 2 +- packages/expo-sqlite/build/SQLite.types.d.ts | 8 + .../expo-sqlite/build/SQLite.types.d.ts.map | 2 +- .../expo-sqlite/build/SQLite.types.js.map | 2 +- packages/expo-sqlite/src/SQLite.ts | 89 +++++++++- packages/expo-sqlite/src/SQLite.types.ts | 11 +- 13 files changed, 384 insertions(+), 20 deletions(-) diff --git a/apps/test-suite/tests/SQLite.js b/apps/test-suite/tests/SQLite.js index dcac486dee2f4..931b83b5195ff 100644 --- a/apps/test-suite/tests/SQLite.js +++ b/apps/test-suite/tests/SQLite.js @@ -455,4 +455,159 @@ export function test(t) { }); } }); + + if (Platform.OS !== 'web') { + t.describe('SQLiteAsync', () => { + const throws = async (run) => { + let error = null; + try { + await run(); + } catch (e) { + error = e; + } + t.expect(error).toBeTruthy(); + }; + + t.it('should support async transaction', async () => { + const db = SQLite.openDatabase('test.db'); + + // create table + await db.transactionAsync(async (tx) => { + await tx.executeSqlAsync('DROP TABLE IF EXISTS Users;', []); + await tx.executeSqlAsync( + 'CREATE TABLE IF NOT EXISTS Users (user_id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(64));', + [] + ); + }); + + // fetch data from network + async function fakeUserFetcher(userID) { + switch (userID) { + case 1: { + return Promise.resolve('Tim Duncan'); + } + case 2: { + return Promise.resolve('Manu Ginobili'); + } + case 3: { + return Promise.resolve('Nikhilesh Sigatapu'); + } + default: { + return null; + } + } + } + + const userName = await fakeUserFetcher(1); + await db.transactionAsync(async (tx) => { + await tx.executeSqlAsync('INSERT INTO Users (name) VALUES (?)', [userName]); + + const currentUser = (await tx.executeSqlAsync('SELECT * FROM Users LIMIT 1')).rows[0] + .name; + t.expect(currentUser).toEqual('Tim Duncan'); + }); + }); + + t.it('should support Promise.all', async () => { + const db = SQLite.openDatabase('test.db'); + + // create table + await db.transactionAsync(async (tx) => { + await tx.executeSqlAsync('DROP TABLE IF EXISTS Users;', []); + await tx.executeSqlAsync( + 'CREATE TABLE IF NOT EXISTS Users (user_id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(64));', + [] + ); + }); + + await db.transactionAsync(async (tx) => { + await Promise.all([ + tx.executeSqlAsync('INSERT INTO Users (name) VALUES (?)', ['aaa']), + tx.executeSqlAsync('INSERT INTO Users (name) VALUES (?)', ['bbb']), + tx.executeSqlAsync('INSERT INTO Users (name) VALUES (?)', ['ccc']), + ]); + + const recordCount = (await tx.executeSqlAsync('SELECT COUNT(*) FROM Users')).rows[0][ + 'COUNT(*)' + ]; + t.expect(recordCount).toEqual(3); + }); + }); + + t.it( + 'should return `could not prepare ...` error when having write statements in readOnly transaction', + async () => { + const db = SQLite.openDatabase('test.db'); + + // create table in readOnly transaction + await db.transactionAsync(async (tx) => { + const result = await tx.executeSqlAsync('DROP TABLE IF EXISTS Users;', []); + t.expect(result.error).toBeDefined(); + t.expect(result.error.message).toContain('could not prepare '); + }, true); + } + ); + + t.it('should rollback transaction when exception happens inside a transaction', async () => { + const db = SQLite.openDatabase('test.db'); + + // create table + await db.transactionAsync(async (tx) => { + await tx.executeSqlAsync('DROP TABLE IF EXISTS Users;', []); + await tx.executeSqlAsync( + 'CREATE TABLE IF NOT EXISTS Users (user_id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(64));', + [] + ); + }); + await db.transactionAsync(async (tx) => { + await tx.executeSqlAsync('INSERT INTO Users (name) VALUES (?)', ['aaa']); + }); + await db.transactionAsync(async (tx) => { + const recordCount = (await tx.executeSqlAsync('SELECT COUNT(*) FROM Users')).rows[0][ + 'COUNT(*)' + ]; + t.expect(recordCount).toEqual(1); + }, true); + + await throws(() => + db.transactionAsync(async (tx) => { + await tx.executeSqlAsync('INSERT INTO Users (name) VALUES (?)', ['bbb']); + await tx.executeSqlAsync('INSERT INTO Users (name) VALUES (?)', ['ccc']); + // exeuting invalid sql statement will throw an exception + await tx.executeSqlAsync(undefined); + }) + ); + + await db.transactionAsync(async (tx) => { + const recordCount = (await tx.executeSqlAsync('SELECT COUNT(*) FROM Users')).rows[0][ + 'COUNT(*)' + ]; + t.expect(recordCount).toEqual(1); + }, true); + }); + + t.it('should support async PRAGMA statements', async () => { + const db = SQLite.openDatabase('test.db'); + await db.transactionAsync(async (tx) => { + await tx.executeSqlAsync('DROP TABLE IF EXISTS SomeTable;', []); + await tx.executeSqlAsync( + 'CREATE TABLE IF NOT EXISTS SomeTable (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(64));', + [] + ); + // a result-returning pragma + let results = await tx.executeSqlAsync('PRAGMA table_info(SomeTable);', []); + t.expect(results.rows.length).toEqual(2); + t.expect(results.rows[0].name).toEqual('id'); + t.expect(results.rows[1].name).toEqual('name'); + // a no-result pragma + await tx.executeSqlAsync('PRAGMA case_sensitive_like = true;', []); + // a setter/getter pragma + await tx.executeSqlAsync('PRAGMA user_version = 123;', []); + results = await tx.executeSqlAsync('PRAGMA user_version;', []); + t.expect(results.rows.length).toEqual(1); + t.expect(results.rows[0].user_version).toEqual(123); + }); + }); + }); // t.describe('SQLiteAsync') + } } diff --git a/docs/pages/versions/unversioned/sdk/sqlite.mdx b/docs/pages/versions/unversioned/sdk/sqlite.mdx index c7254b0a97b51..05a385286ea28 100644 --- a/docs/pages/versions/unversioned/sdk/sqlite.mdx +++ b/docs/pages/versions/unversioned/sdk/sqlite.mdx @@ -74,6 +74,18 @@ async function openDatabase(pathToDatabaseFile: string): Promise +### Executing statements with an async transaction + +```js +const db = SQLite.openDatabase('dbName', version); + +const readOnly = true; +await db.transactionAsync(async tx => { + const result = await tx.executeSqlAsync('SELECT COUNT(*) FROM USERS', []); + console.log('Count:', result.rows[0]['COUNT(*)']); +}, readOnly); +``` + ### Executing statements outside of a transaction > You should use this kind of execution only when it is necessary. For instance, when code is a no-op within transactions. Example: `PRAGMA foreign_keys = ON;`. @@ -81,9 +93,8 @@ async function openDatabase(pathToDatabaseFile: string): Promise - console.log('Foreign keys turned on') -); +await db.execAsync([{ sql: 'PRAGMA foreign_keys = ON;', args: [] }], false); +console.log('Foreign keys turned on'); ``` ## API diff --git a/docs/public/static/data/unversioned/expo-sqlite.json b/docs/public/static/data/unversioned/expo-sqlite.json index d4ed559796beb..ac7ad33fd7e96 100644 --- a/docs/public/static/data/unversioned/expo-sqlite.json +++ b/docs/public/static/data/unversioned/expo-sqlite.json @@ -1 +1 @@ -{"name":"expo-sqlite","kind":1,"children":[{"name":"SQLError","kind":128,"children":[{"name":"constructor","kind":512,"signatures":[{"name":"new SQLError","kind":16384,"type":{"type":"reference","name":"SQLError"}}]},{"name":"code","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"message","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"CONSTRAINT_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"DATABASE_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"QUOTA_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"SYNTAX_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"TIMEOUT_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"TOO_LARGE_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"UNKNOWN_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"VERSION_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}}]},{"name":"Database","kind":256,"comment":{"summary":[{"kind":"code","text":"`Database`"},{"kind":"text","text":" objects are returned by calls to "},{"kind":"code","text":"`SQLite.openDatabase()`"},{"kind":"text","text":". Such an object represents a\nconnection to a database on your device."}]},"children":[{"name":"version","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"readTransaction","kind":2048,"signatures":[{"name":"readTransaction","kind":4096,"parameters":[{"name":"callback","kind":32768,"type":{"type":"reference","name":"SQLTransactionCallback"}},{"name":"errorCallback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"SQLTransactionErrorCallback"}},{"name":"successCallback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"intrinsic","name":"void"}}]},{"name":"transaction","kind":2048,"signatures":[{"name":"transaction","kind":4096,"comment":{"summary":[{"kind":"text","text":"Execute a database transaction."}]},"parameters":[{"name":"callback","kind":32768,"comment":{"summary":[{"kind":"text","text":"A function representing the transaction to perform. Takes a Transaction\n(see below) as its only parameter, on which it can add SQL statements to execute."}]},"type":{"type":"reference","name":"SQLTransactionCallback"}},{"name":"errorCallback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called if an error occurred processing this transaction. Takes a single\nparameter describing the error."}]},"type":{"type":"reference","name":"SQLTransactionErrorCallback"}},{"name":"successCallback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called when the transaction has completed executing on the database."}]},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"intrinsic","name":"void"}}]}],"extendedBy":[{"type":"reference","name":"WebSQLDatabase"}]},{"name":"SQLResultSetRowList","kind":256,"children":[{"name":"_array","kind":1024,"comment":{"summary":[{"kind":"text","text":"The actual array of rows returned by the query. Can be used directly instead of\ngetting rows through rows.item()."}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}},{"name":"length","kind":1024,"comment":{"summary":[{"kind":"text","text":"The number of rows returned by the query."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"item","kind":2048,"signatures":[{"name":"item","kind":4096,"comment":{"summary":[{"kind":"text","text":"Returns the row with the given "},{"kind":"code","text":"`index`"},{"kind":"text","text":". If there is no such row, returns "},{"kind":"code","text":"`null`"},{"kind":"text","text":"."}]},"parameters":[{"name":"index","kind":32768,"comment":{"summary":[{"kind":"text","text":"Index of row to get."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"intrinsic","name":"any"}}]}]},{"name":"SQLTransaction","kind":256,"comment":{"summary":[{"kind":"text","text":"A "},{"kind":"code","text":"`SQLTransaction`"},{"kind":"text","text":" object is passed in as a parameter to the "},{"kind":"code","text":"`callback`"},{"kind":"text","text":" parameter for the\n"},{"kind":"code","text":"`db.transaction()`"},{"kind":"text","text":" method on a "},{"kind":"code","text":"`Database`"},{"kind":"text","text":" (see above). It allows enqueuing SQL statements to\nperform in a database transaction."}]},"children":[{"name":"executeSql","kind":2048,"signatures":[{"name":"executeSql","kind":4096,"comment":{"summary":[{"kind":"text","text":"Enqueue a SQL statement to execute in the transaction. Authors are strongly recommended to make\nuse of the "},{"kind":"code","text":"`?`"},{"kind":"text","text":" placeholder feature of the method to avoid against SQL injection attacks, and to\nnever construct SQL statements on the fly."}]},"parameters":[{"name":"sqlStatement","kind":32768,"comment":{"summary":[{"kind":"text","text":"A string containing a database query to execute expressed as SQL. The string\nmay contain "},{"kind":"code","text":"`?`"},{"kind":"text","text":" placeholders, with values to be substituted listed in the "},{"kind":"code","text":"`arguments`"},{"kind":"text","text":" parameter."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"args","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"An array of values (numbers, strings or nulls) to substitute for "},{"kind":"code","text":"`?`"},{"kind":"text","text":" placeholders in the\nSQL statement."}]},"type":{"type":"array","elementType":{"type":"union","types":[{"type":"literal","value":null},{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}}},{"name":"callback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called when the query is successfully completed during the transaction. Takes\ntwo parameters: the transaction itself, and a "},{"kind":"code","text":"`ResultSet`"},{"kind":"text","text":" object (see below) with the results\nof the query."}]},"type":{"type":"reference","name":"SQLStatementCallback"}},{"name":"errorCallback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called if an error occurred executing this particular query in the\ntransaction. Takes two parameters: the transaction itself, and the error object."}]},"type":{"type":"reference","name":"SQLStatementErrorCallback"}}],"type":{"type":"intrinsic","name":"void"}}]}]},{"name":"WebSQLDatabase","kind":256,"comment":{"summary":[{"kind":"code","text":"`Database`"},{"kind":"text","text":" objects are returned by calls to "},{"kind":"code","text":"`SQLite.openDatabase()`"},{"kind":"text","text":". Such an object represents a\nconnection to a database on your device."}]},"children":[{"name":"version","kind":1024,"type":{"type":"intrinsic","name":"string"},"inheritedFrom":{"type":"reference","name":"Database.version"}},{"name":"closeAsync","kind":2048,"signatures":[{"name":"closeAsync","kind":4096,"comment":{"summary":[{"kind":"text","text":"Close the database."}]},"type":{"type":"intrinsic","name":"void"}}]},{"name":"deleteAsync","kind":2048,"signatures":[{"name":"deleteAsync","kind":4096,"comment":{"summary":[{"kind":"text","text":"Delete the database file.\n> The database has to be closed prior to deletion."}]},"type":{"type":"reference","typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","qualifiedName":"Promise","package":"typescript"}}]},{"name":"exec","kind":2048,"signatures":[{"name":"exec","kind":4096,"parameters":[{"name":"queries","kind":32768,"type":{"type":"array","elementType":{"type":"reference","name":"Query"}}},{"name":"readOnly","kind":32768,"type":{"type":"intrinsic","name":"boolean"}},{"name":"callback","kind":32768,"type":{"type":"reference","name":"SQLiteCallback"}}],"type":{"type":"intrinsic","name":"void"}}]},{"name":"readTransaction","kind":2048,"signatures":[{"name":"readTransaction","kind":4096,"parameters":[{"name":"callback","kind":32768,"type":{"type":"reference","name":"SQLTransactionCallback"}},{"name":"errorCallback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"SQLTransactionErrorCallback"}},{"name":"successCallback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"Database.readTransaction"}}],"inheritedFrom":{"type":"reference","name":"Database.readTransaction"}},{"name":"transaction","kind":2048,"signatures":[{"name":"transaction","kind":4096,"comment":{"summary":[{"kind":"text","text":"Execute a database transaction."}]},"parameters":[{"name":"callback","kind":32768,"comment":{"summary":[{"kind":"text","text":"A function representing the transaction to perform. Takes a Transaction\n(see below) as its only parameter, on which it can add SQL statements to execute."}]},"type":{"type":"reference","name":"SQLTransactionCallback"}},{"name":"errorCallback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called if an error occurred processing this transaction. Takes a single\nparameter describing the error."}]},"type":{"type":"reference","name":"SQLTransactionErrorCallback"}},{"name":"successCallback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called when the transaction has completed executing on the database."}]},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"Database.transaction"}}],"inheritedFrom":{"type":"reference","name":"Database.transaction"}}],"extendedTypes":[{"type":"reference","name":"Database"}]},{"name":"Window","kind":256,"children":[{"name":"openDatabase","kind":1024,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"name","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"version","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"displayName","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"estimatedSize","kind":32768,"type":{"type":"intrinsic","name":"number"}},{"name":"creationCallback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"DatabaseCallback"}}],"type":{"type":"reference","name":"Database"}}]}}}]},{"name":"DatabaseCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"database","kind":32768,"type":{"type":"reference","name":"Database"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"Query","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"children":[{"name":"args","kind":1024,"type":{"type":"array","elementType":{"type":"intrinsic","name":"unknown"}}},{"name":"sql","kind":1024,"type":{"type":"intrinsic","name":"string"}}]}}},{"name":"ResultSet","kind":4194304,"comment":{"summary":[{"kind":"code","text":"`ResultSet`"},{"kind":"text","text":" objects are returned through second parameter of the "},{"kind":"code","text":"`success`"},{"kind":"text","text":" callback for the\n"},{"kind":"code","text":"`tx.executeSql()`"},{"kind":"text","text":" method on a "},{"kind":"code","text":"`SQLTransaction`"},{"kind":"text","text":" (see above)."}]},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"children":[{"name":"insertId","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The row ID of the row that the SQL statement inserted into the database, if a row was inserted."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"rows","kind":1024,"type":{"type":"array","elementType":{"type":"reflection","declaration":{"name":"__type","kind":65536,"indexSignature":{"name":"__index","kind":8192,"parameters":[{"name":"column","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"any"}}}}}},{"name":"rowsAffected","kind":1024,"comment":{"summary":[{"kind":"text","text":"The number of rows that were changed by the SQL statement."}]},"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"ResultSetError","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"children":[{"name":"error","kind":1024,"type":{"type":"reference","name":"Error","qualifiedName":"Error","package":"typescript"}}]}}},{"name":"SQLResultSet","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"children":[{"name":"insertId","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The row ID of the row that the SQL statement inserted into the database, if a row was inserted."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"rows","kind":1024,"type":{"type":"reference","name":"SQLResultSetRowList"}},{"name":"rowsAffected","kind":1024,"comment":{"summary":[{"kind":"text","text":"The number of rows that were changed by the SQL statement."}]},"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"SQLStatementCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"transaction","kind":32768,"type":{"type":"reference","name":"SQLTransaction"}},{"name":"resultSet","kind":32768,"type":{"type":"reference","name":"SQLResultSet"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"SQLStatementErrorCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"transaction","kind":32768,"type":{"type":"reference","name":"SQLTransaction"}},{"name":"error","kind":32768,"type":{"type":"reference","name":"SQLError"}}],"type":{"type":"intrinsic","name":"boolean"}}]}}},{"name":"SQLTransactionCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"transaction","kind":32768,"type":{"type":"reference","name":"SQLTransaction"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"SQLTransactionErrorCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"error","kind":32768,"type":{"type":"reference","name":"SQLError"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"SQLiteCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"error","kind":32768,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"Error","qualifiedName":"Error","package":"typescript"},{"type":"literal","value":null}]}},{"name":"resultSet","kind":32768,"flags":{"isOptional":true},"type":{"type":"array","elementType":{"type":"union","types":[{"type":"reference","name":"ResultSetError"},{"type":"reference","name":"ResultSet"}]}}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"openDatabase","kind":64,"signatures":[{"name":"openDatabase","kind":4096,"comment":{"summary":[{"kind":"text","text":"Open a database, creating it if it doesn't exist, and return a "},{"kind":"code","text":"`Database`"},{"kind":"text","text":" object. On disk,\nthe database will be created under the app's [documents directory](./filesystem), i.e.\n"},{"kind":"code","text":"`${FileSystem.documentDirectory}/SQLite/${name}`"},{"kind":"text","text":".\n> The "},{"kind":"code","text":"`version`"},{"kind":"text","text":", "},{"kind":"code","text":"`description`"},{"kind":"text","text":" and "},{"kind":"code","text":"`size`"},{"kind":"text","text":" arguments are ignored, but are accepted by the function\nfor compatibility with the WebSQL specification."}],"blockTags":[{"tag":"@returns","content":[]}]},"parameters":[{"name":"name","kind":32768,"comment":{"summary":[{"kind":"text","text":"Name of the database file to open."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"version","kind":32768,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'1.0'"},{"name":"description","kind":32768,"type":{"type":"intrinsic","name":"string"},"defaultValue":"name"},{"name":"size","kind":32768,"type":{"type":"intrinsic","name":"number"},"defaultValue":"1"},{"name":"callback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"db","kind":32768,"type":{"type":"reference","name":"WebSQLDatabase"}}],"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"WebSQLDatabase"}}]}]} \ No newline at end of file +{"name":"expo-sqlite","kind":1,"children":[{"name":"ExpoSQLTransactionAsync","kind":128,"comment":{"summary":[{"kind":"text","text":"Internal data structure for the async transaction API."}],"modifierTags":["@internal"]},"children":[{"name":"constructor","kind":512,"signatures":[{"name":"new ExpoSQLTransactionAsync","kind":16384,"parameters":[{"name":"db","kind":32768,"type":{"type":"reference","name":"SQLiteDatabase"}},{"name":"readOnly","kind":32768,"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","name":"ExpoSQLTransactionAsync"}}]},{"name":"executeSqlAsync","kind":2048,"signatures":[{"name":"executeSqlAsync","kind":4096,"comment":{"summary":[{"kind":"text","text":"Executes a SQL statement in async mode."}]},"parameters":[{"name":"sqlStatement","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"args","kind":32768,"flags":{"isOptional":true},"type":{"type":"array","elementType":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}}}],"type":{"type":"reference","typeArguments":[{"type":"reference","name":"ResultSet"}],"name":"Promise","qualifiedName":"Promise","package":"typescript"},"implementationOf":{"type":"reference","name":"SQLTransactionAsync.executeSqlAsync"}}],"implementationOf":{"type":"reference","name":"SQLTransactionAsync.executeSqlAsync"}}],"implementedTypes":[{"type":"reference","name":"SQLTransactionAsync"}]},{"name":"SQLError","kind":128,"children":[{"name":"constructor","kind":512,"signatures":[{"name":"new SQLError","kind":16384,"type":{"type":"reference","name":"SQLError"}}]},{"name":"code","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"message","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"CONSTRAINT_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"DATABASE_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"QUOTA_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"SYNTAX_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"TIMEOUT_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"TOO_LARGE_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"UNKNOWN_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}},{"name":"VERSION_ERR","kind":1024,"flags":{"isStatic":true},"type":{"type":"intrinsic","name":"number"}}]},{"name":"SQLiteDatabase","kind":128,"comment":{"summary":[{"kind":"text","text":"The database returned by "},{"kind":"code","text":"`openDatabase()`"}]},"children":[{"name":"constructor","kind":512,"signatures":[{"name":"new SQLiteDatabase","kind":16384,"parameters":[{"name":"name","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"SQLiteDatabase"}}]},{"name":"_closed","kind":1024,"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"false"},{"name":"_name","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"close","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`closeAsync()`"},{"kind":"text","text":" instead."}]}]},"type":{"type":"intrinsic","name":"void"}}]}},"defaultValue":"..."},{"name":"closeAsync","kind":2048,"signatures":[{"name":"closeAsync","kind":4096,"comment":{"summary":[{"kind":"text","text":"Close the database."}]},"type":{"type":"intrinsic","name":"void"}}]},{"name":"deleteAsync","kind":2048,"signatures":[{"name":"deleteAsync","kind":4096,"comment":{"summary":[{"kind":"text","text":"Delete the database file.\n> The database has to be closed prior to deletion."}]},"type":{"type":"reference","typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","qualifiedName":"Promise","package":"typescript"}}]},{"name":"exec","kind":2048,"signatures":[{"name":"exec","kind":4096,"comment":{"summary":[{"kind":"text","text":"Executes the SQL statement and returns a callback resolving with the result."}]},"parameters":[{"name":"queries","kind":32768,"type":{"type":"array","elementType":{"type":"reference","name":"Query"}}},{"name":"readOnly","kind":32768,"type":{"type":"intrinsic","name":"boolean"}},{"name":"callback","kind":32768,"type":{"type":"reference","name":"SQLiteCallback"}}],"type":{"type":"intrinsic","name":"void"}}]},{"name":"execAsync","kind":2048,"signatures":[{"name":"execAsync","kind":4096,"comment":{"summary":[{"kind":"text","text":"Executes the SQL statement and returns a Promise resolving with the result."}]},"parameters":[{"name":"queries","kind":32768,"type":{"type":"array","elementType":{"type":"reference","name":"Query"}}},{"name":"readOnly","kind":32768,"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","typeArguments":[{"type":"array","elementType":{"type":"reference","name":"ResultSet"}}],"name":"Promise","qualifiedName":"Promise","package":"typescript"}}]},{"name":"transactionAsync","kind":2048,"signatures":[{"name":"transactionAsync","kind":4096,"comment":{"summary":[{"kind":"text","text":"Creates a new transaction with Promise support."}]},"parameters":[{"name":"asyncCallback","kind":32768,"comment":{"summary":[{"kind":"text","text":"A "},{"kind":"code","text":"`SQLTransactionAsyncCallback`"},{"kind":"text","text":" function that can perform SQL statements in a transaction."}]},"type":{"type":"reference","name":"SQLTransactionAsyncCallback"}},{"name":"readOnly","kind":32768,"comment":{"summary":[{"kind":"text","text":"true if all the SQL statements in the callback are read only."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"false"}],"type":{"type":"reference","typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","qualifiedName":"Promise","package":"typescript"}}]}]},{"name":"Database","kind":256,"comment":{"summary":[{"kind":"code","text":"`Database`"},{"kind":"text","text":" objects are returned by calls to "},{"kind":"code","text":"`SQLite.openDatabase()`"},{"kind":"text","text":". Such an object represents a\nconnection to a database on your device."}]},"children":[{"name":"version","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"readTransaction","kind":2048,"signatures":[{"name":"readTransaction","kind":4096,"parameters":[{"name":"callback","kind":32768,"type":{"type":"reference","name":"SQLTransactionCallback"}},{"name":"errorCallback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"SQLTransactionErrorCallback"}},{"name":"successCallback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"intrinsic","name":"void"}}]},{"name":"transaction","kind":2048,"signatures":[{"name":"transaction","kind":4096,"comment":{"summary":[{"kind":"text","text":"Execute a database transaction."}]},"parameters":[{"name":"callback","kind":32768,"comment":{"summary":[{"kind":"text","text":"A function representing the transaction to perform. Takes a Transaction\n(see below) as its only parameter, on which it can add SQL statements to execute."}]},"type":{"type":"reference","name":"SQLTransactionCallback"}},{"name":"errorCallback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called if an error occurred processing this transaction. Takes a single\nparameter describing the error."}]},"type":{"type":"reference","name":"SQLTransactionErrorCallback"}},{"name":"successCallback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called when the transaction has completed executing on the database."}]},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"intrinsic","name":"void"}}]}],"extendedBy":[{"type":"reference","name":"WebSQLDatabase"}]},{"name":"SQLResultSetRowList","kind":256,"children":[{"name":"_array","kind":1024,"comment":{"summary":[{"kind":"text","text":"The actual array of rows returned by the query. Can be used directly instead of\ngetting rows through rows.item()."}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}},{"name":"length","kind":1024,"comment":{"summary":[{"kind":"text","text":"The number of rows returned by the query."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"item","kind":2048,"signatures":[{"name":"item","kind":4096,"comment":{"summary":[{"kind":"text","text":"Returns the row with the given "},{"kind":"code","text":"`index`"},{"kind":"text","text":". If there is no such row, returns "},{"kind":"code","text":"`null`"},{"kind":"text","text":"."}]},"parameters":[{"name":"index","kind":32768,"comment":{"summary":[{"kind":"text","text":"Index of row to get."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"intrinsic","name":"any"}}]}]},{"name":"SQLTransaction","kind":256,"comment":{"summary":[{"kind":"text","text":"A "},{"kind":"code","text":"`SQLTransaction`"},{"kind":"text","text":" object is passed in as a parameter to the "},{"kind":"code","text":"`callback`"},{"kind":"text","text":" parameter for the\n"},{"kind":"code","text":"`db.transaction()`"},{"kind":"text","text":" method on a "},{"kind":"code","text":"`Database`"},{"kind":"text","text":" (see above). It allows enqueuing SQL statements to\nperform in a database transaction."}]},"children":[{"name":"executeSql","kind":2048,"signatures":[{"name":"executeSql","kind":4096,"comment":{"summary":[{"kind":"text","text":"Enqueue a SQL statement to execute in the transaction. Authors are strongly recommended to make\nuse of the "},{"kind":"code","text":"`?`"},{"kind":"text","text":" placeholder feature of the method to avoid against SQL injection attacks, and to\nnever construct SQL statements on the fly."}]},"parameters":[{"name":"sqlStatement","kind":32768,"comment":{"summary":[{"kind":"text","text":"A string containing a database query to execute expressed as SQL. The string\nmay contain "},{"kind":"code","text":"`?`"},{"kind":"text","text":" placeholders, with values to be substituted listed in the "},{"kind":"code","text":"`arguments`"},{"kind":"text","text":" parameter."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"args","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"An array of values (numbers, strings or nulls) to substitute for "},{"kind":"code","text":"`?`"},{"kind":"text","text":" placeholders in the\nSQL statement."}]},"type":{"type":"array","elementType":{"type":"union","types":[{"type":"literal","value":null},{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}}},{"name":"callback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called when the query is successfully completed during the transaction. Takes\ntwo parameters: the transaction itself, and a "},{"kind":"code","text":"`ResultSet`"},{"kind":"text","text":" object (see below) with the results\nof the query."}]},"type":{"type":"reference","name":"SQLStatementCallback"}},{"name":"errorCallback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called if an error occurred executing this particular query in the\ntransaction. Takes two parameters: the transaction itself, and the error object."}]},"type":{"type":"reference","name":"SQLStatementErrorCallback"}}],"type":{"type":"intrinsic","name":"void"}}]}]},{"name":"SQLTransactionAsync","kind":256,"comment":{"summary":[{"kind":"text","text":"A transaction object to perform SQL statements in async mode."}]},"children":[{"name":"executeSqlAsync","kind":2048,"signatures":[{"name":"executeSqlAsync","kind":4096,"comment":{"summary":[{"kind":"text","text":"Executes a SQL statement in async mode."}]},"parameters":[{"name":"sqlStatement","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"args","kind":32768,"flags":{"isOptional":true},"type":{"type":"array","elementType":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}}}],"type":{"type":"reference","typeArguments":[{"type":"reference","name":"ResultSet"}],"name":"Promise","qualifiedName":"Promise","package":"typescript"}}]}],"implementedBy":[{"type":"reference","name":"ExpoSQLTransactionAsync"}]},{"name":"WebSQLDatabase","kind":256,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`SQLiteDatabase`"},{"kind":"text","text":" instead."}]}]},"children":[{"name":"version","kind":1024,"type":{"type":"intrinsic","name":"string"},"inheritedFrom":{"type":"reference","name":"Database.version"}},{"name":"closeAsync","kind":2048,"signatures":[{"name":"closeAsync","kind":4096,"comment":{"summary":[{"kind":"text","text":"Close the database."}]},"type":{"type":"intrinsic","name":"void"}}]},{"name":"deleteAsync","kind":2048,"signatures":[{"name":"deleteAsync","kind":4096,"comment":{"summary":[{"kind":"text","text":"Delete the database file.\n> The database has to be closed prior to deletion."}]},"type":{"type":"reference","typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","qualifiedName":"Promise","package":"typescript"}}]},{"name":"exec","kind":2048,"signatures":[{"name":"exec","kind":4096,"parameters":[{"name":"queries","kind":32768,"type":{"type":"array","elementType":{"type":"reference","name":"Query"}}},{"name":"readOnly","kind":32768,"type":{"type":"intrinsic","name":"boolean"}},{"name":"callback","kind":32768,"type":{"type":"reference","name":"SQLiteCallback"}}],"type":{"type":"intrinsic","name":"void"}}]},{"name":"readTransaction","kind":2048,"signatures":[{"name":"readTransaction","kind":4096,"parameters":[{"name":"callback","kind":32768,"type":{"type":"reference","name":"SQLTransactionCallback"}},{"name":"errorCallback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"SQLTransactionErrorCallback"}},{"name":"successCallback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"Database.readTransaction"}}],"inheritedFrom":{"type":"reference","name":"Database.readTransaction"}},{"name":"transaction","kind":2048,"signatures":[{"name":"transaction","kind":4096,"comment":{"summary":[{"kind":"text","text":"Execute a database transaction."}]},"parameters":[{"name":"callback","kind":32768,"comment":{"summary":[{"kind":"text","text":"A function representing the transaction to perform. Takes a Transaction\n(see below) as its only parameter, on which it can add SQL statements to execute."}]},"type":{"type":"reference","name":"SQLTransactionCallback"}},{"name":"errorCallback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called if an error occurred processing this transaction. Takes a single\nparameter describing the error."}]},"type":{"type":"reference","name":"SQLTransactionErrorCallback"}},{"name":"successCallback","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Called when the transaction has completed executing on the database."}]},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"Database.transaction"}}],"inheritedFrom":{"type":"reference","name":"Database.transaction"}}],"extendedTypes":[{"type":"reference","name":"Database"}]},{"name":"Window","kind":256,"children":[{"name":"openDatabase","kind":1024,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"name","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"version","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"displayName","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"estimatedSize","kind":32768,"type":{"type":"intrinsic","name":"number"}},{"name":"creationCallback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"DatabaseCallback"}}],"type":{"type":"reference","name":"Database"}}]}}}]},{"name":"DatabaseCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"database","kind":32768,"type":{"type":"reference","name":"Database"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"Query","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"children":[{"name":"args","kind":1024,"type":{"type":"array","elementType":{"type":"intrinsic","name":"unknown"}}},{"name":"sql","kind":1024,"type":{"type":"intrinsic","name":"string"}}]}}},{"name":"ResultSet","kind":4194304,"comment":{"summary":[{"kind":"code","text":"`ResultSet`"},{"kind":"text","text":" objects are returned through second parameter of the "},{"kind":"code","text":"`success`"},{"kind":"text","text":" callback for the\n"},{"kind":"code","text":"`tx.executeSql()`"},{"kind":"text","text":" method on a "},{"kind":"code","text":"`SQLTransaction`"},{"kind":"text","text":" (see above)."}]},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"children":[{"name":"insertId","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The row ID of the row that the SQL statement inserted into the database, if a row was inserted."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"rows","kind":1024,"type":{"type":"array","elementType":{"type":"reflection","declaration":{"name":"__type","kind":65536,"indexSignature":{"name":"__index","kind":8192,"parameters":[{"name":"column","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"any"}}}}}},{"name":"rowsAffected","kind":1024,"comment":{"summary":[{"kind":"text","text":"The number of rows that were changed by the SQL statement."}]},"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"ResultSetError","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"children":[{"name":"error","kind":1024,"type":{"type":"reference","name":"Error","qualifiedName":"Error","package":"typescript"}}]}}},{"name":"SQLResultSet","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"children":[{"name":"insertId","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The row ID of the row that the SQL statement inserted into the database, if a row was inserted."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"rows","kind":1024,"type":{"type":"reference","name":"SQLResultSetRowList"}},{"name":"rowsAffected","kind":1024,"comment":{"summary":[{"kind":"text","text":"The number of rows that were changed by the SQL statement."}]},"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"SQLStatementCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"transaction","kind":32768,"type":{"type":"reference","name":"SQLTransaction"}},{"name":"resultSet","kind":32768,"type":{"type":"reference","name":"SQLResultSet"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"SQLStatementErrorCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"transaction","kind":32768,"type":{"type":"reference","name":"SQLTransaction"}},{"name":"error","kind":32768,"type":{"type":"reference","name":"SQLError"}}],"type":{"type":"intrinsic","name":"boolean"}}]}}},{"name":"SQLTransactionAsyncCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"comment":{"summary":[{"kind":"text","text":"A transaction callback with given "},{"kind":"code","text":"`SQLTransactionAsync`"},{"kind":"text","text":" object to perform SQL statements in async mode."}]},"parameters":[{"name":"transaction","kind":32768,"type":{"type":"reference","name":"SQLTransactionAsync"}}],"type":{"type":"reference","typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","qualifiedName":"Promise","package":"typescript"}}]}}},{"name":"SQLTransactionCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"transaction","kind":32768,"type":{"type":"reference","name":"SQLTransaction"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"SQLTransactionErrorCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"error","kind":32768,"type":{"type":"reference","name":"SQLError"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"SQLiteCallback","kind":4194304,"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"error","kind":32768,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"Error","qualifiedName":"Error","package":"typescript"},{"type":"literal","value":null}]}},{"name":"resultSet","kind":32768,"flags":{"isOptional":true},"type":{"type":"array","elementType":{"type":"union","types":[{"type":"reference","name":"ResultSetError"},{"type":"reference","name":"ResultSet"}]}}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"openDatabase","kind":64,"signatures":[{"name":"openDatabase","kind":4096,"comment":{"summary":[{"kind":"text","text":"Open a database, creating it if it doesn't exist, and return a "},{"kind":"code","text":"`Database`"},{"kind":"text","text":" object. On disk,\nthe database will be created under the app's [documents directory](./filesystem), i.e.\n"},{"kind":"code","text":"`${FileSystem.documentDirectory}/SQLite/${name}`"},{"kind":"text","text":".\n> The "},{"kind":"code","text":"`version`"},{"kind":"text","text":", "},{"kind":"code","text":"`description`"},{"kind":"text","text":" and "},{"kind":"code","text":"`size`"},{"kind":"text","text":" arguments are ignored, but are accepted by the function\nfor compatibility with the WebSQL specification."}],"blockTags":[{"tag":"@returns","content":[]}]},"parameters":[{"name":"name","kind":32768,"comment":{"summary":[{"kind":"text","text":"Name of the database file to open."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"version","kind":32768,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'1.0'"},{"name":"description","kind":32768,"type":{"type":"intrinsic","name":"string"},"defaultValue":"name"},{"name":"size","kind":32768,"type":{"type":"intrinsic","name":"number"},"defaultValue":"1"},{"name":"callback","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","kind":65536,"signatures":[{"name":"__type","kind":4096,"parameters":[{"name":"db","kind":32768,"type":{"type":"reference","name":"SQLiteDatabase"}}],"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"SQLiteDatabase"}}]}]} \ No newline at end of file diff --git a/packages/expo-sqlite/CHANGELOG.md b/packages/expo-sqlite/CHANGELOG.md index 248bf8d4fec1a..d3ff739038a37 100644 --- a/packages/expo-sqlite/CHANGELOG.md +++ b/packages/expo-sqlite/CHANGELOG.md @@ -7,6 +7,7 @@ ### 🎉 New features - Migrated Android codebase to Expo Modules API. ([#23115](https://github.com/expo/expo/pull/23115) by [@alanjhughes](https://github.com/alanjhughes)) +- Added experimental `Promise` based `execAsync` and `transactionAsync` functions. ([#23109](https://github.com/expo/expo/pull/23109) by [@kudo](https://github.com/kudo)) ### 🐛 Bug fixes diff --git a/packages/expo-sqlite/build/SQLite.d.ts b/packages/expo-sqlite/build/SQLite.d.ts index aaf68722e6e78..108342529aaca 100644 --- a/packages/expo-sqlite/build/SQLite.d.ts +++ b/packages/expo-sqlite/build/SQLite.d.ts @@ -1,5 +1,38 @@ import './polyfillNextTick'; -import { WebSQLDatabase } from './SQLite.types'; +import type { Query, ResultSet, SQLiteCallback, SQLTransactionAsyncCallback, SQLTransactionAsync } from './SQLite.types'; +/** The database returned by `openDatabase()` */ +export declare class SQLiteDatabase { + _name: string; + _closed: boolean; + constructor(name: string); + /** + * Executes the SQL statement and returns a callback resolving with the result. + */ + exec(queries: Query[], readOnly: boolean, callback: SQLiteCallback): void; + /** + * Executes the SQL statement and returns a Promise resolving with the result. + */ + execAsync(queries: Query[], readOnly: boolean): Promise; + /** + * @deprecated Use `closeAsync()` instead. + */ + close: () => void; + /** + * Close the database. + */ + closeAsync(): void; + /** + * Delete the database file. + * > The database has to be closed prior to deletion. + */ + deleteAsync(): Promise; + /** + * Creates a new transaction with Promise support. + * @param asyncCallback A `SQLTransactionAsyncCallback` function that can perform SQL statements in a transaction. + * @param readOnly true if all the SQL statements in the callback are read only. + */ + transactionAsync(asyncCallback: SQLTransactionAsyncCallback, readOnly?: boolean): Promise; +} /** * Open a database, creating it if it doesn't exist, and return a `Database` object. On disk, * the database will be created under the app's [documents directory](./filesystem), i.e. @@ -13,5 +46,15 @@ import { WebSQLDatabase } from './SQLite.types'; * @param callback * @return */ -export declare function openDatabase(name: string, version?: string, description?: string, size?: number, callback?: (db: WebSQLDatabase) => void): WebSQLDatabase; +export declare function openDatabase(name: string, version?: string, description?: string, size?: number, callback?: (db: SQLiteDatabase) => void): SQLiteDatabase; +/** + * Internal data structure for the async transaction API. + * @internal + */ +export declare class ExpoSQLTransactionAsync implements SQLTransactionAsync { + private readonly db; + private readonly readOnly; + constructor(db: SQLiteDatabase, readOnly: boolean); + executeSqlAsync(sqlStatement: string, args?: (number | string)[]): Promise; +} //# sourceMappingURL=SQLite.d.ts.map \ No newline at end of file diff --git a/packages/expo-sqlite/build/SQLite.d.ts.map b/packages/expo-sqlite/build/SQLite.d.ts.map index 2f0f41a2b1582..70ff818084d71 100644 --- a/packages/expo-sqlite/build/SQLite.d.ts.map +++ b/packages/expo-sqlite/build/SQLite.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"SQLite.d.ts","sourceRoot":"","sources":["../src/SQLite.ts"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,CAAC;AAM5B,OAAO,EAAoD,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA4FlG;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,MAAc,EACvB,WAAW,GAAE,MAAa,EAC1B,IAAI,GAAE,MAAU,EAChB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,cAAc,KAAK,IAAI,GACtC,cAAc,CAShB"} \ No newline at end of file +{"version":3,"file":"SQLite.d.ts","sourceRoot":"","sources":["../src/SQLite.ts"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,CAAC;AAM5B,OAAO,KAAK,EACV,KAAK,EACL,SAAS,EAET,cAAc,EACd,2BAA2B,EAC3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAYxB,gDAAgD;AAChD,qBAAa,cAAc;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAS;gBAEb,IAAI,EAAE,MAAM;IAIxB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI;IAgBzE;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAa1E;;OAEG;IACH,KAAK,QAKS,IAAI,CALM;IAExB;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;;OAGG;IACH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAU5B;;;;OAIG;IACG,gBAAgB,CACpB,aAAa,EAAE,2BAA2B,EAC1C,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,IAAI,CAAC;CAWjB;AA0CD;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,MAAc,EACvB,WAAW,GAAE,MAAa,EAC1B,IAAI,GAAE,MAAU,EAChB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,cAAc,KAAK,IAAI,GACtC,cAAc,CAWhB;AAED;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,mBAAmB;IACrD,OAAO,CAAC,QAAQ,CAAC,EAAE;IAAkB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAA7C,EAAE,EAAE,cAAc,EAAmB,QAAQ,EAAE,OAAO;IAE7E,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC;CAO5F"} \ No newline at end of file diff --git a/packages/expo-sqlite/build/SQLite.js b/packages/expo-sqlite/build/SQLite.js index ee57cc9f22521..4f0c9c4ccb29a 100644 --- a/packages/expo-sqlite/build/SQLite.js +++ b/packages/expo-sqlite/build/SQLite.js @@ -10,12 +10,16 @@ function zipObject(keys, values) { } return result; } -class SQLiteDatabase { +/** The database returned by `openDatabase()` */ +export class SQLiteDatabase { _name; _closed = false; constructor(name) { this._name = name; } + /** + * Executes the SQL statement and returns a callback resolving with the result. + */ exec(queries, readOnly, callback) { if (this._closed) { throw new Error(`The SQLite database is closed`); @@ -27,16 +31,54 @@ class SQLiteDatabase { callback(error instanceof Error ? error : new Error(error)); }); } - close() { + /** + * Executes the SQL statement and returns a Promise resolving with the result. + */ + async execAsync(queries, readOnly) { + if (this._closed) { + throw new Error(`The SQLite database is closed`); + } + const nativeResultSets = await ExpoSQLite.exec(this._name, queries.map(_serializeQuery), readOnly); + return nativeResultSets.map(_deserializeResultSet); + } + /** + * @deprecated Use `closeAsync()` instead. + */ + close = this.closeAsync; + /** + * Close the database. + */ + closeAsync() { this._closed = true; return ExpoSQLite.close(this._name); } + /** + * Delete the database file. + * > The database has to be closed prior to deletion. + */ deleteAsync() { if (!this._closed) { throw new Error(`Unable to delete '${this._name}' database that is currently open. Close it prior to deletion.`); } return ExpoSQLite.deleteAsync(this._name); } + /** + * Creates a new transaction with Promise support. + * @param asyncCallback A `SQLTransactionAsyncCallback` function that can perform SQL statements in a transaction. + * @param readOnly true if all the SQL statements in the callback are read only. + */ + async transactionAsync(asyncCallback, readOnly = false) { + await this.execAsync([{ sql: 'BEGIN;', args: [] }], false); + try { + const transaction = new ExpoSQLTransactionAsync(this, readOnly); + await asyncCallback(transaction); + await this.execAsync([{ sql: 'END;', args: [] }], false); + } + catch (e) { + await this.execAsync([{ sql: 'ROLLBACK;', args: [] }], false); + throw e; + } + } } function _serializeQuery(query) { return Platform.OS === 'android' @@ -93,8 +135,26 @@ export function openDatabase(name, version = '1.0', description = name, size = 1 } const db = _openExpoSQLiteDatabase(name, version, description, size, callback); db.exec = db._db.exec.bind(db._db); - db.closeAsync = db._db.close.bind(db._db); + db.execAsync = db._db.execAsync.bind(db._db); + db.closeAsync = db._db.closeAsync.bind(db._db); db.deleteAsync = db._db.deleteAsync.bind(db._db); + db.transactionAsync = db._db.transactionAsync.bind(db._db); return db; } +/** + * Internal data structure for the async transaction API. + * @internal + */ +export class ExpoSQLTransactionAsync { + db; + readOnly; + constructor(db, readOnly) { + this.db = db; + this.readOnly = readOnly; + } + async executeSqlAsync(sqlStatement, args) { + const resultSets = await this.db.execAsync([{ sql: sqlStatement, args: args ?? [] }], this.readOnly); + return resultSets[0]; + } +} //# sourceMappingURL=SQLite.js.map \ No newline at end of file diff --git a/packages/expo-sqlite/build/SQLite.js.map b/packages/expo-sqlite/build/SQLite.js.map index ea92503561d97..977e96656fda0 100644 --- a/packages/expo-sqlite/build/SQLite.js.map +++ b/packages/expo-sqlite/build/SQLite.js.map @@ -1 +1 @@ -{"version":3,"file":"SQLite.js","sourceRoot":"","sources":["../src/SQLite.ts"],"names":[],"mappings":"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","sourcesContent":["import './polyfillNextTick';\n\nimport customOpenDatabase from '@expo/websql/custom';\nimport { requireNativeModule } from 'expo-modules-core';\nimport { Platform } from 'react-native';\n\nimport { Query, ResultSet, ResultSetError, SQLiteCallback, WebSQLDatabase } from './SQLite.types';\n\nconst ExpoSQLite = requireNativeModule('ExpoSQLite');\n\nfunction zipObject(keys: string[], values: any[]) {\n const result = {};\n for (let i = 0; i < keys.length; i++) {\n result[keys[i]] = values[i];\n }\n return result;\n}\n\nclass SQLiteDatabase {\n _name: string;\n _closed: boolean = false;\n\n constructor(name: string) {\n this._name = name;\n }\n\n exec(queries: Query[], readOnly: boolean, callback: SQLiteCallback): void {\n if (this._closed) {\n throw new Error(`The SQLite database is closed`);\n }\n\n ExpoSQLite.exec(this._name, queries.map(_serializeQuery), readOnly).then(\n (nativeResultSets) => {\n callback(null, nativeResultSets.map(_deserializeResultSet));\n },\n (error) => {\n // TODO: make the native API consistently reject with an error, not a string or other type\n callback(error instanceof Error ? error : new Error(error));\n }\n );\n }\n\n close() {\n this._closed = true;\n return ExpoSQLite.close(this._name);\n }\n\n deleteAsync(): Promise {\n if (!this._closed) {\n throw new Error(\n `Unable to delete '${this._name}' database that is currently open. Close it prior to deletion.`\n );\n }\n\n return ExpoSQLite.deleteAsync(this._name);\n }\n}\n\nfunction _serializeQuery(query: Query): Query | [string, any[]] {\n return Platform.OS === 'android'\n ? {\n sql: query.sql,\n args: query.args.map(_escapeBlob),\n }\n : [query.sql, query.args];\n}\n\nfunction _deserializeResultSet(nativeResult): ResultSet | ResultSetError {\n const [errorMessage, insertId, rowsAffected, columns, rows] = nativeResult;\n // TODO: send more structured error information from the native module so we can better construct\n // a SQLException object\n if (errorMessage !== null) {\n return { error: new Error(errorMessage) } as ResultSetError;\n }\n\n return {\n insertId,\n rowsAffected,\n rows: rows.map((row) => zipObject(columns, row)),\n };\n}\n\nfunction _escapeBlob(data: T): T {\n if (typeof data === 'string') {\n /* eslint-disable no-control-regex */\n return data\n .replace(/\\u0002/g, '\\u0002\\u0002')\n .replace(/\\u0001/g, '\\u0001\\u0002')\n .replace(/\\u0000/g, '\\u0001\\u0001') as any;\n /* eslint-enable no-control-regex */\n } else {\n return data;\n }\n}\n\nconst _openExpoSQLiteDatabase = customOpenDatabase(SQLiteDatabase);\n\n// @needsAudit @docsMissing\n/**\n * Open a database, creating it if it doesn't exist, and return a `Database` object. On disk,\n * the database will be created under the app's [documents directory](./filesystem), i.e.\n * `${FileSystem.documentDirectory}/SQLite/${name}`.\n * > The `version`, `description` and `size` arguments are ignored, but are accepted by the function\n * for compatibility with the WebSQL specification.\n * @param name Name of the database file to open.\n * @param version\n * @param description\n * @param size\n * @param callback\n * @return\n */\nexport function openDatabase(\n name: string,\n version: string = '1.0',\n description: string = name,\n size: number = 1,\n callback?: (db: WebSQLDatabase) => void\n): WebSQLDatabase {\n if (name === undefined) {\n throw new TypeError(`The database name must not be undefined`);\n }\n const db = _openExpoSQLiteDatabase(name, version, description, size, callback);\n db.exec = db._db.exec.bind(db._db);\n db.closeAsync = db._db.close.bind(db._db);\n db.deleteAsync = db._db.deleteAsync.bind(db._db);\n return db;\n}\n"]} \ No newline at end of file +{"version":3,"file":"SQLite.js","sourceRoot":"","sources":["../src/SQLite.ts"],"names":[],"mappings":"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","sourcesContent":["import './polyfillNextTick';\n\nimport customOpenDatabase from '@expo/websql/custom';\nimport { requireNativeModule } from 'expo-modules-core';\nimport { Platform } from 'react-native';\n\nimport type {\n Query,\n ResultSet,\n ResultSetError,\n SQLiteCallback,\n SQLTransactionAsyncCallback,\n SQLTransactionAsync,\n} from './SQLite.types';\n\nconst ExpoSQLite = requireNativeModule('ExpoSQLite');\n\nfunction zipObject(keys: string[], values: any[]) {\n const result = {};\n for (let i = 0; i < keys.length; i++) {\n result[keys[i]] = values[i];\n }\n return result;\n}\n\n/** The database returned by `openDatabase()` */\nexport class SQLiteDatabase {\n _name: string;\n _closed: boolean = false;\n\n constructor(name: string) {\n this._name = name;\n }\n\n /**\n * Executes the SQL statement and returns a callback resolving with the result.\n */\n exec(queries: Query[], readOnly: boolean, callback: SQLiteCallback): void {\n if (this._closed) {\n throw new Error(`The SQLite database is closed`);\n }\n\n ExpoSQLite.exec(this._name, queries.map(_serializeQuery), readOnly).then(\n (nativeResultSets) => {\n callback(null, nativeResultSets.map(_deserializeResultSet));\n },\n (error) => {\n // TODO: make the native API consistently reject with an error, not a string or other type\n callback(error instanceof Error ? error : new Error(error));\n }\n );\n }\n\n /**\n * Executes the SQL statement and returns a Promise resolving with the result.\n */\n async execAsync(queries: Query[], readOnly: boolean): Promise {\n if (this._closed) {\n throw new Error(`The SQLite database is closed`);\n }\n\n const nativeResultSets = await ExpoSQLite.exec(\n this._name,\n queries.map(_serializeQuery),\n readOnly\n );\n return nativeResultSets.map(_deserializeResultSet);\n }\n\n /**\n * @deprecated Use `closeAsync()` instead.\n */\n close = this.closeAsync;\n\n /**\n * Close the database.\n */\n closeAsync(): void {\n this._closed = true;\n return ExpoSQLite.close(this._name);\n }\n\n /**\n * Delete the database file.\n * > The database has to be closed prior to deletion.\n */\n deleteAsync(): Promise {\n if (!this._closed) {\n throw new Error(\n `Unable to delete '${this._name}' database that is currently open. Close it prior to deletion.`\n );\n }\n\n return ExpoSQLite.deleteAsync(this._name);\n }\n\n /**\n * Creates a new transaction with Promise support.\n * @param asyncCallback A `SQLTransactionAsyncCallback` function that can perform SQL statements in a transaction.\n * @param readOnly true if all the SQL statements in the callback are read only.\n */\n async transactionAsync(\n asyncCallback: SQLTransactionAsyncCallback,\n readOnly: boolean = false\n ): Promise {\n await this.execAsync([{ sql: 'BEGIN;', args: [] }], false);\n try {\n const transaction = new ExpoSQLTransactionAsync(this, readOnly);\n await asyncCallback(transaction);\n await this.execAsync([{ sql: 'END;', args: [] }], false);\n } catch (e: unknown) {\n await this.execAsync([{ sql: 'ROLLBACK;', args: [] }], false);\n throw e;\n }\n }\n}\n\nfunction _serializeQuery(query: Query): Query | [string, any[]] {\n return Platform.OS === 'android'\n ? {\n sql: query.sql,\n args: query.args.map(_escapeBlob),\n }\n : [query.sql, query.args];\n}\n\nfunction _deserializeResultSet(nativeResult): ResultSet | ResultSetError {\n const [errorMessage, insertId, rowsAffected, columns, rows] = nativeResult;\n // TODO: send more structured error information from the native module so we can better construct\n // a SQLException object\n if (errorMessage !== null) {\n return { error: new Error(errorMessage) } as ResultSetError;\n }\n\n return {\n insertId,\n rowsAffected,\n rows: rows.map((row) => zipObject(columns, row)),\n };\n}\n\nfunction _escapeBlob(data: T): T {\n if (typeof data === 'string') {\n /* eslint-disable no-control-regex */\n return data\n .replace(/\\u0002/g, '\\u0002\\u0002')\n .replace(/\\u0001/g, '\\u0001\\u0002')\n .replace(/\\u0000/g, '\\u0001\\u0001') as any;\n /* eslint-enable no-control-regex */\n } else {\n return data;\n }\n}\n\nconst _openExpoSQLiteDatabase = customOpenDatabase(SQLiteDatabase);\n\n// @needsAudit @docsMissing\n/**\n * Open a database, creating it if it doesn't exist, and return a `Database` object. On disk,\n * the database will be created under the app's [documents directory](./filesystem), i.e.\n * `${FileSystem.documentDirectory}/SQLite/${name}`.\n * > The `version`, `description` and `size` arguments are ignored, but are accepted by the function\n * for compatibility with the WebSQL specification.\n * @param name Name of the database file to open.\n * @param version\n * @param description\n * @param size\n * @param callback\n * @return\n */\nexport function openDatabase(\n name: string,\n version: string = '1.0',\n description: string = name,\n size: number = 1,\n callback?: (db: SQLiteDatabase) => void\n): SQLiteDatabase {\n if (name === undefined) {\n throw new TypeError(`The database name must not be undefined`);\n }\n const db = _openExpoSQLiteDatabase(name, version, description, size, callback);\n db.exec = db._db.exec.bind(db._db);\n db.execAsync = db._db.execAsync.bind(db._db);\n db.closeAsync = db._db.closeAsync.bind(db._db);\n db.deleteAsync = db._db.deleteAsync.bind(db._db);\n db.transactionAsync = db._db.transactionAsync.bind(db._db);\n return db;\n}\n\n/**\n * Internal data structure for the async transaction API.\n * @internal\n */\nexport class ExpoSQLTransactionAsync implements SQLTransactionAsync {\n constructor(private readonly db: SQLiteDatabase, private readonly readOnly: boolean) {}\n\n async executeSqlAsync(sqlStatement: string, args?: (number | string)[]): Promise {\n const resultSets = await this.db.execAsync(\n [{ sql: sqlStatement, args: args ?? [] }],\n this.readOnly\n );\n return resultSets[0];\n }\n}\n"]} \ No newline at end of file diff --git a/packages/expo-sqlite/build/SQLite.types.d.ts b/packages/expo-sqlite/build/SQLite.types.d.ts index 98bb415597c94..84ddefd2126d1 100644 --- a/packages/expo-sqlite/build/SQLite.types.d.ts +++ b/packages/expo-sqlite/build/SQLite.types.d.ts @@ -84,6 +84,7 @@ export declare class SQLError { code: number; message: string; } +/** @deprecated Use `SQLiteDatabase` instead. */ export interface WebSQLDatabase extends Database { exec(queries: Query[], readOnly: boolean, callback: SQLiteCallback): void; /** @@ -121,4 +122,11 @@ export type ResultSet = { }[]; }; export type SQLiteCallback = (error?: Error | null, resultSet?: (ResultSetError | ResultSet)[]) => void; +/** A transaction object to perform SQL statements in async mode. */ +export interface SQLTransactionAsync { + /** Executes a SQL statement in async mode. */ + executeSqlAsync(sqlStatement: string, args?: (number | string)[]): Promise; +} +/** A transaction callback with given `SQLTransactionAsync` object to perform SQL statements in async mode. */ +export type SQLTransactionAsyncCallback = (transaction: SQLTransactionAsync) => Promise; //# sourceMappingURL=SQLite.types.d.ts.map \ No newline at end of file diff --git a/packages/expo-sqlite/build/SQLite.types.d.ts.map b/packages/expo-sqlite/build/SQLite.types.d.ts.map index 7bc92de7110a8..a26cd68fd76d2 100644 --- a/packages/expo-sqlite/build/SQLite.types.d.ts.map +++ b/packages/expo-sqlite/build/SQLite.types.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"SQLite.types.d.ts","sourceRoot":"","sources":["../src/SQLite.types.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"SQLite.types.d.ts","sourceRoot":"","sources":["../src/SQLite.types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-sqlite/build/SQLite.types.js.map b/packages/expo-sqlite/build/SQLite.types.js.map index ce87496ead2d3..6be29cabc998a 100644 --- a/packages/expo-sqlite/build/SQLite.types.js.map +++ b/packages/expo-sqlite/build/SQLite.types.js.map @@ -1 +1 @@ -{"version":3,"file":"SQLite.types.js","sourceRoot":"","sources":["../src/SQLite.types.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,8CAA8C;AAC9C,gDAAgD;AAChD,2DAA2D;AAC3D,EAAE;AACF,0EAA0E","sourcesContent":["// Definitions copied from `@types/websql` as we want\n// to expose a custom version of the API that:\n// - uses primitive `string` instead of `String`\n// - excludes some methods that are not exposed by our API.\n//\n// Original definitions by: TeamworkGuy2 \n\n// @docsMissing\nexport interface Window {\n openDatabase?: (\n name: string,\n version: string,\n displayName: string,\n estimatedSize: number,\n creationCallback?: DatabaseCallback\n ) => Database;\n}\n\n// @docsMissing\nexport type DatabaseCallback = (database: Database) => void;\n\n// @needsAudit @docsMissing\n/**\n * `Database` objects are returned by calls to `SQLite.openDatabase()`. Such an object represents a\n * connection to a database on your device.\n */\nexport interface Database {\n version: string;\n\n /**\n * Execute a database transaction.\n * @param callback A function representing the transaction to perform. Takes a Transaction\n * (see below) as its only parameter, on which it can add SQL statements to execute.\n * @param errorCallback Called if an error occurred processing this transaction. Takes a single\n * parameter describing the error.\n * @param successCallback Called when the transaction has completed executing on the database.\n */\n transaction(\n callback: SQLTransactionCallback,\n errorCallback?: SQLTransactionErrorCallback,\n successCallback?: () => void\n ): void;\n\n readTransaction(\n callback: SQLTransactionCallback,\n errorCallback?: SQLTransactionErrorCallback,\n successCallback?: () => void\n ): void;\n}\n\n// @docsMissing\nexport type SQLTransactionCallback = (transaction: SQLTransaction) => void;\n\n// @docsMissing\nexport type SQLTransactionErrorCallback = (error: SQLError) => void;\n\n// @needsAudit\n/**\n * A `SQLTransaction` object is passed in as a parameter to the `callback` parameter for the\n * `db.transaction()` method on a `Database` (see above). It allows enqueuing SQL statements to\n * perform in a database transaction.\n */\nexport interface SQLTransaction {\n /**\n * Enqueue a SQL statement to execute in the transaction. Authors are strongly recommended to make\n * use of the `?` placeholder feature of the method to avoid against SQL injection attacks, and to\n * never construct SQL statements on the fly.\n * @param sqlStatement A string containing a database query to execute expressed as SQL. The string\n * may contain `?` placeholders, with values to be substituted listed in the `arguments` parameter.\n * @param args An array of values (numbers, strings or nulls) to substitute for `?` placeholders in the\n * SQL statement.\n * @param callback Called when the query is successfully completed during the transaction. Takes\n * two parameters: the transaction itself, and a `ResultSet` object (see below) with the results\n * of the query.\n * @param errorCallback Called if an error occurred executing this particular query in the\n * transaction. Takes two parameters: the transaction itself, and the error object.\n */\n executeSql(\n sqlStatement: string,\n args?: (number | string | null)[],\n callback?: SQLStatementCallback,\n errorCallback?: SQLStatementErrorCallback\n ): void;\n}\n\n// @docsMissing\nexport type SQLStatementCallback = (transaction: SQLTransaction, resultSet: SQLResultSet) => void;\n\n// @docsMissing\nexport type SQLStatementErrorCallback = (transaction: SQLTransaction, error: SQLError) => boolean;\n\n// @needsAudit\nexport type SQLResultSet = {\n /**\n * The row ID of the row that the SQL statement inserted into the database, if a row was inserted.\n */\n insertId?: number;\n /**\n * The number of rows that were changed by the SQL statement.\n */\n rowsAffected: number;\n rows: SQLResultSetRowList;\n};\n\n// @needsAudit\nexport interface SQLResultSetRowList {\n /**\n * The number of rows returned by the query.\n */\n length: number;\n /**\n * Returns the row with the given `index`. If there is no such row, returns `null`.\n * @param index Index of row to get.\n */\n item(index: number): any;\n /**\n * The actual array of rows returned by the query. Can be used directly instead of\n * getting rows through rows.item().\n */\n _array: any[];\n}\n\n// @docsMissing\nexport declare class SQLError {\n static UNKNOWN_ERR: number;\n static DATABASE_ERR: number;\n static VERSION_ERR: number;\n static TOO_LARGE_ERR: number;\n static QUOTA_ERR: number;\n static SYNTAX_ERR: number;\n static CONSTRAINT_ERR: number;\n static TIMEOUT_ERR: number;\n\n code: number;\n message: string;\n}\n\n// @docsMissing\nexport interface WebSQLDatabase extends Database {\n exec(queries: Query[], readOnly: boolean, callback: SQLiteCallback): void;\n\n /**\n * Close the database.\n */\n closeAsync(): void;\n\n /**\n * Delete the database file.\n * > The database has to be closed prior to deletion.\n */\n deleteAsync(): Promise;\n}\n\n// @docsMissing\nexport type Query = { sql: string; args: unknown[] };\n\n// @docsMissing\nexport type ResultSetError = {\n error: Error;\n};\n\n// @needsAudit\n/**\n * `ResultSet` objects are returned through second parameter of the `success` callback for the\n * `tx.executeSql()` method on a `SQLTransaction` (see above).\n */\nexport type ResultSet = {\n /**\n * The row ID of the row that the SQL statement inserted into the database, if a row was inserted.\n */\n insertId?: number;\n /**\n * The number of rows that were changed by the SQL statement.\n */\n rowsAffected: number;\n rows: { [column: string]: any }[];\n};\n\n// @docsMissing\nexport type SQLiteCallback = (\n error?: Error | null,\n resultSet?: (ResultSetError | ResultSet)[]\n) => void;\n"]} \ No newline at end of file +{"version":3,"file":"SQLite.types.js","sourceRoot":"","sources":["../src/SQLite.types.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,8CAA8C;AAC9C,gDAAgD;AAChD,2DAA2D;AAC3D,EAAE;AACF,0EAA0E","sourcesContent":["// Definitions copied from `@types/websql` as we want\n// to expose a custom version of the API that:\n// - uses primitive `string` instead of `String`\n// - excludes some methods that are not exposed by our API.\n//\n// Original definitions by: TeamworkGuy2 \n\n// @docsMissing\nexport interface Window {\n openDatabase?: (\n name: string,\n version: string,\n displayName: string,\n estimatedSize: number,\n creationCallback?: DatabaseCallback\n ) => Database;\n}\n\n// @docsMissing\nexport type DatabaseCallback = (database: Database) => void;\n\n// @needsAudit @docsMissing\n/**\n * `Database` objects are returned by calls to `SQLite.openDatabase()`. Such an object represents a\n * connection to a database on your device.\n */\nexport interface Database {\n version: string;\n\n /**\n * Execute a database transaction.\n * @param callback A function representing the transaction to perform. Takes a Transaction\n * (see below) as its only parameter, on which it can add SQL statements to execute.\n * @param errorCallback Called if an error occurred processing this transaction. Takes a single\n * parameter describing the error.\n * @param successCallback Called when the transaction has completed executing on the database.\n */\n transaction(\n callback: SQLTransactionCallback,\n errorCallback?: SQLTransactionErrorCallback,\n successCallback?: () => void\n ): void;\n\n readTransaction(\n callback: SQLTransactionCallback,\n errorCallback?: SQLTransactionErrorCallback,\n successCallback?: () => void\n ): void;\n}\n\n// @docsMissing\nexport type SQLTransactionCallback = (transaction: SQLTransaction) => void;\n\n// @docsMissing\nexport type SQLTransactionErrorCallback = (error: SQLError) => void;\n\n// @needsAudit\n/**\n * A `SQLTransaction` object is passed in as a parameter to the `callback` parameter for the\n * `db.transaction()` method on a `Database` (see above). It allows enqueuing SQL statements to\n * perform in a database transaction.\n */\nexport interface SQLTransaction {\n /**\n * Enqueue a SQL statement to execute in the transaction. Authors are strongly recommended to make\n * use of the `?` placeholder feature of the method to avoid against SQL injection attacks, and to\n * never construct SQL statements on the fly.\n * @param sqlStatement A string containing a database query to execute expressed as SQL. The string\n * may contain `?` placeholders, with values to be substituted listed in the `arguments` parameter.\n * @param args An array of values (numbers, strings or nulls) to substitute for `?` placeholders in the\n * SQL statement.\n * @param callback Called when the query is successfully completed during the transaction. Takes\n * two parameters: the transaction itself, and a `ResultSet` object (see below) with the results\n * of the query.\n * @param errorCallback Called if an error occurred executing this particular query in the\n * transaction. Takes two parameters: the transaction itself, and the error object.\n */\n executeSql(\n sqlStatement: string,\n args?: (number | string | null)[],\n callback?: SQLStatementCallback,\n errorCallback?: SQLStatementErrorCallback\n ): void;\n}\n\n// @docsMissing\nexport type SQLStatementCallback = (transaction: SQLTransaction, resultSet: SQLResultSet) => void;\n\n// @docsMissing\nexport type SQLStatementErrorCallback = (transaction: SQLTransaction, error: SQLError) => boolean;\n\n// @needsAudit\nexport type SQLResultSet = {\n /**\n * The row ID of the row that the SQL statement inserted into the database, if a row was inserted.\n */\n insertId?: number;\n /**\n * The number of rows that were changed by the SQL statement.\n */\n rowsAffected: number;\n rows: SQLResultSetRowList;\n};\n\n// @needsAudit\nexport interface SQLResultSetRowList {\n /**\n * The number of rows returned by the query.\n */\n length: number;\n /**\n * Returns the row with the given `index`. If there is no such row, returns `null`.\n * @param index Index of row to get.\n */\n item(index: number): any;\n /**\n * The actual array of rows returned by the query. Can be used directly instead of\n * getting rows through rows.item().\n */\n _array: any[];\n}\n\n// @docsMissing\nexport declare class SQLError {\n static UNKNOWN_ERR: number;\n static DATABASE_ERR: number;\n static VERSION_ERR: number;\n static TOO_LARGE_ERR: number;\n static QUOTA_ERR: number;\n static SYNTAX_ERR: number;\n static CONSTRAINT_ERR: number;\n static TIMEOUT_ERR: number;\n\n code: number;\n message: string;\n}\n\n/** @deprecated Use `SQLiteDatabase` instead. */\nexport interface WebSQLDatabase extends Database {\n exec(queries: Query[], readOnly: boolean, callback: SQLiteCallback): void;\n\n /**\n * Close the database.\n */\n closeAsync(): void;\n\n /**\n * Delete the database file.\n * > The database has to be closed prior to deletion.\n */\n deleteAsync(): Promise;\n}\n\n// @docsMissing\nexport type Query = { sql: string; args: unknown[] };\n\n// @docsMissing\nexport type ResultSetError = {\n error: Error;\n};\n\n// @needsAudit\n/**\n * `ResultSet` objects are returned through second parameter of the `success` callback for the\n * `tx.executeSql()` method on a `SQLTransaction` (see above).\n */\nexport type ResultSet = {\n /**\n * The row ID of the row that the SQL statement inserted into the database, if a row was inserted.\n */\n insertId?: number;\n /**\n * The number of rows that were changed by the SQL statement.\n */\n rowsAffected: number;\n rows: { [column: string]: any }[];\n};\n\n// @docsMissing\nexport type SQLiteCallback = (\n error?: Error | null,\n resultSet?: (ResultSetError | ResultSet)[]\n) => void;\n\n/** A transaction object to perform SQL statements in async mode. */\nexport interface SQLTransactionAsync {\n /** Executes a SQL statement in async mode. */\n executeSqlAsync(sqlStatement: string, args?: (number | string)[]): Promise;\n}\n\n/** A transaction callback with given `SQLTransactionAsync` object to perform SQL statements in async mode. */\nexport type SQLTransactionAsyncCallback = (transaction: SQLTransactionAsync) => Promise;\n"]} \ No newline at end of file diff --git a/packages/expo-sqlite/src/SQLite.ts b/packages/expo-sqlite/src/SQLite.ts index 44b34550df7dd..ed0d1cc4f0f31 100644 --- a/packages/expo-sqlite/src/SQLite.ts +++ b/packages/expo-sqlite/src/SQLite.ts @@ -4,7 +4,14 @@ import customOpenDatabase from '@expo/websql/custom'; import { requireNativeModule } from 'expo-modules-core'; import { Platform } from 'react-native'; -import { Query, ResultSet, ResultSetError, SQLiteCallback, WebSQLDatabase } from './SQLite.types'; +import type { + Query, + ResultSet, + ResultSetError, + SQLiteCallback, + SQLTransactionAsyncCallback, + SQLTransactionAsync, +} from './SQLite.types'; const ExpoSQLite = requireNativeModule('ExpoSQLite'); @@ -16,7 +23,8 @@ function zipObject(keys: string[], values: any[]) { return result; } -class SQLiteDatabase { +/** The database returned by `openDatabase()` */ +export class SQLiteDatabase { _name: string; _closed: boolean = false; @@ -24,6 +32,9 @@ class SQLiteDatabase { this._name = name; } + /** + * Executes the SQL statement and returns a callback resolving with the result. + */ exec(queries: Query[], readOnly: boolean, callback: SQLiteCallback): void { if (this._closed) { throw new Error(`The SQLite database is closed`); @@ -40,11 +51,39 @@ class SQLiteDatabase { ); } - close() { + /** + * Executes the SQL statement and returns a Promise resolving with the result. + */ + async execAsync(queries: Query[], readOnly: boolean): Promise { + if (this._closed) { + throw new Error(`The SQLite database is closed`); + } + + const nativeResultSets = await ExpoSQLite.exec( + this._name, + queries.map(_serializeQuery), + readOnly + ); + return nativeResultSets.map(_deserializeResultSet); + } + + /** + * @deprecated Use `closeAsync()` instead. + */ + close = this.closeAsync; + + /** + * Close the database. + */ + closeAsync(): void { this._closed = true; return ExpoSQLite.close(this._name); } + /** + * Delete the database file. + * > The database has to be closed prior to deletion. + */ deleteAsync(): Promise { if (!this._closed) { throw new Error( @@ -54,6 +93,26 @@ class SQLiteDatabase { return ExpoSQLite.deleteAsync(this._name); } + + /** + * Creates a new transaction with Promise support. + * @param asyncCallback A `SQLTransactionAsyncCallback` function that can perform SQL statements in a transaction. + * @param readOnly true if all the SQL statements in the callback are read only. + */ + async transactionAsync( + asyncCallback: SQLTransactionAsyncCallback, + readOnly: boolean = false + ): Promise { + await this.execAsync([{ sql: 'BEGIN;', args: [] }], false); + try { + const transaction = new ExpoSQLTransactionAsync(this, readOnly); + await asyncCallback(transaction); + await this.execAsync([{ sql: 'END;', args: [] }], false); + } catch (e: unknown) { + await this.execAsync([{ sql: 'ROLLBACK;', args: [] }], false); + throw e; + } + } } function _serializeQuery(query: Query): Query | [string, any[]] { @@ -114,14 +173,32 @@ export function openDatabase( version: string = '1.0', description: string = name, size: number = 1, - callback?: (db: WebSQLDatabase) => void -): WebSQLDatabase { + callback?: (db: SQLiteDatabase) => void +): SQLiteDatabase { if (name === undefined) { throw new TypeError(`The database name must not be undefined`); } const db = _openExpoSQLiteDatabase(name, version, description, size, callback); db.exec = db._db.exec.bind(db._db); - db.closeAsync = db._db.close.bind(db._db); + db.execAsync = db._db.execAsync.bind(db._db); + db.closeAsync = db._db.closeAsync.bind(db._db); db.deleteAsync = db._db.deleteAsync.bind(db._db); + db.transactionAsync = db._db.transactionAsync.bind(db._db); return db; } + +/** + * Internal data structure for the async transaction API. + * @internal + */ +export class ExpoSQLTransactionAsync implements SQLTransactionAsync { + constructor(private readonly db: SQLiteDatabase, private readonly readOnly: boolean) {} + + async executeSqlAsync(sqlStatement: string, args?: (number | string)[]): Promise { + const resultSets = await this.db.execAsync( + [{ sql: sqlStatement, args: args ?? [] }], + this.readOnly + ); + return resultSets[0]; + } +} diff --git a/packages/expo-sqlite/src/SQLite.types.ts b/packages/expo-sqlite/src/SQLite.types.ts index 66dd8179c1250..9314f6066bf01 100644 --- a/packages/expo-sqlite/src/SQLite.types.ts +++ b/packages/expo-sqlite/src/SQLite.types.ts @@ -135,7 +135,7 @@ export declare class SQLError { message: string; } -// @docsMissing +/** @deprecated Use `SQLiteDatabase` instead. */ export interface WebSQLDatabase extends Database { exec(queries: Query[], readOnly: boolean, callback: SQLiteCallback): void; @@ -181,3 +181,12 @@ export type SQLiteCallback = ( error?: Error | null, resultSet?: (ResultSetError | ResultSet)[] ) => void; + +/** A transaction object to perform SQL statements in async mode. */ +export interface SQLTransactionAsync { + /** Executes a SQL statement in async mode. */ + executeSqlAsync(sqlStatement: string, args?: (number | string)[]): Promise; +} + +/** A transaction callback with given `SQLTransactionAsync` object to perform SQL statements in async mode. */ +export type SQLTransactionAsyncCallback = (transaction: SQLTransactionAsync) => Promise;