-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into api/graphql-cancel-fix
- Loading branch information
Showing
17 changed files
with
915 additions
and
570 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
packages/datastore-storage-adapter/ExpoSQLiteAdapter/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
if (process.env.NODE_ENV === 'production') { | ||
module.exports = require('../dist/aws-amplify-datastore-sqlite-adapter-expo.min.js'); | ||
} else { | ||
module.exports = require('../dist/aws-amplify-datastore-sqlite-adapter-expo.js'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
if (process.env.NODE_ENV === 'production') { | ||
module.exports = require('../dist/aws-amplify-datastore-storage-adapter.min.js'); | ||
} else { | ||
module.exports = require('../dist/aws-amplify-datastore-storage-adapter.js'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
packages/datastore-storage-adapter/src/ExpoSQLiteAdapter/ExpoSQLiteAdapter.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { CommonSQLiteAdapter } from '../common/CommonSQLiteAdapter'; | ||
import ExpoSQLiteDatabase from './ExpoSQLiteDatabase'; | ||
|
||
const ExpoSQLiteAdapter: CommonSQLiteAdapter = new CommonSQLiteAdapter( | ||
new ExpoSQLiteDatabase() | ||
); | ||
|
||
export default ExpoSQLiteAdapter; |
282 changes: 282 additions & 0 deletions
282
packages/datastore-storage-adapter/src/ExpoSQLiteAdapter/ExpoSQLiteDatabase.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,282 @@ | ||
import { ConsoleLogger as Logger } from '@aws-amplify/core'; | ||
import { PersistentModel } from '@aws-amplify/datastore'; | ||
import { deleteAsync, documentDirectory } from 'expo-file-system'; | ||
import { openDatabase, WebSQLDatabase } from 'expo-sqlite'; | ||
import { DB_NAME } from '../common/constants'; | ||
import { CommonSQLiteDatabase, ParameterizedStatement } from '../common/types'; | ||
|
||
const logger = new Logger('ExpoSQLiteDatabase'); | ||
|
||
/* | ||
Note: | ||
ExpoSQLite transaction error callbacks require returning a boolean value to indicate whether the | ||
error was handled or not. Returning a true value indicates the error was handled and does not | ||
rollback the whole transaction. | ||
*/ | ||
|
||
class ExpoSQLiteDatabase implements CommonSQLiteDatabase { | ||
private db: WebSQLDatabase; | ||
|
||
public async init(): Promise<void> { | ||
// only open database once. | ||
|
||
if (!this.db) { | ||
// As per expo docs version, description and size arguments are ignored, | ||
// but are accepted by the function for compatibility with the WebSQL specification. | ||
// Hence, we do not need those arguments. | ||
this.db = openDatabase(DB_NAME); | ||
} | ||
} | ||
|
||
public createSchema(statements: string[]): Promise<void> { | ||
return this.executeStatements(statements); | ||
} | ||
|
||
public async clear(): Promise<void> { | ||
try { | ||
logger.debug('Clearing database'); | ||
await this.closeDB(); | ||
// delete database is not supported by expo-sqlite. | ||
// Database file needs to be deleted using deleteAsync from expo-file-system | ||
await deleteAsync(`${documentDirectory}SQLite/${DB_NAME}`); | ||
logger.debug('Database cleared'); | ||
} catch (error) { | ||
logger.warn('Error clearing the database.', error); | ||
// open database if it was closed earlier and this.db was set to undefined. | ||
this.init(); | ||
} | ||
} | ||
|
||
public async get<T extends PersistentModel>( | ||
statement: string, | ||
params: (string | number)[] | ||
): Promise<T> { | ||
const results: T[] = await this.getAll(statement, params); | ||
return results[0]; | ||
} | ||
|
||
public getAll<T extends PersistentModel>( | ||
statement: string, | ||
params: (string | number)[] | ||
): Promise<T[]> { | ||
return new Promise((resolve, reject) => { | ||
this.db.readTransaction(transaction => { | ||
transaction.executeSql( | ||
statement, | ||
params, | ||
(_, result) => { | ||
resolve(result.rows._array || []); | ||
}, | ||
(_, error) => { | ||
reject(error); | ||
logger.warn(error); | ||
return true; | ||
} | ||
); | ||
}); | ||
}); | ||
} | ||
|
||
public save(statement: string, params: (string | number)[]): Promise<void> { | ||
return new Promise((resolve, reject) => { | ||
this.db.transaction(transaction => { | ||
transaction.executeSql( | ||
statement, | ||
params, | ||
() => { | ||
resolve(null); | ||
}, | ||
(_, error) => { | ||
reject(error); | ||
logger.warn(error); | ||
return true; | ||
} | ||
); | ||
}); | ||
}); | ||
} | ||
|
||
public batchQuery<T = any>( | ||
queryParameterizedStatements: Set<ParameterizedStatement> = new Set() | ||
): Promise<T[]> { | ||
return new Promise((resolveTransaction, rejectTransaction) => { | ||
this.db.transaction(async transaction => { | ||
try { | ||
const results: any[] = await Promise.all( | ||
[...queryParameterizedStatements].map( | ||
([statement, params]) => | ||
new Promise((resolve, reject) => { | ||
transaction.executeSql( | ||
statement, | ||
params, | ||
(_, result) => { | ||
resolve(result.rows._array[0]); | ||
}, | ||
(_, error) => { | ||
reject(error); | ||
logger.warn(error); | ||
return true; | ||
} | ||
); | ||
}) | ||
) | ||
); | ||
resolveTransaction(results); | ||
} catch (error) { | ||
rejectTransaction(error); | ||
logger.warn(error); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
public batchSave( | ||
saveParameterizedStatements: Set<ParameterizedStatement> = new Set(), | ||
deleteParameterizedStatements?: Set<ParameterizedStatement> | ||
): Promise<void> { | ||
return new Promise((resolveTransaction, rejectTransaction) => { | ||
this.db.transaction(async transaction => { | ||
try { | ||
// await for all sql statements promises to resolve | ||
await Promise.all( | ||
[...saveParameterizedStatements].map( | ||
([statement, params]) => | ||
new Promise((resolve, reject) => { | ||
transaction.executeSql( | ||
statement, | ||
params, | ||
() => { | ||
resolve(null); | ||
}, | ||
(_, error) => { | ||
reject(error); | ||
logger.warn(error); | ||
return true; | ||
} | ||
); | ||
}) | ||
) | ||
); | ||
if (deleteParameterizedStatements) { | ||
await Promise.all( | ||
[...deleteParameterizedStatements].map( | ||
([statement, params]) => | ||
new Promise((resolve, reject) => | ||
transaction.executeSql( | ||
statement, | ||
params, | ||
() => { | ||
resolve(null); | ||
}, | ||
(_, error) => { | ||
reject(error); | ||
logger.warn(error); | ||
return true; | ||
} | ||
) | ||
) | ||
) | ||
); | ||
} | ||
resolveTransaction(null); | ||
} catch (error) { | ||
rejectTransaction(error); | ||
logger.warn(error); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
public selectAndDelete<T = any>( | ||
queryParameterizedStatement: ParameterizedStatement, | ||
deleteParameterizedStatement: ParameterizedStatement | ||
): Promise<T[]> { | ||
const [queryStatement, queryParams] = queryParameterizedStatement; | ||
const [deleteStatement, deleteParams] = deleteParameterizedStatement; | ||
|
||
return new Promise((resolveTransaction, rejectTransaction) => { | ||
this.db.transaction(async transaction => { | ||
try { | ||
const result: T[] = await new Promise((resolve, reject) => { | ||
transaction.executeSql( | ||
queryStatement, | ||
queryParams, | ||
(_, result) => { | ||
resolve(result.rows._array || []); | ||
}, | ||
(_, error) => { | ||
reject(error); | ||
logger.warn(error); | ||
return true; | ||
} | ||
); | ||
}); | ||
await new Promise((resolve, reject) => { | ||
transaction.executeSql( | ||
deleteStatement, | ||
deleteParams, | ||
() => { | ||
resolve(null); | ||
}, | ||
(_, error) => { | ||
reject(error); | ||
logger.warn(error); | ||
return true; | ||
} | ||
); | ||
}); | ||
resolveTransaction(result); | ||
} catch (error) { | ||
rejectTransaction(error); | ||
logger.warn(error); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
private executeStatements(statements: string[]): Promise<void> { | ||
return new Promise((resolveTransaction, rejectTransaction) => { | ||
this.db.transaction(async transaction => { | ||
try { | ||
await Promise.all( | ||
statements.map( | ||
statement => | ||
new Promise((resolve, reject) => { | ||
transaction.executeSql( | ||
statement, | ||
[], | ||
() => { | ||
resolve(null); | ||
}, | ||
(_, error) => { | ||
reject(error); | ||
return true; | ||
} | ||
); | ||
}) | ||
) | ||
); | ||
resolveTransaction(null); | ||
} catch (error) { | ||
rejectTransaction(error); | ||
logger.warn(error); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
private async closeDB() { | ||
if (this.db) { | ||
logger.debug('Closing Database'); | ||
// closing database is not supported by expo-sqlite. | ||
// Workaround is to access the private db variable and call the close() method. | ||
await (this.db as any)._db.close(); | ||
logger.debug('Database closed'); | ||
this.db = undefined; | ||
} | ||
} | ||
} | ||
|
||
export default ExpoSQLiteDatabase; |
Oops, something went wrong.