2022-01-25 09:33:40 +01:00
|
|
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
import { mock } from '@/testing/utils';
|
2022-02-03 13:23:08 +01:00
|
|
|
import { CoreDatabaseTable } from '@classes/database/database-table';
|
2022-02-03 12:35:16 +01:00
|
|
|
import {
|
|
|
|
CoreDatabaseCachingStrategy,
|
|
|
|
CoreDatabaseConfiguration,
|
|
|
|
CoreDatabaseTableProxy,
|
|
|
|
} from '@classes/database/database-table-proxy';
|
2022-01-25 09:33:40 +01:00
|
|
|
import { SQLiteDB, SQLiteDBRecordValues } from '@classes/sqlitedb';
|
|
|
|
|
|
|
|
interface User extends SQLiteDBRecordValues {
|
|
|
|
id: number;
|
|
|
|
name: string;
|
|
|
|
surname: string;
|
|
|
|
}
|
|
|
|
|
2022-02-03 12:35:16 +01:00
|
|
|
function userMatches(user: User, conditions: Partial<User>) {
|
|
|
|
return !Object.entries(conditions).some(([column, value]) => user[column] !== value);
|
|
|
|
}
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
function prepareStubs(config: Partial<CoreDatabaseConfiguration> = {}): [User[], SQLiteDB, CoreDatabaseTable<User>] {
|
2022-02-03 12:35:16 +01:00
|
|
|
const records: User[] = [];
|
|
|
|
const database = mock<SQLiteDB>({
|
|
|
|
getRecord: async <T>(_, conditions) => {
|
|
|
|
const record = records.find(record => userMatches(record, conditions));
|
|
|
|
|
|
|
|
if (!record) {
|
|
|
|
throw new Error();
|
|
|
|
}
|
|
|
|
|
|
|
|
return record as unknown as T;
|
|
|
|
},
|
|
|
|
getRecords: async <T>(_, conditions) => records.filter(record => userMatches(record, conditions)) as unknown as T[],
|
|
|
|
getAllRecords: async <T>() => records as unknown as T[],
|
|
|
|
deleteRecords: async (_, conditions) => {
|
|
|
|
const usersToDelete: User[] = [];
|
|
|
|
|
|
|
|
for (const user of records) {
|
|
|
|
if (conditions && !userMatches(user, conditions)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
usersToDelete.push(user);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const user of usersToDelete) {
|
|
|
|
records.splice(records.indexOf(user), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return usersToDelete.length;
|
|
|
|
},
|
|
|
|
insertRecord: async (_, user: User) => records.push(user) && 1,
|
|
|
|
});
|
|
|
|
const table = new CoreDatabaseTableProxy<User>(config, database, 'users');
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 12:35:16 +01:00
|
|
|
return [records, database, table];
|
2022-01-25 09:33:40 +01:00
|
|
|
}
|
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
async function testFindItems(records: User[], table: CoreDatabaseTable<User>) {
|
|
|
|
const john = { id: 1, name: 'John', surname: 'Doe' };
|
|
|
|
const amy = { id: 2, name: 'Amy', surname: 'Doe' };
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
records.push(john);
|
|
|
|
records.push(amy);
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
await table.initialize();
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-07 14:02:29 +01:00
|
|
|
await expect(table.getOneByPrimaryKey({ id: 1 })).resolves.toEqual(john);
|
|
|
|
await expect(table.getOneByPrimaryKey({ id: 2 })).resolves.toEqual(amy);
|
|
|
|
await expect(table.getOne({ surname: 'Doe', name: 'John' })).resolves.toEqual(john);
|
|
|
|
await expect(table.getOne({ surname: 'Doe', name: 'Amy' })).resolves.toEqual(amy);
|
2022-02-03 13:23:08 +01:00
|
|
|
}
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
async function testInsertItems(records: User[], database: SQLiteDB, table: CoreDatabaseTable<User>) {
|
|
|
|
// Arrange.
|
|
|
|
const john = { id: 1, name: 'John', surname: 'Doe' };
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
await table.initialize();
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
// Act.
|
|
|
|
await table.insert(john);
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
// Assert.
|
|
|
|
expect(database.insertRecord).toHaveBeenCalledWith('users', john);
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-07 14:02:29 +01:00
|
|
|
await expect(table.getOneByPrimaryKey({ id: 1 })).resolves.toEqual(john);
|
2022-02-03 13:23:08 +01:00
|
|
|
}
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
async function testDeleteItems(records: User[], database: SQLiteDB, table: CoreDatabaseTable<User>) {
|
|
|
|
// Arrange.
|
|
|
|
const john = { id: 1, name: 'John', surname: 'Doe' };
|
|
|
|
const amy = { id: 2, name: 'Amy', surname: 'Doe' };
|
|
|
|
const jane = { id: 3, name: 'Jane', surname: 'Smith' };
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
records.push(john);
|
|
|
|
records.push(amy);
|
|
|
|
records.push(jane);
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
await table.initialize();
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
// Act.
|
|
|
|
await table.delete({ surname: 'Doe' });
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
// Assert.
|
|
|
|
expect(database.deleteRecords).toHaveBeenCalledWith('users', { surname: 'Doe' });
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-07 14:02:29 +01:00
|
|
|
await expect(table.getOneByPrimaryKey({ id: 1 })).rejects.toThrow();
|
|
|
|
await expect(table.getOneByPrimaryKey({ id: 2 })).rejects.toThrow();
|
|
|
|
await expect(table.getOneByPrimaryKey({ id: 3 })).resolves.toEqual(jane);
|
2022-02-03 13:23:08 +01:00
|
|
|
}
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
async function testDeleteItemsByPrimaryKey(records: User[], database: SQLiteDB, table: CoreDatabaseTable<User>) {
|
|
|
|
// Arrange.
|
|
|
|
const john = { id: 1, name: 'John', surname: 'Doe' };
|
|
|
|
const amy = { id: 2, name: 'Amy', surname: 'Doe' };
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
records.push(john);
|
|
|
|
records.push(amy);
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
await table.initialize();
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
// Act.
|
|
|
|
await table.deleteByPrimaryKey({ id: 1 });
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
// Assert.
|
|
|
|
expect(database.deleteRecords).toHaveBeenCalledWith('users', { id: 1 });
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-07 14:02:29 +01:00
|
|
|
await expect(table.getOneByPrimaryKey({ id: 1 })).rejects.toThrow();
|
|
|
|
await expect(table.getOneByPrimaryKey({ id: 2 })).resolves.toEqual(amy);
|
2022-02-03 13:23:08 +01:00
|
|
|
}
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
describe('CoreDatabaseTable with eager caching', () => {
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
let records: User[];
|
|
|
|
let database: SQLiteDB;
|
|
|
|
let table: CoreDatabaseTable<User>;
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
beforeEach(() => [records, database, table] = prepareStubs({ cachingStrategy: CoreDatabaseCachingStrategy.Eager }));
|
|
|
|
|
|
|
|
it('reads all records on initialization', async () => {
|
2022-02-03 12:35:16 +01:00
|
|
|
await table.initialize();
|
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
expect(database.getAllRecords).toHaveBeenCalledWith('users');
|
|
|
|
});
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
it('finds items', async () => {
|
|
|
|
await testFindItems(records, table);
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
expect(database.getRecord).not.toHaveBeenCalled();
|
2022-02-03 12:35:16 +01:00
|
|
|
});
|
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
it('inserts items', () => testInsertItems(records, database, table));
|
|
|
|
it('deletes items', () => testDeleteItems(records, database, table));
|
|
|
|
it('deletes items by primary key', () => testDeleteItemsByPrimaryKey(records, database, table));
|
|
|
|
|
2022-02-03 12:35:16 +01:00
|
|
|
});
|
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
describe('CoreDatabaseTable with lazy caching', () => {
|
2022-02-03 12:35:16 +01:00
|
|
|
|
|
|
|
let records: User[];
|
|
|
|
let database: SQLiteDB;
|
2022-02-03 13:23:08 +01:00
|
|
|
let table: CoreDatabaseTable<User>;
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
beforeEach(() => [records, database, table] = prepareStubs({ cachingStrategy: CoreDatabaseCachingStrategy.Lazy }));
|
2022-02-03 12:35:16 +01:00
|
|
|
|
|
|
|
it('reads no records on initialization', async () => {
|
|
|
|
await table.initialize();
|
|
|
|
|
|
|
|
expect(database.getRecords).not.toHaveBeenCalled();
|
|
|
|
expect(database.getAllRecords).not.toHaveBeenCalled();
|
|
|
|
});
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 12:35:16 +01:00
|
|
|
it('finds items', async () => {
|
2022-02-03 13:23:08 +01:00
|
|
|
await testFindItems(records, table);
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
expect(database.getRecord).toHaveBeenCalledTimes(2);
|
2022-02-03 12:35:16 +01:00
|
|
|
});
|
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
it('inserts items', () => testInsertItems(records, database, table));
|
|
|
|
it('deletes items', () => testDeleteItems(records, database, table));
|
|
|
|
it('deletes items by primary key', () => testDeleteItemsByPrimaryKey(records, database, table));
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
});
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
describe('CoreDatabaseTable with no caching', () => {
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
let records: User[];
|
|
|
|
let database: SQLiteDB;
|
|
|
|
let table: CoreDatabaseTable<User>;
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
beforeEach(() => [records, database, table] = prepareStubs({ cachingStrategy: CoreDatabaseCachingStrategy.None }));
|
2022-02-03 12:35:16 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
it('reads no records on initialization', async () => {
|
2022-02-03 12:35:16 +01:00
|
|
|
await table.initialize();
|
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
expect(database.getRecords).not.toHaveBeenCalled();
|
|
|
|
expect(database.getAllRecords).not.toHaveBeenCalled();
|
2022-02-03 12:35:16 +01:00
|
|
|
});
|
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
it('finds items', async () => {
|
|
|
|
await testFindItems(records, table);
|
2022-01-25 09:33:40 +01:00
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
expect(database.getRecord).toHaveBeenCalledTimes(4);
|
2022-01-25 09:33:40 +01:00
|
|
|
});
|
|
|
|
|
2022-02-03 13:23:08 +01:00
|
|
|
it('inserts items', () => testInsertItems(records, database, table));
|
|
|
|
it('deletes items', () => testDeleteItems(records, database, table));
|
|
|
|
it('deletes items by primary key', () => testDeleteItemsByPrimaryKey(records, database, table));
|
|
|
|
|
2022-01-25 09:33:40 +01:00
|
|
|
});
|