@getanthill/datastore
Version:
Event-Sourced Datastore
900 lines (804 loc) • 22 kB
text/typescript
import Model from './Model';
import Datastore from './Datastore';
import usersConfig from '../../test/fixtures/users';
describe('sdk/Model', () => {
let client;
let model;
beforeEach(() => {
client = new Datastore();
client.core._axios = {
request: jest.fn().mockImplementation(() => ({ data: null })),
};
model = new Model(client, usersConfig);
});
afterEach(() => {
jest.restoreAllMocks();
});
describe('constructor', () => {
it('creates a new model client with datastore and model configuration attached', () => {
model = new Model(client, usersConfig);
expect(model).toHaveProperty('modelConfig');
expect(model).toHaveProperty('datastore');
expect(model.modelConfig).toEqual(usersConfig);
expect(model.datastore).toEqual(client);
});
});
describe('get name', () => {
it('returns the name of the model', () => {
expect(model.name).toEqual('users');
});
});
describe('#heartbeat', () => {
it('calls the heartbeat route', async () => {
await model.heartbeat();
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'get',
url: '/heartbeat',
headers: {
'force-primary': undefined,
},
});
});
});
/**
* Admin routes
*/
describe('#createModel', () => {
it('calls the admin create model route', async () => {
await model.createModel();
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/admin',
data: model.modelConfig,
headers: {
'force-primary': undefined,
},
});
});
});
describe('#updateModel', () => {
it('calls the admin update model route', async () => {
await model.updateModel();
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/admin/users',
data: model.modelConfig,
headers: {
'force-primary': undefined,
},
});
});
});
describe('#createModelIndexes', () => {
it('calls the admin create model indexes route', async () => {
await model.createModelIndexes({
db: 'datastore',
name: 'users',
});
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/admin/users/indexes',
data: model.modelConfig,
headers: {
'force-primary': undefined,
},
});
});
});
describe('#getSchema', () => {
it('calls the admin get model schema route', async () => {
await model.getSchema();
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'get',
url: '/api/admin/users/schema',
headers: {
'force-primary': undefined,
},
});
});
});
/**
* Non admin routes
*/
describe('#encryptOne', () => {
beforeEach(() => {
client.core._axios = {
request: jest.fn().mockImplementation(({ data }) => ({
data,
})),
};
});
it('calls the encrypt model route to encrypt a single object', async () => {
await model.encryptOne({
firstname: 'azerty',
});
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/encrypt',
params: {
fields: [],
},
data: [
{
firstname: 'azerty',
},
],
headers: {
'force-primary': undefined,
},
});
});
it('calls the encrypt model route to encrypt a single object on extra encryption fields', async () => {
await model.encryptOne(
{
firstname: 'azerty',
},
['firstname'],
);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/encrypt',
params: {
fields: ['firstname'],
},
data: [
{
firstname: 'azerty',
},
],
headers: {
'force-primary': undefined,
},
});
});
});
describe('#encryptMany', () => {
beforeEach(() => {
client.core._axios = {
request: jest.fn().mockImplementation(({ data }) => ({
data,
})),
};
});
it('calls the encrypt model route for all requested objects', async () => {
await model.encryptMany([
{
firstname: 'azerty',
},
{
firstname: 'qwerty',
},
]);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/encrypt',
params: {
fields: [],
},
data: [
{
firstname: 'azerty',
},
{
firstname: 'qwerty',
},
],
headers: {
'force-primary': undefined,
},
});
});
it('calls the encrypt model route for all requested objects on additional encryption fields', async () => {
await model.encryptMany(
[
{
firstname: 'azerty',
},
{
firstname: 'qwerty',
},
],
['firstname'],
);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/encrypt',
params: {
fields: ['firstname'],
},
data: [
{
firstname: 'azerty',
},
{
firstname: 'qwerty',
},
],
headers: {
'force-primary': undefined,
},
});
});
});
describe('#decryptOne', () => {
beforeEach(() => {
client.core._axios = {
request: jest.fn().mockImplementation(({ data }) => ({
data,
})),
};
});
it('calls the decrypt model route to decrypt a single object', async () => {
await model.decryptOne({
firstname: 'azerty',
});
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/decrypt',
params: {
fields: [],
},
data: [
{
firstname: 'azerty',
},
],
headers: {
'force-primary': undefined,
},
});
});
it('calls the decrypt model route to decrypt a single object on extra encryption fields', async () => {
await model.decryptOne(
{
firstname: 'azerty',
},
['firstname'],
);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/decrypt',
params: {
fields: ['firstname'],
},
data: [
{
firstname: 'azerty',
},
],
headers: {
'force-primary': undefined,
},
});
});
});
describe('#decryptMany', () => {
beforeEach(() => {
client.core._axios = {
request: jest.fn().mockImplementation(({ data }) => ({
data,
})),
};
});
it('calls the decrypt model route for all requested objects', async () => {
await model.decryptMany([
{
firstname: 'azerty',
},
{
firstname: 'qwerty',
},
]);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/decrypt',
params: {
fields: [],
},
data: [
{
firstname: 'azerty',
},
{
firstname: 'qwerty',
},
],
headers: {
'force-primary': undefined,
},
});
});
it('calls the decrypt model route for all requested objects on additional encryption fields', async () => {
await model.decryptMany(
[
{
firstname: 'azerty',
},
{
firstname: 'qwerty',
},
],
['firstname'],
);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/decrypt',
params: {
fields: ['firstname'],
},
data: [
{
firstname: 'azerty',
},
{
firstname: 'qwerty',
},
],
headers: {
'force-primary': undefined,
},
});
});
});
describe('#createOne', () => {
it('calls the create model route to create a single object', async () => {
await model.createOne({
firstname: 'John',
});
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users',
data: {
firstname: 'John',
},
headers: {
'force-primary': undefined,
},
});
});
});
describe('#createMany', () => {
it('calls the create model route for each object defined in the payloads array', async () => {
await model.createMany([
{
firstname: 'John',
},
{
firstname: 'Jack',
},
]);
expect(model.datastore.core._axios.request).toHaveReturnedTimes(2);
expect(model.datastore.core._axios.request.mock.calls).toEqual([
[
{
data: { firstname: 'John' },
method: 'post',
url: '/api/users',
headers: {
'force-primary': undefined,
},
},
],
[
{
data: { firstname: 'Jack' },
method: 'post',
url: '/api/users',
headers: {
'force-primary': undefined,
},
},
],
]);
});
});
describe('#create (deprecated)', () => {
it('calls the create model route to create a single object', async () => {
await model.create({
firstname: 'John',
});
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users',
data: {
firstname: 'John',
},
headers: {
'force-primary': undefined,
},
});
});
it('calls the create model route for each object defined in the payloads array', async () => {
await model.create([
{
firstname: 'John',
},
{
firstname: 'Jack',
},
]);
expect(model.datastore.core._axios.request).toHaveReturnedTimes(2);
expect(model.datastore.core._axios.request.mock.calls).toEqual([
[
{
data: { firstname: 'John' },
method: 'post',
url: '/api/users',
headers: {
'force-primary': undefined,
},
},
],
[
{
data: { firstname: 'Jack' },
method: 'post',
url: '/api/users',
headers: {
'force-primary': undefined,
},
},
],
]);
});
});
describe('#updateOne', () => {
it('calls the update model route on a single object', async () => {
await model.updateOne({
firstname: 'Jack',
user_id: 'user_correlation_id',
});
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/user_correlation_id',
data: {
firstname: 'Jack',
},
headers: {
'force-primary': undefined,
},
});
});
});
describe('#updateMany', () => {
it('calls the update model route for each object defined in the payloads array with the correct correlation_id', async () => {
await model.updateMany([
{
firstname: 'John',
user_id: 'john',
},
{
firstname: 'Jack',
user_id: 'jack',
},
]);
expect(model.datastore.core._axios.request).toHaveReturnedTimes(2);
expect(model.datastore.core._axios.request.mock.calls).toEqual([
[
{
data: { firstname: 'John' },
method: 'post',
url: '/api/users/john',
headers: {
'force-primary': undefined,
},
},
],
[
{
data: { firstname: 'Jack' },
method: 'post',
url: '/api/users/jack',
headers: {
'force-primary': undefined,
},
},
],
]);
});
});
describe('#update (deprecated)', () => {
it('calls the update model route on a single object', async () => {
await model.update({
firstname: 'Jack',
user_id: 'user_correlation_id',
});
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/user_correlation_id',
data: {
firstname: 'Jack',
},
headers: {
'force-primary': undefined,
},
});
});
it('calls the update model route for each object defined in the payloads array with the correct correlation_id', async () => {
await model.update([
{
firstname: 'John',
user_id: 'john',
},
{
firstname: 'Jack',
user_id: 'jack',
},
]);
expect(model.datastore.core._axios.request).toHaveReturnedTimes(2);
expect(model.datastore.core._axios.request.mock.calls).toEqual([
[
{
data: { firstname: 'John' },
method: 'post',
url: '/api/users/john',
headers: {
'force-primary': undefined,
},
},
],
[
{
data: { firstname: 'Jack' },
method: 'post',
url: '/api/users/jack',
headers: {
'force-primary': undefined,
},
},
],
]);
});
});
describe('#apply', () => {
it('calls the apply model route', async () => {
await model.apply('FIRSTNAME_UPDATED', {
firstname: 'Jack',
user_id: 'user_correlation_id',
});
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/user_correlation_id/firstname_updated/0_0_0',
data: {
firstname: 'Jack',
},
headers: {
'force-primary': undefined,
},
});
});
});
describe('#get', () => {
it('calls the get model route', async () => {
await model.get('user_correlation_id');
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'get',
url: '/api/users/user_correlation_id',
headers: {
'force-primary': undefined,
},
});
});
});
describe('#count', () => {
it('calls the find model route with a pageSize of 0', async () => {
client.core._axios = {
request: jest.fn().mockImplementation(() => ({
headers: {
count: '1',
},
})),
};
const count = await model.count({
firstname: 'Jack',
});
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'get',
url: '/api/users',
params: {
firstname: 'Jack',
},
headers: {
page: 0,
'page-size': 0,
'force-primary': undefined,
},
});
expect(count).toEqual(1);
});
});
describe('#find', () => {
it('calls the find model route', async () => {
await model.find({
firstname: 'Jack',
});
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'get',
url: '/api/users',
params: {
firstname: 'Jack',
},
headers: {
'force-primary': undefined,
},
});
});
});
describe('#events', () => {
it('calls the get events model route', async () => {
await model.events('user_correlation_id');
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'get',
url: '/api/users/user_correlation_id/events',
headers: {
'force-primary': undefined,
},
});
});
});
describe('#version', () => {
it('calls the get version model route', async () => {
await model.version('user_correlation_id', 2);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'get',
url: '/api/users/user_correlation_id/2',
headers: {
'force-primary': undefined,
},
});
});
});
describe('#at', () => {
it('calls the get at model route', async () => {
await model.at('user_correlation_id', '2020-01-01T00:00:00.000Z');
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'get',
url: '/api/users/user_correlation_id/2020-01-01T00:00:00.000Z',
headers: {
'force-primary': undefined,
},
});
});
});
describe('#restore', () => {
it('calls the restore model route', async () => {
await model.restore('user_correlation_id', 1);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/user_correlation_id/1/restore',
headers: {
'force-primary': undefined,
},
});
});
});
describe('#snapshot', () => {
it('calls the create snapshot model route', async () => {
await model.snapshot('user_correlation_id');
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/user_correlation_id/snapshot',
headers: {
'force-primary': undefined,
},
});
});
});
describe('#archive', () => {
it('calls the archive model route', async () => {
await model.archive('user_correlation_id');
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/user_correlation_id/archive',
params: {
deep: false,
},
headers: {
'force-primary': undefined,
},
});
});
it('calls the archive model route with deep graph request', async () => {
await model.archive('user_correlation_id', true);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/user_correlation_id/archive',
params: {
deep: true,
},
headers: {
'force-primary': undefined,
},
});
});
});
describe('#unarchive', () => {
it('calls the unarchive model route', async () => {
await model.unarchive('user_correlation_id');
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/user_correlation_id/unarchive',
params: {
deep: false,
},
headers: {
'force-primary': undefined,
},
});
});
it('calls the unarchive model route with deep graph request', async () => {
await model.unarchive('user_correlation_id', true);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'post',
url: '/api/users/user_correlation_id/unarchive',
params: {
deep: true,
},
headers: {
'force-primary': undefined,
},
});
});
});
describe('#delete', () => {
it('calls the delete model route', async () => {
await model.delete('user_correlation_id');
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'delete',
url: '/api/users/user_correlation_id',
params: {
deep: false,
},
headers: {
'force-primary': undefined,
},
});
});
it('calls the delete model route with deep graph request', async () => {
await model.delete('user_correlation_id', true);
expect(model.datastore.core._axios.request).toHaveBeenLastCalledWith({
method: 'delete',
url: '/api/users/user_correlation_id',
params: {
deep: true,
},
headers: {
'force-primary': undefined,
},
});
});
});
describe('#updateOverwhelmingly', () => {
it('calls the updateOverwhelmingly model route', async () => {
model.datastore.updateOverwhelmingly = jest.fn();
const query = {};
const handler = jest.fn();
const progress = jest.fn();
const pageSize = 1;
await model.updateOverwhelmingly(query, handler, progress, pageSize);
expect(model.datastore.updateOverwhelmingly).toHaveBeenCalledWith(
model.name,
query,
handler,
progress,
pageSize,
);
});
});
describe('typing', () => {
interface User {
firstname: string;
lastname?: string;
}
it('instanciates a new Model with this type in return', async () => {
const User = new Model<User>(client, usersConfig);
client.core._axios = {
request: jest.fn().mockImplementation((r) => ({ data: r.data })),
};
const user = await User.createOne({
firstname: 'John',
});
const users = await User.find({ firstname: 'John' });
});
});
});