forest-express-sequelize
Version:
Official Express/Sequelize Liana for Forest
207 lines (175 loc) • 6.37 kB
JavaScript
const Interface = require('forest-express');
const { STRING, INTEGER } = require('sequelize');
const { Op } = require('sequelize');
const databases = require('../databases');
const runWithConnection = require('../helpers/run-with-connection');
const ResourcesGetter = require('../../src/services/resources-getter');
function rot13(s) {
return s.replace(/[A-Z]/gi, (c) =>
'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm'[
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.indexOf(c)]);
}
const user = { renderingId: 1 };
async function setup(sequelize) {
Interface.Schemas = { schemas: {} };
// Shelves
const Shelves = sequelize.define('shelves', {
id: { type: INTEGER, primaryKey: true },
floor: { field: 'floor', type: INTEGER },
}, { tableName: 'shelves', timestamps: false });
Interface.Schemas.schemas.shelves = {
name: 'shelves',
idField: 'id',
primaryKeys: ['id'],
isCompositePrimary: false,
fields: [
{ field: 'id', type: 'Number' },
{ field: 'floor', columnName: 'floor', type: 'Number' },
],
};
// Books
const Books = sequelize.define('books', {
id: { type: INTEGER, primaryKey: true },
title: { field: 'title', type: STRING },
}, { tableName: 'books', timestamps: false });
Interface.Schemas.schemas.books = {
name: 'books',
idField: 'id',
primaryKeys: ['id'],
isCompositePrimary: false,
fields: [
{ field: 'id', type: 'Number' },
{ field: 'title', columnName: 'title', type: 'String' },
{
field: 'encrypted',
isVirtual: true,
type: 'String',
get: (record) => rot13(record.title),
search: (query, search) => {
query.where[Op.and][0][Op.or].push({
title: rot13(search),
});
},
},
],
};
// Reviews
const Reviews = sequelize.define('reviews', {
id: { type: INTEGER, primaryKey: true },
content: { field: 'content', type: STRING },
}, { tableName: 'reviews', timestamps: false });
Interface.Schemas.schemas.reviews = {
name: 'reviews',
idField: 'id',
primaryKeys: ['id'],
isCompositePrimary: false,
fields: [
{ field: 'id', type: 'Number' },
{ field: 'content', columnName: 'content', type: 'String' },
{
field: 'floor',
isVirtual: true,
type: 'String',
get: () => null,
search: (query, search) => {
query.include.push({
association: 'book',
include: [{ association: 'shelve' }],
});
query.where[Op.and][0][Op.or].push({
'$book.shelve.floor$': Number.parseInt(search, 10),
});
},
},
],
};
// Relations
Books.belongsTo(Shelves, {
foreignKey: { name: 'shelveId' },
as: 'shelve',
});
Reviews.belongsTo(Books, {
foreignKey: { name: 'bookId' },
as: 'book',
});
await sequelize.sync({ force: true });
await Shelves.create({ id: 1, floor: 666 });
await Shelves.create({ id: 2, floor: 667 });
await Books.create({ id: 1, shelveId: 1, title: 'nowhere' });
await Reviews.create({ id: 1, bookId: 1, content: 'abc' });
return { Shelves, Books, Reviews };
}
describe('integration > Smart field', () => {
Object.values(databases).forEach((connectionManager) => {
describe(`dialect ${connectionManager.getDialect()}`, () => {
it('should not find books matching the encrypted field', async () => {
expect.assertions(1);
await runWithConnection(connectionManager, async (sequelize) => {
const spy = jest.spyOn(Interface.scopeManager, 'getScopeForUser').mockReturnValue(null);
const { Books } = await setup(sequelize);
const params = {
fields: { books: 'id,title,encrypted' },
sort: 'id',
page: { number: '1', size: '30' },
timezone: 'Europe/Paris',
search: 'hello',
};
const count = await new ResourcesGetter(Books, null, params, user).count();
expect(count).toStrictEqual(0);
spy.mockRestore();
});
});
it('should find books matching the encrypted field', async () => {
expect.assertions(1);
await runWithConnection(connectionManager, async (sequelize) => {
const spy = jest.spyOn(Interface.scopeManager, 'getScopeForUser').mockReturnValue(null);
const { Books } = await setup(sequelize);
const params = {
fields: { books: 'id,title,encrypted' },
sort: 'id',
page: { number: '1', size: '30' },
timezone: 'Europe/Paris',
search: 'abjurer',
};
const count = await new ResourcesGetter(Books, null, params, user).count();
expect(count).toStrictEqual(1);
spy.mockRestore();
});
});
it('should not find reviews on the floor 500', async () => {
expect.assertions(1);
await runWithConnection(connectionManager, async (sequelize) => {
const spy = jest.spyOn(Interface.scopeManager, 'getScopeForUser').mockReturnValue(null);
const { Reviews } = await setup(sequelize);
const params = {
fields: { books: 'id,title,encrypted' },
sort: 'id',
page: { number: '1', size: '30' },
timezone: 'Europe/Paris',
search: '500',
};
const count = await new ResourcesGetter(Reviews, null, params, user).count();
expect(count).toStrictEqual(0);
spy.mockRestore();
});
});
it('should find reviews on the floor 666', async () => {
expect.assertions(1);
await runWithConnection(connectionManager, async (sequelize) => {
const spy = jest.spyOn(Interface.scopeManager, 'getScopeForUser').mockReturnValue(null);
const { Reviews } = await setup(sequelize);
const params = {
fields: { books: 'id,title,encrypted' },
sort: 'id',
page: { number: '1', size: '30' },
timezone: 'Europe/Paris',
search: '666',
};
const count = await new ResourcesGetter(Reviews, null, params, user).count();
expect(count).toStrictEqual(1);
spy.mockRestore();
});
});
});
});
});