@pangza/orm 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +2 -2
  2. package/dist/BaseMapper.d.ts +112 -0
  3. package/dist/BaseMapper.d.ts.map +1 -0
  4. package/dist/BaseMapper.js +653 -0
  5. package/dist/BaseMapper.js.map +1 -0
  6. package/dist/DataSource.d.ts +61 -0
  7. package/dist/DataSource.d.ts.map +1 -0
  8. package/dist/DataSource.js +350 -0
  9. package/dist/DataSource.js.map +1 -0
  10. package/dist/Db.d.ts +67 -0
  11. package/dist/Db.d.ts.map +1 -0
  12. package/dist/Db.js +222 -0
  13. package/dist/Db.js.map +1 -0
  14. package/dist/IdType.d.ts +22 -0
  15. package/dist/IdType.d.ts.map +1 -0
  16. package/dist/IdType.js +34 -0
  17. package/dist/IdType.js.map +1 -0
  18. package/dist/QueryWrapper.d.ts +110 -0
  19. package/dist/QueryWrapper.d.ts.map +1 -0
  20. package/dist/QueryWrapper.js +343 -0
  21. package/dist/QueryWrapper.js.map +1 -0
  22. package/dist/config.d.ts +12 -0
  23. package/dist/config.d.ts.map +1 -0
  24. package/dist/config.js +80 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/dialect.d.ts +41 -0
  27. package/dist/dialect.d.ts.map +1 -0
  28. package/dist/dialect.js +171 -0
  29. package/dist/dialect.js.map +1 -0
  30. package/dist/enable.d.ts +12 -0
  31. package/dist/enable.d.ts.map +1 -0
  32. package/dist/enable.js +31 -0
  33. package/dist/enable.js.map +1 -0
  34. package/dist/entityDecorators.d.ts +77 -0
  35. package/dist/entityDecorators.d.ts.map +1 -0
  36. package/dist/entityDecorators.js +150 -0
  37. package/dist/entityDecorators.js.map +1 -0
  38. package/dist/errors.d.ts +11 -0
  39. package/dist/errors.d.ts.map +1 -0
  40. package/dist/errors.js +22 -0
  41. package/dist/errors.js.map +1 -0
  42. package/dist/fieldSelect.d.ts +49 -0
  43. package/dist/fieldSelect.d.ts.map +1 -0
  44. package/dist/fieldSelect.js +53 -0
  45. package/dist/fieldSelect.js.map +1 -0
  46. package/dist/fill.d.ts +8 -0
  47. package/dist/fill.d.ts.map +1 -0
  48. package/dist/fill.js +47 -0
  49. package/dist/fill.js.map +1 -0
  50. package/dist/flag.d.ts +2 -0
  51. package/dist/flag.d.ts.map +1 -0
  52. package/dist/flag.js +8 -0
  53. package/dist/flag.js.map +1 -0
  54. package/dist/hydrate.d.ts +38 -0
  55. package/dist/hydrate.d.ts.map +1 -0
  56. package/dist/hydrate.js +325 -0
  57. package/dist/hydrate.js.map +1 -0
  58. package/dist/identifier.d.ts +14 -0
  59. package/dist/identifier.d.ts.map +1 -0
  60. package/dist/identifier.js +51 -0
  61. package/dist/identifier.js.map +1 -0
  62. package/dist/index.d.ts +41 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +122 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/relation.d.ts +72 -0
  67. package/dist/relation.d.ts.map +1 -0
  68. package/dist/relation.js +150 -0
  69. package/dist/relation.js.map +1 -0
  70. package/dist/resultMap.d.ts +7 -0
  71. package/dist/resultMap.d.ts.map +1 -0
  72. package/dist/resultMap.js +25 -0
  73. package/dist/resultMap.js.map +1 -0
  74. package/dist/security.d.ts +16 -0
  75. package/dist/security.d.ts.map +1 -0
  76. package/dist/security.js +50 -0
  77. package/dist/security.js.map +1 -0
  78. package/dist/sqlDecorators.d.ts +60 -0
  79. package/dist/sqlDecorators.d.ts.map +1 -0
  80. package/dist/sqlDecorators.js +147 -0
  81. package/dist/sqlDecorators.js.map +1 -0
  82. package/dist/sqlLog.d.ts +30 -0
  83. package/dist/sqlLog.d.ts.map +1 -0
  84. package/dist/sqlLog.js +183 -0
  85. package/dist/sqlLog.js.map +1 -0
  86. package/dist/sqlTemplate.d.ts +38 -0
  87. package/dist/sqlTemplate.d.ts.map +1 -0
  88. package/dist/sqlTemplate.js +112 -0
  89. package/dist/sqlTemplate.js.map +1 -0
  90. package/dist/table.d.ts +17 -0
  91. package/dist/table.d.ts.map +1 -0
  92. package/dist/table.js +55 -0
  93. package/dist/table.js.map +1 -0
  94. package/dist/tableSearch.d.ts +72 -0
  95. package/dist/tableSearch.d.ts.map +1 -0
  96. package/dist/tableSearch.js +232 -0
  97. package/dist/tableSearch.js.map +1 -0
  98. package/dist/transactional.d.ts +27 -0
  99. package/dist/transactional.d.ts.map +1 -0
  100. package/dist/transactional.js +57 -0
  101. package/dist/transactional.js.map +1 -0
  102. package/dist/types.d.ts +155 -0
  103. package/dist/types.d.ts.map +1 -0
  104. package/dist/types.js +3 -0
  105. package/dist/types.js.map +1 -0
  106. package/dist/xml/MapperXml.d.ts +24 -0
  107. package/dist/xml/MapperXml.d.ts.map +1 -0
  108. package/dist/xml/MapperXml.js +92 -0
  109. package/dist/xml/MapperXml.js.map +1 -0
  110. package/dist/xml/execute.d.ts +12 -0
  111. package/dist/xml/execute.d.ts.map +1 -0
  112. package/dist/xml/execute.js +54 -0
  113. package/dist/xml/execute.js.map +1 -0
  114. package/dist/xml/index.d.ts +11 -0
  115. package/dist/xml/index.d.ts.map +1 -0
  116. package/dist/xml/index.js +29 -0
  117. package/dist/xml/index.js.map +1 -0
  118. package/dist/xml/loadMappers.d.ts +14 -0
  119. package/dist/xml/loadMappers.d.ts.map +1 -0
  120. package/dist/xml/loadMappers.js +171 -0
  121. package/dist/xml/loadMappers.js.map +1 -0
  122. package/dist/xml/parseMapperXml.d.ts +6 -0
  123. package/dist/xml/parseMapperXml.d.ts.map +1 -0
  124. package/dist/xml/parseMapperXml.js +225 -0
  125. package/dist/xml/parseMapperXml.js.map +1 -0
  126. package/dist/xml/registry.d.ts +15 -0
  127. package/dist/xml/registry.d.ts.map +1 -0
  128. package/dist/xml/registry.js +57 -0
  129. package/dist/xml/registry.js.map +1 -0
  130. package/dist/xml/renderSql.d.ts +6 -0
  131. package/dist/xml/renderSql.d.ts.map +1 -0
  132. package/dist/xml/renderSql.js +187 -0
  133. package/dist/xml/renderSql.js.map +1 -0
  134. package/dist/xml/types.d.ts +52 -0
  135. package/dist/xml/types.d.ts.map +1 -0
  136. package/dist/xml/types.js +3 -0
  137. package/dist/xml/types.js.map +1 -0
  138. package/dist/xml/xmlMapper.d.ts +16 -0
  139. package/dist/xml/xmlMapper.d.ts.map +1 -0
  140. package/dist/xml/xmlMapper.js +49 -0
  141. package/dist/xml/xmlMapper.js.map +1 -0
  142. package/package.json +35 -4
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Delete = exports.Update = exports.Insert = exports.MAPPER_ENTITY_KEY = void 0;
7
+ exports.Param = Param;
8
+ exports.Select = Select;
9
+ require("reflect-metadata");
10
+ const Db_1 = __importDefault(require("./Db"));
11
+ const fieldSelect_1 = require("./fieldSelect");
12
+ const resultMap_1 = require("./resultMap");
13
+ const sqlTemplate_1 = require("./sqlTemplate");
14
+ const PARAM_NAMES_KEY = Symbol.for("pangza.orm.sqlParamNames");
15
+ /** Mapper 类上挂的实体(供方法级 @Select 结果自动填充字段 @Select) */
16
+ exports.MAPPER_ENTITY_KEY = Symbol.for("pangza.orm.mapperEntity");
17
+ function resolveDatasource(options) {
18
+ if (options?.datasource?.trim()) {
19
+ return options.datasource.trim();
20
+ }
21
+ if (options?.db) {
22
+ return Db_1.default.findByType(options.db);
23
+ }
24
+ return "default";
25
+ }
26
+ function getNamedParams(target, methodName) {
27
+ return (Reflect.getOwnMetadata(PARAM_NAMES_KEY, target, methodName) ?? {});
28
+ }
29
+ /**
30
+ * @Param("id")
31
+ * 为方法参数命名,供 SQL 中 #{id} / ${id} 引用。
32
+ */
33
+ function Param(name) {
34
+ return (target, propertyKey, parameterIndex) => {
35
+ if (propertyKey === undefined)
36
+ return;
37
+ const key = String(name).trim();
38
+ if (!key) {
39
+ throw new Error("@Param 名称不能为空");
40
+ }
41
+ const map = {
42
+ ...getNamedParams(target, propertyKey),
43
+ [parameterIndex]: key,
44
+ };
45
+ Reflect.defineMetadata(PARAM_NAMES_KEY, map, target, propertyKey);
46
+ };
47
+ }
48
+ function createSqlMethodDecorator(kind) {
49
+ return (sql, options) => {
50
+ if (!sql || !String(sql).trim()) {
51
+ throw new Error(`@${kind[0].toUpperCase()}${kind.slice(1)} SQL 不能为空`);
52
+ }
53
+ const template = String(sql);
54
+ const datasource = resolveDatasource(options);
55
+ return (target, propertyKey, descriptor) => {
56
+ const methodName = String(propertyKey);
57
+ const named = () => getNamedParams(target, propertyKey);
58
+ const executor = async function (...args) {
59
+ const ctx = (0, sqlTemplate_1.buildParamContext)(args, named());
60
+ const parsed = (0, sqlTemplate_1.parseMybatisSql)(template, ctx);
61
+ const result = await Db_1.default.queryOn(datasource, parsed.sql, parsed.params);
62
+ if (kind === "select") {
63
+ // 方法级 @Select 常用于批量查询,不自动填字段 @Select,避免 N+1。
64
+ // 需要时:hydrateFieldSelects(Entity, rows, { datasource })
65
+ return (0, resultMap_1.mapResultRows)(result ?? []);
66
+ }
67
+ const dialect = Db_1.default.getDialect(datasource);
68
+ if (kind === "insert") {
69
+ // 自定义 INSERT 若含 RETURNING / OUTPUT,优先取第一行第一列
70
+ if (Array.isArray(result) && result[0] && typeof result[0] === "object") {
71
+ const row = result[0];
72
+ const first = Object.values(row)[0];
73
+ if (first != null)
74
+ return Number(first);
75
+ }
76
+ return dialect.extractInsertId(result, "id", false);
77
+ }
78
+ return dialect.extractAffectedRows(result);
79
+ };
80
+ executor[Symbol.for("pangza.orm.sqlBound")] = kind;
81
+ if (descriptor) {
82
+ descriptor.value = executor;
83
+ return descriptor;
84
+ }
85
+ Object.defineProperty(target, methodName, {
86
+ value: executor,
87
+ writable: true,
88
+ configurable: true,
89
+ });
90
+ };
91
+ };
92
+ }
93
+ /**
94
+ * @Select — 方法装饰器或字段装饰器。
95
+ *
96
+ * 方法:执行 SQL,返回行数组。
97
+ * 字段:查询结果映射到该属性(父行字段可用 #{id} / #{parentId} 等引用)。
98
+ *
99
+ * @example
100
+ * @Select("SELECT * FROM user WHERE id = #{id}")
101
+ * findById(@Param("id") id: string) {}
102
+ *
103
+ * @Select('SELECT * FROM "user" WHERE id = #{id}', { db: "postgresql" })
104
+ * findOnPg(@Param("id") id: string) {}
105
+ *
106
+ * @Select("SELECT * FROM menu WHERE parent_id = #{id}", { many: true })
107
+ * children?: Menu[];
108
+ */
109
+ function Select(sql, options) {
110
+ const template = String(sql ?? "").trim();
111
+ if (!template) {
112
+ throw new Error("@Select SQL 不能为空");
113
+ }
114
+ return ((target, propertyKey, descriptor) => {
115
+ // 方法装饰器:descriptor.value 为函数
116
+ if (propertyKey !== undefined &&
117
+ descriptor &&
118
+ typeof descriptor.value === "function") {
119
+ return createSqlMethodDecorator("select")(template, options)(target, propertyKey, descriptor);
120
+ }
121
+ // 属性装饰器
122
+ if (propertyKey === undefined) {
123
+ throw new Error("@Select 不能用于类");
124
+ }
125
+ const ctor = target.constructor;
126
+ (0, fieldSelect_1.registerFieldSelect)(ctor, String(propertyKey), template, options);
127
+ });
128
+ }
129
+ /**
130
+ * @Insert("INSERT INTO user(name) VALUES(#{name})")
131
+ * 返回 insertId;PostgreSQL / SQL Server 建议在 SQL 中写 RETURNING / OUTPUT。
132
+ *
133
+ * @example
134
+ * @Insert("INSERT INTO user(name) VALUES(#{name})", { datasource: "pg" })
135
+ */
136
+ exports.Insert = createSqlMethodDecorator("insert");
137
+ /**
138
+ * @Update("UPDATE user SET name = #{name} WHERE id = #{id}")
139
+ * 返回 affectedRows。
140
+ */
141
+ exports.Update = createSqlMethodDecorator("update");
142
+ /**
143
+ * @Delete("DELETE FROM user WHERE id = #{id}")
144
+ * 返回 affectedRows(物理删除;逻辑删除请用 BaseMapper.delete*)。
145
+ */
146
+ exports.Delete = createSqlMethodDecorator("delete");
147
+ //# sourceMappingURL=sqlDecorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlDecorators.js","sourceRoot":"","sources":["../src/sqlDecorators.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { SqlLogFormatFn, SqlLogInfo, SqlLogParts } from "./types";
2
+ declare const DEFAULT_FORMAT = "{time} [{type}] {cost}ms | {sql} | params={params}";
3
+ export interface SqlLogRuntime {
4
+ enabled: boolean;
5
+ /** 占位符模板,或自定义函数 */
6
+ format: string | SqlLogFormatFn;
7
+ /** 控制输出哪些片段(模板里对应占位符为空时跳过) */
8
+ parts: Required<SqlLogParts>;
9
+ /** pino 级别 */
10
+ level: "trace" | "debug" | "info" | "warn";
11
+ }
12
+ export declare function getSqlLogRuntime(): SqlLogRuntime;
13
+ export declare function configureSqlLog(patch?: Partial<{
14
+ enabled: boolean;
15
+ format: string | SqlLogFormatFn;
16
+ parts: SqlLogParts;
17
+ level: SqlLogRuntime["level"];
18
+ }>): void;
19
+ /** 从 SQL 推断类型:SELECT / INSERT / UPDATE / DELETE / OTHER */
20
+ export declare function detectSqlType(sql: string): string;
21
+ /**
22
+ * 默认模板替换。
23
+ * 占位符:{time} {type} {sql} {params} {cost}
24
+ * 若某 part 关闭,对应占位符替换为空,并清理多余分隔符。
25
+ */
26
+ export declare function renderSqlLog(info: SqlLogInfo, format?: string | SqlLogFormatFn, parts?: Required<SqlLogParts>): string;
27
+ /** 执行前后包装:记录耗时并按配置输出 */
28
+ export declare function withSqlLog<T>(sql: string, params: unknown[], run: () => Promise<T>): Promise<T>;
29
+ export { DEFAULT_FORMAT as DEFAULT_SQL_LOG_FORMAT };
30
+ //# sourceMappingURL=sqlLog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlLog.d.ts","sourceRoot":"","sources":["../src/sqlLog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAIvE,QAAA,MAAM,cAAc,uDACkC,CAAC;AAUvD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB;IACnB,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC;IAChC,8BAA8B;IAC9B,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC7B,cAAc;IACd,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;CAC5C;AASD,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,wBAAgB,eAAe,CAC7B,KAAK,GAAE,OAAO,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC;IAChC,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B,CAAM,GACN,IAAI,CAON;AAED,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQjD;AA0DD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,MAAM,GAAG,cAA+B,EAChD,KAAK,GAAE,QAAQ,CAAC,WAAW,CAAiB,GAC3C,MAAM,CAmCR;AAED,wBAAwB;AACxB,wBAAsB,UAAU,CAAC,CAAC,EAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,OAAO,EAAE,EACjB,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACpB,OAAO,CAAC,CAAC,CAAC,CAuDZ;AAED,OAAO,EAAE,cAAc,IAAI,sBAAsB,EAAE,CAAC"}
package/dist/sqlLog.js ADDED
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_SQL_LOG_FORMAT = void 0;
4
+ exports.getSqlLogRuntime = getSqlLogRuntime;
5
+ exports.configureSqlLog = configureSqlLog;
6
+ exports.detectSqlType = detectSqlType;
7
+ exports.renderSqlLog = renderSqlLog;
8
+ exports.withSqlLog = withSqlLog;
9
+ const Logger_1 = require("@pangza/core/Logger");
10
+ const log = (0, Logger_1.getLogger)("ORM.SQL");
11
+ const DEFAULT_FORMAT = "{time} [{type}] {cost}ms | {sql} | params={params}";
12
+ exports.DEFAULT_SQL_LOG_FORMAT = DEFAULT_FORMAT;
13
+ const DEFAULT_PARTS = {
14
+ time: true,
15
+ type: true,
16
+ sql: true,
17
+ params: true,
18
+ cost: true,
19
+ };
20
+ let runtime = {
21
+ enabled: false,
22
+ format: DEFAULT_FORMAT,
23
+ parts: { ...DEFAULT_PARTS },
24
+ level: "info",
25
+ };
26
+ function getSqlLogRuntime() {
27
+ return runtime;
28
+ }
29
+ function configureSqlLog(patch = {}) {
30
+ runtime = {
31
+ enabled: patch.enabled ?? runtime.enabled,
32
+ format: patch.format ?? runtime.format,
33
+ parts: { ...runtime.parts, ...(patch.parts ?? {}) },
34
+ level: patch.level ?? runtime.level,
35
+ };
36
+ }
37
+ /** 从 SQL 推断类型:SELECT / INSERT / UPDATE / DELETE / OTHER */
38
+ function detectSqlType(sql) {
39
+ const m = String(sql)
40
+ .trim()
41
+ .match(/^(WITH|SELECT|INSERT|UPDATE|DELETE|REPLACE|CALL|SHOW|DESCRIBE|EXPLAIN|SET|BEGIN|COMMIT|ROLLBACK)\b/i);
42
+ if (!m)
43
+ return "OTHER";
44
+ const raw = m[1].toUpperCase();
45
+ if (raw === "WITH")
46
+ return "SELECT";
47
+ return raw;
48
+ }
49
+ function formatTime(date) {
50
+ const pad = (n, len = 2) => String(n).padStart(len, "0");
51
+ return (`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +
52
+ `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.` +
53
+ `${pad(date.getMilliseconds(), 3)}`);
54
+ }
55
+ /** 日志参数脱敏:键名含这些片段时替换为 *** */
56
+ const SENSITIVE_KEY_RE = /password|passwd|pwd|secret|token|authorization|credential|private.?key|access.?key/i;
57
+ function walkRedact(value, key) {
58
+ if (key && SENSITIVE_KEY_RE.test(key))
59
+ return "***";
60
+ if (typeof value === "bigint")
61
+ return value.toString();
62
+ if (value instanceof Date)
63
+ return value.toISOString();
64
+ if (Buffer.isBuffer(value))
65
+ return `<Buffer ${value.length}b>`;
66
+ if (Array.isArray(value)) {
67
+ return value.map((item, i) => walkRedact(item, String(i)));
68
+ }
69
+ if (value !== null && typeof value === "object") {
70
+ const out = {};
71
+ for (const [k, v] of Object.entries(value)) {
72
+ out[k] = walkRedact(v, k);
73
+ }
74
+ return out;
75
+ }
76
+ return value;
77
+ }
78
+ function safeParams(params) {
79
+ try {
80
+ return JSON.stringify(params.map((p) => walkRedact(p)));
81
+ }
82
+ catch {
83
+ return String(params);
84
+ }
85
+ }
86
+ function compactSql(sql) {
87
+ return String(sql).replace(/\s+/g, " ").trim();
88
+ }
89
+ function applyParts(info, parts) {
90
+ return {
91
+ time: parts.time ? info.time : "",
92
+ type: parts.type ? info.type : "",
93
+ sql: parts.sql ? info.sql : "",
94
+ params: parts.params ? info.paramsText : "",
95
+ cost: parts.cost ? String(info.cost) : "",
96
+ };
97
+ }
98
+ /**
99
+ * 默认模板替换。
100
+ * 占位符:{time} {type} {sql} {params} {cost}
101
+ * 若某 part 关闭,对应占位符替换为空,并清理多余分隔符。
102
+ */
103
+ function renderSqlLog(info, format = runtime.format, parts = runtime.parts) {
104
+ if (typeof format === "function") {
105
+ return format(info);
106
+ }
107
+ const values = applyParts(info, parts);
108
+ let out = String(format).replace(/\{(time|type|sql|params|cost)\}/g, (_m, key) => values[key] ?? "");
109
+ // 清理因关闭某段产生的空标签 / 多余分隔
110
+ out = out
111
+ .replace(/\bparams=\s*(?=\||$)/gi, "")
112
+ .replace(/\s*\|\s*\|/g, " |")
113
+ .replace(/\[\s*\]/g, "")
114
+ .replace(/\s{2,}/g, " ")
115
+ .replace(/\s+\|/g, " |")
116
+ .replace(/\|\s+/g, "| ")
117
+ .replace(/^\s*\|\s*/, "")
118
+ .replace(/\s*\|\s*$/, "")
119
+ .trim();
120
+ // 默认模板 `{cost}ms`:cost 关闭时去掉孤立 ms
121
+ if (!parts.cost) {
122
+ out = out
123
+ .replace(/(^|\|\s*)ms(\s*\||$)/g, "$1$2")
124
+ .replace(/\s+ms$/g, "")
125
+ .replace(/\s*\|\s*\|/g, " |")
126
+ .replace(/^\s*\|\s*/, "")
127
+ .replace(/\s*\|\s*$/, "")
128
+ .trim();
129
+ }
130
+ return out;
131
+ }
132
+ /** 执行前后包装:记录耗时并按配置输出 */
133
+ async function withSqlLog(sql, params, run) {
134
+ if (!runtime.enabled) {
135
+ return run();
136
+ }
137
+ const startedAt = Date.now();
138
+ const startDate = new Date(startedAt);
139
+ try {
140
+ const result = await run();
141
+ const cost = Date.now() - startedAt;
142
+ const info = {
143
+ time: formatTime(startDate),
144
+ type: detectSqlType(sql),
145
+ sql: compactSql(sql),
146
+ params,
147
+ paramsText: safeParams(params),
148
+ cost,
149
+ error: false,
150
+ };
151
+ const message = renderSqlLog(info);
152
+ // 结构化字段 + 消息,避免仅依赖 msg 在部分终端丢编码
153
+ log[runtime.level]({
154
+ sqlType: info.type,
155
+ cost: info.cost,
156
+ sql: info.sql,
157
+ params: info.params,
158
+ }, message);
159
+ return result;
160
+ }
161
+ catch (err) {
162
+ const cost = Date.now() - startedAt;
163
+ const info = {
164
+ time: formatTime(startDate),
165
+ type: detectSqlType(sql),
166
+ sql: compactSql(sql),
167
+ params,
168
+ paramsText: safeParams(params),
169
+ cost,
170
+ error: true,
171
+ };
172
+ const message = renderSqlLog(info);
173
+ log.error({
174
+ err,
175
+ sqlType: info.type,
176
+ cost: info.cost,
177
+ sql: info.sql,
178
+ params: info.params,
179
+ }, message);
180
+ throw err;
181
+ }
182
+ }
183
+ //# sourceMappingURL=sqlLog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlLog.js","sourceRoot":"","sources":["../src/sqlLog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * MyBatis 风格 SQL 模板:
3
+ * - #{name} → ? 占位 + 参数绑定(防注入)
4
+ * - ${name} → 字符串直接替换(仅用于可信标识符等,勿接用户输入)
5
+ * - 支持 #{id, jdbcType=INTEGER} 形式(忽略逗号后选项)
6
+ */
7
+ export interface ParsedSql {
8
+ sql: string;
9
+ params: unknown[];
10
+ }
11
+ declare function isPlainObject(value: unknown): value is Record<string, unknown>;
12
+ /** 从对象取 a.b.c 路径 */
13
+ export declare function getPath(root: unknown, path: string): unknown;
14
+ /**
15
+ * 从方法实参构建命名参数表(对齐 MyBatis 常用约定):
16
+ * - @Param("x") 标注的名字
17
+ * - param1 / param2 ...(从 1 起)
18
+ * - arg0 / arg1 ...
19
+ * - 单参数且为对象:展开其字段
20
+ * - 单参数原始值:任意 #{name} 都映射到该值
21
+ */
22
+ export declare function buildParamContext(args: unknown[], namedByIndex?: Record<number, string>): Record<string, unknown>;
23
+ export interface ParseSqlOptions {
24
+ /**
25
+ * 为 true 时不打印 `${}` 告警(仍做危险字符校验)。
26
+ * 仅用于框架内部已知安全的模板。
27
+ */
28
+ silenceDollarWarn?: boolean;
29
+ }
30
+ /**
31
+ * 解析含 #{} / ${} 的 SQL。
32
+ * 按出现顺序处理;${} 直接拼进 SQL,#{} 变为 ? 并收集 params。
33
+ *
34
+ * 安全:优先使用 `#{}`。`${}` 仅用于可信标识符;含 `;`/`--`/引号/SQL 关键字等会抛错,并默认打告警。
35
+ */
36
+ export declare function parseMybatisSql(template: string, ctx: Record<string, unknown>, options?: ParseSqlOptions): ParsedSql;
37
+ export { isPlainObject };
38
+ //# sourceMappingURL=sqlTemplate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlTemplate.d.ts","sourceRoot":"","sources":["../src/sqlTemplate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB;AAID,iBAAS,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQvE;AAED,oBAAoB;AACpB,wBAAgB,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAS5D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EAAE,EACf,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACxC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBzB;AAgCD,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,CAAC,EAAE,eAAe,GACxB,SAAS,CA6BX;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ /**
3
+ * MyBatis 风格 SQL 模板:
4
+ * - #{name} → ? 占位 + 参数绑定(防注入)
5
+ * - ${name} → 字符串直接替换(仅用于可信标识符等,勿接用户输入)
6
+ * - 支持 #{id, jdbcType=INTEGER} 形式(忽略逗号后选项)
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getPath = getPath;
10
+ exports.buildParamContext = buildParamContext;
11
+ exports.parseMybatisSql = parseMybatisSql;
12
+ exports.isPlainObject = isPlainObject;
13
+ const PLACEHOLDER_RE = /([#$])\{([^}]+)\}/g;
14
+ function isPlainObject(value) {
15
+ return (value !== null &&
16
+ typeof value === "object" &&
17
+ !Array.isArray(value) &&
18
+ !(value instanceof Date) &&
19
+ !(value instanceof Buffer));
20
+ }
21
+ /** 从对象取 a.b.c 路径 */
22
+ function getPath(root, path) {
23
+ if (!path)
24
+ return undefined;
25
+ const parts = path.split(".").map((p) => p.trim()).filter(Boolean);
26
+ let cur = root;
27
+ for (const part of parts) {
28
+ if (cur == null || typeof cur !== "object")
29
+ return undefined;
30
+ cur = cur[part];
31
+ }
32
+ return cur;
33
+ }
34
+ /**
35
+ * 从方法实参构建命名参数表(对齐 MyBatis 常用约定):
36
+ * - @Param("x") 标注的名字
37
+ * - param1 / param2 ...(从 1 起)
38
+ * - arg0 / arg1 ...
39
+ * - 单参数且为对象:展开其字段
40
+ * - 单参数原始值:任意 #{name} 都映射到该值
41
+ */
42
+ function buildParamContext(args, namedByIndex = {}) {
43
+ const ctx = {};
44
+ args.forEach((arg, i) => {
45
+ ctx[`param${i + 1}`] = arg;
46
+ ctx[`arg${i}`] = arg;
47
+ const named = namedByIndex[i];
48
+ if (named)
49
+ ctx[named] = arg;
50
+ });
51
+ if (args.length === 1) {
52
+ const only = args[0];
53
+ if (isPlainObject(only)) {
54
+ Object.assign(ctx, only);
55
+ }
56
+ else {
57
+ ctx.__single__ = only;
58
+ }
59
+ }
60
+ return ctx;
61
+ }
62
+ function resolveExpr(ctx, rawExpr) {
63
+ // #{id, jdbcType=INTEGER} → id
64
+ const key = rawExpr.split(",")[0].trim();
65
+ if (!key) {
66
+ throw new Error("SQL 占位符名不能为空");
67
+ }
68
+ if (Object.prototype.hasOwnProperty.call(ctx, key)) {
69
+ return ctx[key];
70
+ }
71
+ const nested = getPath(ctx, key);
72
+ if (nested !== undefined) {
73
+ return nested;
74
+ }
75
+ if (Object.prototype.hasOwnProperty.call(ctx, "__single__")) {
76
+ return ctx.__single__;
77
+ }
78
+ throw new Error(`[SQL] 找不到参数: ${key}`);
79
+ }
80
+ /** ${} 危险片段:拒绝拼进 SQL */
81
+ const DOLLAR_UNSAFE_RE = /;|--|\/\*|\*\/|'|"|\\|\b(union|select|insert|update|delete|drop|alter|exec|execute)\b/i;
82
+ let dollarWarnCount = 0;
83
+ /**
84
+ * 解析含 #{} / ${} 的 SQL。
85
+ * 按出现顺序处理;${} 直接拼进 SQL,#{} 变为 ? 并收集 params。
86
+ *
87
+ * 安全:优先使用 `#{}`。`${}` 仅用于可信标识符;含 `;`/`--`/引号/SQL 关键字等会抛错,并默认打告警。
88
+ */
89
+ function parseMybatisSql(template, ctx, options) {
90
+ const params = [];
91
+ const sql = String(template).replace(PLACEHOLDER_RE, (_whole, kind, expr) => {
92
+ const value = resolveExpr(ctx, expr);
93
+ if (kind === "$") {
94
+ if (value === undefined || value === null) {
95
+ throw new Error(`[SQL] \${${expr.trim()}} 的值不能为空`);
96
+ }
97
+ const text = String(value);
98
+ if (DOLLAR_UNSAFE_RE.test(text)) {
99
+ throw new Error(`[SQL] \${${expr.trim()}} 的值含有危险字符或关键字,已拒绝。请改用 #{} 参数绑定,或仅传入可信标识符`);
100
+ }
101
+ if (!options?.silenceDollarWarn && dollarWarnCount < 20) {
102
+ dollarWarnCount += 1;
103
+ console.warn(`[ORM] SQL 使用了 \${${expr.trim()}} 字符串拼接,存在注入风险;仅可用于可信表名/列名。优先改用 #{}。`);
104
+ }
105
+ return text;
106
+ }
107
+ params.push(value);
108
+ return "?";
109
+ });
110
+ return { sql, params };
111
+ }
112
+ //# sourceMappingURL=sqlTemplate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlTemplate.js","sourceRoot":"","sources":["../src/sqlTemplate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { BaseMapper } from "./BaseMapper";
2
+ import type { MapperOptions, MapperTableOptions } from "./types";
3
+ declare function normalizeOptions(tableName: string, idFieldOrOptions?: string | MapperTableOptions): MapperOptions;
4
+ /**
5
+ * 获取表对应的 BaseMapper(单例缓存)
6
+ *
7
+ * @example
8
+ * await table('user').selectById(1)
9
+ * await table('user', { logicDelete: true }).selectList()
10
+ */
11
+ export declare function table<T extends Record<string, any> = Record<string, any>>(tableName: string, idFieldOrOptions?: string | MapperTableOptions): BaseMapper<T>;
12
+ /** 清除 Mapper 缓存(一般仅测试用;改全局 ORM 配置后可调用) */
13
+ export declare function clearTableCache(): void;
14
+ /** useTable 别名,语义更贴近 hooks 风格 */
15
+ export declare const useTable: typeof table;
16
+ export { normalizeOptions };
17
+ //# sourceMappingURL=table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../src/table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAKjE,iBAAS,gBAAgB,CACvB,SAAS,EAAE,MAAM,EACjB,gBAAgB,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAC7C,aAAa,CAKf;AAmBD;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACvE,SAAS,EAAE,MAAM,EACjB,gBAAgB,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAC7C,UAAU,CAAC,CAAC,CAAC,CASf;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED,iCAAiC;AACjC,eAAO,MAAM,QAAQ,cAAQ,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
package/dist/table.js ADDED
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useTable = void 0;
4
+ exports.table = table;
5
+ exports.clearTableCache = clearTableCache;
6
+ exports.normalizeOptions = normalizeOptions;
7
+ const BaseMapper_1 = require("./BaseMapper");
8
+ /** 按表配置缓存 Mapper,避免重复 new */
9
+ const mapperCache = new Map();
10
+ function normalizeOptions(tableName, idFieldOrOptions) {
11
+ if (typeof idFieldOrOptions === "string" || idFieldOrOptions === undefined) {
12
+ return { table: tableName, idField: idFieldOrOptions ?? "id" };
13
+ }
14
+ return { table: tableName, idField: "id", ...idFieldOrOptions };
15
+ }
16
+ function cacheKey(options) {
17
+ return JSON.stringify({
18
+ table: options.table,
19
+ idField: options.idField ?? "id",
20
+ datasource: options.datasource ?? "default",
21
+ logicDelete: options.logicDelete ?? null,
22
+ logicDeleteField: options.logicDeleteField ?? null,
23
+ logicDeleteValue: options.logicDeleteValue ?? null,
24
+ logicNotDeleteValue: options.logicNotDeleteValue ?? null,
25
+ optimisticLock: options.optimisticLock ?? null,
26
+ versionField: options.versionField ?? null,
27
+ fill: options.fill ?? null,
28
+ updateNullStrategy: options.updateNullStrategy ?? null,
29
+ entity: options.entity?.name ?? null,
30
+ });
31
+ }
32
+ /**
33
+ * 获取表对应的 BaseMapper(单例缓存)
34
+ *
35
+ * @example
36
+ * await table('user').selectById(1)
37
+ * await table('user', { logicDelete: true }).selectList()
38
+ */
39
+ function table(tableName, idFieldOrOptions) {
40
+ const options = normalizeOptions(tableName, idFieldOrOptions);
41
+ const key = cacheKey(options);
42
+ let mapper = mapperCache.get(key);
43
+ if (!mapper) {
44
+ mapper = new BaseMapper_1.BaseMapper(options);
45
+ mapperCache.set(key, mapper);
46
+ }
47
+ return mapper;
48
+ }
49
+ /** 清除 Mapper 缓存(一般仅测试用;改全局 ORM 配置后可调用) */
50
+ function clearTableCache() {
51
+ mapperCache.clear();
52
+ }
53
+ /** useTable 别名,语义更贴近 hooks 风格 */
54
+ exports.useTable = table;
55
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.js","sourceRoot":"","sources":["../src/table.ts"],"names":[],"mappings":";;;AAwCA,sBAYC;AAGD,0CAEC;AAKQ,4CAAgB;AA9DzB,6CAA0C;AAG1C,6BAA6B;AAC7B,MAAM,WAAW,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEvD,SAAS,gBAAgB,CACvB,SAAiB,EACjB,gBAA8C;IAE9C,IAAI,OAAO,gBAAgB,KAAK,QAAQ,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;QAC3E,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,IAAI,IAAI,EAAE,CAAC;IACjE,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,gBAAgB,EAAE,CAAC;AAClE,CAAC;AAED,SAAS,QAAQ,CAAC,OAAsB;IACtC,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,SAAS;QAC3C,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;QACxC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,IAAI;QAClD,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,IAAI;QAClD,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,IAAI,IAAI;QACxD,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI;QAC9C,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,IAAI;QAC1C,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI;QAC1B,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,IAAI,IAAI;QACtD,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI;KACrC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,KAAK,CACnB,SAAiB,EACjB,gBAA8C;IAE9C,MAAM,OAAO,GAAG,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC9B,IAAI,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAA8B,CAAC;IAC/D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,IAAI,uBAAU,CAAI,OAAO,CAAC,CAAC;QACpC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,0CAA0C;AAC1C,SAAgB,eAAe;IAC7B,WAAW,CAAC,KAAK,EAAE,CAAC;AACtB,CAAC;AAED,iCAAiC;AACpB,QAAA,QAAQ,GAAG,KAAK,CAAC"}