Comparing version
@@ -1,2 +0,2 @@ | ||
import { KmoreQueryBuilder, PageRawType, PageWrapType } from './builder.types.js'; | ||
import type { CtxBuilderPreProcessor, CtxBuilderResultPreProcessor, CtxExceptionHandler, KmoreQueryBuilder, PageRawType, PageWrapType } from './builder.types.js'; | ||
import { CaseType, EventCallbacks, KmoreTransaction, KmoreTransactionConfig, QueryContext, TrxIdQueryMap } from './types.js'; | ||
@@ -39,2 +39,5 @@ export declare abstract class KmoreBase<Context = any> { | ||
thenHandler: (options: ProxyGetHandlerOptions) => KmoreQueryBuilder['then']; | ||
ctxBuilderPreProcessor: CtxBuilderPreProcessor | undefined; | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor | undefined; | ||
ctxExceptionHandler: CtxExceptionHandler | undefined; | ||
resultPagerHandler?: ResultPagerHandler | undefined; | ||
@@ -47,2 +50,5 @@ } | ||
receiver: unknown; | ||
ctxBuilderPreProcessor: CtxBuilderPreProcessor | undefined; | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor | undefined; | ||
ctxExceptionHandler: CtxExceptionHandler | undefined; | ||
resultPagerHandler?: ResultPagerHandler | undefined; | ||
@@ -53,5 +59,8 @@ } | ||
builder: KmoreQueryBuilder; | ||
ctxBuilderPreProcessor: CtxBuilderPreProcessor | undefined; | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor | undefined; | ||
ctxExceptionHandler: CtxExceptionHandler | undefined; | ||
} | ||
declare type ResultPagerHandler<T = unknown> = (options: PagerOptions, proxyCreator: (options: CreateQueryBuilderGetProxyOptions) => KmoreQueryBuilder) => Promise<PageRawType<T> | PageWrapType<T> | undefined>; | ||
type ResultPagerHandler<T = unknown> = (options: PagerOptions, proxyCreator: (options: CreateQueryBuilderGetProxyOptions) => KmoreQueryBuilder) => Promise<PageRawType<T> | PageWrapType<T> | undefined>; | ||
export {}; | ||
//# sourceMappingURL=base.d.ts.map |
@@ -39,2 +39,5 @@ import assert from 'node:assert'; | ||
thenHandler: proxyGetThen, | ||
ctxBuilderPreProcessor: options.ctxBuilderPreProcessor, | ||
ctxBuilderResultPreProcessor: options.ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler: options.ctxExceptionHandler, | ||
}); | ||
@@ -146,3 +149,3 @@ // const builderPagerSql = builderPagerPatched.toQuery() | ||
builderPager = builderBindEvents(kmore, builderPager, caseConvert, ctx, kmoreQueryId2); | ||
builderPager = createBuilderProperties(builderPager, caseConvert, kmoreQueryId2, dbDict); | ||
builderPager = createBuilderProperties(builderPager, caseConvert, kmoreQueryId2, dbDict, kmore.dbId); | ||
const trx = kmore.getTrxByKmoreQueryId(kmoreQueryId); | ||
@@ -149,0 +152,0 @@ if (trx) { |
@@ -0,1 +1,3 @@ | ||
/* eslint-disable max-params */ | ||
/* eslint-disable @typescript-eslint/ban-types */ | ||
import assert from 'assert'; | ||
@@ -23,9 +25,11 @@ import { pager } from './builder.auto-paging.js'; | ||
const name = `${prefix}${refName}`; | ||
// @ts-expect-error | ||
const queryBuilderCreator = (options) => { | ||
const ctx2 = options?.ctx ?? { id: kmore.dbId, instanceId: kmore.instanceId }; | ||
return extRefTableFnProperty(kmore, refName, caseConvert, ctx2, options?.ctxBuilderPreProcessor, options?.ctxBuilderResultPreProcessor, options?.ctxExceptionHandler); | ||
}; // must dynamically!! | ||
Object.defineProperty(rb, name, { | ||
...defaultPropDescriptor, | ||
writable: true, | ||
value: (ctx) => { | ||
const ctx2 = ctx ?? { id: kmore.dbId, instanceId: kmore.instanceId }; | ||
return extRefTableFnProperty(kmore, refName, caseConvert, ctx2); | ||
}, // must dynamically!! | ||
value: queryBuilderCreator, | ||
}); | ||
@@ -39,3 +43,3 @@ Object.defineProperty(rb[name], 'name', { | ||
} | ||
function extRefTableFnProperty(kmore, refName, caseConvert, ctx) { | ||
function extRefTableFnProperty(kmore, refName, caseConvert, ctx, ctxBuilderPreProcessor, ctxBuilderResultPreProcessor, ctxExceptionHandler) { | ||
assert(caseConvert, 'caseConvert must be defined'); | ||
@@ -54,2 +58,5 @@ const kmoreQueryId = Symbol(`${kmore.dbId}-${Date.now()}`); | ||
thenHandler: proxyGetThen, | ||
ctxBuilderPreProcessor, | ||
ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler, | ||
resultPagerHandler: pager, | ||
@@ -61,5 +68,5 @@ }); | ||
refTable = extRefTableFnPropertyAutoPaging(refTable); | ||
refTable = createBuilderProperties(refTable, caseConvert, kmoreQueryId, kmore.dict); | ||
refTable = createBuilderProperties(refTable, caseConvert, kmoreQueryId, kmore.dict, kmore.dbId); | ||
return refTable; | ||
} | ||
//# sourceMappingURL=builder.index.js.map |
@@ -1,4 +0,4 @@ | ||
import type { KmoreQueryBuilder } from './builder.types.js'; | ||
import { KmoreQueryBuilder } from './builder.types.js'; | ||
import { CaseType } from './types.js'; | ||
export declare function createBuilderProperties(refTable: KmoreQueryBuilder, caseConvert: CaseType, kmoreQueryId: symbol, dict: unknown): KmoreQueryBuilder; | ||
export declare function createBuilderProperties(refTable: KmoreQueryBuilder, caseConvert: CaseType, kmoreQueryId: symbol, dict: unknown, dbId: string): KmoreQueryBuilder; | ||
//# sourceMappingURL=builder.props.d.ts.map |
import assert from 'assert'; | ||
import { QueryBuilderExtKey } from './builder.types.js'; | ||
import { defaultPropDescriptor } from './config.js'; | ||
export function createBuilderProperties(refTable, caseConvert, kmoreQueryId, dict) { | ||
export function createBuilderProperties(refTable, caseConvert, kmoreQueryId, dict, dbId) { | ||
assert(caseConvert, 'caseConvert must be defined'); | ||
void Object.defineProperty(refTable, 'kmoreQueryId', { | ||
void Object.defineProperty(refTable, QueryBuilderExtKey.kmoreQueryId, { | ||
...defaultPropDescriptor, | ||
value: kmoreQueryId, | ||
}); | ||
void Object.defineProperty(refTable, 'dbDict', { | ||
void Object.defineProperty(refTable, QueryBuilderExtKey.dbDict, { | ||
...defaultPropDescriptor, | ||
value: dict, | ||
}); | ||
void Object.defineProperty(refTable, '_tablesJoin', { | ||
void Object.defineProperty(refTable, QueryBuilderExtKey.tablesJoin, { | ||
...defaultPropDescriptor, | ||
value: [], | ||
}); | ||
void Object.defineProperty(refTable, 'caseConvert', { | ||
void Object.defineProperty(refTable, QueryBuilderExtKey.caseConvert, { | ||
...defaultPropDescriptor, | ||
value: caseConvert, | ||
}); | ||
assert(dbId, 'dbId must be defined'); | ||
void Object.defineProperty(refTable, QueryBuilderExtKey.dbId, { | ||
...defaultPropDescriptor, | ||
value: dbId, | ||
}); | ||
return refTable; | ||
} | ||
//# sourceMappingURL=builder.props.js.map |
import { CaseConvertTable, CaseType, DbScopedColsByKey, DbScopedColsByTableType, JoinTableWithCaseConvert, SplitScopedColumn, StrKey, UnwrapArrayMember } from '@waiting/shared-types'; | ||
import { DbDict } from 'kmore-types'; | ||
import type { Knex } from 'knex'; | ||
import { PropagationType } from './propagation.types.js'; | ||
/** | ||
@@ -9,5 +10,5 @@ * - 0: No paging | ||
*/ | ||
declare type PagingCategory = 0 | 1 | 2; | ||
export declare type KmoreQueryBuilder<D extends {} = {}, CaseConvert extends CaseType = CaseType, EnablePage extends PagingCategory = 0, TRecord extends {} = any, TResult = any> = QueryBuilderExtName<D> & QueryBuilderExtMethod<D, CaseConvert, EnablePage, TRecord> & QueryBuilder<D, CaseConvert, EnablePage, TRecord, AddPagingMeta<TResult, EnablePage>>; | ||
declare type OmitQueryBuilderKeys = 'select' | 'where' | 'orderBy' | keyof Knex.ChainableInterface; | ||
type PagingCategory = 0 | 1 | 2; | ||
export type KmoreQueryBuilder<D extends {} = {}, CaseConvert extends CaseType = CaseType, EnablePage extends PagingCategory = 0, TRecord extends {} = any, TResult = any> = QueryBuilderExtName<D> & QueryBuilderExtMethod<D, CaseConvert, EnablePage, TRecord> & QueryBuilder<D, CaseConvert, EnablePage, TRecord, AddPagingMeta<TResult, EnablePage>>; | ||
type OmitQueryBuilderKeys = 'select' | 'where' | 'orderBy' | keyof Knex.ChainableInterface; | ||
interface QueryBuilder<D extends {} = {}, CaseConvert extends CaseType = CaseType, EnablePage extends PagingCategory = 0, TRecord extends {} = any, TResult = any> extends Knex.ChainableInterface<AddPagingMeta<ResolveResult<TResult>, EnablePage>>, Omit<Knex.QueryBuilder<TRecord, TResult>, OmitQueryBuilderKeys> { | ||
@@ -18,6 +19,24 @@ select: Select<D, CaseConvert, EnablePage, TRecord, TResult>; | ||
} | ||
export declare type DbQueryBuilder<Context, D, Prefix extends string, CaseConvert extends CaseType> = { | ||
export type DbQueryBuilder<Context, D, Prefix extends string, CaseConvert extends CaseType> = { | ||
[tb in keyof D as `${Prefix}${tb & string}`]: TbQueryBuilder<D, CaseConvert, CaseConvertTable<D[tb], CaseConvert>, Context>; | ||
}; | ||
export declare type TbQueryBuilder<D extends {}, CaseConvert extends CaseType, TRecord extends {}, Context> = (ctx?: Context) => KmoreQueryBuilder<D, CaseConvert, 0, TRecord, TRecord[]>; | ||
export type TbQueryBuilder<D extends {}, CaseConvert extends CaseType, TRecord extends {}, Context> = (options?: Partial<TbQueryBuilderOptions<Context>>) => KmoreQueryBuilder<D, CaseConvert, 0, TRecord, TRecord[]>; | ||
export interface TbQueryBuilderOptions<Context> { | ||
ctx: Context; | ||
ctxBuilderPreProcessor: CtxBuilderPreProcessor | undefined; | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor | undefined; | ||
ctxExceptionHandler: CtxExceptionHandler | undefined; | ||
} | ||
export declare enum QueryBuilderExtKey { | ||
caseConvert = "caseConvert", | ||
kmoreQueryId = "kmoreQueryId", | ||
dbDict = "dbDict", | ||
dbId = "dbId", | ||
tablesJoin = "_tablesJoin", | ||
pagingType = "pagingType", | ||
transactionalProcessed = "transactionalProcessed", | ||
trxPropagateOptions = "trxPropagateOptions", | ||
trxPropagated = "trxPropagated", | ||
rowLockLevel = "rowLockLevel" | ||
} | ||
interface QueryBuilderExtName<D extends {} = {}> { | ||
@@ -27,5 +46,40 @@ caseConvert: CaseType; | ||
dbDict: DbDict<D>; | ||
dbId: string; | ||
_tablesJoin: string[]; | ||
pagingType?: 'counter' | 'pager'; | ||
trxPropagateOptions?: TrxPropagateOptions; | ||
trxPropagated?: boolean; | ||
/** | ||
* Propagation rowlock level | ||
* @default {@link RowLockLevel} | ||
*/ | ||
rowLockLevel: RowLockLevel | undefined; | ||
transactionalProcessed: boolean | undefined; | ||
} | ||
export interface TrxPropagateOptions { | ||
dbId: string; | ||
type: PropagationType; | ||
path: string; | ||
className: string; | ||
funcName: string; | ||
methodName: string; | ||
line: number; | ||
column: number; | ||
/** | ||
* @default {@link RowLockLevel.ForShare} | ||
*/ | ||
readRowLockLevel: RowLockLevel; | ||
/** | ||
* @default {@link RowLockLevel.ForUpdate} | ||
*/ | ||
writeRowLockLevel: RowLockLevel; | ||
} | ||
/** | ||
* Used for `@Transactional()` decorator | ||
*/ | ||
export declare enum RowLockLevel { | ||
ForShare = "FOR_SHARE", | ||
ForUpdate = "FOR_UPDATE", | ||
None = "None" | ||
} | ||
interface QueryBuilderExtMethod<D extends {} = {}, CaseConvert extends CaseType = CaseType, EnablePage extends PagingCategory = 0, TRecord extends {} = any> { | ||
@@ -39,7 +93,7 @@ smartCrossJoin: SmartJoin<D, CaseConvert, EnablePage, TRecord>; | ||
} | ||
declare type AutoPaging<D extends {} = {}, CaseConvert extends CaseType = CaseType, TRecord extends {} = any> = <Wrap extends boolean | undefined = false>(options?: Partial<PagingOptions>, wrapOutput?: Wrap) => KmoreQueryBuilder<D, CaseConvert, CalcPagingCat<Wrap>, TRecord, TRecord[]>; | ||
declare type CalcPagingCat<T> = T extends true ? 2 : 1; | ||
declare type AddPagingMeta<TSelection, EnablePage extends PagingCategory = 0> = EnablePage extends 0 ? TSelection : TSelection extends (infer R)[] ? EnablePage extends 2 ? WrapPageOutput<R> : PageRawType<R> : TSelection; | ||
declare type WrapPageOutput<T> = T extends PageWrapType ? T : PageWrapType<T>; | ||
declare type SmartJoin<D extends {} = {}, CaseConvert extends CaseType = CaseType, EnablePage extends PagingCategory = 0, TResult = unknown[]> = <TRecord1 = UnwrapArrayMember<TResult>, C2 extends DbScopedColsByKey<D> = DbScopedColsByKey<D>, C1 extends DbScopedColsByKey<D> = DbScopedColsByTableType<D, TRecord1>, TTable2 extends StrKey<D> = SplitScopedColumn<D, C2>[0], TRecord2 extends D[TTable2] = D[TTable2], TResult2 = JoinTableWithCaseConvert<TRecord1, TRecord2 extends any ? D[TTable2] : TRecord2, TTable2, CaseConvert>>( | ||
type AutoPaging<D extends {} = {}, CaseConvert extends CaseType = CaseType, TRecord extends {} = any> = <Wrap extends boolean | undefined = false>(options?: Partial<PagingOptions>, wrapOutput?: Wrap) => KmoreQueryBuilder<D, CaseConvert, CalcPagingCat<Wrap>, TRecord, TRecord[]>; | ||
type CalcPagingCat<T> = T extends true ? 2 : 1; | ||
type AddPagingMeta<TSelection, EnablePage extends PagingCategory = 0> = EnablePage extends 0 ? TSelection : TSelection extends (infer R)[] ? EnablePage extends 2 ? WrapPageOutput<R> : PageRawType<R> : TSelection; | ||
type WrapPageOutput<T> = T extends PageWrapType ? T : PageWrapType<T>; | ||
type SmartJoin<D extends {} = {}, CaseConvert extends CaseType = CaseType, EnablePage extends PagingCategory = 0, TResult = unknown[]> = <TRecord1 = UnwrapArrayMember<TResult>, C2 extends DbScopedColsByKey<D> = DbScopedColsByKey<D>, C1 extends DbScopedColsByKey<D> = DbScopedColsByTableType<D, TRecord1>, TTable2 extends StrKey<D> = SplitScopedColumn<D, C2>[0], TRecord2 extends D[TTable2] = D[TTable2], TResult2 = JoinTableWithCaseConvert<TRecord1, TRecord2 extends any ? D[TTable2] : TRecord2, TTable2, CaseConvert>>( | ||
/** | ||
@@ -73,3 +127,3 @@ * scoped column name, e.g. 'tb_name.col_name', | ||
*/ | ||
export declare type PageRawType<T = unknown> = T[] & PagingMeta; | ||
export type PageRawType<T = unknown> = T[] & PagingMeta; | ||
export interface PageWrapType<T = unknown> extends PagingMeta { | ||
@@ -129,24 +183,24 @@ rows: T[]; | ||
} | ||
declare type ArrayIfAlready<T1, T2> = AnyToUnknown<T1> extends any[] ? T2[] : T2; | ||
declare type ArrayMember<T> = T extends (infer M)[] ? M : never; | ||
declare type AnyToUnknown<T> = unknown extends T ? unknown : T; | ||
declare type CurlyCurlyToAny<T> = T extends unknown ? (<U>() => U extends T ? 0 : 1) extends <U>() => U extends {} ? 0 : 1 ? any : T : never; | ||
type ArrayIfAlready<T1, T2> = AnyToUnknown<T1> extends any[] ? T2[] : T2; | ||
type ArrayMember<T> = T extends (infer M)[] ? M : never; | ||
type AnyToUnknown<T> = unknown extends T ? unknown : T; | ||
type CurlyCurlyToAny<T> = T extends unknown ? (<U>() => U extends T ? 0 : 1) extends <U>() => U extends {} ? 0 : 1 ? any : T : never; | ||
interface Dict<T = any> { | ||
[k: string]: T; | ||
} | ||
declare type IncompatibleToAlt<T, TBase, TAlt> = T extends TBase ? T : TAlt; | ||
declare type MappedAliasType<TBase, TAliasMapping> = {} & { | ||
type IncompatibleToAlt<T, TBase, TAlt> = T extends TBase ? T : TAlt; | ||
type MappedAliasType<TBase, TAliasMapping> = {} & { | ||
[K in keyof TAliasMapping]: TAliasMapping[K] extends keyof TBase ? TBase[TAliasMapping[K]] : any; | ||
}; | ||
declare type UnknownOrCurlyCurlyToAny<T> = [UnknownToAny<T> | CurlyCurlyToAny<T>][0]; | ||
declare type UnknownToAny<T> = unknown extends T ? any : T; | ||
declare type AugmentParams<TTarget, TParams> = TParams extends {} ? keyof TParams extends never ? TTarget : {} & TTarget & TParams : TTarget; | ||
declare type PartialOrAny<TBase, TKeys> = Boxed<TKeys> extends Boxed<never> ? {} : Boxed<TKeys> extends Boxed<keyof TBase> ? SafePick<TBase, TKeys & keyof TBase> : any; | ||
type UnknownOrCurlyCurlyToAny<T> = [UnknownToAny<T> | CurlyCurlyToAny<T>][0]; | ||
type UnknownToAny<T> = unknown extends T ? any : T; | ||
type AugmentParams<TTarget, TParams> = TParams extends {} ? keyof TParams extends never ? TTarget : {} & TTarget & TParams : TTarget; | ||
type PartialOrAny<TBase, TKeys> = Boxed<TKeys> extends Boxed<never> ? {} : Boxed<TKeys> extends Boxed<keyof TBase> ? SafePick<TBase, TKeys & keyof TBase> : any; | ||
interface Boxed<T> { | ||
_value: T; | ||
} | ||
declare type SafePick<T, K extends keyof T> = T extends {} ? Pick<T, K> : any; | ||
declare type SafePartial<T> = Partial<AnyOrUnknownToOther<T, {}>>; | ||
declare type AnyOrUnknownToOther<T1, T2> = unknown extends T1 ? T2 : T1; | ||
declare type Any = DeferredKeySelection<any, any, any, any, any, any, any>; | ||
type SafePick<T, K extends keyof T> = T extends {} ? Pick<T, K> : any; | ||
type SafePartial<T> = Partial<AnyOrUnknownToOther<T, {}>>; | ||
type AnyOrUnknownToOther<T1, T2> = unknown extends T1 ? T2 : T1; | ||
type Any = DeferredKeySelection<any, any, any, any, any, any, any>; | ||
interface DeferredKeySelection<TBase, TKeys extends string, THasSelect extends true | false = false, TAliasMapping extends {} = {}, TSingle extends boolean = false, TIntersectProps extends {} = {}, TUnionProps = never> { | ||
@@ -172,4 +226,4 @@ _base: TBase; | ||
} | ||
declare type ResolveResult<S, EnablePage extends PagingCategory = 0> = AddPagingMeta<DeferredKeySelectionNS.Resolve<S>, EnablePage>; | ||
declare type ComparisonOperator = '=' | '>' | '>=' | '<' | '<=' | '<>'; | ||
type ResolveResult<S, EnablePage extends PagingCategory = 0> = AddPagingMeta<DeferredKeySelectionNS.Resolve<S>, EnablePage>; | ||
type ComparisonOperator = '=' | '>' | '>=' | '<' | '<=' | '<>'; | ||
export interface Where<D extends {} = {}, CaseConvert extends CaseType = CaseType, EnablePage extends PagingCategory = 0, TRecord extends {} = any, TResult = any> extends WhereRaw<D, CaseConvert, EnablePage, TRecord, TResult> { | ||
@@ -192,3 +246,24 @@ (raw: Knex.Raw): KmoreQueryBuilder<D, CaseConvert, EnablePage, TRecord, TResult>; | ||
} | ||
export type CtxBuilderPreProcessor = (builder: KmoreQueryBuilder) => Promise<{ | ||
builder: KmoreQueryBuilder; | ||
}>; | ||
export type CtxBuilderResultPreProcessor<T = unknown> = (options: CtxBuilderResultPreProcessorOptions<T>) => Promise<T>; | ||
export type CtxExceptionHandler = (options: CtxExceptionHandlerOptions) => Promise<never>; | ||
export interface CtxBuilderResultPreProcessorOptions<Resp = unknown> { | ||
kmoreQueryId: symbol; | ||
kmoreTrxId: symbol | undefined; | ||
response: Resp; | ||
transactionalProcessed: boolean | undefined; | ||
trxPropagateOptions: TrxPropagateOptions | undefined; | ||
trxPropagated: boolean | undefined; | ||
/** | ||
* Propagation rowlock level | ||
* @default {@link RowLockLevel} | ||
*/ | ||
rowLockLevel: RowLockLevel | undefined; | ||
} | ||
export interface CtxExceptionHandlerOptions extends Omit<CtxBuilderResultPreProcessorOptions, 'response'> { | ||
exception: unknown; | ||
} | ||
export {}; | ||
//# sourceMappingURL=builder.types.d.ts.map |
@@ -1,2 +0,23 @@ | ||
export {}; | ||
export var QueryBuilderExtKey; | ||
(function (QueryBuilderExtKey) { | ||
QueryBuilderExtKey["caseConvert"] = "caseConvert"; | ||
QueryBuilderExtKey["kmoreQueryId"] = "kmoreQueryId"; | ||
QueryBuilderExtKey["dbDict"] = "dbDict"; | ||
QueryBuilderExtKey["dbId"] = "dbId"; | ||
QueryBuilderExtKey["tablesJoin"] = "_tablesJoin"; | ||
QueryBuilderExtKey["pagingType"] = "pagingType"; | ||
QueryBuilderExtKey["transactionalProcessed"] = "transactionalProcessed"; | ||
QueryBuilderExtKey["trxPropagateOptions"] = "trxPropagateOptions"; | ||
QueryBuilderExtKey["trxPropagated"] = "trxPropagated"; | ||
QueryBuilderExtKey["rowLockLevel"] = "rowLockLevel"; | ||
})(QueryBuilderExtKey = QueryBuilderExtKey || (QueryBuilderExtKey = {})); | ||
/** | ||
* Used for `@Transactional()` decorator | ||
*/ | ||
export var RowLockLevel; | ||
(function (RowLockLevel) { | ||
RowLockLevel["ForShare"] = "FOR_SHARE"; | ||
RowLockLevel["ForUpdate"] = "FOR_UPDATE"; | ||
RowLockLevel["None"] = "None"; | ||
})(RowLockLevel = RowLockLevel || (RowLockLevel = {})); | ||
//# sourceMappingURL=builder.types.js.map |
@@ -6,8 +6,8 @@ import { RecordCamelKeys, RecordPascalKeys, RecordSnakeKeys } from '@waiting/shared-types'; | ||
export declare function postProcessResponse<T extends PostProcessInput = PostProcessInput>(result: T, queryContext?: QueryContext): T | PostProcessRespRet<T, QueryContext['postProcessResponseCaseConvert']>; | ||
export declare type PostProcessPlain = number | string | undefined | null | boolean; | ||
export declare type PostProcessRecord = Record<string, PostProcessPlain> | object; | ||
export declare type PostProcessArray = PostProcessPlain[]; | ||
export declare type PostProcessInput = PostProcessPlain | PostProcessRecord | PostProcessArray; | ||
export declare type PostProcessRespRet<T extends PostProcessInput, CaseConvert extends CaseType | undefined> = T extends PostProcessPlain ? T : T extends PostProcessArray ? PostProcessArray : T extends PostProcessRecord ? PostProcessRecordCaseConvert<T, CaseConvert> : never; | ||
declare type PostProcessRecordCaseConvert<T extends PostProcessRecord, CaseConvert extends CaseType | undefined> = CaseConvert extends CaseType.camel ? RecordCamelKeys<T> : CaseConvert extends CaseType.pascal ? RecordPascalKeys<T> : CaseConvert extends CaseType.snake ? RecordSnakeKeys<T> : T; | ||
export type PostProcessPlain = number | string | undefined | null | boolean; | ||
export type PostProcessRecord = Record<string, PostProcessPlain> | object; | ||
export type PostProcessArray = PostProcessPlain[]; | ||
export type PostProcessInput = PostProcessPlain | PostProcessRecord | PostProcessArray; | ||
export type PostProcessRespRet<T extends PostProcessInput, CaseConvert extends CaseType | undefined> = T extends PostProcessPlain ? T : T extends PostProcessArray ? PostProcessArray : T extends PostProcessRecord ? PostProcessRecordCaseConvert<T, CaseConvert> : never; | ||
type PostProcessRecordCaseConvert<T extends PostProcessRecord, CaseConvert extends CaseType | undefined> = CaseConvert extends CaseType.camel ? RecordCamelKeys<T> : CaseConvert extends CaseType.pascal ? RecordPascalKeys<T> : CaseConvert extends CaseType.snake ? RecordSnakeKeys<T> : T; | ||
/** | ||
@@ -14,0 +14,0 @@ * Convert keys of result to camelcase, if input is object |
export * from './kmore.js'; | ||
export * from './types.js'; | ||
export * from './builder.types.js'; | ||
export * from './propagation.types.js'; | ||
export { initKmoreEvent } from './config.js'; | ||
export { getCurrentTime, mergeDoWithInitData, } from './helper.js'; | ||
export { genKmoreTrxId } from './util.js'; | ||
//# sourceMappingURL=index.d.ts.map |
export * from './kmore.js'; | ||
export * from './types.js'; | ||
export * from './builder.types.js'; | ||
export * from './propagation.types.js'; | ||
export { initKmoreEvent } from './config.js'; | ||
export { getCurrentTime, mergeDoWithInitData, } from './helper.js'; | ||
export { genKmoreTrxId } from './util.js'; | ||
//# sourceMappingURL=index.js.map |
@@ -66,3 +66,2 @@ import type { DbDict } from 'kmore-types'; | ||
* Start a transaction. | ||
* @param id - For generation of kmoreTrxId | ||
*/ | ||
@@ -69,0 +68,0 @@ transaction(config?: KmoreTransactionConfig): Promise<KmoreTransaction>; |
@@ -120,6 +120,5 @@ /* eslint-disable max-lines-per-function */ | ||
* Start a transaction. | ||
* @param id - For generation of kmoreTrxId | ||
*/ | ||
async transaction(config) { | ||
const kmoreTrxId = genKmoreTrxId(config?.kmoreTrxId); | ||
const kmoreTrxId = config?.kmoreTrxId ?? genKmoreTrxId(config?.kmoreTrxId); | ||
delete config?.kmoreTrxId; | ||
@@ -126,0 +125,0 @@ const trx = await this.dbh.transaction(void 0, config); |
import type { KmoreBase } from './base.js'; | ||
interface ProcessThenRetOptions { | ||
import { CtxBuilderResultPreProcessor, CtxBuilderResultPreProcessorOptions, CtxExceptionHandler } from './builder.types.js'; | ||
interface ProcessThenRetOptions<Resp = unknown> extends Omit<CtxBuilderResultPreProcessorOptions<Resp>, 'response'> { | ||
kmore: KmoreBase; | ||
kmoreQueryId: symbol; | ||
input: Promise<unknown>; | ||
done: undefined | ((data: unknown) => unknown); | ||
input: Promise<Resp>; | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor<Resp> | undefined; | ||
ctxExceptionHandler: CtxExceptionHandler | undefined; | ||
transactionalProcessed: boolean | undefined; | ||
done: undefined | ((data: Resp) => Resp); | ||
reject: undefined | ((data: unknown) => Error); | ||
@@ -8,0 +12,0 @@ } |
@@ -6,4 +6,26 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
export async function processThenRet(options) { | ||
const { kmore, kmoreQueryId, input, done, reject } = options; | ||
return input | ||
const { ctxBuilderResultPreProcessor, ctxExceptionHandler, input, kmore, kmoreQueryId, kmoreTrxId, rowLockLevel, transactionalProcessed, trxPropagated, trxPropagateOptions, done, reject, } = options; | ||
const pm1 = ctxBuilderResultPreProcessor | ||
? input.then((response) => ctxBuilderResultPreProcessor({ | ||
kmoreQueryId, | ||
kmoreTrxId, | ||
response, | ||
transactionalProcessed, | ||
trxPropagateOptions, | ||
trxPropagated, | ||
rowLockLevel, | ||
})) | ||
: input; | ||
const pm2 = ctxExceptionHandler | ||
? pm1.catch((ex) => ctxExceptionHandler({ | ||
kmoreQueryId, | ||
kmoreTrxId, | ||
transactionalProcessed, | ||
trxPropagateOptions, | ||
trxPropagated, | ||
rowLockLevel, | ||
exception: ex, | ||
})) | ||
: pm1; | ||
return pm2 | ||
.catch((ex) => processTrxOnEx(kmore, kmoreQueryId, ex)) | ||
@@ -10,0 +32,0 @@ .then((resp) => processThen(resp, done)) |
import { defaultPropDescriptor } from './config.js'; | ||
export function createQueryBuilderGetProxy(options) { | ||
const { kmore, thenHandler, resultPagerHandler, } = options; | ||
const { kmore, thenHandler, resultPagerHandler, ctxBuilderPreProcessor, ctxBuilderResultPreProcessor, ctxExceptionHandler, } = options; | ||
const ret = new Proxy(options.builder, { | ||
@@ -15,2 +15,5 @@ get: (target, propKey, receiver) => { | ||
resultPagerHandler, | ||
ctxBuilderPreProcessor, | ||
ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler, | ||
}); | ||
@@ -17,0 +20,0 @@ default: |
@@ -11,7 +11,18 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
export function proxyGetThen(options) { | ||
const { kmore, builder: origBuilder, propKey, resultPagerHandler, } = options; | ||
const { kmore, builder: origBuilder, propKey, resultPagerHandler, ctxBuilderPreProcessor, ctxBuilderResultPreProcessor, ctxExceptionHandler, } = options; | ||
assert(propKey === 'then', `propKey should be "then", but got: ${propKey.toString()}`); | ||
const getThenProxy = async (done, reject) => { | ||
const builder = origBuilder; | ||
const builder = typeof ctxBuilderPreProcessor === 'function' | ||
? (await ctxBuilderPreProcessor(origBuilder)).builder | ||
: origBuilder; | ||
const { kmoreQueryId } = builder; | ||
if (!kmoreQueryId) { | ||
const errMsg = 'kmoreQueryId should be defined, builder may not be a KmoreQueryBuilder'; | ||
console.error(errMsg); | ||
const err = new Error(errMsg); | ||
if (reject) { | ||
return reject(err); | ||
} | ||
throw err; | ||
} | ||
let getThenProxyRet; | ||
@@ -23,3 +34,10 @@ if (resultPagerHandler && Object.hasOwn(builder, KmorePageKey.PagingOptions) | ||
// pager() | ||
getThenProxyRet = resultPagerHandler({ builder, kmore }, createQueryBuilderGetProxy); | ||
const opts = { | ||
builder, | ||
kmore, | ||
ctxBuilderPreProcessor: options.ctxBuilderPreProcessor, | ||
ctxBuilderResultPreProcessor: options.ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler: options.ctxExceptionHandler, | ||
}; | ||
getThenProxyRet = resultPagerHandler(opts, createQueryBuilderGetProxy); | ||
} | ||
@@ -30,6 +48,15 @@ else { | ||
} | ||
const kmoreTrxId = kmore.getTrxByKmoreQueryId(kmoreQueryId)?.kmoreTrxId; | ||
const { rowLockLevel, transactionalProcessed, trxPropagated, trxPropagateOptions } = builder; | ||
return processThenRet({ | ||
ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler, | ||
input: getThenProxyRet, | ||
kmore, | ||
kmoreQueryId, | ||
input: getThenProxyRet, | ||
kmoreTrxId, | ||
rowLockLevel, | ||
transactionalProcessed, | ||
trxPropagated, | ||
trxPropagateOptions, | ||
done, | ||
@@ -36,0 +63,0 @@ reject, |
@@ -54,2 +54,3 @@ import assert from 'node:assert'; | ||
}); | ||
assert(trx3.kmoreTrxId !== ctx.kmoreTrxId, 'trx3.kmoreTrxId === ctx.kmoreTrxId'); | ||
return trx3; | ||
@@ -101,2 +102,3 @@ }, | ||
assert(kmoreTrxId, 'kmoreTrxId must be provided from parent trx when creating savepoint'); | ||
assert(kmoreTrxId !== parentTrx.kmoreTrxId, 'kmoreTrxId === parentTrx.kmoreTrxId'); | ||
assert(trx.isTransaction === true, 'output trx not a transaction when creating savepoint'); | ||
@@ -103,0 +105,0 @@ assert(!trx.isCompleted(), 'output trx already completed when creating savepoint'); |
import type { TraceContext, Span } from '@mwcp/otel'; | ||
import { CaseType } from '@waiting/shared-types'; | ||
import type { Knex } from 'knex'; | ||
import type { KmoreQueryBuilder } from './builder.types.js'; | ||
import { KmoreQueryBuilder, QueryBuilderExtKey, TrxPropagateOptions } from './builder.types.js'; | ||
export { CaseType }; | ||
export declare type KnexConfig = Knex.Config; | ||
export declare type KmoreTransaction = Knex.Transaction & { | ||
export type KnexConfig = Knex.Config; | ||
export type KmoreTransaction = Knex.Transaction & { | ||
dbId: string; | ||
@@ -13,2 +13,3 @@ hrtime: bigint; | ||
* Auto transction action (rollback|commit|none) on builder error (Rejection or Exception), | ||
* declarative transaction always rollback on end | ||
* | ||
@@ -20,8 +21,10 @@ * @default rollback | ||
trxActionOnEnd: NonNullable<KmoreTransactionConfig['trxActionOnEnd']>; | ||
[QueryBuilderExtKey.trxPropagateOptions]?: TrxPropagateOptions; | ||
savepoint: (id?: PropertyKey, config?: KmoreTransactionConfig) => Promise<KmoreTransaction>; | ||
}; | ||
export declare type KmoreTransactionConfig = Knex.TransactionConfig & { | ||
kmoreTrxId?: PropertyKey; | ||
export type KmoreTransactionConfig = Knex.TransactionConfig & { | ||
kmoreTrxId?: PropertyKey | undefined; | ||
/** | ||
* Auto transction action (rollback|commit|none) on builder error (Rejection or Exception), | ||
* declarative transaction always rollback on end | ||
* | ||
@@ -53,3 +56,3 @@ * @default rollback | ||
} | ||
export declare type EventType = 'query' | 'queryError' | 'queryResponse' | 'start' | 'unknown'; | ||
export type EventType = 'query' | 'queryError' | 'queryResponse' | 'start' | 'unknown'; | ||
export interface KmoreEvent<T = unknown> { | ||
@@ -177,7 +180,7 @@ dbId: string; | ||
*/ | ||
export declare type EventCallbackType = Exclude<EventType, 'unknown'>; | ||
export type EventCallbackType = Exclude<EventType, 'unknown'>; | ||
/** | ||
* @docs https://knexjs.org/guide/interfaces.html#query-response | ||
*/ | ||
export declare type EventCallbacks<Ctx = any> = Partial<EventCallbackList<Ctx>>; | ||
export type EventCallbacks<Ctx = any> = Partial<EventCallbackList<Ctx>>; | ||
export interface EventCallbackList<Ctx = any> { | ||
@@ -205,4 +208,4 @@ start: (event: KmoreEvent, ctx?: Ctx) => void; | ||
*/ | ||
export declare type TrxIdQueryMap = Map<symbol, Set<symbol>>; | ||
export declare type TrxSavePointCallback = (trx: KmoreTransaction) => Promise<unknown>; | ||
export type TrxIdQueryMap = Map<symbol, Set<symbol>>; | ||
export type TrxSavePointCallback = (trx: KmoreTransaction) => Promise<unknown>; | ||
export interface BuilderInput { | ||
@@ -209,0 +212,0 @@ ctx?: unknown; |
import { CaseType } from '@waiting/shared-types'; | ||
import { QueryBuilderExtKey, } from './builder.types.js'; | ||
export { CaseType }; | ||
@@ -3,0 +4,0 @@ export var EnumClient; |
@@ -8,17 +8,22 @@ import assert from 'node:assert'; | ||
else if (typeof id === 'string' || typeof id === 'number') { | ||
const str = id.toString() + (suffix ? `-${suffix}` : ''); | ||
const str = id.toString() + Date.now().toString() + (suffix ? `-${suffix}` : ''); | ||
return Symbol(str); | ||
} | ||
const str = id.toString(); | ||
let key2 = ''; | ||
if (str.startsWith('Symbol(trx-')) { | ||
const key = str.match(/Symbol\((trx-\S+)\)/u)?.[1]; | ||
assert(key, 'retrieve key from id failed, input should like "Symbol(trx-1234567890)"'); | ||
const key2 = `${key}-${Date.now()}` + (suffix ? `-${suffix}` : ''); | ||
return Symbol(key2); | ||
key2 = `${key}-${Date.now()}`; | ||
} | ||
else if (str.startsWith('trx-')) { | ||
key2 = str; | ||
} | ||
else { | ||
const key = `trx-${str}` + (suffix ? `-${suffix}` : ''); | ||
return Symbol(key); | ||
key2 = `trx-${str}`; | ||
} | ||
const key3 = suffix ? `${key2}-${suffix}` : `${key2}-${Date.now()}`; | ||
assert(key3 !== str, 'result should not equal to the input id'); | ||
return Symbol(key3); | ||
} | ||
//# sourceMappingURL=util.js.map |
{ | ||
"name": "kmore", | ||
"author": "waiting", | ||
"version": "49.0.3", | ||
"version": "50.0.0", | ||
"description": "A SQL query builder based on knex with powerful TypeScript type support", | ||
@@ -41,9 +41,9 @@ "keywords": [ | ||
"dependencies": { | ||
"@waiting/shared-core": "^20.8.0" | ||
"@waiting/shared-core": "^20.10.1" | ||
}, | ||
"devDependencies": { | ||
"@mwcp/otel": "^3.8.7", | ||
"@mwcp/otel": "^3.16.0", | ||
"cross-env": "7", | ||
"kmore-cli": "^49.0.2", | ||
"kmore-types": "^49.0.0", | ||
"kmore-cli": "^50.0.0", | ||
"kmore-types": "^50.0.0", | ||
"knex": "^2.3.0", | ||
@@ -82,3 +82,3 @@ "pg": "^8.7.3" | ||
}, | ||
"gitHead": "bc502f37437e0476a56531534f7afd795b52021e" | ||
"gitHead": "be013fb26526d9cf2984e6051faf6a270bfa5165" | ||
} |
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { KmoreQueryBuilder, PageRawType, PageWrapType } from './builder.types.js' | ||
import type { | ||
CtxBuilderPreProcessor, | ||
CtxBuilderResultPreProcessor, | ||
CtxExceptionHandler, | ||
KmoreQueryBuilder, | ||
PageRawType, | ||
PageWrapType, | ||
} from './builder.types.js' | ||
import { | ||
@@ -76,2 +83,5 @@ CaseType, | ||
thenHandler: (options: ProxyGetHandlerOptions) => KmoreQueryBuilder['then'] | ||
ctxBuilderPreProcessor: CtxBuilderPreProcessor | undefined | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor | undefined | ||
ctxExceptionHandler: CtxExceptionHandler | undefined | ||
resultPagerHandler?: ResultPagerHandler | undefined | ||
@@ -85,2 +95,5 @@ } | ||
receiver: unknown | ||
ctxBuilderPreProcessor: CtxBuilderPreProcessor | undefined | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor | undefined | ||
ctxExceptionHandler: CtxExceptionHandler | undefined | ||
resultPagerHandler?: ResultPagerHandler | undefined | ||
@@ -91,2 +104,5 @@ } | ||
builder: KmoreQueryBuilder | ||
ctxBuilderPreProcessor: CtxBuilderPreProcessor | undefined | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor | undefined | ||
ctxExceptionHandler: CtxExceptionHandler | undefined | ||
} | ||
@@ -93,0 +109,0 @@ |
@@ -59,2 +59,5 @@ import assert from 'node:assert' | ||
thenHandler: proxyGetThen, | ||
ctxBuilderPreProcessor: options.ctxBuilderPreProcessor, | ||
ctxBuilderResultPreProcessor: options.ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler: options.ctxExceptionHandler, | ||
}) | ||
@@ -222,3 +225,9 @@ | ||
builderPager = createBuilderProperties(builderPager, caseConvert, kmoreQueryId2, dbDict) | ||
builderPager = createBuilderProperties( | ||
builderPager, | ||
caseConvert, | ||
kmoreQueryId2, | ||
dbDict, | ||
kmore.dbId, | ||
) | ||
@@ -225,0 +234,0 @@ const trx = kmore.getTrxByKmoreQueryId(kmoreQueryId) |
@@ -0,1 +1,3 @@ | ||
/* eslint-disable max-params */ | ||
/* eslint-disable @typescript-eslint/ban-types */ | ||
import assert from 'assert' | ||
@@ -7,3 +9,10 @@ | ||
import { createBuilderProperties } from './builder.props.js' | ||
import type { DbQueryBuilder, KmoreQueryBuilder } from './builder.types.js' | ||
import type { | ||
CtxBuilderPreProcessor, | ||
CtxBuilderResultPreProcessor, | ||
CtxExceptionHandler, | ||
DbQueryBuilder, | ||
KmoreQueryBuilder, | ||
TbQueryBuilder, | ||
} from './builder.types.js' | ||
import { defaultPropDescriptor } from './config.js' | ||
@@ -41,9 +50,21 @@ import { builderApplyTransactingProxy } from './proxy.apply.js' | ||
const name = `${prefix}${refName}` | ||
// @ts-expect-error | ||
const queryBuilderCreator: TbQueryBuilder<D, CaseType, {}, Context> = (options) => { | ||
const ctx2 = options?.ctx ?? { id: kmore.dbId, instanceId: kmore.instanceId } | ||
return extRefTableFnProperty( | ||
kmore, | ||
refName, | ||
caseConvert, | ||
ctx2, | ||
options?.ctxBuilderPreProcessor, | ||
options?.ctxBuilderResultPreProcessor, | ||
options?.ctxExceptionHandler, | ||
) | ||
} // must dynamically!! | ||
Object.defineProperty(rb, name, { | ||
...defaultPropDescriptor, | ||
writable: true, | ||
value: (ctx?: Context) => { | ||
const ctx2 = ctx ?? { id: kmore.dbId, instanceId: kmore.instanceId } | ||
return extRefTableFnProperty(kmore, refName, caseConvert, ctx2) | ||
}, // must dynamically!! | ||
value: queryBuilderCreator, | ||
}) | ||
@@ -66,2 +87,5 @@ | ||
ctx: unknown, | ||
ctxBuilderPreProcessor: CtxBuilderPreProcessor | undefined, | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor | undefined, | ||
ctxExceptionHandler: CtxExceptionHandler | undefined, | ||
): KmoreQueryBuilder { | ||
@@ -85,2 +109,5 @@ | ||
thenHandler: proxyGetThen, | ||
ctxBuilderPreProcessor, | ||
ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler, | ||
resultPagerHandler: pager, | ||
@@ -106,2 +133,3 @@ }) | ||
kmore.dict, | ||
kmore.dbId, | ||
) | ||
@@ -108,0 +136,0 @@ |
import assert from 'assert' | ||
import type { KmoreQueryBuilder } from './builder.types.js' | ||
import { KmoreQueryBuilder, QueryBuilderExtKey } from './builder.types.js' | ||
import { defaultPropDescriptor } from './config.js' | ||
@@ -13,2 +13,3 @@ import { CaseType } from './types.js' | ||
dict: unknown, | ||
dbId: string, | ||
): KmoreQueryBuilder { | ||
@@ -18,3 +19,3 @@ | ||
void Object.defineProperty(refTable, 'kmoreQueryId', { | ||
void Object.defineProperty(refTable, QueryBuilderExtKey.kmoreQueryId, { | ||
...defaultPropDescriptor, | ||
@@ -24,3 +25,3 @@ value: kmoreQueryId, | ||
void Object.defineProperty(refTable, 'dbDict', { | ||
void Object.defineProperty(refTable, QueryBuilderExtKey.dbDict, { | ||
...defaultPropDescriptor, | ||
@@ -30,3 +31,3 @@ value: dict, | ||
void Object.defineProperty(refTable, '_tablesJoin', { | ||
void Object.defineProperty(refTable, QueryBuilderExtKey.tablesJoin, { | ||
...defaultPropDescriptor, | ||
@@ -36,3 +37,3 @@ value: [], | ||
void Object.defineProperty(refTable, 'caseConvert', { | ||
void Object.defineProperty(refTable, QueryBuilderExtKey.caseConvert, { | ||
...defaultPropDescriptor, | ||
@@ -42,4 +43,10 @@ value: caseConvert, | ||
assert(dbId, 'dbId must be defined') | ||
void Object.defineProperty(refTable, QueryBuilderExtKey.dbId, { | ||
...defaultPropDescriptor, | ||
value: dbId, | ||
}) | ||
return refTable | ||
} | ||
@@ -18,3 +18,5 @@ /* eslint-disable max-len */ | ||
import { PropagationType } from './propagation.types.js' | ||
/** | ||
@@ -67,4 +69,24 @@ * - 0: No paging | ||
export type TbQueryBuilder<D extends {}, CaseConvert extends CaseType, TRecord extends {}, Context> | ||
= (ctx?: Context) => KmoreQueryBuilder<D, CaseConvert, 0, TRecord, TRecord[]> | ||
= (options?: Partial<TbQueryBuilderOptions<Context>>) => KmoreQueryBuilder<D, CaseConvert, 0, TRecord, TRecord[]> | ||
export interface TbQueryBuilderOptions<Context> { | ||
ctx: Context | ||
ctxBuilderPreProcessor: CtxBuilderPreProcessor | undefined | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor | undefined | ||
ctxExceptionHandler: CtxExceptionHandler | undefined | ||
} | ||
export enum QueryBuilderExtKey { | ||
caseConvert = 'caseConvert', | ||
kmoreQueryId = 'kmoreQueryId', | ||
dbDict = 'dbDict', | ||
dbId = 'dbId', | ||
tablesJoin = '_tablesJoin', | ||
pagingType = 'pagingType', | ||
transactionalProcessed = 'transactionalProcessed', | ||
trxPropagateOptions = 'trxPropagateOptions', | ||
trxPropagated = 'trxPropagated', | ||
rowLockLevel = 'rowLockLevel', | ||
} | ||
interface QueryBuilderExtName<D extends {} = {}> { | ||
@@ -74,6 +96,42 @@ caseConvert: CaseType | ||
dbDict: DbDict<D> | ||
dbId: string | ||
_tablesJoin: string[] | ||
pagingType?: 'counter' | 'pager' | ||
trxPropagateOptions?: TrxPropagateOptions | ||
trxPropagated?: boolean | ||
/** | ||
* Propagation rowlock level | ||
* @default {@link RowLockLevel} | ||
*/ | ||
rowLockLevel: RowLockLevel | undefined | ||
transactionalProcessed: boolean | undefined | ||
} | ||
export interface TrxPropagateOptions { | ||
dbId: string | ||
type: PropagationType | ||
path: string | ||
className: string | ||
funcName: string | ||
methodName: string | ||
line: number | ||
column: number | ||
/** | ||
* @default {@link RowLockLevel.ForShare} | ||
*/ | ||
readRowLockLevel: RowLockLevel | ||
/** | ||
* @default {@link RowLockLevel.ForUpdate} | ||
*/ | ||
writeRowLockLevel: RowLockLevel | ||
} | ||
/** | ||
* Used for `@Transactional()` decorator | ||
*/ | ||
export enum RowLockLevel { | ||
ForShare = 'FOR_SHARE', | ||
ForUpdate = 'FOR_UPDATE', | ||
None = 'None', | ||
} | ||
interface QueryBuilderExtMethod< | ||
@@ -733,1 +791,23 @@ D extends {} = {}, | ||
export type CtxBuilderPreProcessor = (builder: KmoreQueryBuilder) => Promise<{ builder: KmoreQueryBuilder }> | ||
export type CtxBuilderResultPreProcessor<T = unknown> = (options: CtxBuilderResultPreProcessorOptions<T>) => Promise<T> | ||
export type CtxExceptionHandler = (options: CtxExceptionHandlerOptions) => Promise<never> | ||
export interface CtxBuilderResultPreProcessorOptions<Resp = unknown> { | ||
kmoreQueryId: symbol | ||
kmoreTrxId: symbol | undefined | ||
response: Resp | ||
transactionalProcessed: boolean | undefined | ||
trxPropagateOptions: TrxPropagateOptions | undefined | ||
trxPropagated: boolean | undefined | ||
/** | ||
* Propagation rowlock level | ||
* @default {@link RowLockLevel} | ||
*/ | ||
rowLockLevel: RowLockLevel | undefined | ||
} | ||
export interface CtxExceptionHandlerOptions extends Omit<CtxBuilderResultPreProcessorOptions, 'response'> { | ||
exception: unknown | ||
} |
@@ -5,2 +5,3 @@ | ||
export * from './builder.types.js' | ||
export * from './propagation.types.js' | ||
@@ -12,2 +13,3 @@ export { initKmoreEvent } from './config.js' | ||
} from './helper.js' | ||
export { genKmoreTrxId } from './util.js' | ||
@@ -95,3 +95,2 @@ /* eslint-disable max-lines-per-function */ | ||
constructor(options: KmoreFactoryOpts<D, Context>) { | ||
@@ -160,6 +159,5 @@ super() | ||
* Start a transaction. | ||
* @param id - For generation of kmoreTrxId | ||
*/ | ||
async transaction(config?: KmoreTransactionConfig): Promise<KmoreTransaction> { | ||
const kmoreTrxId = genKmoreTrxId(config?.kmoreTrxId) | ||
const kmoreTrxId = config?.kmoreTrxId ?? genKmoreTrxId(config?.kmoreTrxId) | ||
delete config?.kmoreTrxId | ||
@@ -166,0 +164,0 @@ const trx = await this.dbh.transaction(void 0, config) as KmoreTransaction |
@@ -5,2 +5,3 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import type { KmoreBase } from './base.js' | ||
import { CtxBuilderResultPreProcessor, CtxBuilderResultPreProcessorOptions, CtxExceptionHandler } from './builder.types.js' | ||
import { defaultPropDescriptor } from './config.js' | ||
@@ -10,7 +11,10 @@ import { KmoreProxyKey } from './types.js' | ||
interface ProcessThenRetOptions { | ||
interface ProcessThenRetOptions<Resp = unknown> extends Omit<CtxBuilderResultPreProcessorOptions<Resp>, 'response'> { | ||
kmore: KmoreBase | ||
kmoreQueryId: symbol | ||
input: Promise<unknown> | ||
done: undefined | ((data: unknown) => unknown) | ||
input: Promise<Resp> | ||
ctxBuilderResultPreProcessor: CtxBuilderResultPreProcessor<Resp> | undefined | ||
ctxExceptionHandler: CtxExceptionHandler | undefined | ||
transactionalProcessed: boolean | undefined | ||
done: undefined | ((data: Resp) => Resp) | ||
reject: undefined | ((data: unknown) => Error) | ||
@@ -23,5 +27,41 @@ } | ||
const { kmore, kmoreQueryId, input, done, reject } = options | ||
const { | ||
ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler, | ||
input, | ||
kmore, | ||
kmoreQueryId, | ||
kmoreTrxId, | ||
rowLockLevel, | ||
transactionalProcessed, | ||
trxPropagated, | ||
trxPropagateOptions, | ||
done, | ||
reject, | ||
} = options | ||
return input | ||
const pm1 = ctxBuilderResultPreProcessor | ||
? input.then((response: unknown) => ctxBuilderResultPreProcessor({ | ||
kmoreQueryId, | ||
kmoreTrxId, | ||
response, | ||
transactionalProcessed, | ||
trxPropagateOptions, | ||
trxPropagated, | ||
rowLockLevel, | ||
})) | ||
: input | ||
const pm2 = ctxExceptionHandler | ||
? pm1.catch((ex: unknown) => ctxExceptionHandler({ | ||
kmoreQueryId, | ||
kmoreTrxId, | ||
transactionalProcessed, | ||
trxPropagateOptions, | ||
trxPropagated, | ||
rowLockLevel, | ||
exception: ex, | ||
})) | ||
: pm1 | ||
return pm2 | ||
.catch((ex: unknown) => processTrxOnEx(kmore, kmoreQueryId, ex)) | ||
@@ -28,0 +68,0 @@ .then((resp: unknown) => processThen(resp, done)) |
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import assert from 'assert' | ||
import type { ProxyGetHandlerOptions } from './base.js' | ||
import type { PagerOptions, ProxyGetHandlerOptions } from './base.js' | ||
import type { KmoreQueryBuilder } from './builder.types.js' | ||
@@ -24,2 +24,5 @@ import { defaultPropDescriptor } from './config.js' | ||
resultPagerHandler, | ||
ctxBuilderPreProcessor, | ||
ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler, | ||
} = options | ||
@@ -33,5 +36,16 @@ assert(propKey === 'then', `propKey should be "then", but got: ${propKey.toString()}`) | ||
const builder = origBuilder | ||
const builder = typeof ctxBuilderPreProcessor === 'function' | ||
? (await ctxBuilderPreProcessor(origBuilder)).builder | ||
: origBuilder | ||
const { kmoreQueryId } = builder | ||
if (! kmoreQueryId) { | ||
const errMsg = 'kmoreQueryId should be defined, builder may not be a KmoreQueryBuilder' | ||
console.error(errMsg) | ||
const err = new Error(errMsg) | ||
if (reject) { | ||
return reject(err) | ||
} | ||
throw err | ||
} | ||
@@ -46,3 +60,11 @@ let getThenProxyRet: Promise<unknown> | ||
// pager() | ||
getThenProxyRet = resultPagerHandler({ builder, kmore }, createQueryBuilderGetProxy) | ||
const opts: PagerOptions = { | ||
builder, | ||
kmore, | ||
ctxBuilderPreProcessor: options.ctxBuilderPreProcessor, | ||
ctxBuilderResultPreProcessor: options.ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler: options.ctxExceptionHandler, | ||
} | ||
getThenProxyRet = resultPagerHandler(opts, createQueryBuilderGetProxy) | ||
} | ||
@@ -54,6 +76,16 @@ else { | ||
const kmoreTrxId = kmore.getTrxByKmoreQueryId(kmoreQueryId)?.kmoreTrxId | ||
const { rowLockLevel, transactionalProcessed, trxPropagated, trxPropagateOptions } = builder | ||
return processThenRet({ | ||
ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler, | ||
input: getThenProxyRet, | ||
kmore, | ||
kmoreQueryId, | ||
input: getThenProxyRet, | ||
kmoreTrxId, | ||
rowLockLevel, | ||
transactionalProcessed, | ||
trxPropagated, | ||
trxPropagateOptions, | ||
done, | ||
@@ -60,0 +92,0 @@ reject, |
@@ -14,2 +14,5 @@ import type { CreateQueryBuilderGetProxyOptions } from './base.js' | ||
resultPagerHandler, | ||
ctxBuilderPreProcessor, | ||
ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler, | ||
} = options | ||
@@ -28,2 +31,5 @@ | ||
resultPagerHandler, | ||
ctxBuilderPreProcessor, | ||
ctxBuilderResultPreProcessor, | ||
ctxExceptionHandler, | ||
}) | ||
@@ -30,0 +36,0 @@ default: |
@@ -63,2 +63,3 @@ import assert from 'node:assert' | ||
}) | ||
assert(trx3.kmoreTrxId !== ctx.kmoreTrxId, 'trx3.kmoreTrxId === ctx.kmoreTrxId') | ||
return trx3 | ||
@@ -135,2 +136,3 @@ }, | ||
assert(kmoreTrxId, 'kmoreTrxId must be provided from parent trx when creating savepoint') | ||
assert(kmoreTrxId !== parentTrx.kmoreTrxId, 'kmoreTrxId === parentTrx.kmoreTrxId') | ||
@@ -137,0 +139,0 @@ assert(trx.isTransaction === true, 'output trx not a transaction when creating savepoint') |
@@ -7,3 +7,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import type { KmoreQueryBuilder } from './builder.types.js' | ||
import { | ||
KmoreQueryBuilder, | ||
QueryBuilderExtKey, | ||
TrxPropagateOptions, | ||
} from './builder.types.js' | ||
@@ -20,2 +24,3 @@ | ||
* Auto transction action (rollback|commit|none) on builder error (Rejection or Exception), | ||
* declarative transaction always rollback on end | ||
* | ||
@@ -28,2 +33,4 @@ * @default rollback | ||
[QueryBuilderExtKey.trxPropagateOptions]?: TrxPropagateOptions, | ||
savepoint: ( | ||
@@ -35,5 +42,6 @@ id?: PropertyKey, | ||
export type KmoreTransactionConfig = Knex.TransactionConfig & { | ||
kmoreTrxId?: PropertyKey, | ||
kmoreTrxId?: PropertyKey | undefined, | ||
/** | ||
* Auto transction action (rollback|commit|none) on builder error (Rejection or Exception), | ||
* declarative transaction always rollback on end | ||
* | ||
@@ -40,0 +48,0 @@ * @default rollback |
@@ -14,3 +14,3 @@ import assert from 'node:assert' | ||
else if (typeof id === 'string' || typeof id === 'number') { | ||
const str = id.toString() + (suffix ? `-${suffix}` : '') | ||
const str = id.toString() + Date.now().toString() + (suffix ? `-${suffix}` : '') | ||
return Symbol(str) | ||
@@ -20,13 +20,19 @@ } | ||
const str = id.toString() | ||
let key2 = '' | ||
if (str.startsWith('Symbol(trx-')) { | ||
const key = str.match(/Symbol\((trx-\S+)\)/u)?.[1] | ||
assert(key, 'retrieve key from id failed, input should like "Symbol(trx-1234567890)"') | ||
const key2 = `${key}-${Date.now()}` + (suffix ? `-${suffix}` : '') | ||
return Symbol(key2) | ||
key2 = `${key}-${Date.now()}` | ||
} | ||
else if (str.startsWith('trx-')) { | ||
key2 = str | ||
} | ||
else { | ||
const key = `trx-${str}` + (suffix ? `-${suffix}` : '') | ||
return Symbol(key) | ||
key2 = `trx-${str}` | ||
} | ||
const key3 = suffix ? `${key2}-${suffix}` : `${key2}-${Date.now()}` | ||
assert(key3 !== str, 'result should not equal to the input id') | ||
return Symbol(key3) | ||
} | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
396332
9.06%122
4.27%6618
9.81%