Skip to content

Commit 5b68474

Browse files
manueliglesiasiartemievdavid-mcafeeDane Pilchersvidgen
committed
feat(datastore): custom pk support
Co-authored-by: Ivan Artemiev <29709626+iartemiev@users.noreply.github.com> Co-authored-by: David McAfee <mcafd@amazon.com> Co-authored-by: Dane Pilcher <dppilche@amazon.com> Co-authored-by: Jon Wire <iambipedal@gmail.com>
1 parent 1fd1443 commit 5b68474

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+5561
-1084
lines changed

.circleci/config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ jobs:
369369
command: |
370370
cd packages/datastore-storage-adapter
371371
npm install --build-from-source
372+
rm -rf node_modules/@aws-amplify node_modules/@aws-sdk
372373
- run:
373374
name: 'Run Amplify JS unit tests'
374375
command: |
@@ -1218,6 +1219,7 @@ releasable_branches: &releasable_branches
12181219
- ui-components/main
12191220
- 1.0-stable
12201221
- geo/main
1222+
- ds-custom-pk
12211223

12221224
test_browsers: &test_browsers
12231225
browser: [chrome, firefox]

.envrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use node 14

.vscode/launch.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// A launch configuration that compiles the extension and then opens it inside a new window
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
{
6+
"version": "0.2.0",
7+
"configurations": [
8+
{
9+
"name": "debug tests",
10+
"type": "node",
11+
"request": "launch",
12+
// The debugger will only run tests for the package specified here:
13+
"cwd": "${workspaceFolder}/packages/datastore",
14+
"runtimeArgs": [
15+
"--inspect-brk",
16+
"${workspaceRoot}/node_modules/.bin/jest",
17+
// Optionally specify a single test file to run/debug:
18+
"storage.test.ts",
19+
"--runInBand",
20+
"--testTimeout",
21+
"600000", // 10 min timeout so jest doesn't error while we're stepping through code
22+
"false"
23+
],
24+
"console": "integratedTerminal",
25+
"internalConsoleOptions": "neverOpen"
26+
}
27+
]
28+
}

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
"publish:1.0-stable": "lerna publish --conventional-commits --yes --dist-tag=stable-1.0 --message 'chore(release): Publish [ci skip]' --no-verify-access",
2828
"publish:ui-components/main": "lerna publish --canary --force-publish \"*\" --yes --dist-tag=ui-preview --preid=ui-preview --exact --no-verify-access",
2929
"publish:verdaccio": "lerna publish --no-push --canary minor --dist-tag=unstable --preid=unstable --exact --force-publish --yes --no-verify-access",
30-
"publish:geo/main": "lerna publish --canary --force-publish \"*\" --yes --dist-tag=geo --preid=geo --exact --no-verify-access"
30+
"publish:geo/main": "lerna publish --canary --force-publish \"*\" --yes --dist-tag=geo --preid=geo --exact --no-verify-access",
31+
"publish:ds-custom-pk": "lerna publish --canary --force-publish \"*\" --yes --dist-tag=custom-pk --preid=custom-pk --exact --no-verify-access",
32+
"temp-ds-safe-push": "yarn build --scope @aws-amplify/datastore && yarn test --scope @aws-amplify/datastore && git push origin"
3133
},
3234
"husky": {
3335
"hooks": {

packages/datastore-storage-adapter/__tests__/SQLiteAdapter.test.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ class InnerSQLiteDatabase {
7676
statement,
7777
params,
7878
async (err, row) => {
79+
if (err) {
80+
console.error('SQLite ERROR', new Error(err));
81+
console.warn(statement, params);
82+
}
7983
rows.push(row);
8084
},
8185
() => {
@@ -86,7 +90,14 @@ class InnerSQLiteDatabase {
8690
if (callback) await callback(this, resultSet);
8791
});
8892
} else {
89-
return await this.innerDB.run(statement, params, callback);
93+
return await this.innerDB.run(statement, params, err => {
94+
if (typeof callback === 'function') {
95+
callback(err);
96+
} else if (err) {
97+
console.error('calback', err);
98+
throw err;
99+
}
100+
});
90101
}
91102
}
92103

packages/datastore-storage-adapter/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@
5151
"es5",
5252
"es2015",
5353
"esnext.asynciterable",
54-
"es2019"
54+
"es2019",
55+
"dom"
5556
],
5657
"allowJs": true,
5758
"esModuleInterop": true,

packages/datastore-storage-adapter/src/common/CommonSQLiteAdapter.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
ModelSortPredicateCreator,
1818
InternalSchema,
1919
isPredicateObj,
20-
ModelInstanceMetadata,
2120
ModelPredicate,
2221
NamespaceResolver,
2322
OpType,
@@ -29,7 +28,7 @@ import {
2928
QueryOne,
3029
utils,
3130
} from '@aws-amplify/datastore';
32-
import { CommonSQLiteDatabase, ParameterizedStatement } from './types';
31+
import { CommonSQLiteDatabase, ParameterizedStatement, ModelInstanceMetadataWithId } from './types';
3332

3433
const { traverseModel, validatePredicate, isModelConstructor } = utils;
3534

@@ -407,7 +406,7 @@ export class CommonSQLiteAdapter implements StorageAdapter {
407406

408407
async batchSave<T extends PersistentModel>(
409408
modelConstructor: PersistentModelConstructor<any>,
410-
items: ModelInstanceMetadata[]
409+
items: ModelInstanceMetadataWithId[]
411410
): Promise<[T, OpType][]> {
412411
const { name: tableName } = modelConstructor;
413412
const result: [T, OpType][] = [];

packages/datastore-storage-adapter/src/common/SQLiteUtils.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export function modelCreateTableStatement(
148148
let fields = Object.values(model.fields).reduce((acc, field: ModelField) => {
149149
if (isGraphQLScalarType(field.type)) {
150150
if (field.name === 'id') {
151-
return acc + '"id" PRIMARY KEY NOT NULL';
151+
return [...acc, '"id" PRIMARY KEY NOT NULL'];
152152
}
153153

154154
let columnParam = `"${field.name}" ${getSQLiteType(field.type)}`;
@@ -157,7 +157,7 @@ export function modelCreateTableStatement(
157157
columnParam += ' NOT NULL';
158158
}
159159

160-
return acc + `, ${columnParam}`;
160+
return [...acc, `${columnParam}`];
161161
}
162162

163163
if (isModelFieldType(field.type)) {
@@ -167,7 +167,7 @@ export function modelCreateTableStatement(
167167
if (isTargetNameAssociation(field.association)) {
168168
// check if this field has been explicitly defined in the model
169169
const fkDefinedInModel = Object.values(model.fields).find(
170-
(f: ModelField) => f.name === field.association.targetName
170+
(f: ModelField) => f.name === field?.association?.targetName
171171
);
172172

173173
// if the FK is not explicitly defined in the model, we have to add it here
@@ -179,7 +179,7 @@ export function modelCreateTableStatement(
179179

180180
// ignore isRequired param for model fields, since they will not contain
181181
// the related data locally
182-
return acc + `, ${columnParam}`;
182+
return [...acc, `${columnParam}`];
183183
}
184184

185185
// default to TEXT
@@ -189,19 +189,25 @@ export function modelCreateTableStatement(
189189
columnParam += ' NOT NULL';
190190
}
191191

192-
return acc + `, ${columnParam}`;
193-
}, '');
192+
return [...acc, `${columnParam}`];
193+
}, [] as string[]);
194194

195195
implicitAuthFields.forEach((authField: string) => {
196-
fields += `, ${authField} TEXT`;
196+
fields.push(`${authField} TEXT`);
197197
});
198198

199199
if (userModel) {
200-
fields +=
201-
', "_version" INTEGER, "_lastChangedAt" INTEGER, "_deleted" INTEGER';
200+
fields = [
201+
...fields,
202+
`"_version" INTEGER`,
203+
`"_lastChangedAt" INTEGER`,
204+
`"_deleted" INTEGER`,
205+
];
202206
}
203207

204-
const createTableStatement = `CREATE TABLE IF NOT EXISTS "${model.name}" (${fields});`;
208+
const createTableStatement = `CREATE TABLE IF NOT EXISTS "${
209+
model.name
210+
}" (${fields.join(', ')});`;
205211
return createTableStatement;
206212
}
207213

packages/datastore-storage-adapter/src/common/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PersistentModel } from '@aws-amplify/datastore';
1+
import { PersistentModel, ModelInstanceMetadata } from '@aws-amplify/datastore';
22

33
export interface CommonSQLiteDatabase {
44
init(): Promise<void>;
@@ -27,3 +27,8 @@ export interface CommonSQLiteDatabase {
2727
}
2828

2929
export type ParameterizedStatement = [string, any[]];
30+
31+
// TODO: remove once we implement CPK for this adapter
32+
export type ModelInstanceMetadataWithId = ModelInstanceMetadata & {
33+
id: string;
34+
};

packages/datastore/__tests__/AsyncStorage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ describe('AsyncStorage tests', () => {
168168

169169
test('save function 1:1 insert', async () => {
170170
await DataStore.save(blog);
171+
171172
await DataStore.save(owner);
172173

173174
const get1 = JSON.parse(

0 commit comments

Comments
 (0)