@smallprod/models
Version:
693 lines (676 loc) • 19 kB
text/typescript
import { DbManager, EntityManager, GlobalModel } from '../..';
import { expect as chaiexp } from 'chai';
import query from '../_utils/query';
describe.each([
['MariaDB', 'maria'],
['MySql', 'mysql'],
['PostgresSql', 'postgres'],
])('CRUD query tests with %s', (dbName: string, name: string) => {
let dbManager: DbManager;
let model: GlobalModel;
beforeAll(async (done) => {
dbManager = DbManager.getInstance();
const m = dbManager.get(name);
if (m) {
model = m;
} else {
throw new Error(`Database connection not found ${name}`);
}
await query.create(model, name);
done();
});
beforeEach(async (done) => {
await model.startTransaction();
done();
});
test('An insert query should add a row in the database', async () => {
const res = await model.insert('categories', [
{ column: 'label', value: 'test' },
]);
chaiexp(res).to.be.equal(1);
});
test('An update query should update a row', async () => {
await model.insert('categories', [{ column: 'label', value: 'test' }]);
const upRes = await model.update(
'categories',
[{ column: 'label', value: 'toto' }],
[{ column: 'label', operator: '=', value: 'test' }],
);
chaiexp(upRes).to.be.equal(1);
const res = await model.select(
'categories',
true,
[],
[],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res).to.be.deep.equal([{ id: 2, label: 'toto' }]);
});
test('A delete query should delete a row', async () => {
await model.insert('categories', [{ column: 'label', value: 'test' }]);
const delRes = await model.delete('categories', [
{ column: 'label', operator: '=', value: 'test' },
]);
chaiexp(delRes).to.be.equal(1);
const res = await model.select(
'categories',
true,
[],
[],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res.length).to.be.equal(0);
});
describe('SELECT', () => {
test('Simple select', async () => {
await model.insert('categories', [{ column: 'label', value: 'test' }]);
const res = await model.select(
'categories',
false,
[],
[],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res.length).to.be.equal(1);
});
test('Distinct select', async () => {
await model.insert('categories', [{ column: 'label', value: 'test' }]);
await model.insert('categories', [{ column: 'label', value: 'test' }]);
const res1 = await model.select(
'categories',
false,
[{ attribute: 'label' }],
[],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res1.length).to.be.equal(2);
const res2 = await model.select(
'categories',
true,
[{ attribute: 'label' }],
[],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res2.length).to.be.equal(1);
});
test('Attributes selection', async () => {
await model.insert('articles', [
{ column: 'title', value: 'Article #1' },
{ column: 'nbpages', value: 100 },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #2' },
{ column: 'nbpages', value: 50 },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #3' },
{ column: 'nbpages', value: 25 },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #4' },
{ column: 'nbpages', value: 75 },
]);
const res1 = await model.select(
'articles',
false,
[
{ attribute: 'nbpages', function: 'AVG', alias: 'avg' },
{ attribute: 'nbpages', function: 'SUM', alias: 'sum' },
{ attribute: 'nbpages', function: 'MAX', alias: 'max' },
{ attribute: 'nbpages', function: 'MIN', alias: 'min' },
{ attribute: '*', function: 'COUNT', alias: 'count' },
],
[],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(parseFloat(res1[0].avg).toFixed(1)).to.be.equal('62.5');
chaiexp(parseFloat(res1[0].sum)).to.be.equal(250);
chaiexp(parseFloat(res1[0].max)).to.be.equal(100);
chaiexp(parseFloat(res1[0].min)).to.be.equal(25);
chaiexp(parseFloat(res1[0].count)).to.be.equal(4);
const res2 = await model.select(
'articles',
false,
[{ attribute: 'nbpages', alias: 'pages' }],
[],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res2[0].pages).not.to.be.undefined;
});
test('Where clause', async () => {
await model.insert('users', [
{ column: 'firstname', value: 'John' },
{ column: 'lastname', value: 'Doe' },
{ column: 'email', value: 'test@test.com' },
{ column: 'birthdate', value: '1997-09-17' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'Jane' },
{ column: 'lastname', value: 'Doe' },
{ column: 'email', value: 'jane@test.com' },
{ column: 'birthdate', value: '1998-09-17' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'Jack' },
{ column: 'lastname', value: 'Lang' },
{ column: 'email', value: 'jack@test.com' },
{ column: 'birthdate', value: '1995-09-17' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'JJ' },
{ column: 'lastname', value: 'Bob' },
{ column: 'email', value: 'jj@test.com' },
{ column: 'birthdate', value: '2000-01-01' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'Ane' },
{ column: 'lastname', value: 'Harris' },
{ column: 'email', value: 'ane@test.com' },
{ column: 'birthdate', value: '1990-01-01' },
]);
const res1 = await model.select(
'users',
false,
[],
[
{ column: 'firstname', operator: '=', value: 'Jack' },
{ keyword: 'OR' },
{ keyword: 'STARTGROUP' },
{ column: 'lastname', operator: '=', value: 'Doe' },
{ keyword: 'AND' },
{ column: 'email', operator: 'LIKE', value: 'test%' },
{ keyword: 'ENDGROUP' },
{ keyword: 'OR' },
{ keyword: 'NOT' },
{ column: 'firstname', operator: 'LIKE', value: 'J%' },
],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res1.length).to.be.equal(3);
const res2 = await model.select(
'users',
false,
[],
[
{ column: 'birthdate', operator: '<=', value: '1990-01-01' },
{ keyword: 'OR' },
{ column: 'birthdate', operator: '>=', value: '2000-01-01' },
{ keyword: 'OR' },
{ keyword: 'STARTGROUP' },
{ column: 'birthdate', operator: '>', value: '1995-01-01' },
{ keyword: 'AND' },
{ column: 'birthdate', operator: '<', value: '1996-01-01' },
{ keyword: 'ENDGROUP' },
],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res2.length).to.be.equal(3);
const res3 = await model.select(
'users',
false,
[],
[{ column: 'birthdate', operator: '<>', value: '2000-01-01' }],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res3.length).to.be.equal(4);
const res4 = await model.select(
'users',
false,
[],
[
{
column: 'birthdate',
operator: 'BETWEEN',
value: ['1995-01-01', '1996-01-01'],
},
],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res4.length).to.be.equal(1);
const res5 = await model.select(
'users',
false,
[],
[
{
column: 'birthdate',
operator: 'IN',
value: ['1997-09-17', '1998-09-17', '1995-09-17'],
},
],
[],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res5.length).to.be.equal(3);
});
test('Sort clause', async () => {
await model.insert('users', [
{ column: 'firstname', value: 'John' },
{ column: 'lastname', value: 'Doe' },
{ column: 'email', value: 'test@test.com' },
{ column: 'birthdate', value: '1997-09-17' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'Jane' },
{ column: 'lastname', value: 'Doe' },
{ column: 'email', value: 'jane@test.com' },
{ column: 'birthdate', value: '1998-09-17' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'Jack' },
{ column: 'lastname', value: 'Lang' },
{ column: 'email', value: 'jack@test.com' },
{ column: 'birthdate', value: '1995-09-17' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'JJ' },
{ column: 'lastname', value: 'Bob' },
{ column: 'email', value: 'jj@test.com' },
{ column: 'birthdate', value: '2000-01-01' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'Ane' },
{ column: 'lastname', value: 'Harris' },
{ column: 'email', value: 'ane@test.com' },
{ column: 'birthdate', value: '1990-01-01' },
]);
const res1 = await model.select(
'users',
false,
[],
[],
[{ attribute: 'birthdate', mode: 'ASC' }],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res1[0].firstname).to.be.equal('Ane');
chaiexp(res1[res1.length - 1].firstname).to.be.equal('JJ');
const res2 = await model.select(
'users',
false,
[],
[],
[{ attribute: 'firstname', mode: 'DESC' }],
'',
-1,
-1,
[],
[],
[],
);
chaiexp(res2[0].firstname).to.be.equal('John');
chaiexp(res2[res2.length - 1].firstname).to.be.equal('Ane');
});
test('Limit and offset', async () => {
await model.insert('users', [
{ column: 'firstname', value: 'John' },
{ column: 'lastname', value: 'Doe' },
{ column: 'email', value: 'test@test.com' },
{ column: 'birthdate', value: '1997-09-17' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'Jane' },
{ column: 'lastname', value: 'Doe' },
{ column: 'email', value: 'jane@test.com' },
{ column: 'birthdate', value: '1998-09-17' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'Jack' },
{ column: 'lastname', value: 'Lang' },
{ column: 'email', value: 'jack@test.com' },
{ column: 'birthdate', value: '1995-09-17' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'JJ' },
{ column: 'lastname', value: 'Bob' },
{ column: 'email', value: 'jj@test.com' },
{ column: 'birthdate', value: '2000-01-01' },
]);
await model.insert('users', [
{ column: 'firstname', value: 'Ane' },
{ column: 'lastname', value: 'Harris' },
{ column: 'email', value: 'ane@test.com' },
{ column: 'birthdate', value: '1990-01-01' },
]);
const res1 = await model.select(
'users',
false,
[],
[],
[{ attribute: 'birthdate', mode: 'ASC' }],
'',
2,
0,
[],
[],
[],
);
chaiexp(res1.length).to.be.equal(2);
chaiexp(res1[0].firstname).to.be.equal('Ane');
const res2 = await model.select(
'users',
false,
[],
[],
[{ attribute: 'birthdate', mode: 'ASC' }],
'',
3,
1,
[],
[],
[],
);
chaiexp(res2.length).to.be.equal(3);
chaiexp(res2[0].firstname).to.be.equal('Jack');
});
test('Join clause', async () => {
const cat1Id = await model.insert('categories', [
{ column: 'label', value: 'Cat#1' },
]);
const cat2Id = await model.insert('categories', [
{ column: 'label', value: 'Cat#2' },
]);
const cat3Id = await model.insert('categories', [
{ column: 'label', value: 'Cat#3' },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #1' },
{ column: 'nbpages', value: 100 },
{ column: 'category_id', value: cat1Id },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #2' },
{ column: 'nbpages', value: 50 },
{ column: 'category_id', value: cat1Id },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #3' },
{ column: 'nbpages', value: 25 },
{ column: 'category_id', value: cat2Id },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #4' },
{ column: 'nbpages', value: 75 },
{ column: 'category_id', value: cat2Id },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #5' },
{ column: 'nbpages', value: 75 },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #6' },
{ column: 'nbpages', value: 75 },
]);
const res1 = await model.select(
'articles',
true,
[],
[],
[],
'a',
-1,
-1,
[
{
tableName: 'categories',
alias: 'c',
method: 'inner',
wheres: [{ column: 'a.category_id', operator: '=', value: 'c.id' }],
},
],
[],
[],
);
chaiexp(res1.length).to.be.equal(4);
expect(res1.map((r: any) => r.title)).toEqual(
expect.arrayContaining([
'Article #1',
'Article #2',
'Article #3',
'Article #4',
]),
);
const res2 = await model.select(
'articles',
true,
[],
[],
[],
'a',
-1,
-1,
[
{
tableName: 'categories',
alias: 'c',
method: 'left',
wheres: [{ column: 'a.category_id', operator: '=', value: 'c.id' }],
},
],
[],
[],
);
chaiexp(res2.length).to.be.equal(6);
expect(res2.map((r: any) => r.title)).toEqual(
expect.arrayContaining([
'Article #1',
'Article #2',
'Article #3',
'Article #4',
'Article #5',
'Article #6',
]),
);
const res3 = await model.select(
'articles',
true,
[],
[],
[],
'a',
-1,
-1,
[
{
tableName: 'categories',
alias: 'c',
method: 'right',
wheres: [{ column: 'a.category_id', operator: '=', value: 'c.id' }],
},
],
[],
[],
);
chaiexp(res3.length).to.be.equal(5);
expect(res3.map((r: any) => r.label)).toEqual(
expect.arrayContaining(['Cat#1', 'Cat#2', 'Cat#3', 'Cat#1', 'Cat#2']),
);
});
test('Group by', async () => {
const cat1Id = await model.insert('categories', [
{ column: 'label', value: 'Cat#1' },
]);
const cat2Id = await model.insert('categories', [
{ column: 'label', value: 'Cat#2' },
]);
const cat3Id = await model.insert('categories', [
{ column: 'label', value: 'Cat#3' },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #1' },
{ column: 'nbpages', value: 100 },
{ column: 'category_id', value: cat1Id },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #2' },
{ column: 'nbpages', value: 50 },
{ column: 'category_id', value: cat1Id },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #3' },
{ column: 'nbpages', value: 25 },
{ column: 'category_id', value: cat2Id },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #4' },
{ column: 'nbpages', value: 75 },
{ column: 'category_id', value: cat2Id },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #5' },
{ column: 'nbpages', value: 75 },
{ column: 'category_id', value: cat2Id },
]);
await model.insert('articles', [
{ column: 'title', value: 'Article #6' },
{ column: 'nbpages', value: 75 },
]);
const res1 = await model.select(
'articles',
false,
[
{ attribute: 'c.label' },
{ attribute: '*', function: 'COUNT', alias: 'count' },
],
[],
[],
'a',
-1,
-1,
[
{
tableName: 'categories',
alias: 'c',
method: 'inner',
wheres: [{ column: 'a.category_id', operator: '=', value: 'c.id' }],
},
],
['c.label'],
[],
);
chaiexp(res1.length).to.be.equal(2);
chaiexp(
res1.map((r: any) => ({
label: r.label,
count: parseInt(r.count, 10),
})),
).to.be.deep.equal([
{ label: 'Cat#1', count: 2 },
{ label: 'Cat#2', count: 3 },
]);
const res2 = await model.select(
'articles',
false,
[
{ attribute: 'c.label' },
{ attribute: '*', function: 'COUNT', alias: 'count' },
],
[],
[],
'a',
-1,
-1,
[
{
tableName: 'categories',
alias: 'c',
method: 'inner',
wheres: [{ column: 'a.category_id', operator: '=', value: 'c.id' }],
},
],
['c.label'],
[{ column: 'COUNT(*)', operator: '>=', value: 3 }],
);
chaiexp(res2.length).to.be.equal(1);
chaiexp(
res2.map((r: any) => ({
label: r.label,
count: parseInt(r.count, 10),
})),
).to.be.deep.equal([{ label: 'Cat#2', count: 3 }]);
});
});
afterEach(async (done) => {
await model.rollback();
done();
});
afterAll(async (done) => {
await query.delete(model);
done();
});
});