@rawsql-ts/sql-contract 0.1.0 → 0.2.0

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.
@@ -0,0 +1,377 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CatalogExecutionError = exports.ContractViolationError = exports.BinderError = exports.RewriterError = exports.SQLLoaderError = exports.CatalogError = void 0;
4
+ exports.createCatalogExecutor = createCatalogExecutor;
5
+ const mapper_1 = require("../mapper");
6
+ let execIdCounter = 0;
7
+ function createExecId() {
8
+ execIdCounter += 1;
9
+ return `catalog-exec-${Date.now()}-${execIdCounter}`;
10
+ }
11
+ /**
12
+ * Root error class for catalog execution failures.
13
+ */
14
+ class CatalogError extends Error {
15
+ constructor(message, specId, cause) {
16
+ super(message);
17
+ this.name = this.constructor.name;
18
+ this.specId = specId;
19
+ this.cause = cause;
20
+ Object.setPrototypeOf(this, new.target.prototype);
21
+ }
22
+ }
23
+ exports.CatalogError = CatalogError;
24
+ /** Wraps failures encountered while loading catalog SQL assets. */
25
+ class SQLLoaderError extends CatalogError {
26
+ }
27
+ exports.SQLLoaderError = SQLLoaderError;
28
+ /** Wraps failures thrown by catalog rewriters. */
29
+ class RewriterError extends CatalogError {
30
+ }
31
+ exports.RewriterError = RewriterError;
32
+ /** Wraps binder failures or invalid binder output. */
33
+ class BinderError extends CatalogError {
34
+ }
35
+ exports.BinderError = BinderError;
36
+ /** Captures violations of the declared query/catalog contract before hitting the executor. */
37
+ class ContractViolationError extends CatalogError {
38
+ }
39
+ exports.ContractViolationError = ContractViolationError;
40
+ /** Wraps failures from the query executor or result shaping.
41
+ * Contract violations must throw `ContractViolationError` instead so observability
42
+ * can consistently classify them as `contract`.
43
+ */
44
+ class CatalogExecutionError extends CatalogError {
45
+ }
46
+ exports.CatalogExecutionError = CatalogExecutionError;
47
+ function assertPositionalParams(specId, params) {
48
+ if (!Array.isArray(params)) {
49
+ throw new ContractViolationError(`Spec "${specId}" expects positional parameters.`, specId);
50
+ }
51
+ return params;
52
+ }
53
+ function isPlainObject(value) {
54
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
55
+ return false;
56
+ }
57
+ const proto = Object.getPrototypeOf(value);
58
+ // Accept `{}`-like objects and those created via Object.create(null).
59
+ return proto === Object.prototype || proto === null;
60
+ }
61
+ function assertNamedParams(specId, params) {
62
+ if (!isPlainObject(params)) {
63
+ throw new ContractViolationError(`Spec "${specId}" expects named parameters.`, specId);
64
+ }
65
+ return params;
66
+ }
67
+ function assertParamsShape(specId, expectedShape, params) {
68
+ if (expectedShape === 'positional') {
69
+ return assertPositionalParams(specId, params);
70
+ }
71
+ return assertNamedParams(specId, params);
72
+ }
73
+ /**
74
+ * Creates a CatalogExecutor that enforces the QuerySpec contract and applies
75
+ * optional rewriters and binders before delegating to the target query executor.
76
+ */
77
+ function createCatalogExecutor(options) {
78
+ var _a, _b, _c, _d, _e;
79
+ const cache = (_a = options.sqlCache) !== null && _a !== void 0 ? _a : new Map();
80
+ const rewriters = (_b = options.rewriters) !== null && _b !== void 0 ? _b : [];
81
+ const binders = (_c = options.binders) !== null && _c !== void 0 ? _c : [];
82
+ const allowNamedWithoutBinder = (_d = options.allowNamedParamsWithoutBinder) !== null && _d !== void 0 ? _d : false;
83
+ const extensions = (_e = options.extensions) !== null && _e !== void 0 ? _e : [];
84
+ const sink = options.observabilitySink;
85
+ async function loadSql(spec) {
86
+ const cached = cache.get(spec.sqlFile);
87
+ if (cached !== undefined) {
88
+ return cached;
89
+ }
90
+ try {
91
+ const sql = await options.loader.load(spec.sqlFile);
92
+ cache.set(spec.sqlFile, sql);
93
+ return sql;
94
+ }
95
+ catch (cause) {
96
+ throw new SQLLoaderError(`Failed to load SQL file "${spec.sqlFile}".`, spec.id, cause);
97
+ }
98
+ }
99
+ function normalizeToQueryParams(value, specId) {
100
+ if (Array.isArray(value)) {
101
+ return value;
102
+ }
103
+ if (isPlainObject(value)) {
104
+ return value;
105
+ }
106
+ throw new ContractViolationError(`Parameters must be positional or named (array or record).`, specId);
107
+ }
108
+ function applyRewriters(spec, sql, params, options) {
109
+ let currentSql = sql;
110
+ let currentParams = params;
111
+ for (const rewriter of rewriters) {
112
+ try {
113
+ const rewritten = rewriter.rewrite({
114
+ specId: spec.id,
115
+ spec,
116
+ sql: currentSql,
117
+ params: currentParams,
118
+ options,
119
+ });
120
+ currentSql = rewritten.sql;
121
+ currentParams = rewritten.params;
122
+ }
123
+ catch (cause) {
124
+ throw new RewriterError(`Rewriter "${rewriter.name}" failed for spec "${spec.id}".`, spec.id, cause);
125
+ }
126
+ }
127
+ return {
128
+ sql: currentSql,
129
+ params: currentParams,
130
+ };
131
+ }
132
+ function applyBinders(spec, sql, params) {
133
+ if (binders.length === 0) {
134
+ return { binderUsed: false, sql, params };
135
+ }
136
+ let currentSql = sql;
137
+ let currentParams = params;
138
+ for (const binder of binders) {
139
+ try {
140
+ const bound = binder.bind({
141
+ specId: spec.id,
142
+ sql: currentSql,
143
+ params: normalizeToQueryParams(currentParams, spec.id),
144
+ });
145
+ if (!Array.isArray(bound.params)) {
146
+ throw new BinderError(`Binder "${binder.name}" returned invalid params for spec "${spec.id}".`, spec.id);
147
+ }
148
+ currentSql = bound.sql;
149
+ currentParams = bound.params;
150
+ }
151
+ catch (cause) {
152
+ if (cause instanceof CatalogError) {
153
+ throw cause;
154
+ }
155
+ throw new BinderError(`Binder "${binder.name}" failed for spec "${spec.id}".`, spec.id, cause);
156
+ }
157
+ }
158
+ if (!Array.isArray(currentParams)) {
159
+ throw new BinderError(`Binder chain did not produce positional params for spec "${spec.id}".`, spec.id);
160
+ }
161
+ return {
162
+ binderUsed: true,
163
+ sql: currentSql,
164
+ params: currentParams,
165
+ };
166
+ }
167
+ function describeParamsShape(params) {
168
+ if (Array.isArray(params)) {
169
+ return 'positional';
170
+ }
171
+ if (isPlainObject(params)) {
172
+ return 'named';
173
+ }
174
+ return 'unknown';
175
+ }
176
+ function createSqlPreview(sql) {
177
+ const maxLength = 2048;
178
+ return sql.length <= maxLength ? sql : sql.slice(0, maxLength);
179
+ }
180
+ function getErrorKind(error) {
181
+ if (error instanceof CatalogExecutionError) {
182
+ return 'db';
183
+ }
184
+ if (error instanceof CatalogError) {
185
+ return 'contract';
186
+ }
187
+ return 'unknown';
188
+ }
189
+ function emitQueryStartEvent(spec, execId, attempt, snapshot) {
190
+ if (!sink) {
191
+ return;
192
+ }
193
+ sink.emit({
194
+ kind: 'query_start',
195
+ specId: spec.id,
196
+ sqlFile: spec.sqlFile,
197
+ execId,
198
+ attempt,
199
+ timeMs: snapshot.startTime,
200
+ attributes: spec.tags,
201
+ sqlPreview: createSqlPreview(snapshot.sql),
202
+ paramsShape: snapshot.paramsShape,
203
+ });
204
+ }
205
+ function emitQueryEndEvent(spec, execId, attempt, baseStartTime, rowCount) {
206
+ if (!sink) {
207
+ return;
208
+ }
209
+ const now = Date.now();
210
+ sink.emit({
211
+ kind: 'query_end',
212
+ specId: spec.id,
213
+ sqlFile: spec.sqlFile,
214
+ execId,
215
+ attempt,
216
+ timeMs: now,
217
+ attributes: spec.tags,
218
+ durationMs: Math.max(now - baseStartTime, 0),
219
+ rowCount,
220
+ });
221
+ }
222
+ function emitQueryErrorEvent(spec, execId, attempt, baseStartTime, error) {
223
+ if (!sink) {
224
+ return;
225
+ }
226
+ const now = Date.now();
227
+ sink.emit({
228
+ kind: 'query_error',
229
+ specId: spec.id,
230
+ sqlFile: spec.sqlFile,
231
+ execId,
232
+ attempt,
233
+ timeMs: now,
234
+ attributes: spec.tags,
235
+ durationMs: Math.max(now - baseStartTime, 0),
236
+ errorKind: getErrorKind(error),
237
+ errorMessage: error instanceof Error ? error.message : String(error !== null && error !== void 0 ? error : 'unknown'),
238
+ });
239
+ }
240
+ async function executeRows(spec, params, executionOptions, execId, attempt) {
241
+ const validatedParams = assertParamsShape(spec.id, spec.params.shape, params);
242
+ const sql = await loadSql(spec);
243
+ const rewritten = applyRewriters(spec, sql, validatedParams, executionOptions);
244
+ const rewrittenParams = assertParamsShape(spec.id, spec.params.shape, rewritten.params);
245
+ assertNamedAllowed(spec, binders, allowNamedWithoutBinder);
246
+ const bound = applyBinders(spec, rewritten.sql, rewrittenParams);
247
+ const paramsShape = describeParamsShape(bound.params);
248
+ const snapshot = {
249
+ sql: bound.sql,
250
+ params: bound.params,
251
+ paramsShape,
252
+ startTime: Date.now(),
253
+ };
254
+ emitQueryStartEvent(spec, execId, attempt, snapshot);
255
+ try {
256
+ const rows = await options.executor(bound.sql, bound.params);
257
+ return { rows, snapshot };
258
+ }
259
+ catch (cause) {
260
+ throw new CatalogExecutionError(`Query executor failed while processing catalog spec "${spec.id}".`, spec.id, cause);
261
+ }
262
+ }
263
+ function createPipelineExec(spec, finalize) {
264
+ return async (input) => {
265
+ var _a, _b;
266
+ const invocationStart = Date.now();
267
+ let snapshot;
268
+ try {
269
+ const { rows, snapshot: rowSnapshot } = await executeRows(spec, input.params, input.options, input.execId, input.attempt);
270
+ snapshot = rowSnapshot;
271
+ const value = finalize(rows);
272
+ const durationBase = (_a = snapshot === null || snapshot === void 0 ? void 0 : snapshot.startTime) !== null && _a !== void 0 ? _a : invocationStart;
273
+ // durationMs reflects the executor round-trip after loading/rewriting/binding SQL.
274
+ emitQueryEndEvent(spec, input.execId, input.attempt, durationBase, rows.length);
275
+ return { value, rowCount: rows.length };
276
+ }
277
+ catch (error) {
278
+ const durationBase = (_b = snapshot === null || snapshot === void 0 ? void 0 : snapshot.startTime) !== null && _b !== void 0 ? _b : invocationStart;
279
+ emitQueryErrorEvent(spec, input.execId, input.attempt, durationBase, error);
280
+ throw error;
281
+ }
282
+ };
283
+ }
284
+ function wrapWithExtensions(core) {
285
+ return extensions.reduceRight((next, extension) => extension.wrap(next), core);
286
+ }
287
+ function applyOutputTransformation(spec, rows) {
288
+ const mappedRows = spec.output.mapping
289
+ ? (0, mapper_1.mapRows)(rows, spec.output.mapping)
290
+ : rows;
291
+ const decode = spec.output.validate;
292
+ if (!decode) {
293
+ return mappedRows;
294
+ }
295
+ // The decoder/validator runs after mapping so it receives the mapped DTO.
296
+ return mappedRows.map((value) => decode(value));
297
+ }
298
+ function expectExactlyOneRow(rows, specId) {
299
+ if (rows.length === 0) {
300
+ throw new ContractViolationError('Expected exactly one row but received none.', specId);
301
+ }
302
+ if (rows.length > 1) {
303
+ throw new ContractViolationError(`Expected exactly one row but received ${rows.length}.`, specId);
304
+ }
305
+ return rows[0];
306
+ }
307
+ function extractScalar(rows, specId) {
308
+ const row = expectExactlyOneRow(rows, specId);
309
+ const columns = Object.keys(row);
310
+ if (columns.length !== 1) {
311
+ throw new ContractViolationError(`Expected exactly one column but received ${columns.length}.`, specId);
312
+ }
313
+ return row[columns[0]];
314
+ }
315
+ function applyScalarResult(spec, value) {
316
+ const decode = spec.output.validate;
317
+ if (decode) {
318
+ // The decoder/validator runs against the extracted scalar value.
319
+ return decode(value);
320
+ }
321
+ return value;
322
+ }
323
+ return {
324
+ async list(spec, params, options) {
325
+ const exec = wrapWithExtensions(createPipelineExec(spec, (rows) => applyOutputTransformation(spec, rows)));
326
+ const execId = createExecId();
327
+ const attempt = 1;
328
+ const result = await exec({
329
+ specId: spec.id,
330
+ sqlFile: spec.sqlFile,
331
+ params,
332
+ options,
333
+ execId,
334
+ attempt,
335
+ });
336
+ return result.value;
337
+ },
338
+ async one(spec, params, options) {
339
+ const exec = wrapWithExtensions(createPipelineExec(spec, (rows) => expectExactlyOneRow(applyOutputTransformation(spec, rows), spec.id)));
340
+ const execId = createExecId();
341
+ const attempt = 1;
342
+ const result = await exec({
343
+ specId: spec.id,
344
+ sqlFile: spec.sqlFile,
345
+ params,
346
+ options,
347
+ execId,
348
+ attempt,
349
+ });
350
+ return result.value;
351
+ },
352
+ async scalar(spec, params, options) {
353
+ const exec = wrapWithExtensions(createPipelineExec(spec, (rows) => {
354
+ const value = extractScalar(rows, spec.id);
355
+ return applyScalarResult(spec, value);
356
+ }));
357
+ const execId = createExecId();
358
+ const attempt = 1;
359
+ const result = await exec({
360
+ specId: spec.id,
361
+ sqlFile: spec.sqlFile,
362
+ params,
363
+ options,
364
+ execId,
365
+ attempt,
366
+ });
367
+ return result.value;
368
+ },
369
+ };
370
+ }
371
+ /** Named parameters are forbidden unless a binder is configured or explicit allowance is granted. */
372
+ function assertNamedAllowed(spec, binders, allow) {
373
+ if (spec.params.shape === 'named' && binders.length === 0 && !allow) {
374
+ throw new ContractViolationError(`Spec "${spec.id}" declares named parameters without a binder; enable allowNamedParamsWithoutBinder or add a binder.`, spec.id);
375
+ }
376
+ }
377
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/catalog/index.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
+ export * from './catalog';
1
2
  export * from './mapper';
2
3
  export * from './writer';
4
+ export * from './utils/coercions';
package/dist/index.js CHANGED
@@ -14,6 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./catalog"), exports);
17
18
  __exportStar(require("./mapper"), exports);
18
19
  __exportStar(require("./writer"), exports);
20
+ __exportStar(require("./utils/coercions"), exports);
19
21
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAwB;AACxB,2CAAwB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAAyB;AACzB,2CAAwB;AACxB,2CAAwB;AACxB,oDAAiC"}
@@ -1,4 +1,5 @@
1
1
  import type { QueryParams } from '../query-params';
2
+ import { normalizeKeyFromRow, normalizeKeyValue } from './internal';
2
3
  export type { QueryParams } from '../query-params';
3
4
  /**
4
5
  * A single database row returned by a SQL driver.
@@ -15,7 +16,7 @@ export type QueryExecutor = (sql: string, params: QueryParams) => Promise<Row[]>
15
16
  /**
16
17
  * Defines how a column prefix, key, and optional overrides describe a row mapping.
17
18
  */
18
- export interface RowMappingOptions<T, K extends Extract<keyof T, string>> {
19
+ export interface RowMappingOptions<T, K extends RowMappingKey<T> = RowMappingKey<T>> {
19
20
  name: string;
20
21
  key: K;
21
22
  prefix?: string;
@@ -60,13 +61,52 @@ export interface MapperOptions {
60
61
  value: unknown;
61
62
  }) => unknown;
62
63
  }
64
+ /** Primitive types that can appear in row keys. */
65
+ export type KeyPrimitive = string | number | bigint;
66
+ /** A key value: either a single primitive or an ordered list for composites. */
67
+ export type KeyValue = KeyPrimitive | readonly KeyPrimitive[];
68
+ /** Extracts a key value from a row. */
69
+ export type KeyExtractor<T> = (row: T) => KeyValue;
70
+ /**
71
+ * Describes how a row mapping derives its key.
72
+ * - A property name resolves via `resolveColumnName`.
73
+ * - An array lists explicit column names for composites.
74
+ * - A key extractor derives the key from a row object.
75
+ */
76
+ export type RowMappingKey<T> = Extract<keyof T, string> | readonly string[] | KeyExtractor<T>;
63
77
  /**
64
78
  * A mapping-bound reader that executes SQL and enforces row-count contracts.
65
79
  */
66
80
  export interface MapperReader<T> {
67
81
  list(sql: string, params?: QueryParams): Promise<T[]>;
68
82
  one(sql: string, params?: QueryParams): Promise<T>;
83
+ scalar(sql: string, params?: QueryParams): Promise<unknown>;
84
+ validator<U>(validator: ReaderValidatorInput<T, U>): MapperReader<U>;
69
85
  }
86
+ /**
87
+ * Validates a mapped value and returns the validated output.
88
+ */
89
+ export type ReaderValidator<T, U = T> = (value: T) => U;
90
+ /**
91
+ * Minimal schema-like contract recognized by reader validators.
92
+ * Implementations expose either `parse(value)` or `assert(value)` to describe
93
+ * the validated output type `U`.
94
+ */
95
+ type ReaderParseLike<U> = {
96
+ parse(value: unknown): U;
97
+ };
98
+ type ReaderAssertLike<U> = {
99
+ assert(value: unknown): U;
100
+ } | {
101
+ assert(value: unknown): asserts value is U;
102
+ };
103
+ export type ReaderSchemaLike<U = unknown> = ReaderParseLike<U> | ReaderAssertLike<U>;
104
+ /**
105
+ * Input accepted by `MapperReader.validator`. The value may be a plain validator function,
106
+ * or any schema-like object that implements `parse(value): U`. `T` is the row-mapped input type
107
+ * and `U` is the validated output emitted by the reader.
108
+ */
109
+ export type ReaderValidatorInput<T, U = T> = ReaderValidator<T, U> | ReaderSchemaLike<U>;
70
110
  /**
71
111
  * Named presets for simple mapping that avoid implicit inference.
72
112
  */
@@ -84,10 +124,7 @@ type RowContext = {
84
124
  row: Row;
85
125
  normalizedColumns: Map<string, string>;
86
126
  };
87
- /**
88
- * Builds a row mapping that can be consumed by {@link Mapper#query} or {@link mapRows}.
89
- */
90
- export declare class RowMapping<T, K extends Extract<keyof T, string> = Extract<keyof T, string>> {
127
+ export declare class RowMapping<T, K extends RowMappingKey<T> = RowMappingKey<T>> {
91
128
  readonly name: string;
92
129
  readonly key: K;
93
130
  readonly prefix: string;
@@ -98,6 +135,9 @@ export declare class RowMapping<T, K extends Extract<keyof T, string> = Extract<
98
135
  private readonly prefixLength;
99
136
  private readonly shouldCoerce;
100
137
  private readonly coerceFn;
138
+ private readonly keyDescriptor;
139
+ private readonly keyExtractor;
140
+ private readonly keyColumns?;
101
141
  constructor(options: RowMappingOptions<T, K>);
102
142
  /**
103
143
  * Registers a parent relationship that will be attached after the current row is mapped.
@@ -113,19 +153,28 @@ export declare class RowMapping<T, K extends Extract<keyof T, string> = Extract<
113
153
  belongsToOptional<P, PK extends Extract<keyof P, string>>(propertyName: Extract<keyof T, string>, parent: RowMapping<P, PK>, localKey?: Extract<keyof T, string>): this;
114
154
  matchColumn(columnName: string): string | undefined;
115
155
  resolveColumnName(propertyName: string): string;
116
- readKeyValue(ctx: RowContext): unknown;
156
+ readKeyValue(ctx: RowContext): KeyValue | undefined;
157
+ /**
158
+ * Returns a human-readable description of the key for error reporting.
159
+ */
160
+ get keyDescription(): string;
161
+ /**
162
+ * Lists the resolved key column names, if the key is not derived.
163
+ */
164
+ get keyColumnNames(): readonly string[] | undefined;
117
165
  assignFields(target: Record<string, unknown>, ctx: RowContext): void;
118
166
  private normalizeColumnValue;
167
+ private buildMappedRowForKey;
119
168
  }
120
169
  export { RowMapping as EntityMapping };
121
170
  /**
122
171
  * Creates a new row mapping from the provided options.
123
172
  */
124
- export declare function rowMapping<T, K extends Extract<keyof T, string> = Extract<keyof T, string>>(options: RowMappingOptions<T, K>): RowMapping<T, K>;
173
+ export declare function rowMapping<T, K extends RowMappingKey<T> = RowMappingKey<T>>(options: RowMappingOptions<T, K>): RowMapping<T, K>;
125
174
  /**
126
175
  * @deprecated Use {@link rowMapping} instead.
127
176
  */
128
- export declare function entity<T, K extends Extract<keyof T, string> = Extract<keyof T, string>>(options: RowMappingOptions<T, K>): RowMapping<T, K>;
177
+ export declare function entity<T, K extends RowMappingKey<T> = RowMappingKey<T>>(options: RowMappingOptions<T, K>): RowMapping<T, K>;
129
178
  /**
130
179
  * Builds a column map by prefixing each property with the provided prefix and
131
180
  * converting property names to snake_case.
@@ -190,3 +239,7 @@ export declare function mapRows<T>(rows: Row[], mapping: RowMapping<T>): T[];
190
239
  * @returns An array of `T` instances synthesized from `rows`.
191
240
  */
192
241
  export declare function mapSimpleRows<T>(rows: Row[], options?: MapperOptions): T[];
242
+ export declare const __internal: {
243
+ normalizeKeyValue: typeof normalizeKeyValue;
244
+ normalizeKeyFromRow: typeof normalizeKeyFromRow;
245
+ };