Skip to content

Commit

Permalink
fix(@aws-amplify/datastore-storage-adapter): remove extra, invalid sq…
Browse files Browse the repository at this point in the history
…lite mutations again (aws-amplify#9921)

* testing expanded, refixed sqlite adapter

* ported sqlite adapter test expansion to indexeddbadapter tests

* working on making all adapter tests share common test script

* shared tests working in both datastore and datastore-storage-adapter

* moved and incorporated record adder helper in common adapter tests

* cleanup cruft

* cleaned up crufty lib include
  • Loading branch information
svidgen authored May 20, 2022
1 parent 7656bc8 commit 00923cf
Show file tree
Hide file tree
Showing 11 changed files with 585 additions and 571 deletions.
421 changes: 99 additions & 322 deletions packages/datastore-storage-adapter/__tests__/SQLiteAdapter.test.ts

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion packages/datastore-storage-adapter/__tests__/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
MutableModel,
Schema,
InternalSchema,
SchemaModel,
} from '@aws-amplify/datastore';

export declare class Model {
Expand Down
3 changes: 2 additions & 1 deletion packages/datastore-storage-adapter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@
"/node_modules/",
"dist",
"lib",
"lib-esm"
"lib-esm",
"../datastore"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,10 @@ export class CommonSQLiteAdapter implements StorageAdapter {
? modelUpdateStatement(instance, modelName)
: modelInsertStatement(instance, modelName);

saveStatements.add(saveStatement);

result.push([instance, opType]);
if (id === model.id || opType === OpType.INSERT) {
saveStatements.add(saveStatement);
result.push([instance, opType]);
}
}

await this.db.batchSave(saveStatements);
Expand Down
2 changes: 1 addition & 1 deletion packages/datastore-storage-adapter/tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"space-before-function-paren": [
true,
{
"anonymous": "always",
"anonymous": "never",
"named": "never"
}
],
Expand Down
20 changes: 19 additions & 1 deletion packages/datastore/__tests__/AsyncStorageAdapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import {
initSchema as initSchemaType,
} from '../src/datastore/datastore';
import { PersistentModelConstructor, SortDirection } from '../src/types';
import { Model, User, Profile, testSchema } from './helpers';
import { pause, Model, User, Profile, testSchema } from './helpers';
import { Predicates } from '../src/predicates';
import { addCommonQueryTests } from './commonAdapterTests';

let initSchema: typeof initSchemaType;
let DataStore: typeof DataStoreType;
Expand All @@ -17,6 +18,19 @@ describe('AsyncStorageAdapter tests', () => {
jest.clearAllMocks();
});

async function getMutations(adapter) {
await pause(250);
return await adapter.getAll('sync_MutationEvent');
}

({ initSchema, DataStore } = require('../src/datastore/datastore'));
addCommonQueryTests({
initSchema,
DataStore,
storageAdapter: AsyncStorageAdapter,
getMutations,
});

describe('Query', () => {
let Model: PersistentModelConstructor<Model>;
let model1Id: string;
Expand Down Expand Up @@ -67,6 +81,10 @@ describe('AsyncStorageAdapter tests', () => {
);
});

afterAll(async () => {
await DataStore.clear();
});

it('Should call getById for query by id', async () => {
const result = await DataStore.query(Model, model1Id);

Expand Down
267 changes: 28 additions & 239 deletions packages/datastore/__tests__/IndexedDBAdapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,38 @@ import {
initSchema as initSchemaType,
} from '../src/datastore/datastore';
import { PersistentModelConstructor, SortDirection } from '../src/types';
import { Model, User, Profile, Post, Comment, testSchema } from './helpers';
import {
pause,
expectMutation,
Model,
User,
Profile,
Post,
Comment,
testSchema,
} from './helpers';
import { Predicates } from '../src/predicates';
import { addCommonQueryTests } from './commonAdapterTests';

let initSchema: typeof initSchemaType;
let DataStore: typeof DataStoreType;
// using any to get access to private methods
const IDBAdapter = <any>Adapter;

async function pause(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

describe('IndexedDBAdapter tests', () => {
async function getMutations(adapter) {
await pause(250);
return await adapter.getAll('sync_MutationEvent');
}

({ initSchema, DataStore } = require('../src/datastore/datastore'));
addCommonQueryTests({
initSchema,
DataStore,
storageAdapter: Adapter,
getMutations,
});

describe('Query', () => {
let Model: PersistentModelConstructor<Model>;
let model1Id: string;
Expand All @@ -29,6 +48,7 @@ describe('IndexedDBAdapter tests', () => {

beforeAll(async () => {
({ initSchema, DataStore } = require('../src/datastore/datastore'));
DataStore.configure({ storageAdapter: Adapter });

const classes = initSchema(testSchema());

Expand All @@ -43,6 +63,9 @@ describe('IndexedDBAdapter tests', () => {

const baseDate = new Date();

await DataStore.start();
await DataStore.clear();

({ id: model1Id } = await DataStore.save(
new Model({
field1: 'field1 value 0',
Expand Down Expand Up @@ -119,120 +142,6 @@ describe('IndexedDBAdapter tests', () => {
expect(spyOnEngine).not.toHaveBeenCalled();
expect(spyOnMemory).not.toHaveBeenCalled();
});

it('should match fields of any non-empty value for `("ne", undefined)`', async () => {
const results = await DataStore.query(Model, m =>
m.field1('ne', undefined)
);
expect(results.length).toEqual(3);
});

it('should match fields of any non-empty value for `("ne", null)`', async () => {
const results = await DataStore.query(Model, m => m.field1('ne', null));
expect(results.length).toEqual(3);
});

it('should NOT match fields of any non-empty value for `("eq", undefined)`', async () => {
const results = await DataStore.query(Model, m =>
m.field1('eq', undefined)
);
expect(results.length).toEqual(0);
});

it('should NOT match fields of any non-empty value for `("eq", null)`', async () => {
const results = await DataStore.query(Model, m => m.field1('eq', null));
expect(results.length).toEqual(0);
});

it('should NOT match fields of any non-empty value for `("gt", null)`', async () => {
const results = await DataStore.query(Model, m => m.field1('gt', null));
expect(results.length).toEqual(0);
});

it('should NOT match fields of any non-empty value for `("ge", null)`', async () => {
const results = await DataStore.query(Model, m => m.field1('ge', null));
expect(results.length).toEqual(0);
});

it('should NOT match fields of any non-empty value for `("lt", null)`', async () => {
const results = await DataStore.query(Model, m => m.field1('lt', null));
expect(results.length).toEqual(0);
});

it('should NOT match fields of any non-empty value for `("le", null)`', async () => {
const results = await DataStore.query(Model, m => m.field1('le', null));
expect(results.length).toEqual(0);
});

it('should NOT match fields of any non-empty value for `("gt", undefined)`', async () => {
const results = await DataStore.query(Model, m =>
m.field1('gt', undefined)
);
expect(results.length).toEqual(0);
});

it('should NOT match fields of any non-empty value for `("ge", undefined)`', async () => {
const results = await DataStore.query(Model, m =>
m.field1('ge', undefined)
);
expect(results.length).toEqual(0);
});

it('should NOT match fields of any non-empty value for `("lt", undefined)`', async () => {
const results = await DataStore.query(Model, m =>
m.field1('lt', undefined)
);
expect(results.length).toEqual(0);
});

it('should NOT match fields of any non-empty value for `("le", undefined)`', async () => {
const results = await DataStore.query(Model, m =>
m.field1('le', undefined)
);
expect(results.length).toEqual(0);
});

it('should match gt', async () => {
const results = await DataStore.query(Model, m =>
m.field1('gt', 'field1 value 0')
);
expect(results.length).toEqual(2);
});

it('should match ge', async () => {
const results = await DataStore.query(Model, m =>
m.field1('ge', 'field1 value 1')
);
expect(results.length).toEqual(2);
});

it('should match lt', async () => {
const results = await DataStore.query(Model, m =>
m.field1('lt', 'field1 value 2')
);
expect(results.length).toEqual(2);
});

it('should match le', async () => {
const results = await DataStore.query(Model, m =>
m.field1('le', 'field1 value 1')
);
expect(results.length).toEqual(2);
});

it('should match eq', async () => {
const results = await DataStore.query(Model, m =>
m.field1('eq', 'field1 value 1')
);
expect(results.length).toEqual(1);
});

it('should match ne', async () => {
const results = await DataStore.query(Model, m =>
m.field1('ne', 'field1 value 1')
);
expect(results.length).toEqual(2);
});
});

describe('Delete', () => {
Expand Down Expand Up @@ -281,124 +190,4 @@ describe('IndexedDBAdapter tests', () => {
expect(profile).toBeUndefined;
});
});

describe('Save', () => {
let User: PersistentModelConstructor<User>;
let Profile: PersistentModelConstructor<Profile>;
let Comment: PersistentModelConstructor<Comment>;
let Post: PersistentModelConstructor<Post>;
let adapter: any;

async function getMutations() {
await pause(250);
return await adapter.getAll('sync_MutationEvent');
}

beforeEach(async () => {
({ initSchema, DataStore } = require('../src/datastore/datastore'));

DataStore.configure({
storageAdapter: Adapter,
});
(DataStore as any).amplifyConfig.aws_appsync_graphqlEndpoint =
'https://0.0.0.0/does/not/exist/graphql';

const classes = initSchema(testSchema());

({ User, Profile, Comment, Post } = classes as {
User: PersistentModelConstructor<User>;
Profile: PersistentModelConstructor<Profile>;
Comment: PersistentModelConstructor<Comment>;
Post: PersistentModelConstructor<Post>;
});

await DataStore.clear();

// ensure `.storageAdapter` is set.
await DataStore.start();

adapter = (DataStore as any).storageAdapter;
const syncEngine = (DataStore as any).sync;

// my jest spy-fu wasn't up to snuff here. but, this succesfully
// prevents the mutation process from clearing the mutation queue, which
// allows us to observe the state of mutations.
(syncEngine as any).mutationsProcessor.isReady = () => false;
});

it('should allow linking model via model field', async () => {
const profile = await DataStore.save(
new Profile({ firstName: 'Rick', lastName: 'Bob' })
);

const savedUser = await DataStore.save(
new User({ name: 'test', profile })
);
const user1Id = savedUser.id;

const user = await DataStore.query(User, user1Id);
expect(user.profileID).toEqual(profile.id);
expect(user.profile).toEqual(profile);
});

it('should allow linking model via FK', async () => {
const profile = await DataStore.save(
new Profile({ firstName: 'Rick', lastName: 'Bob' })
);

const savedUser = await DataStore.save(
new User({ name: 'test', profileID: profile.id })
);
const user1Id = savedUser.id;

const user = await DataStore.query(User, user1Id);
expect(user.profileID).toEqual(profile.id);
expect(user.profile).toEqual(profile);
});

it('should produce a single mutation for an updated model with a BelongTo (regression test)', async () => {
// SQLite adapter, for example, was producing an extra mutation
// in this scenario.

const post = await DataStore.save(
new Post({
title: 'some post',
})
);

const comment = await DataStore.save(
new Comment({
content: 'some comment',
post,
})
);

const updatedComment = await DataStore.save(
Comment.copyOf(comment, draft => {
draft.content = 'updated content';
})
);

const mutations = await getMutations();

// comment update should be smashed to together with post
expect(mutations.length).toBe(2);
});

it('should produce a mutation for a nested BELONGS_TO insert', async () => {
const comment = await DataStore.save(
new Comment({
content: 'newly created comment',
post: new Post({
title: 'newly created post',
}),
})
);

const mutations = await getMutations();

// one for the new comment, one for the new post
expect(mutations.length).toBe(2);
});
});
});
Loading

0 comments on commit 00923cf

Please sign in to comment.