059 inmem full join with spec
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
component {
|
||||
|
||||
/**
|
||||
* HSQL 1.8
|
||||
* Принимает Lucee Query, создает в HSQL временную таблицу и льет в нее данные
|
||||
* @name Имя таблицы, которое ты хочешь использовать в SQL
|
||||
* @data Сам запрос (результат queryExecute или cfhttp)
|
||||
* @dsn Имя datasource для HSQL (по умолчанию "inmem")
|
||||
*/
|
||||
public string function register(required string name, required query data, string dsn = "inmem") {
|
||||
var cols = arguments.data.columnList;
|
||||
var meta = getMetaData(arguments.data);
|
||||
|
||||
//writedump(meta);
|
||||
var colDefs = [];
|
||||
var colTypes = {};
|
||||
var params = [];
|
||||
|
||||
// 1. Генерируем "CREATE TEMP TABLE name (col1 TYPE, col2 TYPE...)"
|
||||
for (var i = 1; i <= arrayLen(meta); i++) {
|
||||
var colName = meta[i].name;
|
||||
// Маппинг типов Lucee -> типы H2
|
||||
var dbType = mapType(meta[i].typeName);
|
||||
arrayAppend(colDefs, "#colName# #dbType#");
|
||||
colTypes[colName] = meta[i].typeName;
|
||||
}
|
||||
//writedump(colDefs);
|
||||
//var checkSql = "SELECT * FROM INFORMATION_SCHEMA.SYSTEM_TABLES WHERE TABLE_NAME = '#ucase(arguments.name)#';"
|
||||
//var res = queryExecute(checkSql, {}, { datasource: arguments.dsn });
|
||||
|
||||
//if (res.recordCount EQ 0) {
|
||||
var createSql = "DROP TABLE IF EXISTS #arguments.name#;
|
||||
CREATE TEMPORARY TABLE #arguments.name#(#arrayToList(colDefs, ', ')#) ON COMMIT PRESERVE ROWS";
|
||||
queryExecute(createSql, {}, { datasource: arguments.dsn });
|
||||
//}
|
||||
|
||||
// 2. Цикл вставки
|
||||
var insertSql = "INSERT INTO #arguments.name# (#cols#) VALUES (#repeatString("?,", listLen(cols)-1)#?)";
|
||||
|
||||
for (var row in arguments.data) {
|
||||
var rowData = [];
|
||||
for (var col in cols) {
|
||||
|
||||
arrayAppend(rowData, formatValue(row[col], colTypes[col]));
|
||||
}
|
||||
|
||||
queryExecute(insertSql, rowData, { datasource: arguments.dsn });
|
||||
}
|
||||
|
||||
return arguments.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удалить временные таблицы (опционально, база сама почистит при закрытии коннекта)
|
||||
*/
|
||||
public void function drop(required string names, string dsn = "inmem") {
|
||||
var list = arguments.names;
|
||||
if (!isArray(list)) list = [list];
|
||||
for (var name in list) {
|
||||
queryExecute("DROP TABLE IF EXISTS #name#", {}, { datasource: arguments.dsn });
|
||||
}
|
||||
}
|
||||
|
||||
// --- Вспомогательная функция маппинга типов ---
|
||||
private string function mapType(required string luceeType) {
|
||||
switch (arguments.luceeType) {
|
||||
case "VARCHAR": case "CHAR": case "LONGVARCHAR": return "LONGVARCHAR";
|
||||
case "INTEGER": case "BIGINT": case "SMALLINT": case "TINYINT": return "INT";
|
||||
case "DOUBLE": case "FLOAT": case "REAL": return "DOUBLE";
|
||||
case "BOOLEAN": case "BIT": return "BIT";
|
||||
case "DECIMAL": case "NUMERIC": return "DECIMAL(20,6)";
|
||||
default: return "LONGVARCHAR"; // И тут тоже
|
||||
}
|
||||
}
|
||||
|
||||
private function formatValue(required any val, required string targetType) {
|
||||
var isTextType = listFindNoCase("VARCHAR,CHAR,LONGVARCHAR", arguments.targetType);
|
||||
|
||||
// 1. Обработка пустых значений
|
||||
if (isNull(arguments.val) || (isSimpleValue(arguments.val) && len(trim(arguments.val)) == 0)) {
|
||||
// Если это текстовое поле — сохраняем пустую строку как есть
|
||||
if (isTextType) {
|
||||
return "";
|
||||
}
|
||||
// Для чисел, дат и булев — отдаем настоящий SQL NULL
|
||||
return javaCast("null", "");
|
||||
}
|
||||
|
||||
// 2. Форматирование непустых дат
|
||||
if (listFindNoCase("DATE,TIMESTAMP,TIME", arguments.targetType)) {
|
||||
return dateFormat(arguments.val, "yyyy-mm-dd") & " " & timeFormat(arguments.val, "HH:mm:ss");
|
||||
}
|
||||
|
||||
// 3. Числа и непустой текст отдаем как есть
|
||||
return arguments.val;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user