igo
Version:
Igo is a Node.js Web Framework based on Express
695 lines (588 loc) • 31.5 kB
JavaScript
const assert = require('assert');
const PaginatedOptimizedQuery = require('../../src/db/PaginatedOptimizedQuery');
const PaginatedOptimizedSql = require('../../src/db/PaginatedOptimizedSql');
const Model = require('../../src/db/Model');
const mockGetDb = (query) => {
query.getDb = () => ({
driver: {
dialect: {
esc: '`',
param: (i) => '?',
in: 'IN',
notin: 'NOT IN',
limit: (offsetParam, limitParam) => `LIMIT ?, ?`
}
}
});
return query;
};
describe('db.PaginatedOptimizedQuery', function() {
class Country extends Model({
table: 'countries',
columns: {
id: 'integer',
code: 'string',
name: 'string'
}
}) {}
class Company extends Model({
table: 'companies',
primary: ['id'],
columns: {
id: 'integer',
name: 'string',
siret: 'string',
country_id: 'integer'
},
associations: [
['belongs_to', 'country', Country, 'country_id', 'id']
]
}) {}
class PmeFolder extends Model({
table: 'pme_folders',
primary: ['id'],
columns: {
id: 'integer',
status: 'string',
company_id: 'integer',
company_name: 'string',
block_studies_id: 'integer'
},
associations: [
['belongs_to', 'company', Company, 'company_id', 'id']
]
}) {}
class PmeFolderWithBlocks extends PmeFolder {}
PmeFolderWithBlocks.schema.columns.block_studies_id = 'integer';
PmeFolderWithBlocks.schema.columns.block_travel_wishes_id = 'integer';
PmeFolderWithBlocks.schema.colsByName = PmeFolderWithBlocks.schema.colsByName || {};
PmeFolderWithBlocks.schema.colsByName.block_studies_id = 'integer';
PmeFolderWithBlocks.schema.colsByName.block_travel_wishes_id = 'integer';
class Applicant extends Model({
table: 'applicants',
primary: ['id'],
columns: [
'id',
'first_name',
'last_name',
'email'
]
}) {}
class Folder extends Model({
table: 'folders',
primary: ['id'],
columns: {
id: 'integer',
type: 'string',
status: 'string',
applicant_id: 'integer',
pme_folder_id: 'integer',
created_at: 'datetime'
},
associations: [
['belongs_to', 'applicant', Applicant, 'applicant_id', 'id'],
['belongs_to', 'pme_folder', PmeFolder, 'pme_folder_id', 'id']
]
}) {}
class StudiesBlock extends Model({
table: 'block_studies',
primary: ['id'],
columns: [
'id',
'ine_number',
'student_status',
'studies_year',
'studies_field',
{ name: 'bac_year', type: 'integer' }
]
}) {}
class TravelWishesBlock extends Model({
table: 'block_travel_wishes',
primary: ['id'],
columns: [
'id',
{ name: 'departure_date', type: 'date' },
{ name: 'return_date', type: 'date' },
'destination'
]
}) {}
PmeFolderWithBlocks.schema.associations = [
['belongs_to', 'company', Company, 'company_id', 'id'],
['belongs_to', 'block_study', StudiesBlock, 'block_studies_id', 'id'],
['belongs_to', 'block_travel_wish', TravelWishesBlock, 'block_travel_wishes_id', 'id']
];
class FolderWithNestedBlocks extends Model({
table: 'folders',
primary: ['id'],
columns: {
id: 'integer',
type: 'string',
status: 'string',
applicant_id: 'integer',
pme_folder_id: 'integer',
created_at: 'datetime'
},
associations: [
['belongs_to', 'applicant', Applicant, 'applicant_id', 'id'],
['belongs_to', 'pme_folder', PmeFolderWithBlocks, 'pme_folder_id', 'id']
]
}) {}
class PMEFolderWithBlocks extends Model({
table: 'pme_folders_with_blocks',
primary: ['id'],
columns: [
'id',
{ name: 'block_studies_id', type: 'integer' },
{ name: 'block_travel_wishes_id', type: 'integer' },
'professional_activity',
{ name: 'is_initial', type: 'boolean' }
],
associations: () => [
['belongs_to', 'studies', StudiesBlock, 'block_studies_id', 'id'],
['belongs_to', 'travel_wishes', TravelWishesBlock, 'block_travel_wishes_id', 'id']
]
}) {}
class Library extends Model({
table: 'libraries',
primary: ['id'],
columns: {
id: 'integer',
title: 'string',
collection: 'string'
}
}) {}
class BookWithExtraWhere extends Model({
table: 'books',
primary: ['id'],
columns: {
id: 'integer',
code: 'string',
title: 'string',
library_id: 'integer'
},
associations: () => ([
['belongs_to', 'library', Library, 'library_id', 'id', { collection: 'A' }]
])
}) {}
class BookWithMultipleExtraWhere extends Model({
table: 'books_multi',
primary: ['id'],
columns: {
id: 'integer',
title: 'string',
library_id: 'integer'
},
associations: () => ([
['belongs_to', 'library', Library, 'library_id', 'id', { collection: 'A', title: 'Main' }]
])
}) {}
// -------------------------------------------------------
// 1. Unit operators
// -------------------------------------------------------
describe('Unit operators on main table', function() {
it('should generate equality condition', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ status: 'SUBMITTED' });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE `folders`.`status` = ?');
assert.deepStrictEqual(params, ['SUBMITTED']);
});
it('should generate IS NULL', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ applicant_id: null });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE `folders`.`applicant_id` IS NULL');
assert.deepStrictEqual(params, []);
});
it('should generate IN for array values', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ status: ['SUBMITTED', 'VALIDATED'] });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE `folders`.`status` IN (?)');
assert.deepStrictEqual(params, [['SUBMITTED', 'VALIDATED']]);
});
it('should generate FALSE for empty array', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ status: [] });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE FALSE');
assert.deepStrictEqual(params, []);
});
it('should generate explicit $like', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ status: { $like: 'TRANS%' } });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE `folders`.`status` LIKE ?');
assert.deepStrictEqual(params, ['TRANS%']);
});
it('should treat string with % as equality (no implicit LIKE)', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ status: 'TRANS%' });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE `folders`.`status` = ?');
assert.deepStrictEqual(params, ['TRANS%']);
});
it('should generate $between', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ created_at: { $between: ['2024-01-01', '2024-12-31'] } });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE `folders`.`created_at` BETWEEN ? AND ?');
assert.deepStrictEqual(params, ['2024-01-01', '2024-12-31']);
});
it('should generate $gte, $lte, $gt, $lt', () => {
const operators = [
{ op: '$gte', symbol: '>=' },
{ op: '$lte', symbol: '<=' },
{ op: '$gt', symbol: '>' },
{ op: '$lt', symbol: '<' },
];
for (const { op, symbol } of operators) {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ created_at: { [op]: '2024-01-01' } });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, `SELECT COUNT(0) as \`count\` FROM \`folders\` WHERE \`folders\`.\`created_at\` ${symbol} ?`);
assert.deepStrictEqual(params, ['2024-01-01']);
}
});
});
// -------------------------------------------------------
// 2. Logical operators
// -------------------------------------------------------
describe('Logical operators', function() {
it('should generate implicit AND', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ status: 'SUBMITTED', type: 'agp' });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE `folders`.`status` = ? AND `folders`.`type` = ?');
assert.deepStrictEqual(params, ['SUBMITTED', 'agp']);
});
it('should generate explicit $and', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ $and: [{ status: 'SUBMITTED' }, { type: 'agp' }] });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE (`folders`.`status` = ? AND `folders`.`type` = ?)');
assert.deepStrictEqual(params, ['SUBMITTED', 'agp']);
});
it('should generate simple $or', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ $or: [{ applicant_id: null }, { pme_folder_id: null }] });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE (`folders`.`applicant_id` IS NULL OR `folders`.`pme_folder_id` IS NULL)');
assert.deepStrictEqual(params, []);
});
it('should generate $or with sibling condition (implicit AND)', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({
status: 'TRANSMIS',
$or: [{ applicant_id: null }, { pme_folder_id: null }]
});
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE (`folders`.`applicant_id` IS NULL OR `folders`.`pme_folder_id` IS NULL) AND `folders`.`status` = ?');
assert.deepStrictEqual(params, ['TRANSMIS']);
});
it('should generate $or with implicit AND inside one branch', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({
$or: [
{ applicant_id: null },
{ pme_folder_id: null, type: 'agp' }
]
});
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE (`folders`.`applicant_id` IS NULL OR (`folders`.`pme_folder_id` IS NULL AND `folders`.`type` = ?))');
assert.deepStrictEqual(params, ['agp']);
});
it('should generate nested $or / $and at 3 levels', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({
type: 'agp',
$or: [
{ applicant_id: null },
{
$and: [
{ pme_folder_id: null },
{ $or: [
{ status: { $like: 'TRANS%' } },
{ status: 'DRAFT' }
]}
]
}
]
});
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE (`folders`.`applicant_id` IS NULL OR (`folders`.`pme_folder_id` IS NULL AND (`folders`.`status` LIKE ? OR `folders`.`status` = ?))) AND `folders`.`type` = ?');
assert.deepStrictEqual(params, ['TRANS%', 'DRAFT', 'agp']);
});
it('should not produce WHERE clause for empty where({})', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({});
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders`');
assert.deepStrictEqual(params, []);
});
});
// -------------------------------------------------------
// 3. EXISTS joins (verb 'count')
// -------------------------------------------------------
describe('EXISTS joins', function() {
it('should generate 1-level EXISTS', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ status: 'SUBMITTED', 'applicant.last_name': { $like: 'Dupont%' } });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE `folders`.`status` = ? AND EXISTS (SELECT 1 FROM `applicants` WHERE `applicants`.`id` = `folders`.`applicant_id` AND `applicants`.`last_name` LIKE ? )');
assert.deepStrictEqual(params, ['SUBMITTED', 'Dupont%']);
});
it('should group conditions on the same table into one EXISTS', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ 'applicant.last_name': { $like: 'Dupont%' }, 'applicant.email': 'test@test.com' });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE EXISTS (SELECT 1 FROM `applicants` WHERE `applicants`.`id` = `folders`.`applicant_id` AND `applicants`.`last_name` LIKE ? AND `applicants`.`email` = ? )');
assert.deepStrictEqual(params, ['Dupont%', 'test@test.com']);
});
it('should generate 2 separate EXISTS for 2 different joined tables', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ 'applicant.last_name': { $like: 'Dupont%' }, 'pme_folder.status': 'ACTIVE' });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE EXISTS (SELECT 1 FROM `applicants` WHERE `applicants`.`id` = `folders`.`applicant_id` AND `applicants`.`last_name` LIKE ? ) AND EXISTS (SELECT 1 FROM `pme_folders` WHERE `pme_folders`.`id` = `folders`.`pme_folder_id` AND `pme_folders`.`status` = ? )');
assert.deepStrictEqual(params, ['Dupont%', 'ACTIVE']);
});
it('should generate deeply nested EXISTS (3 levels)', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ 'pme_folder.company.country.code': 'FR' });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE EXISTS (SELECT 1 FROM `pme_folders` WHERE `pme_folders`.`id` = `folders`.`pme_folder_id` AND EXISTS (SELECT 1 FROM `companies` WHERE `companies`.`id` = `pme_folders`.`company_id` AND EXISTS (SELECT 1 FROM `countries` WHERE `countries`.`id` = `companies`.`country_id` AND `countries`.`code` = ? ) ) )');
assert.deepStrictEqual(params, ['FR']);
});
it('should generate OR-ed EXISTS for $or with joined table conditions', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({
$or: [
{ 'applicant.last_name': { $like: 'Dupont%' } },
{ 'pme_folder.status': 'ACTIVE' }
]
});
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE (EXISTS (SELECT 1 FROM `applicants` WHERE `applicants`.`id` = `folders`.`applicant_id` AND `applicants`.`last_name` LIKE ?) OR EXISTS (SELECT 1 FROM `pme_folders` WHERE `pme_folders`.`id` = `folders`.`pme_folder_id` AND `pme_folders`.`status` = ?))');
assert.deepStrictEqual(params, ['Dupont%', 'ACTIVE']);
});
it('should include extraWhere in EXISTS clause', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(BookWithExtraWhere));
query.query.verb = 'count';
query.where({ 'library.title': { $like: 'Test%' } });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `books` WHERE EXISTS (SELECT 1 FROM `libraries` WHERE `libraries`.`id` = `books`.`library_id` AND `libraries`.`collection` = ? AND `libraries`.`title` LIKE ? )');
assert.deepStrictEqual(params, ['A', 'Test%']);
});
});
// -------------------------------------------------------
// 4. COUNT and IDS phases (optimizations)
// -------------------------------------------------------
describe('COUNT and IDS phase optimizations', function() {
it('COUNT should have no LEFT JOIN, no ORDER BY, and use EXISTS for filters', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'count';
query.where({ type: 'agp', 'applicant.last_name': { $like: 'Dupont%' } })
.order('applicants.last_name ASC')
.join('applicant');
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `folders` WHERE `folders`.`type` = ? AND EXISTS (SELECT 1 FROM `applicants` WHERE `applicants`.`id` = `folders`.`applicant_id` AND `applicants`.`last_name` LIKE ? )');
assert.deepStrictEqual(params, ['agp', 'Dupont%']);
});
it('IDS should SELECT only id, use EXISTS, ORDER BY + LIMIT, and no LEFT JOIN when sort is on main table', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'select_ids';
query.where({ type: 'agp', 'applicant.last_name': { $like: 'Dupont%' } })
.order('folders.created_at DESC')
.limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `folders`.`id` FROM `folders` WHERE `folders`.`type` = ? AND EXISTS (SELECT 1 FROM `applicants` WHERE `applicants`.`id` = `folders`.`applicant_id` AND `applicants`.`last_name` LIKE ? ) ORDER BY folders.created_at DESC LIMIT ?, ?');
assert.deepStrictEqual(params, ['agp', 'Dupont%', 0, 50]);
});
});
// -------------------------------------------------------
// 5. Sort on joined tables
// -------------------------------------------------------
describe('Sort on joined tables', function() {
it('should add LEFT JOIN when sorting on a joined table column', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'select_ids';
query.where({ type: 'agp' }).order('applicants.last_name ASC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `folders`.`id` FROM `folders` LEFT JOIN `applicants` ON `applicants`.`id` = `folders`.`applicant_id` WHERE `folders`.`type` = ? ORDER BY applicants.last_name ASC LIMIT ?, ?');
assert.deepStrictEqual(params, ['agp', 0, 50]);
});
it('should add cascading LEFT JOINs for nested sort path', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'select_ids';
query.where({ type: 'pme' }).order('pme_folder.company.name ASC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `folders`.`id` FROM `folders` LEFT JOIN `pme_folders` ON `pme_folders`.`id` = `folders`.`pme_folder_id` LEFT JOIN `companies` ON `companies`.`id` = `pme_folders`.`company_id` WHERE `folders`.`type` = ? ORDER BY companies.name ASC LIMIT ?, ?');
assert.deepStrictEqual(params, ['pme', 0, 50]);
});
it('should not add any JOIN when sorting on main table column', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'select_ids';
query.where({ type: 'agp' }).order('folders.created_at DESC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `folders`.`id` FROM `folders` WHERE `folders`.`type` = ? ORDER BY folders.created_at DESC LIMIT ?, ?');
assert.deepStrictEqual(params, ['agp', 0, 50]);
});
it('should transform association name to table name in ORDER BY', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'select_ids';
query.where({ type: 'agp' }).order('pme_folder.company.name ASC').join('pme_folder.company').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `folders`.`id` FROM `folders` LEFT JOIN `pme_folders` ON `pme_folders`.`id` = `folders`.`pme_folder_id` LEFT JOIN `companies` ON `companies`.`id` = `pme_folders`.`company_id` WHERE `folders`.`type` = ? ORDER BY companies.name ASC LIMIT ?, ?');
assert.deepStrictEqual(params, ['agp', 0, 50]);
});
it('should preserve SQL functions (COALESCE, CONCAT, IFNULL) in ORDER BY', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'select_ids';
query.where({ type: 'agp' }).join('applicant')
.order('COALESCE(`applicant`.`last_name`, `applicant`.`first_name`) ASC')
.limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `folders`.`id` FROM `folders` LEFT JOIN `applicants` ON `applicants`.`id` = `folders`.`applicant_id` WHERE `folders`.`type` = ? ORDER BY COALESCE(applicants.last_name, applicants.first_name) ASC LIMIT ?, ?');
assert.deepStrictEqual(params, ['agp', 0, 50]);
});
it('should be idempotent when transforming paths (_transformSinglePath)', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
const sqlGenerator = new PaginatedOptimizedSql(query);
const transformed1 = sqlGenerator._transformSinglePath('applicant.last_name');
const transformed2 = sqlGenerator._transformSinglePath(transformed1);
assert.strictEqual(transformed1, 'applicants.last_name');
assert.strictEqual(transformed1, transformed2);
});
});
// -------------------------------------------------------
// 6. Block tables
// -------------------------------------------------------
describe('Block tables', function() {
it('should add LEFT JOIN and prefix ORDER BY for a block column', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(PMEFolderWithBlocks));
query.query.verb = 'select_ids';
query.where({ is_initial: true }).order('studies_year DESC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `pme_folders_with_blocks`.`id` FROM `pme_folders_with_blocks` LEFT JOIN `block_studies` ON `block_studies`.`id` = `pme_folders_with_blocks`.`block_studies_id` WHERE `pme_folders_with_blocks`.`is_initial` = ? ORDER BY block_studies.studies_year DESC LIMIT ?, ?');
assert.deepStrictEqual(params, [true, 0, 50]);
});
it('should deduplicate LEFT JOINs when multiple columns from the same block', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(PMEFolderWithBlocks));
query.query.verb = 'select_ids';
query.where({ is_initial: true }).order('studies_year DESC').order('bac_year ASC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `pme_folders_with_blocks`.`id` FROM `pme_folders_with_blocks` LEFT JOIN `block_studies` ON `block_studies`.`id` = `pme_folders_with_blocks`.`block_studies_id` WHERE `pme_folders_with_blocks`.`is_initial` = ? ORDER BY block_studies.studies_year DESC, block_studies.bac_year ASC LIMIT ?, ?');
assert.deepStrictEqual(params, [true, 0, 50]);
});
it('should add separate LEFT JOINs for columns from different blocks', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(PMEFolderWithBlocks));
query.query.verb = 'select_ids';
query.where({ is_initial: true }).order('studies_year DESC').order('destination ASC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `pme_folders_with_blocks`.`id` FROM `pme_folders_with_blocks` LEFT JOIN `block_studies` ON `block_studies`.`id` = `pme_folders_with_blocks`.`block_studies_id` LEFT JOIN `block_travel_wishes` ON `block_travel_wishes`.`id` = `pme_folders_with_blocks`.`block_travel_wishes_id` WHERE `pme_folders_with_blocks`.`is_initial` = ? ORDER BY block_studies.studies_year DESC, block_travel_wishes.destination ASC LIMIT ?, ?');
assert.deepStrictEqual(params, [true, 0, 50]);
});
it('should not add JOIN when sorting on a main table column', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(PMEFolderWithBlocks));
query.query.verb = 'select_ids';
query.where({ is_initial: true }).order('professional_activity DESC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `pme_folders_with_blocks`.`id` FROM `pme_folders_with_blocks` WHERE `pme_folders_with_blocks`.`is_initial` = ? ORDER BY professional_activity DESC LIMIT ?, ?');
assert.deepStrictEqual(params, [true, 0, 50]);
});
it('should add LEFT JOIN for unprefixed column found in explicitly joined table', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(Folder));
query.query.verb = 'select_ids';
query.join('applicant');
query.where({ type: 'agp' }).order('first_name ASC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `folders`.`id` FROM `folders` LEFT JOIN `applicants` ON `applicants`.`id` = `folders`.`applicant_id` WHERE `folders`.`type` = ? ORDER BY applicants.first_name ASC LIMIT ?, ?');
assert.deepStrictEqual(params, ['agp', 0, 50]);
});
it('should handle nested path 3 levels (folder -> pme_folder -> block_study)', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(FolderWithNestedBlocks));
query.query.verb = 'select_ids';
query.where({ type: ['agp', 'avt'] }).order('pme_folder.block_study.bac_year DESC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `folders`.`id` FROM `folders` LEFT JOIN `pme_folders` ON `pme_folders`.`id` = `folders`.`pme_folder_id` LEFT JOIN `block_studies` ON `block_studies`.`id` = `pme_folders`.`block_studies_id` WHERE `folders`.`type` IN (?) ORDER BY block_studies.bac_year DESC LIMIT ?, ?');
assert.deepStrictEqual(params, [['agp', 'avt'], 0, 50]);
});
it('should transform nested path correctly for FULL phase (alias vs table name)', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(FolderWithNestedBlocks));
query.where({ type: ['agp', 'avt'] }).order('pme_folder.block_study.bac_year').limit(50);
const sqlGenerator = new PaginatedOptimizedSql(query);
const idsTransform = sqlGenerator._transformOrderClause('pme_folder.block_study.bac_year');
assert.strictEqual(idsTransform, 'block_studies.bac_year');
const fullTransform = sqlGenerator._transformOrderClauseForFullQuery('pme_folder.block_study.bac_year');
assert.strictEqual(fullTransform, 'block_study.bac_year');
const queryBlocks = mockGetDb(new PaginatedOptimizedQuery(PMEFolderWithBlocks));
const sqlGenBlocks = new PaginatedOptimizedSql(queryBlocks);
assert.strictEqual(sqlGenBlocks._transformOrderClauseForFullQuery('studies_year'), 'studies.studies_year');
});
it('should handle COALESCE with block column', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(PMEFolderWithBlocks));
query.query.verb = 'select_ids';
query.where({ is_initial: true }).order('COALESCE(`studies_year`, "N/A") DESC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `pme_folders_with_blocks`.`id` FROM `pme_folders_with_blocks` LEFT JOIN `block_studies` ON `block_studies`.`id` = `pme_folders_with_blocks`.`block_studies_id` WHERE `pme_folders_with_blocks`.`is_initial` = ? ORDER BY COALESCE(block_studies.studies_year, "N/A") DESC LIMIT ?, ?');
assert.deepStrictEqual(params, [true, 0, 50]);
});
});
// -------------------------------------------------------
// 7. extraWhere on associations
// -------------------------------------------------------
describe('extraWhere on associations', function() {
it('should apply extraWhere in LEFT JOIN condition (verb select_ids)', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(BookWithExtraWhere));
query.query.verb = 'select_ids';
query.where({ code: 'ABC' }).order('library.title ASC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `books`.`id` FROM `books` LEFT JOIN `libraries` ON `libraries`.`id` = `books`.`library_id` AND `libraries`.`collection` = ? WHERE `books`.`code` = ? ORDER BY libraries.title ASC LIMIT ?, ?');
assert.deepStrictEqual(params, ['A', 'ABC', 0, 50]);
});
it('should apply extraWhere in both EXISTS and LEFT JOIN when combined', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(BookWithExtraWhere));
query.query.verb = 'select_ids';
query.where({ code: 'ABC', 'library.title': { $like: 'Test%' } }).order('library.title ASC').limit(50);
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT `books`.`id` FROM `books` LEFT JOIN `libraries` ON `libraries`.`id` = `books`.`library_id` AND `libraries`.`collection` = ? WHERE `books`.`code` = ? AND EXISTS (SELECT 1 FROM `libraries` WHERE `libraries`.`id` = `books`.`library_id` AND `libraries`.`collection` = ? AND `libraries`.`title` LIKE ? ) ORDER BY libraries.title ASC LIMIT ?, ?');
assert.deepStrictEqual(params, ['A', 'ABC', 'A', 'Test%', 0, 50]);
});
it('COUNT should not include LEFT JOIN even with extraWhere sort', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(BookWithExtraWhere));
query.query.verb = 'count';
query.where({ code: 'ABC' }).order('library.title ASC');
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `books` WHERE `books`.`code` = ?');
assert.deepStrictEqual(params, ['ABC']);
});
it('should apply multiple extraWhere conditions', () => {
const query = mockGetDb(new PaginatedOptimizedQuery(BookWithMultipleExtraWhere));
query.query.verb = 'count';
query.where({ 'library.title': { $like: 'Test%' } });
const { sql, params } = query.toSQL();
assert.strictEqual(sql, 'SELECT COUNT(0) as `count` FROM `books_multi` WHERE EXISTS (SELECT 1 FROM `libraries` WHERE `libraries`.`id` = `books_multi`.`library_id` AND `libraries`.`collection` = ? AND `libraries`.`title` = ? AND `libraries`.`title` LIKE ? )');
assert.deepStrictEqual(params, ['A', 'Main', 'Test%']);
});
});
});