artmapper
Version:
A simple and intuitive ORM for Node.js with TypeScript and JavaScript support
248 lines • 8.04 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueryBuilder = void 0;
class QueryBuilder {
constructor(definition, databaseType) {
this.definition = definition;
this.databaseType = databaseType;
}
/**
* Build SELECT query
*/
buildSelect(options) {
const { select, where, orderBy, limit, offset } = options || {};
const params = [];
let sql = 'SELECT ';
// Select fields
if (select && select.length > 0) {
sql += select.map(field => this.quoteField(field)).join(', ');
}
else {
sql += '*';
}
sql += ` FROM ${this.quoteTable(this.definition.table)}`;
// WHERE clause
if (where) {
const whereClause = this.buildWhereClause(where, params);
if (whereClause) {
sql += ` WHERE ${whereClause}`;
}
}
// ORDER BY
if (orderBy) {
sql += this.buildOrderByClause(orderBy);
}
// LIMIT and OFFSET
if (limit) {
sql += ` LIMIT ${limit}`;
if (offset) {
sql += ` OFFSET ${offset}`;
}
}
return { sql, params };
}
/**
* Build INSERT query
*/
buildInsert(data) {
const fields = Object.keys(data);
const values = Object.values(data);
const placeholders = this.getPlaceholders(fields.length);
const sql = `INSERT INTO ${this.quoteTable(this.definition.table)} (${fields.map(field => this.quoteField(field)).join(', ')}) VALUES (${placeholders})`;
return { sql, params: values };
}
/**
* Build UPDATE query
*/
buildUpdate(id, data) {
const params = [];
const setClause = Object.keys(data)
.map(field => `${this.quoteField(field)} = ${this.getPlaceholder()}`)
.join(', ');
params.push(...Object.values(data));
params.push(id);
const sql = `UPDATE ${this.quoteTable(this.definition.table)} SET ${setClause} WHERE ${this.quoteField('id')} = ${this.getPlaceholder()}`;
return { sql, params };
}
/**
* Build DELETE query
*/
buildDelete(id) {
const sql = `DELETE FROM ${this.quoteTable(this.definition.table)} WHERE ${this.quoteField('id')} = ${this.getPlaceholder()}`;
return { sql, params: [id] };
}
/**
* Build COUNT query
*/
buildCount(options) {
const { where } = options || {};
const params = [];
let sql = `SELECT COUNT(*) as count FROM ${this.quoteTable(this.definition.table)}`;
if (where) {
const whereClause = this.buildWhereClause(where, params);
if (whereClause) {
sql += ` WHERE ${whereClause}`;
}
}
return { sql, params };
}
/**
* Build CREATE TABLE query
*/
buildCreateTable() {
const fields = Object.entries(this.definition.fields)
.map(([name, field]) => this.buildFieldDefinition(name, field))
.join(',\n ');
return `CREATE TABLE IF NOT EXISTS ${this.quoteTable(this.definition.table)} (\n ${fields}\n)`;
}
/**
* Build DROP TABLE query
*/
buildDropTable() {
return `DROP TABLE IF EXISTS ${this.quoteTable(this.definition.table)}`;
}
/**
* Build WHERE clause
*/
buildWhereClause(where, params) {
const conditions = [];
for (const [field, value] of Object.entries(where)) {
if (value === null) {
conditions.push(`${this.quoteField(field)} IS NULL`);
}
else {
conditions.push(`${this.quoteField(field)} = ${this.getPlaceholder()}`);
params.push(value);
}
}
return conditions.join(' AND ');
}
/**
* Build ORDER BY clause
*/
buildOrderByClause(orderBy) {
const clauses = Object.entries(orderBy)
.map(([field, direction]) => `${this.quoteField(field)} ${direction}`)
.join(', ');
return ` ORDER BY ${clauses}`;
}
/**
* Build field definition for CREATE TABLE
*/
buildFieldDefinition(name, field) {
let definition = `${this.quoteField(name)} ${this.mapFieldType(field.type)}`;
if (field.length) {
definition += `(${field.length})`;
}
if (!field.nullable || field.notNull) {
definition += ' NOT NULL';
}
if (field.unique) {
definition += ' UNIQUE';
}
if (field.primary || field.primaryKey) {
definition += ' PRIMARY KEY';
}
if (field.autoIncrement) {
// SQLite uses AUTOINCREMENT, others use AUTO_INCREMENT
if (this.databaseType === 'sqlite') {
definition += ' AUTOINCREMENT';
}
else {
definition += ' AUTO_INCREMENT';
}
}
if (field.default !== undefined) {
definition += ` DEFAULT ${this.quoteValue(field.default)}`;
}
return definition;
}
/**
* Map field type to database-specific type
*/
mapFieldType(type) {
const typeMap = {
'string': this.databaseType === 'sqlite' ? 'TEXT' : 'VARCHAR',
'text': 'TEXT',
'int': this.databaseType === 'sqlite' ? 'INTEGER' : 'INT',
'integer': this.databaseType === 'sqlite' ? 'INTEGER' : 'INT',
'bigint': this.databaseType === 'sqlite' ? 'INTEGER' : 'BIGINT',
'float': this.databaseType === 'sqlite' ? 'REAL' : 'FLOAT',
'double': this.databaseType === 'sqlite' ? 'REAL' : 'DOUBLE',
'decimal': this.databaseType === 'sqlite' ? 'REAL' : 'DECIMAL',
'boolean': this.databaseType === 'sqlite' ? 'INTEGER' : 'BOOLEAN',
'datetime': this.databaseType === 'sqlite' ? 'TEXT' : 'DATETIME',
'timestamp': this.databaseType === 'sqlite' ? 'TEXT' : 'TIMESTAMP',
'date': this.databaseType === 'sqlite' ? 'TEXT' : 'DATE',
'json': this.databaseType === 'sqlite' ? 'TEXT' : 'JSON'
};
return typeMap[type.toLowerCase()] || type.toUpperCase();
}
/**
* Get placeholders for parameterized queries
*/
getPlaceholders(count) {
switch (this.databaseType) {
case 'postgresql':
return Array.from({ length: count }, (_, i) => `$${i + 1}`).join(', ');
case 'mysql':
case 'sqlite':
default:
return Array.from({ length: count }, () => '?').join(', ');
}
}
/**
* Get single placeholder
*/
getPlaceholder() {
switch (this.databaseType) {
case 'postgresql':
return '$1';
case 'mysql':
case 'sqlite':
default:
return '?';
}
}
/**
* Quote table name
*/
quoteTable(table) {
switch (this.databaseType) {
case 'postgresql':
return `"${table}"`;
case 'mysql':
return `\`${table}\``;
case 'sqlite':
return `"${table}"`;
default:
return table;
}
}
/**
* Quote field name
*/
quoteField(field) {
switch (this.databaseType) {
case 'postgresql':
return `"${field}"`;
case 'mysql':
return `\`${field}\``;
case 'sqlite':
return `"${field}"`;
default:
return field;
}
}
/**
* Quote value for default
*/
quoteValue(value) {
if (typeof value === 'string') {
return `'${value.replace(/'/g, "''")}'`;
}
return String(value);
}
}
exports.QueryBuilder = QueryBuilder;
//# sourceMappingURL=query.js.map