22 * The SQLiteStorage provider stores everything in a key/value store by
33 * converting the value to a JSON string
44 */
5- import type { BatchQueryResult , QuickSQLiteConnection } from 'react-native-quick -sqlite' ;
6- import { open } from 'react-native-quick -sqlite' ;
5+ import type { BatchQueryResult , NitroSQLiteConnection } from 'react-native-nitro -sqlite' ;
6+ import { enableSimpleNullHandling , open } from 'react-native-nitro -sqlite' ;
77import { getFreeDiskStorage } from 'react-native-device-info' ;
88import type StorageProvider from './types' ;
99import utils from '../../utils' ;
1010import type { KeyList , KeyValuePairList } from './types' ;
1111
12+ // By default, NitroSQLite does not accept nullish values due to current limitations in Nitro Modules.
13+ // This flag enables a feature in NitroSQLite that allows for nullish values to be passed to operations, such as "execute" or "executeBatch".
14+ // Simple null handling can potentially add a minor performance overhead,
15+ // since parameters and results from SQLite queries need to be parsed from and to JavaScript nullish values.
16+ // https://github.com/margelo/react-native-nitro-sqlite#sending-and-receiving-nullish-values
17+ enableSimpleNullHandling ( ) ;
18+
19+ /**
20+ * The type of the key-value pair stored in the SQLite database
21+ * @property record_key - the key of the record
22+ * @property valueJSON - the value of the record in JSON string format
23+ */
24+ type OnyxSQLiteKeyValuePair = {
25+ record_key : string ;
26+ valueJSON : string ;
27+ } ;
28+
29+ /**
30+ * The result of the `PRAGMA page_size`, which gets the page size of the SQLite database
31+ */
32+ type PageSizeResult = {
33+ page_size : number ;
34+ } ;
35+
36+ /**
37+ * The result of the `PRAGMA page_count`, which gets the page count of the SQLite database
38+ */
39+ type PageCountResult = {
40+ page_count : number ;
41+ } ;
42+
1243const DB_NAME = 'OnyxDB' ;
13- let db : QuickSQLiteConnection ;
44+ let db : NitroSQLiteConnection ;
1445
1546const provider : StorageProvider = {
1647 /**
@@ -32,18 +63,23 @@ const provider: StorageProvider = {
3263 db . execute ( 'PRAGMA journal_mode=WAL;' ) ;
3364 } ,
3465 getItem ( key ) {
35- return db . executeAsync ( 'SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key = ?;' , [ key ] ) . then ( ( { rows} ) => {
66+ return db . executeAsync < OnyxSQLiteKeyValuePair > ( 'SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key = ?;' , [ key ] ) . then ( ( { rows} ) => {
3667 if ( ! rows || rows ?. length === 0 ) {
3768 return null ;
3869 }
3970 const result = rows ?. item ( 0 ) ;
71+
72+ if ( result == null ) {
73+ return null ;
74+ }
75+
4076 return JSON . parse ( result . valueJSON ) ;
4177 } ) ;
4278 } ,
4379 multiGet ( keys ) {
4480 const placeholders = keys . map ( ( ) => '?' ) . join ( ',' ) ;
4581 const command = `SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key IN (${ placeholders } );` ;
46- return db . executeAsync ( command , keys ) . then ( ( { rows} ) => {
82+ return db . executeAsync < OnyxSQLiteKeyValuePair > ( command , keys ) . then ( ( { rows} ) => {
4783 // eslint-disable-next-line no-underscore-dangle
4884 const result = rows ?. _array . map ( ( row ) => [ row . record_key , JSON . parse ( row . valueJSON ) ] ) ;
4985 return ( result ?? [ ] ) as KeyValuePairList ;
@@ -53,11 +89,12 @@ const provider: StorageProvider = {
5389 return db . executeAsync ( 'REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, ?);' , [ key , JSON . stringify ( value ) ] ) ;
5490 } ,
5591 multiSet ( pairs ) {
56- const stringifiedPairs = pairs . map ( ( pair ) => [ pair [ 0 ] , JSON . stringify ( pair [ 1 ] === undefined ? null : pair [ 1 ] ) ] ) ;
57- if ( utils . isEmptyObject ( stringifiedPairs ) ) {
92+ const query = 'REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, json(?));' ;
93+ const params = pairs . map ( ( pair ) => [ pair [ 0 ] , JSON . stringify ( pair [ 1 ] === undefined ? null : pair [ 1 ] ) ] ) ;
94+ if ( utils . isEmptyObject ( params ) ) {
5895 return Promise . resolve ( ) ;
5996 }
60- return db . executeBatchAsync ( [ [ 'REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, json(?));' , stringifiedPairs ] ] ) ;
97+ return db . executeBatchAsync ( [ { query , params } ] ) ;
6198 } ,
6299 multiMerge ( pairs ) {
63100 // Note: We use `ON CONFLICT DO UPDATE` here instead of `INSERT OR REPLACE INTO`
@@ -68,13 +105,13 @@ const provider: StorageProvider = {
68105 SET valueJSON = JSON_PATCH(valueJSON, JSON(:value));
69106 ` ;
70107
71- const nonNullishPairs = pairs . filter ( ( pair ) => pair [ 1 ] !== undefined ) ;
72- const queryArguments = nonNullishPairs . map ( ( pair ) => {
108+ const nonUndefinedPairs = pairs . filter ( ( pair ) => pair [ 1 ] !== undefined ) ;
109+ const params = nonUndefinedPairs . map ( ( pair ) => {
73110 const value = JSON . stringify ( pair [ 1 ] ) ;
74111 return [ pair [ 0 ] , value ] ;
75112 } ) ;
76113
77- return db . executeBatchAsync ( [ [ query , queryArguments ] ] ) ;
114+ return db . executeBatchAsync ( [ { query, params } ] ) ;
78115 } ,
79116 mergeItem ( key , deltaChanges , preMergedValue , shouldSetValue ) {
80117 if ( shouldSetValue ) {
@@ -97,15 +134,18 @@ const provider: StorageProvider = {
97134 } ,
98135 clear : ( ) => db . executeAsync ( 'DELETE FROM keyvaluepairs;' , [ ] ) ,
99136 getDatabaseSize ( ) {
100- return Promise . all ( [ db . executeAsync ( 'PRAGMA page_size;' ) , db . executeAsync ( 'PRAGMA page_count;' ) , getFreeDiskStorage ( ) ] ) . then ( ( [ pageSizeResult , pageCountResult , bytesRemaining ] ) => {
101- const pageSize : number = pageSizeResult . rows ?. item ( 0 ) . page_size ;
102- const pageCount : number = pageCountResult . rows ?. item ( 0 ) . page_count ;
103- return {
104- bytesUsed : pageSize * pageCount ,
105- bytesRemaining,
106- } ;
107- } ) ;
137+ return Promise . all ( [ db . executeAsync < PageSizeResult > ( 'PRAGMA page_size;' ) , db . executeAsync < PageCountResult > ( 'PRAGMA page_count;' ) , getFreeDiskStorage ( ) ] ) . then (
138+ ( [ pageSizeResult , pageCountResult , bytesRemaining ] ) => {
139+ const pageSize = pageSizeResult . rows ?. item ( 0 ) ?. page_size ?? 0 ;
140+ const pageCount = pageCountResult . rows ?. item ( 0 ) ?. page_count ?? 0 ;
141+ return {
142+ bytesUsed : pageSize * pageCount ,
143+ bytesRemaining,
144+ } ;
145+ } ,
146+ ) ;
108147 } ,
109148} ;
110149
111150export default provider ;
151+ export type { OnyxSQLiteKeyValuePair } ;
0 commit comments