@iarayan/ch-orm
Version:
A Developer-First ClickHouse ORM with Powerful CLI Tools
261 lines • 8.74 kB
JavaScript
import { Blueprint } from "./Blueprint";
/**
* Schema class for managing database schema
* Used for creating and modifying tables, views, and other database objects
*/
export class Schema {
/**
* Create a new Schema instance
* @param connection - ClickHouse connection
*/
constructor(connection) {
this.connection = connection;
}
/**
* Create a new table
* @param table - Table name
* @param callback - Callback function to define table structure using Blueprint
* @returns Promise that resolves when the table is created
*/
async create(table, callback) {
// Create blueprint for the table
const blueprint = new Blueprint(table);
// Call the callback to set up the blueprint
callback(blueprint);
// Execute the create table SQL
await this.connection.query(blueprint.toSql());
}
/**
* Drop a table
* @param table - Table name
* @param ifExists - Whether to include IF EXISTS in the query
* @returns Promise that resolves when the table is dropped
*/
async drop(table, ifExists = true) {
// Create blueprint for generating drop SQL
const blueprint = new Blueprint(table);
// Execute the drop table SQL
await this.connection.query(blueprint.toDropSql(ifExists));
}
/**
* Drop a table if it exists and create a new one
* @param table - Table name
* @param callback - Callback function to define table structure using Blueprint
* @returns Promise that resolves when the table is recreated
*/
async createOrReplace(table, callback) {
// Drop the table if it exists
await this.drop(table, true);
// Create the table
await this.create(table, callback);
}
/**
* Check if a table exists
* @param table - Table name
* @returns Promise that resolves to true if the table exists, false otherwise
*/
async hasTable(table) {
try {
const result = await this.connection.query(`
SELECT 1
FROM system.tables
WHERE database = currentDatabase()
AND name = '${table}'
`);
return result.data.length > 0;
}
catch (error) {
return false;
}
}
/**
* Get information about a table
* @param table - Table name
* @returns Promise that resolves to table information or null if not found
*/
async getTable(table) {
try {
const result = await this.connection.query(`
SELECT *
FROM system.tables
WHERE database = currentDatabase()
AND name = '${table}'
`);
return result.data.length > 0 ? result.data[0] : null;
}
catch (error) {
return null;
}
}
/**
* Get all columns in a table
* @param table - Table name
* @returns Promise that resolves to array of column information
*/
async getColumns(table) {
try {
const result = await this.connection.query(`
SELECT *
FROM system.columns
WHERE database = currentDatabase()
AND table = '${table}'
`);
return result.data;
}
catch (error) {
return [];
}
}
/**
* Check if a column exists in a table
* @param table - Table name
* @param column - Column name
* @returns Promise that resolves to true if the column exists, false otherwise
*/
async hasColumn(table, column) {
try {
const result = await this.connection.query(`
SELECT 1
FROM system.columns
WHERE database = currentDatabase()
AND table = '${table}'
AND name = '${column}'
`);
return result.data.length > 0;
}
catch (error) {
return false;
}
}
/**
* Create a materialized view
* @param viewName - View name
* @param selectQuery - SELECT query for the view
* @param toTable - Target table (optional)
* @param engine - Engine for the view (if not using TO table)
* @returns Promise that resolves when the view is created
*/
async createMaterializedView(viewName, selectQuery, toTable, engine) {
let sql = `CREATE MATERIALIZED VIEW IF NOT EXISTS ${viewName}`;
// Add engine or TO table
if (toTable) {
sql += ` TO ${toTable}`;
}
else if (engine) {
sql += ` ENGINE = ${engine}`;
}
else {
throw new Error("Either toTable or engine must be provided for materialized view");
}
// Add select query
sql += ` AS ${selectQuery}`;
await this.connection.query(sql);
}
/**
* Drop a materialized view
* @param viewName - View name
* @param ifExists - Whether to include IF EXISTS in the query
* @returns Promise that resolves when the view is dropped
*/
async dropMaterializedView(viewName, ifExists = true) {
const sql = `DROP MATERIALIZED VIEW ${ifExists ? "IF EXISTS" : ""} ${viewName}`;
await this.connection.query(sql);
}
/**
* Create a view
* @param viewName - View name
* @param selectQuery - SELECT query for the view
* @returns Promise that resolves when the view is created
*/
async createView(viewName, selectQuery) {
const sql = `CREATE VIEW IF NOT EXISTS ${viewName} AS ${selectQuery}`;
await this.connection.query(sql);
}
/**
* Drop a view
* @param viewName - View name
* @param ifExists - Whether to include IF EXISTS in the query
* @returns Promise that resolves when the view is dropped
*/
async dropView(viewName, ifExists = true) {
const sql = `DROP VIEW ${ifExists ? "IF EXISTS" : ""} ${viewName}`;
await this.connection.query(sql);
}
/**
* Create a dictionary
* @param dictionaryName - Dictionary name
* @param structure - Dictionary structure
* @param source - Dictionary source
* @param layout - Dictionary layout
* @param lifetime - Dictionary lifetime
* @returns Promise that resolves when the dictionary is created
*/
async createDictionary(dictionaryName, structure, source, layout, lifetime) {
const sql = `
CREATE DICTIONARY IF NOT EXISTS ${dictionaryName}
(
${structure}
)
PRIMARY KEY id
SOURCE(${source})
LAYOUT(${layout})
LIFETIME(${lifetime})
`;
await this.connection.query(sql);
}
/**
* Drop a dictionary
* @param dictionaryName - Dictionary name
* @param ifExists - Whether to include IF EXISTS in the query
* @returns Promise that resolves when the dictionary is dropped
*/
async dropDictionary(dictionaryName, ifExists = true) {
const sql = `DROP DICTIONARY ${ifExists ? "IF EXISTS" : ""} ${dictionaryName}`;
await this.connection.query(sql);
}
/**
* Create a database
* @param databaseName - Database name
* @param ifNotExists - Whether to include IF NOT EXISTS in the query
* @returns Promise that resolves when the database is created
*/
async createDatabase(databaseName, ifNotExists = true) {
const sql = `CREATE DATABASE ${ifNotExists ? "IF NOT EXISTS" : ""} ${databaseName}`;
await this.connection.query(sql);
}
/**
* Drop a database
* @param databaseName - Database name
* @param ifExists - Whether to include IF EXISTS in the query
* @returns Promise that resolves when the database is dropped
*/
async dropDatabase(databaseName, ifExists = true) {
const sql = `DROP DATABASE ${ifExists ? "IF EXISTS" : ""} ${databaseName}`;
await this.connection.query(sql);
}
/**
* Execute raw SQL
* @param sql - SQL query
* @returns Promise that resolves with the query result
*/
async raw(sql) {
return this.connection.query(sql);
}
/**
* Alter a table
* @param table - Table name
* @param callback - Callback function to define table alterations using Blueprint
* @returns Promise that resolves when the table is altered
*/
async alter(table, callback) {
// Create blueprint for the table
const blueprint = new Blueprint(table);
// Set the altering context
blueprint.setAltering(true);
// Call the callback to set up the blueprint
callback(blueprint);
// Execute the alter table SQL
await this.connection.query(blueprint.toAlterSql());
}
}
//# sourceMappingURL=Schema.js.map