@minatojs/sql-utils
Advanced tools
Comparing version 1.1.0 to 2.0.0
import { Dict } from 'cosmokit'; | ||
import { Eval, Field, Model, Query } from '@minatojs/core'; | ||
import { Eval, Field, Model, Modifier, Query, Selection } from '@minatojs/core'; | ||
export * from './utils'; | ||
export declare type QueryOperators = { | ||
@@ -12,10 +13,14 @@ [K in keyof Query.FieldExpr]?: (key: string, value: Query.FieldExpr[K]) => string; | ||
}; | ||
export declare abstract class Builder { | ||
export interface Transformer<S = any, T = any> { | ||
types: Field.Type<S>[]; | ||
dump: (value: S) => T; | ||
load: (value: T, initial?: S) => S; | ||
} | ||
export declare class Builder { | ||
tables: Dict<Model>; | ||
protected types: Dict<Transformer>; | ||
protected createEqualQuery: (key: string, value: any) => string; | ||
protected queryOperators: QueryOperators; | ||
protected evalOperators: EvalOperators; | ||
abstract escapeId(value: any): string; | ||
abstract escape(value: any, table?: string, field?: string): string; | ||
abstract format(sql: string, args?: object | any[]): string; | ||
constructor(); | ||
constructor(tables: Dict<Model>); | ||
protected createNullQuery(key: string, value: boolean): string; | ||
@@ -35,16 +40,10 @@ protected createMemberQuery(key: string, value: any[], notStr?: string): string; | ||
private getRecursive; | ||
parseEval(expr: any, table?: string, field?: string): string; | ||
parseEval(expr: any): string; | ||
suffix(modifier: Modifier): string; | ||
get(sel: Selection.Immutable): any; | ||
define<S, T>(converter: Transformer<S, T>): void; | ||
dump(model: Model, obj: any): any; | ||
load(model: Model, obj: any): any; | ||
escape(value: any, field?: Field): string; | ||
stringify(value: any, field?: Field): any; | ||
} | ||
export interface TypeCaster<S = any, T = any> { | ||
types: Field.Type<S>[]; | ||
dump: (value: S) => T; | ||
load: (value: T, initial?: S) => S; | ||
} | ||
export declare class Caster { | ||
private models; | ||
protected types: Dict<TypeCaster>; | ||
constructor(models: Dict<Model>); | ||
register<S, T>(typeCaster: TypeCaster<S, T>): void; | ||
dump(table: string, obj: any): any; | ||
load(table: string, obj: any): any; | ||
} |
188
lib/index.js
@@ -20,12 +20,67 @@ var __defProp = Object.defineProperty; | ||
// packages/sql-utils/src/index.ts | ||
// minato/packages/sql-utils/src/index.ts | ||
var src_exports = {}; | ||
__export(src_exports, { | ||
Builder: () => Builder, | ||
Caster: () => Caster | ||
escape: () => escape, | ||
escapeId: () => escapeId, | ||
quote: () => quote | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
var import_cosmokit2 = require("cosmokit"); | ||
// minato/packages/sql-utils/src/utils.ts | ||
var import_cosmokit = require("cosmokit"); | ||
var ESCAPE_CHARS_MAP = { | ||
"\0": "\\0", | ||
"\b": "\\b", | ||
" ": "\\t", | ||
"\n": "\\n", | ||
"\r": "\\r", | ||
"": "\\Z", | ||
"'": "\\'", | ||
"\\": "\\\\" | ||
}; | ||
var ESCAPE_CHARS_REGEXP = new RegExp(`[${Object.values(ESCAPE_CHARS_MAP).join("")}]`, "g"); | ||
function escapeId(value) { | ||
return "`" + value + "`"; | ||
} | ||
__name(escapeId, "escapeId"); | ||
function escape(value) { | ||
if ((0, import_cosmokit.isNullable)(value)) | ||
return "NULL"; | ||
switch (typeof value) { | ||
case "boolean": | ||
case "number": | ||
return value + ""; | ||
case "object": | ||
return quote(JSON.stringify(value)); | ||
default: | ||
return quote(value); | ||
} | ||
} | ||
__name(escape, "escape"); | ||
function quote(value) { | ||
let chunkIndex = ESCAPE_CHARS_REGEXP.lastIndex = 0; | ||
let escapedVal = ""; | ||
let match; | ||
while (match = ESCAPE_CHARS_REGEXP.exec(value)) { | ||
escapedVal += value.slice(chunkIndex, match.index) + ESCAPE_CHARS_MAP[match[0]]; | ||
chunkIndex = ESCAPE_CHARS_REGEXP.lastIndex; | ||
} | ||
if (chunkIndex === 0) { | ||
return "'" + value + "'"; | ||
} | ||
if (chunkIndex < value.length) { | ||
return "'" + escapedVal + value.slice(chunkIndex) + "'"; | ||
} | ||
return "'" + escapedVal + "'"; | ||
} | ||
__name(quote, "quote"); | ||
// minato/packages/sql-utils/src/index.ts | ||
var Builder = class { | ||
constructor() { | ||
constructor(tables) { | ||
this.tables = tables; | ||
this.types = {}; | ||
this.createEqualQuery = this.comparator("="); | ||
@@ -68,4 +123,4 @@ this.queryOperators = { | ||
$: (key) => this.getRecursive(key), | ||
$if: (args) => `IF(${args.map((arg) => this.parseEval(arg)).join(", ")})`, | ||
$ifNull: (args) => `IFNULL(${args.map((arg) => this.parseEval(arg)).join(", ")})`, | ||
$if: (args) => `if(${args.map((arg) => this.parseEval(arg)).join(", ")})`, | ||
$ifNull: (args) => `ifnull(${args.map((arg) => this.parseEval(arg)).join(", ")})`, | ||
$add: (args) => `(${args.map((arg) => this.parseEval(arg)).join(" + ")})`, | ||
@@ -107,10 +162,10 @@ $multiply: (args) => `(${args.map((arg) => this.parseEval(arg)).join(" * ")})`, | ||
comparator(operator) { | ||
return function(key, value) { | ||
return (key, value) => { | ||
return `${key} ${operator} ${this.escape(value)}`; | ||
}.bind(this); | ||
}; | ||
} | ||
binary(operator) { | ||
return function([left, right]) { | ||
return ([left, right]) => { | ||
return `(${this.parseEval(left)} ${operator} ${this.parseEval(right)})`; | ||
}.bind(this); | ||
}; | ||
} | ||
@@ -142,3 +197,3 @@ logicalAnd(conditions) { | ||
conditions.push(this.createEqualQuery(key, query)); | ||
} else if ((0, import_cosmokit.isNullable)(query)) { | ||
} else if ((0, import_cosmokit2.isNullable)(query)) { | ||
conditions.push(this.createNullQuery(key, false)); | ||
@@ -166,3 +221,3 @@ } else { | ||
} else { | ||
conditions.push(this.parseFieldQuery(this.escapeId(key), query[key])); | ||
conditions.push(this.parseFieldQuery(escapeId(key), query[key])); | ||
} | ||
@@ -172,3 +227,3 @@ } | ||
} | ||
parseEvalExpr(expr, table, field) { | ||
parseEvalExpr(expr) { | ||
for (const key in expr) { | ||
@@ -179,3 +234,3 @@ if (key in this.evalOperators) { | ||
} | ||
return this.escape(expr, table, field); | ||
return this.escape(expr); | ||
} | ||
@@ -189,58 +244,107 @@ parseAggr(expr) { | ||
getRecursive(args) { | ||
var _a; | ||
if (typeof args === "string") { | ||
return this.getRecursive(["_", args]); | ||
} else { | ||
const [, key] = args; | ||
if (!key.includes(".")) | ||
return this.escapeId(key); | ||
const [field, ...rest] = key.split("."); | ||
return `json_unquote(json_extract(${this.escapeId(field)}, '$${rest.map((key2) => `."${key2}"`).join("")}'))`; | ||
const [table, key] = args; | ||
const fields = ((_a = this.tables[table]) == null ? void 0 : _a.fields) || {}; | ||
if (key in fields || !key.includes(".")) | ||
return escapeId(key); | ||
const field = Object.keys(fields).find((k) => key.startsWith(k + ".")) || key.split(".")[0]; | ||
const rest = key.slice(field.length + 1).split("."); | ||
return `json_unquote(json_extract(${escapeId(field)}, '$${rest.map((key2) => `."${key2}"`).join("")}'))`; | ||
} | ||
} | ||
parseEval(expr, table, field) { | ||
parseEval(expr) { | ||
if (typeof expr === "string" || typeof expr === "number" || typeof expr === "boolean" || expr instanceof Date) { | ||
return this.escape(expr, table, field); | ||
return this.escape(expr); | ||
} | ||
return this.parseEvalExpr(expr, table, field); | ||
return this.parseEvalExpr(expr); | ||
} | ||
}; | ||
__name(Builder, "Builder"); | ||
var Caster = class { | ||
constructor(models) { | ||
this.models = models; | ||
this.types = /* @__PURE__ */ Object.create(null); | ||
suffix(modifier) { | ||
const { limit, offset, sort, group, having } = modifier; | ||
let sql = ""; | ||
if (group.length) { | ||
sql += ` GROUP BY ${group.map(escapeId).join(", ")}`; | ||
const filter = this.parseEval(having); | ||
if (filter !== "1") | ||
sql += ` HAVING ${filter}`; | ||
} | ||
if (sort.length) { | ||
sql += " ORDER BY " + sort.map(([expr, dir]) => { | ||
return `${this.parseEval(expr)} ${dir.toUpperCase()}`; | ||
}).join(", "); | ||
} | ||
if (limit < Infinity) | ||
sql += " LIMIT " + limit; | ||
if (offset > 0) | ||
sql += " OFFSET " + offset; | ||
return sql; | ||
} | ||
register(typeCaster) { | ||
typeCaster.types.forEach((type) => this.types[type] = typeCaster); | ||
get(sel) { | ||
const { args, table, query, ref } = sel; | ||
const filter = this.parseQuery(query); | ||
if (filter === "0") | ||
return; | ||
const { fields } = args[0]; | ||
const keys = !fields ? "*" : Object.entries(fields).map(([key, value]) => { | ||
key = escapeId(key); | ||
value = this.parseEval(value); | ||
return key === value ? key : `${value} AS ${key}`; | ||
}).join(", "); | ||
let prefix = `SELECT ${keys} FROM `; | ||
let suffix = this.suffix(args[0]); | ||
if (filter !== "1") { | ||
suffix = ` WHERE ${filter}` + suffix; | ||
} | ||
if (typeof table === "string") { | ||
prefix += escapeId(table); | ||
} else { | ||
const inner = this.get(table); | ||
if (!inner) | ||
return; | ||
if (!fields && !suffix) | ||
return inner; | ||
prefix += `(${inner})`; | ||
} | ||
return `${prefix} ${ref}${suffix}`; | ||
} | ||
dump(table, obj) { | ||
var _a; | ||
obj = this.models[table].format(obj); | ||
const { fields } = this.models[table]; | ||
define(converter) { | ||
converter.types.forEach((type) => this.types[type] = converter); | ||
} | ||
dump(model, obj) { | ||
obj = model.format(obj); | ||
const result = {}; | ||
for (const key in obj) { | ||
const converter = this.types[(_a = fields[key]) == null ? void 0 : _a.type]; | ||
result[key] = converter ? converter.dump(obj[key]) : obj[key]; | ||
result[key] = this.stringify(obj[key], model.fields[key]); | ||
} | ||
return result; | ||
} | ||
load(table, obj) { | ||
const { fields } = this.models[table]; | ||
load(model, obj) { | ||
const result = {}; | ||
for (const key in obj) { | ||
if (!(key in fields)) | ||
if (!(key in model.fields)) | ||
continue; | ||
const { type, initial } = fields[key]; | ||
const { type, initial } = model.fields[key]; | ||
const converter = this.types[type]; | ||
result[key] = converter ? converter.load(obj[key], initial) : obj[key]; | ||
} | ||
return this.models[table].parse(result); | ||
return model.parse(result); | ||
} | ||
escape(value, field) { | ||
return escape(this.stringify(value, field)); | ||
} | ||
stringify(value, field) { | ||
const converter = this.types[field == null ? void 0 : field.type]; | ||
return converter ? converter.dump(value) : value; | ||
} | ||
}; | ||
__name(Caster, "Caster"); | ||
__name(Builder, "Builder"); | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
Builder, | ||
Caster | ||
escape, | ||
escapeId, | ||
quote | ||
}); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@minatojs/sql-utils", | ||
"version": "1.1.0", | ||
"version": "2.0.0", | ||
"description": "SQL Utilities for Minato", | ||
@@ -32,7 +32,7 @@ "main": "lib/index.js", | ||
"peerDependencies": { | ||
"@minatojs/core": "^1.3.0" | ||
"@minatojs/core": "^2.0.0" | ||
}, | ||
"dependencies": { | ||
"cosmokit": "^1.2.1" | ||
"cosmokit": "^1.3.3" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
36176
6
389
+ Added@minatojs/core@2.9.0(transitive)
- Removed@minatojs/core@1.3.2(transitive)
Updatedcosmokit@^1.3.3