@aws-amplify/datastore-storage-adapter 1.2.13 → 1.2.14-unstable.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ExpoSQLiteAdapter/index.js +7 -0
- package/SQLiteAdapter/index.js +7 -0
- package/dist/aws-amplify-datastore-sqlite-adapter-expo.js +2502 -0
- package/dist/aws-amplify-datastore-sqlite-adapter-expo.js.map +1 -0
- package/dist/aws-amplify-datastore-sqlite-adapter-expo.min.js +2 -0
- package/dist/aws-amplify-datastore-sqlite-adapter-expo.min.js.map +1 -0
- package/dist/aws-amplify-datastore-storage-adapter.js +1179 -1151
- package/dist/aws-amplify-datastore-storage-adapter.js.map +1 -1
- package/dist/aws-amplify-datastore-storage-adapter.min.js +1 -1
- package/dist/aws-amplify-datastore-storage-adapter.min.js.map +1 -1
- package/lib/ExpoSQLiteAdapter/ExpoSQLiteAdapter.d.ts +3 -0
- package/lib/ExpoSQLiteAdapter/ExpoSQLiteAdapter.js +10 -0
- package/lib/ExpoSQLiteAdapter/ExpoSQLiteAdapter.js.map +1 -0
- package/lib/ExpoSQLiteAdapter/ExpoSQLiteDatabase.d.ts +17 -0
- package/lib/ExpoSQLiteAdapter/ExpoSQLiteDatabase.js +362 -0
- package/lib/ExpoSQLiteAdapter/ExpoSQLiteDatabase.js.map +1 -0
- package/lib/SQLiteAdapter/SQLiteAdapter.d.ts +3 -23
- package/lib/SQLiteAdapter/SQLiteAdapter.js +3 -582
- package/lib/SQLiteAdapter/SQLiteAdapter.js.map +1 -1
- package/lib/SQLiteAdapter/SQLiteDatabase.d.ts +8 -8
- package/lib/SQLiteAdapter/SQLiteDatabase.js +46 -42
- package/lib/SQLiteAdapter/SQLiteDatabase.js.map +1 -1
- package/lib/common/CommonSQLiteAdapter.d.ts +23 -0
- package/lib/common/CommonSQLiteAdapter.js +579 -0
- package/lib/common/CommonSQLiteAdapter.js.map +1 -0
- package/lib/{SQLiteAdapter → common}/SQLiteUtils.d.ts +3 -2
- package/lib/{SQLiteAdapter → common}/SQLiteUtils.js +26 -2
- package/lib/common/SQLiteUtils.js.map +1 -0
- package/lib/common/constants.d.ts +1 -0
- package/lib/common/constants.js +4 -0
- package/lib/common/constants.js.map +1 -0
- package/lib/common/types.d.ts +13 -0
- package/lib/common/types.js +3 -0
- package/lib/common/types.js.map +1 -0
- package/lib-esm/ExpoSQLiteAdapter/ExpoSQLiteAdapter.d.ts +3 -0
- package/lib-esm/ExpoSQLiteAdapter/ExpoSQLiteAdapter.js +5 -0
- package/lib-esm/ExpoSQLiteAdapter/ExpoSQLiteAdapter.js.map +1 -0
- package/lib-esm/ExpoSQLiteAdapter/ExpoSQLiteDatabase.d.ts +17 -0
- package/lib-esm/ExpoSQLiteAdapter/ExpoSQLiteDatabase.js +360 -0
- package/lib-esm/ExpoSQLiteAdapter/ExpoSQLiteDatabase.js.map +1 -0
- package/lib-esm/SQLiteAdapter/SQLiteAdapter.d.ts +3 -23
- package/lib-esm/SQLiteAdapter/SQLiteAdapter.js +3 -582
- package/lib-esm/SQLiteAdapter/SQLiteAdapter.js.map +1 -1
- package/lib-esm/SQLiteAdapter/SQLiteDatabase.d.ts +8 -8
- package/lib-esm/SQLiteAdapter/SQLiteDatabase.js +46 -42
- package/lib-esm/SQLiteAdapter/SQLiteDatabase.js.map +1 -1
- package/lib-esm/common/CommonSQLiteAdapter.d.ts +23 -0
- package/lib-esm/common/CommonSQLiteAdapter.js +577 -0
- package/lib-esm/common/CommonSQLiteAdapter.js.map +1 -0
- package/lib-esm/{SQLiteAdapter → common}/SQLiteUtils.d.ts +3 -2
- package/lib-esm/{SQLiteAdapter → common}/SQLiteUtils.js +24 -1
- package/lib-esm/common/SQLiteUtils.js.map +1 -0
- package/lib-esm/common/constants.d.ts +1 -0
- package/lib-esm/common/constants.js +2 -0
- package/lib-esm/common/constants.js.map +1 -0
- package/lib-esm/common/types.d.ts +13 -0
- package/lib-esm/common/types.js +1 -0
- package/lib-esm/common/types.js.map +1 -0
- package/package.json +7 -4
- package/src/ExpoSQLiteAdapter/ExpoSQLiteAdapter.ts +8 -0
- package/src/ExpoSQLiteAdapter/ExpoSQLiteDatabase.ts +282 -0
- package/src/SQLiteAdapter/SQLiteAdapter.ts +5 -475
- package/src/SQLiteAdapter/SQLiteDatabase.ts +49 -53
- package/src/common/CommonSQLiteAdapter.ts +478 -0
- package/src/{SQLiteAdapter → common}/SQLiteUtils.ts +32 -3
- package/src/common/constants.ts +1 -0
- package/src/common/types.ts +29 -0
- package/webpack.config.dev.js +2 -0
- package/lib/SQLiteAdapter/SQLiteUtils.js.map +0 -1
- package/lib/SQLiteAdapter/types.d.ts +0 -2
- package/lib/SQLiteAdapter/types.js +0 -28
- package/lib/SQLiteAdapter/types.js.map +0 -1
- package/lib-esm/SQLiteAdapter/SQLiteUtils.js.map +0 -1
- package/lib-esm/SQLiteAdapter/types.d.ts +0 -2
- package/lib-esm/SQLiteAdapter/types.js +0 -25
- package/lib-esm/SQLiteAdapter/types.js.map +0 -1
- package/src/SQLiteAdapter/types.ts +0 -31
|
@@ -1,478 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CommonSQLiteAdapter } from '../common/CommonSQLiteAdapter';
|
|
2
2
|
import SQLiteDatabase from './SQLiteDatabase';
|
|
3
|
-
import {
|
|
4
|
-
generateSchemaStatements,
|
|
5
|
-
queryByIdStatement,
|
|
6
|
-
modelUpdateStatement,
|
|
7
|
-
modelInsertStatement,
|
|
8
|
-
queryAllStatement,
|
|
9
|
-
queryOneStatement,
|
|
10
|
-
deleteByIdStatement,
|
|
11
|
-
deleteByPredicateStatement,
|
|
12
|
-
ParameterizedStatement,
|
|
13
|
-
} from './SQLiteUtils';
|
|
14
3
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
ModelPredicateCreator,
|
|
19
|
-
ModelSortPredicateCreator,
|
|
20
|
-
InternalSchema,
|
|
21
|
-
isPredicateObj,
|
|
22
|
-
ModelInstanceMetadata,
|
|
23
|
-
ModelPredicate,
|
|
24
|
-
NamespaceResolver,
|
|
25
|
-
OpType,
|
|
26
|
-
PaginationInput,
|
|
27
|
-
PersistentModel,
|
|
28
|
-
PersistentModelConstructor,
|
|
29
|
-
PredicateObject,
|
|
30
|
-
PredicatesGroup,
|
|
31
|
-
QueryOne,
|
|
32
|
-
utils,
|
|
33
|
-
} from '@aws-amplify/datastore';
|
|
4
|
+
const SQLiteAdapter: CommonSQLiteAdapter = new CommonSQLiteAdapter(
|
|
5
|
+
new SQLiteDatabase()
|
|
6
|
+
);
|
|
34
7
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const logger = new Logger('DataStore');
|
|
38
|
-
export class SQLiteAdapter implements StorageAdapter {
|
|
39
|
-
private schema: InternalSchema;
|
|
40
|
-
private namespaceResolver: NamespaceResolver;
|
|
41
|
-
private modelInstanceCreator: ModelInstanceCreator;
|
|
42
|
-
private getModelConstructorByModelName: (
|
|
43
|
-
namsespaceName: string,
|
|
44
|
-
modelName: string
|
|
45
|
-
) => PersistentModelConstructor<any>;
|
|
46
|
-
private db: SQLiteDatabase;
|
|
47
|
-
private initPromise: Promise<void>;
|
|
48
|
-
private resolve: (value?: any) => void;
|
|
49
|
-
private reject: (value?: any) => void;
|
|
50
|
-
|
|
51
|
-
public async setUp(
|
|
52
|
-
theSchema: InternalSchema,
|
|
53
|
-
namespaceResolver: NamespaceResolver,
|
|
54
|
-
modelInstanceCreator: ModelInstanceCreator,
|
|
55
|
-
getModelConstructorByModelName: (
|
|
56
|
-
namsespaceName: string,
|
|
57
|
-
modelName: string
|
|
58
|
-
) => PersistentModelConstructor<any>
|
|
59
|
-
) {
|
|
60
|
-
if (!this.initPromise) {
|
|
61
|
-
this.initPromise = new Promise((res, rej) => {
|
|
62
|
-
this.resolve = res;
|
|
63
|
-
this.reject = rej;
|
|
64
|
-
});
|
|
65
|
-
} else {
|
|
66
|
-
await this.initPromise;
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
this.schema = theSchema;
|
|
70
|
-
this.namespaceResolver = namespaceResolver;
|
|
71
|
-
this.modelInstanceCreator = modelInstanceCreator;
|
|
72
|
-
this.getModelConstructorByModelName = getModelConstructorByModelName;
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
if (!this.db) {
|
|
76
|
-
this.db = new SQLiteDatabase();
|
|
77
|
-
await this.db.init();
|
|
78
|
-
|
|
79
|
-
const statements = generateSchemaStatements(this.schema);
|
|
80
|
-
await this.db.createSchema(statements);
|
|
81
|
-
this.resolve();
|
|
82
|
-
}
|
|
83
|
-
} catch (error) {
|
|
84
|
-
this.reject(error);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async clear(): Promise<void> {
|
|
89
|
-
await this.db.clear();
|
|
90
|
-
|
|
91
|
-
this.db = undefined;
|
|
92
|
-
this.initPromise = undefined;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async save<T extends PersistentModel>(
|
|
96
|
-
model: T,
|
|
97
|
-
condition?: ModelPredicate<T>
|
|
98
|
-
): Promise<[T, OpType.INSERT | OpType.UPDATE][]> {
|
|
99
|
-
const modelConstructor = Object.getPrototypeOf(model)
|
|
100
|
-
.constructor as PersistentModelConstructor<T>;
|
|
101
|
-
const { name: tableName } = modelConstructor;
|
|
102
|
-
const connectedModels = traverseModel(
|
|
103
|
-
modelConstructor.name,
|
|
104
|
-
model,
|
|
105
|
-
this.schema.namespaces[this.namespaceResolver(modelConstructor)],
|
|
106
|
-
this.modelInstanceCreator,
|
|
107
|
-
this.getModelConstructorByModelName
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
const connectionStoreNames = Object.values(connectedModels).map(
|
|
111
|
-
({ modelName, item, instance }) => {
|
|
112
|
-
return { modelName, item, instance };
|
|
113
|
-
}
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
const [queryStatement, params] = queryByIdStatement(model.id, tableName);
|
|
117
|
-
|
|
118
|
-
const fromDB = await this.db.get(queryStatement, params);
|
|
119
|
-
|
|
120
|
-
if (condition && fromDB) {
|
|
121
|
-
const predicates = ModelPredicateCreator.getPredicates(condition);
|
|
122
|
-
const { predicates: predicateObjs, type } = predicates;
|
|
123
|
-
|
|
124
|
-
const isValid = validatePredicate(fromDB, type, predicateObjs);
|
|
125
|
-
|
|
126
|
-
if (!isValid) {
|
|
127
|
-
const msg = 'Conditional update failed';
|
|
128
|
-
logger.error(msg, { model: fromDB, condition: predicateObjs });
|
|
129
|
-
|
|
130
|
-
throw new Error(msg);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const result: [T, OpType.INSERT | OpType.UPDATE][] = [];
|
|
135
|
-
const saveStatements = new Set<ParameterizedStatement>();
|
|
136
|
-
|
|
137
|
-
for await (const resItem of connectionStoreNames) {
|
|
138
|
-
const { modelName, item, instance } = resItem;
|
|
139
|
-
const { id } = item;
|
|
140
|
-
|
|
141
|
-
const [queryStatement, params] = queryByIdStatement(id, modelName);
|
|
142
|
-
const fromDB = await this.db.get(queryStatement, params);
|
|
143
|
-
|
|
144
|
-
const opType: OpType =
|
|
145
|
-
fromDB === undefined ? OpType.INSERT : OpType.UPDATE;
|
|
146
|
-
|
|
147
|
-
const saveStatement = fromDB
|
|
148
|
-
? modelUpdateStatement(instance, modelName)
|
|
149
|
-
: modelInsertStatement(instance, modelName);
|
|
150
|
-
|
|
151
|
-
if (id === model.id || opType === OpType.INSERT) {
|
|
152
|
-
saveStatements.add(saveStatement);
|
|
153
|
-
result.push([instance, opType]);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
await this.db.batchSave(saveStatements);
|
|
158
|
-
return result;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
private async load<T>(
|
|
162
|
-
namespaceName: string,
|
|
163
|
-
srcModelName: string,
|
|
164
|
-
records: T[]
|
|
165
|
-
): Promise<T[]> {
|
|
166
|
-
const namespace = this.schema.namespaces[namespaceName];
|
|
167
|
-
const relations = namespace.relationships[srcModelName].relationTypes;
|
|
168
|
-
const connectionTableNames = relations.map(({ modelName }) => modelName);
|
|
169
|
-
|
|
170
|
-
const modelConstructor = this.getModelConstructorByModelName(
|
|
171
|
-
namespaceName,
|
|
172
|
-
srcModelName
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
if (connectionTableNames.length === 0) {
|
|
176
|
-
return records.map(record =>
|
|
177
|
-
this.modelInstanceCreator(modelConstructor, record)
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
for await (const relation of relations) {
|
|
182
|
-
const {
|
|
183
|
-
fieldName,
|
|
184
|
-
modelName: tableName,
|
|
185
|
-
targetName,
|
|
186
|
-
relationType,
|
|
187
|
-
} = relation;
|
|
188
|
-
|
|
189
|
-
const modelConstructor = this.getModelConstructorByModelName(
|
|
190
|
-
namespaceName,
|
|
191
|
-
tableName
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
// TODO: use SQL JOIN instead
|
|
195
|
-
switch (relationType) {
|
|
196
|
-
case 'HAS_ONE':
|
|
197
|
-
for await (const recordItem of records) {
|
|
198
|
-
const getByfield = recordItem[targetName] ? targetName : fieldName;
|
|
199
|
-
if (!recordItem[getByfield]) break;
|
|
200
|
-
|
|
201
|
-
const [queryStatement, params] = queryByIdStatement(
|
|
202
|
-
recordItem[getByfield],
|
|
203
|
-
tableName
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
const connectionRecord = await this.db.get(queryStatement, params);
|
|
207
|
-
|
|
208
|
-
recordItem[fieldName] =
|
|
209
|
-
connectionRecord &&
|
|
210
|
-
this.modelInstanceCreator(modelConstructor, connectionRecord);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
break;
|
|
214
|
-
case 'BELONGS_TO':
|
|
215
|
-
for await (const recordItem of records) {
|
|
216
|
-
if (recordItem[targetName]) {
|
|
217
|
-
const [queryStatement, params] = queryByIdStatement(
|
|
218
|
-
recordItem[targetName],
|
|
219
|
-
tableName
|
|
220
|
-
);
|
|
221
|
-
const connectionRecord = await this.db.get(
|
|
222
|
-
queryStatement,
|
|
223
|
-
params
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
recordItem[fieldName] =
|
|
227
|
-
connectionRecord &&
|
|
228
|
-
this.modelInstanceCreator(modelConstructor, connectionRecord);
|
|
229
|
-
delete recordItem[targetName];
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
break;
|
|
234
|
-
case 'HAS_MANY':
|
|
235
|
-
// TODO: Lazy loading
|
|
236
|
-
break;
|
|
237
|
-
default:
|
|
238
|
-
const _: never = relationType as never;
|
|
239
|
-
throw new Error(`invalid relation type ${relationType}`);
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return records.map(record =>
|
|
245
|
-
this.modelInstanceCreator(modelConstructor, record)
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
async query<T extends PersistentModel>(
|
|
250
|
-
modelConstructor: PersistentModelConstructor<T>,
|
|
251
|
-
predicate?: ModelPredicate<T>,
|
|
252
|
-
pagination?: PaginationInput<T>
|
|
253
|
-
): Promise<T[]> {
|
|
254
|
-
const { name: tableName } = modelConstructor;
|
|
255
|
-
const namespaceName = this.namespaceResolver(modelConstructor);
|
|
256
|
-
|
|
257
|
-
const predicates =
|
|
258
|
-
predicate && ModelPredicateCreator.getPredicates(predicate);
|
|
259
|
-
const sortPredicates =
|
|
260
|
-
pagination &&
|
|
261
|
-
pagination.sort &&
|
|
262
|
-
ModelSortPredicateCreator.getPredicates(pagination.sort);
|
|
263
|
-
const limit = pagination && pagination.limit;
|
|
264
|
-
const page = limit && pagination.page;
|
|
265
|
-
|
|
266
|
-
const queryById = predicates && this.idFromPredicate(predicates);
|
|
267
|
-
|
|
268
|
-
const records: T[] = <T[]>await (async () => {
|
|
269
|
-
if (queryById) {
|
|
270
|
-
const record = await this.getById(tableName, queryById);
|
|
271
|
-
return record ? [record] : [];
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const [queryStatement, params] = queryAllStatement(
|
|
275
|
-
tableName,
|
|
276
|
-
predicates,
|
|
277
|
-
sortPredicates,
|
|
278
|
-
limit,
|
|
279
|
-
page
|
|
280
|
-
);
|
|
281
|
-
|
|
282
|
-
return await this.db.getAll(queryStatement, params);
|
|
283
|
-
})();
|
|
284
|
-
|
|
285
|
-
return await this.load(namespaceName, modelConstructor.name, records);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
private async getById<T extends PersistentModel>(
|
|
289
|
-
tableName: string,
|
|
290
|
-
id: string
|
|
291
|
-
): Promise<T> {
|
|
292
|
-
const [queryStatement, params] = queryByIdStatement(id, tableName);
|
|
293
|
-
const record = await this.db.get<T>(queryStatement, params);
|
|
294
|
-
return record;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
private idFromPredicate<T extends PersistentModel>(
|
|
298
|
-
predicates: PredicatesGroup<T>
|
|
299
|
-
) {
|
|
300
|
-
const { predicates: predicateObjs } = predicates;
|
|
301
|
-
const idPredicate =
|
|
302
|
-
predicateObjs.length === 1 &&
|
|
303
|
-
(predicateObjs.find(
|
|
304
|
-
p => isPredicateObj(p) && p.field === 'id' && p.operator === 'eq'
|
|
305
|
-
) as PredicateObject<T>);
|
|
306
|
-
|
|
307
|
-
return idPredicate && idPredicate.operand;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
async queryOne<T extends PersistentModel>(
|
|
311
|
-
modelConstructor: PersistentModelConstructor<T>,
|
|
312
|
-
firstOrLast: QueryOne = QueryOne.FIRST
|
|
313
|
-
): Promise<T | undefined> {
|
|
314
|
-
const { name: tableName } = modelConstructor;
|
|
315
|
-
const [queryStatement, params] = queryOneStatement(firstOrLast, tableName);
|
|
316
|
-
|
|
317
|
-
const result = await this.db.get<T>(queryStatement, params);
|
|
318
|
-
|
|
319
|
-
const modelInstance =
|
|
320
|
-
result && this.modelInstanceCreator(modelConstructor, result);
|
|
321
|
-
|
|
322
|
-
return modelInstance;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Currently does not cascade
|
|
326
|
-
// TODO: use FKs in relations and have `ON DELETE CASCADE` set
|
|
327
|
-
// For Has Many and Has One relations to have SQL handle cascades automatically
|
|
328
|
-
async delete<T extends PersistentModel>(
|
|
329
|
-
modelOrModelConstructor: T | PersistentModelConstructor<T>,
|
|
330
|
-
condition?: ModelPredicate<T>
|
|
331
|
-
): Promise<[T[], T[]]> {
|
|
332
|
-
if (isModelConstructor(modelOrModelConstructor)) {
|
|
333
|
-
const modelConstructor = modelOrModelConstructor;
|
|
334
|
-
const namespaceName = this.namespaceResolver(modelConstructor);
|
|
335
|
-
const { name: tableName } = modelConstructor;
|
|
336
|
-
|
|
337
|
-
const predicates =
|
|
338
|
-
condition && ModelPredicateCreator.getPredicates(condition);
|
|
339
|
-
|
|
340
|
-
const queryStatement = queryAllStatement(tableName, predicates);
|
|
341
|
-
const deleteStatement = deleteByPredicateStatement(tableName, predicates);
|
|
342
|
-
|
|
343
|
-
const models = await this.db.selectAndDelete(
|
|
344
|
-
queryStatement,
|
|
345
|
-
deleteStatement
|
|
346
|
-
);
|
|
347
|
-
|
|
348
|
-
const modelInstances = await this.load(
|
|
349
|
-
namespaceName,
|
|
350
|
-
modelConstructor.name,
|
|
351
|
-
models
|
|
352
|
-
);
|
|
353
|
-
|
|
354
|
-
return [modelInstances, modelInstances];
|
|
355
|
-
} else {
|
|
356
|
-
const model = modelOrModelConstructor as T;
|
|
357
|
-
const modelConstructor = Object.getPrototypeOf(model)
|
|
358
|
-
.constructor as PersistentModelConstructor<T>;
|
|
359
|
-
const { name: tableName } = modelConstructor;
|
|
360
|
-
|
|
361
|
-
if (condition) {
|
|
362
|
-
const [queryStatement, params] = queryByIdStatement(
|
|
363
|
-
model.id,
|
|
364
|
-
tableName
|
|
365
|
-
);
|
|
366
|
-
|
|
367
|
-
const fromDB = await this.db.get(queryStatement, params);
|
|
368
|
-
|
|
369
|
-
if (fromDB === undefined) {
|
|
370
|
-
const msg = 'Model instance not found in storage';
|
|
371
|
-
logger.warn(msg, { model });
|
|
372
|
-
|
|
373
|
-
return [[model], []];
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
const predicates = ModelPredicateCreator.getPredicates(condition);
|
|
377
|
-
const { predicates: predicateObjs, type } = predicates;
|
|
378
|
-
|
|
379
|
-
const isValid = validatePredicate(fromDB, type, predicateObjs);
|
|
380
|
-
|
|
381
|
-
if (!isValid) {
|
|
382
|
-
const msg = 'Conditional update failed';
|
|
383
|
-
logger.error(msg, { model: fromDB, condition: predicateObjs });
|
|
384
|
-
|
|
385
|
-
throw new Error(msg);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
const [deleteStatement, deleteParams] = deleteByIdStatement(
|
|
389
|
-
model.id,
|
|
390
|
-
tableName
|
|
391
|
-
);
|
|
392
|
-
await this.db.save(deleteStatement, deleteParams);
|
|
393
|
-
return [[model], [model]];
|
|
394
|
-
} else {
|
|
395
|
-
const [deleteStatement, params] = deleteByIdStatement(
|
|
396
|
-
model.id,
|
|
397
|
-
tableName
|
|
398
|
-
);
|
|
399
|
-
await this.db.save(deleteStatement, params);
|
|
400
|
-
return [[model], [model]];
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
async batchSave<T extends PersistentModel>(
|
|
406
|
-
modelConstructor: PersistentModelConstructor<any>,
|
|
407
|
-
items: ModelInstanceMetadata[]
|
|
408
|
-
): Promise<[T, OpType][]> {
|
|
409
|
-
const { name: tableName } = modelConstructor;
|
|
410
|
-
|
|
411
|
-
const result: [T, OpType][] = [];
|
|
412
|
-
|
|
413
|
-
const itemsToSave: T[] = [];
|
|
414
|
-
// To determine whether an item should result in an insert or update operation
|
|
415
|
-
// We first need to query the local DB on the item id
|
|
416
|
-
const queryStatements = new Set<ParameterizedStatement>();
|
|
417
|
-
// Deletes don't need to be queried first, because if the item doesn't exist,
|
|
418
|
-
// the delete operation will be a no-op
|
|
419
|
-
const deleteStatements = new Set<ParameterizedStatement>();
|
|
420
|
-
const saveStatements = new Set<ParameterizedStatement>();
|
|
421
|
-
|
|
422
|
-
for (const item of items) {
|
|
423
|
-
const connectedModels = traverseModel(
|
|
424
|
-
modelConstructor.name,
|
|
425
|
-
this.modelInstanceCreator(modelConstructor, item),
|
|
426
|
-
this.schema.namespaces[this.namespaceResolver(modelConstructor)],
|
|
427
|
-
this.modelInstanceCreator,
|
|
428
|
-
this.getModelConstructorByModelName
|
|
429
|
-
);
|
|
430
|
-
|
|
431
|
-
const { id, _deleted } = item;
|
|
432
|
-
|
|
433
|
-
const { instance } = connectedModels.find(
|
|
434
|
-
({ instance }) => instance.id === id
|
|
435
|
-
);
|
|
436
|
-
|
|
437
|
-
if (_deleted) {
|
|
438
|
-
// create the delete statements right away
|
|
439
|
-
const deleteStatement = deleteByIdStatement(instance.id, tableName);
|
|
440
|
-
deleteStatements.add(deleteStatement);
|
|
441
|
-
result.push([<T>(<unknown>item), OpType.DELETE]);
|
|
442
|
-
} else {
|
|
443
|
-
// query statements for the saves at first
|
|
444
|
-
const queryStatement = queryByIdStatement(id, tableName);
|
|
445
|
-
queryStatements.add(queryStatement);
|
|
446
|
-
// combination of insert and update items
|
|
447
|
-
itemsToSave.push(instance);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// returns the query results for each of the save items
|
|
452
|
-
const queryResponses = await this.db.batchQuery(queryStatements);
|
|
453
|
-
|
|
454
|
-
queryResponses.forEach((response, idx) => {
|
|
455
|
-
if (response === undefined) {
|
|
456
|
-
const insertStatement = modelInsertStatement(
|
|
457
|
-
itemsToSave[idx],
|
|
458
|
-
tableName
|
|
459
|
-
);
|
|
460
|
-
saveStatements.add(insertStatement);
|
|
461
|
-
result.push([<T>(<unknown>itemsToSave[idx]), OpType.INSERT]);
|
|
462
|
-
} else {
|
|
463
|
-
const updateStatement = modelUpdateStatement(
|
|
464
|
-
itemsToSave[idx],
|
|
465
|
-
tableName
|
|
466
|
-
);
|
|
467
|
-
saveStatements.add(updateStatement);
|
|
468
|
-
result.push([<T>(<unknown>itemsToSave[idx]), OpType.UPDATE]);
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
// perform all of the insert/update/delete operations in a single transaction
|
|
473
|
-
await this.db.batchSave(saveStatements, deleteStatements);
|
|
474
|
-
return result;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
export default new SQLiteAdapter();
|
|
8
|
+
export default SQLiteAdapter;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import SQLite from 'react-native-sqlite-storage';
|
|
2
2
|
import { ConsoleLogger as Logger } from '@aws-amplify/core';
|
|
3
3
|
import { PersistentModel } from '@aws-amplify/datastore';
|
|
4
|
-
import {
|
|
4
|
+
import { DB_NAME } from '../common/constants';
|
|
5
|
+
import { CommonSQLiteDatabase, ParameterizedStatement } from '../common/types';
|
|
5
6
|
|
|
6
7
|
const logger = new Logger('SQLiteDatabase');
|
|
7
8
|
|
|
@@ -11,13 +12,6 @@ if (Logger.LOG_LEVEL === 'DEBUG') {
|
|
|
11
12
|
SQLite.DEBUG(true);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
const DB_NAME = 'AmplifyDatastore';
|
|
15
|
-
const DB_DISPLAYNAME = 'AWS Amplify DataStore SQLite Database';
|
|
16
|
-
|
|
17
|
-
// TODO: make these configurable
|
|
18
|
-
const DB_SIZE = 200000;
|
|
19
|
-
const DB_VERSION = '1.0';
|
|
20
|
-
|
|
21
15
|
/*
|
|
22
16
|
|
|
23
17
|
Note:
|
|
@@ -31,47 +25,41 @@ get the result of an `executeSql` command inside of a transaction
|
|
|
31
25
|
|
|
32
26
|
*/
|
|
33
27
|
|
|
34
|
-
class SQLiteDatabase {
|
|
28
|
+
class SQLiteDatabase implements CommonSQLiteDatabase {
|
|
35
29
|
private db: SQLite.SQLiteDatabase;
|
|
36
30
|
|
|
37
31
|
public async init(): Promise<void> {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
// only open database once.
|
|
33
|
+
if (!this.db) {
|
|
34
|
+
this.db = await SQLite.openDatabase({
|
|
35
|
+
name: DB_NAME,
|
|
36
|
+
location: 'default',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
44
39
|
}
|
|
45
40
|
|
|
46
|
-
public async createSchema(statements: string[]) {
|
|
41
|
+
public async createSchema(statements: string[]): Promise<void> {
|
|
47
42
|
return await this.executeStatements(statements);
|
|
48
43
|
}
|
|
49
44
|
|
|
50
|
-
public async clear() {
|
|
45
|
+
public async clear(): Promise<void> {
|
|
51
46
|
await this.closeDB();
|
|
52
47
|
logger.debug('Deleting database');
|
|
53
|
-
await SQLite.deleteDatabase(DB_NAME);
|
|
48
|
+
await SQLite.deleteDatabase({ name: DB_NAME, location: 'default' });
|
|
54
49
|
logger.debug('Database deleted');
|
|
55
50
|
}
|
|
56
51
|
|
|
57
52
|
public async get<T extends PersistentModel>(
|
|
58
53
|
statement: string,
|
|
59
|
-
params:
|
|
54
|
+
params: (string | number)[]
|
|
60
55
|
): Promise<T> {
|
|
61
|
-
const [
|
|
62
|
-
|
|
63
|
-
resultSet &&
|
|
64
|
-
resultSet.rows &&
|
|
65
|
-
resultSet.rows.length &&
|
|
66
|
-
resultSet.rows.raw &&
|
|
67
|
-
resultSet.rows.raw();
|
|
68
|
-
|
|
69
|
-
return result?.[0] || undefined;
|
|
56
|
+
const results: T[] = await this.getAll(statement, params);
|
|
57
|
+
return results[0];
|
|
70
58
|
}
|
|
71
59
|
|
|
72
60
|
public async getAll<T extends PersistentModel>(
|
|
73
61
|
statement: string,
|
|
74
|
-
params:
|
|
62
|
+
params: (string | number)[]
|
|
75
63
|
): Promise<T[]> {
|
|
76
64
|
const [resultSet] = await this.db.executeSql(statement, params);
|
|
77
65
|
const result =
|
|
@@ -84,19 +72,24 @@ class SQLiteDatabase {
|
|
|
84
72
|
return result || [];
|
|
85
73
|
}
|
|
86
74
|
|
|
87
|
-
public async save(
|
|
75
|
+
public async save(
|
|
76
|
+
statement: string,
|
|
77
|
+
params: (string | number)[]
|
|
78
|
+
): Promise<void> {
|
|
88
79
|
await this.db.executeSql(statement, params);
|
|
89
80
|
}
|
|
90
81
|
|
|
91
|
-
public async batchQuery
|
|
82
|
+
public async batchQuery<T = any>(
|
|
83
|
+
queryParameterizedStatements: Set<ParameterizedStatement>
|
|
84
|
+
): Promise<T[]> {
|
|
92
85
|
const results = [];
|
|
93
86
|
|
|
94
|
-
await this.db.readTransaction(
|
|
95
|
-
for (const [statement, params] of
|
|
87
|
+
await this.db.readTransaction(tx => {
|
|
88
|
+
for (const [statement, params] of queryParameterizedStatements) {
|
|
96
89
|
tx.executeSql(
|
|
97
90
|
statement,
|
|
98
91
|
params,
|
|
99
|
-
|
|
92
|
+
(_, res) => {
|
|
100
93
|
results.push(res.rows.raw()[0]);
|
|
101
94
|
},
|
|
102
95
|
logger.warn
|
|
@@ -108,35 +101,37 @@ class SQLiteDatabase {
|
|
|
108
101
|
}
|
|
109
102
|
|
|
110
103
|
public async batchSave(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
) {
|
|
114
|
-
await this.db.transaction(
|
|
115
|
-
for (const [statement, params] of
|
|
104
|
+
saveParameterizedStatements: Set<ParameterizedStatement>,
|
|
105
|
+
deleteParameterizedStatements?: Set<ParameterizedStatement>
|
|
106
|
+
): Promise<void> {
|
|
107
|
+
await this.db.transaction(tx => {
|
|
108
|
+
for (const [statement, params] of saveParameterizedStatements) {
|
|
116
109
|
tx.executeSql(statement, params);
|
|
117
110
|
}
|
|
118
|
-
|
|
119
|
-
|
|
111
|
+
});
|
|
112
|
+
if (deleteParameterizedStatements) {
|
|
113
|
+
await this.db.transaction(tx => {
|
|
114
|
+
for (const [statement, params] of deleteParameterizedStatements) {
|
|
120
115
|
tx.executeSql(statement, params);
|
|
121
116
|
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
124
119
|
}
|
|
125
120
|
|
|
126
|
-
public async selectAndDelete(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
) {
|
|
130
|
-
let results = [];
|
|
121
|
+
public async selectAndDelete<T = any>(
|
|
122
|
+
queryParameterizedStatement: ParameterizedStatement,
|
|
123
|
+
deleteParameterizedStatement: ParameterizedStatement
|
|
124
|
+
): Promise<T[]> {
|
|
125
|
+
let results: T[] = [];
|
|
131
126
|
|
|
132
|
-
const [queryStatement, queryParams] =
|
|
133
|
-
const [deleteStatement, deleteParams] =
|
|
127
|
+
const [queryStatement, queryParams] = queryParameterizedStatement;
|
|
128
|
+
const [deleteStatement, deleteParams] = deleteParameterizedStatement;
|
|
134
129
|
|
|
135
|
-
await this.db.transaction(
|
|
130
|
+
await this.db.transaction(tx => {
|
|
136
131
|
tx.executeSql(
|
|
137
132
|
queryStatement,
|
|
138
133
|
queryParams,
|
|
139
|
-
|
|
134
|
+
(_, res) => {
|
|
140
135
|
results = res.rows.raw();
|
|
141
136
|
},
|
|
142
137
|
logger.warn
|
|
@@ -148,7 +143,7 @@ class SQLiteDatabase {
|
|
|
148
143
|
}
|
|
149
144
|
|
|
150
145
|
private async executeStatements(statements: string[]): Promise<void> {
|
|
151
|
-
|
|
146
|
+
await this.db.transaction(tx => {
|
|
152
147
|
for (const statement of statements) {
|
|
153
148
|
tx.executeSql(statement);
|
|
154
149
|
}
|
|
@@ -160,6 +155,7 @@ class SQLiteDatabase {
|
|
|
160
155
|
logger.debug('Closing Database');
|
|
161
156
|
await this.db.close();
|
|
162
157
|
logger.debug('Database closed');
|
|
158
|
+
this.db = undefined;
|
|
163
159
|
}
|
|
164
160
|
}
|
|
165
161
|
}
|