@cleverbrush/knex-schema 0.0.0-beta-20260413145651
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.
- package/README.md +254 -0
- package/dist/SchemaQueryBuilder.d.ts +567 -0
- package/dist/columns.d.ts +27 -0
- package/dist/extension.d.ts +286 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/mappers.d.ts +61 -0
- package/dist/types.d.ts +92 -0
- package/dist/validate.d.ts +8 -0
- package/package.json +52 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ValidatedSpec } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Built-in named value mapper functions.
|
|
4
|
+
*
|
|
5
|
+
* Each entry maps a string key to a transformation function. Pass the key as
|
|
6
|
+
* the `mapper` argument to {@link mapValue} instead of a custom function.
|
|
7
|
+
*
|
|
8
|
+
* Currently available:
|
|
9
|
+
* - `date_from_json` — converts a JSON date string (`string | null`) to a
|
|
10
|
+
* JavaScript `Date` object (or passes through falsy values unchanged).
|
|
11
|
+
*/
|
|
12
|
+
export declare const MAPPERS: Record<string, (value: any) => any>;
|
|
13
|
+
/**
|
|
14
|
+
* Apply a single mapper to a value.
|
|
15
|
+
*
|
|
16
|
+
* @param mapper - Either a transformation function `(v: any) => any`, or a
|
|
17
|
+
* string key referencing one of the {@link MAPPERS} built-ins (e.g.
|
|
18
|
+
* `'date_from_json'`).
|
|
19
|
+
* @param value - The raw value to transform.
|
|
20
|
+
* @returns The transformed value.
|
|
21
|
+
*
|
|
22
|
+
* @throws If `mapper` is a string that does not exist in {@link MAPPERS}.
|
|
23
|
+
*/
|
|
24
|
+
export declare function mapValue(mapper: ((v: any) => any) | string, value: any): any;
|
|
25
|
+
/**
|
|
26
|
+
* Apply a map of per-key transformations to an object, returning a new object
|
|
27
|
+
* with the transformed values.
|
|
28
|
+
*
|
|
29
|
+
* Keys not present in `mappers` are copied through unchanged. Keys present in
|
|
30
|
+
* `mappers` are passed through {@link mapValue}.
|
|
31
|
+
*
|
|
32
|
+
* @param obj - The source object (e.g. a raw database row).
|
|
33
|
+
* @param mappers - A `Record` mapping property keys to mapper functions or
|
|
34
|
+
* {@link MAPPERS} built-in names.
|
|
35
|
+
* @returns A shallow copy of `obj` with the specified values transformed.
|
|
36
|
+
*
|
|
37
|
+
* @throws If `obj` is `null` or a non-object, it is returned as-is.
|
|
38
|
+
*/
|
|
39
|
+
export declare function mapObject<T extends Record<string, any>>(obj: T, mappers: Record<string, ((v: any) => any) | string>): T;
|
|
40
|
+
/**
|
|
41
|
+
* Apply value mappers to the joined fields of a result row in place.
|
|
42
|
+
*
|
|
43
|
+
* After an eager-loaded query resolves, joined objects and arrays may contain
|
|
44
|
+
* raw database values that need transformation (e.g. date strings → `Date`).
|
|
45
|
+
* This function iterates over the one-to-one and one-to-many specs, applies
|
|
46
|
+
* the `mappers` defined on each spec to the nested data, and returns the
|
|
47
|
+
* mutated row.
|
|
48
|
+
*
|
|
49
|
+
* This is an internal helper used by {@link SchemaQueryBuilder}'s result
|
|
50
|
+
* mapping pipeline. Exported to allow custom post-processing if needed.
|
|
51
|
+
*
|
|
52
|
+
* @param row - The raw result row (mutated in place).
|
|
53
|
+
* @param oneSpecs - Validated one-to-one join specs with optional `mappers`.
|
|
54
|
+
* @param manySpecs - Validated one-to-many join specs with optional `mappers`.
|
|
55
|
+
* @returns The mutated `row` object.
|
|
56
|
+
*/
|
|
57
|
+
export declare function clearRow(row: Record<string, any>, oneSpecs: Array<ValidatedSpec & {
|
|
58
|
+
type: 'one';
|
|
59
|
+
}>, manySpecs: Array<ValidatedSpec & {
|
|
60
|
+
type: 'many';
|
|
61
|
+
}>): Record<string, any>;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { InferType, ObjectSchemaBuilder, PropertyDescriptor, PropertyDescriptorTree } from '@cleverbrush/schema';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
export type SchemaKeys<T extends ObjectSchemaBuilder<any, any, any, any, any, any, any>> = keyof InferType<T> & string;
|
|
4
|
+
/**
|
|
5
|
+
* Strips the `withExtensions()` overlay from a schema type, reducing it to a
|
|
6
|
+
* plain `ObjectSchemaBuilder<TProps, TReq>`. This is necessary so that
|
|
7
|
+
* `PropertyDescriptorTree<SchemaBase<T>, SchemaBase<T>>` resolves without
|
|
8
|
+
* hitting TypeScript's recursion depth limit, which happens when the full
|
|
9
|
+
* intersection type (builder + extension methods + HiddenExtensionMethods) is
|
|
10
|
+
* passed directly.
|
|
11
|
+
*/
|
|
12
|
+
type SchemaBase<T extends ObjectSchemaBuilder<any, any, any, any, any, any, any>> = T extends ObjectSchemaBuilder<infer P, infer Req, any, any, any, any, any> ? ObjectSchemaBuilder<P, Req> : never;
|
|
13
|
+
export type ColumnRef<T extends ObjectSchemaBuilder<any, any, any, any, any, any, any>> = SchemaKeys<T> | ((tree: PropertyDescriptorTree<SchemaBase<T>, SchemaBase<T>>) => PropertyDescriptor<SchemaBase<T>, any, any>);
|
|
14
|
+
export interface JoinOneSpec<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TForeignSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TFieldName extends string = string, TRequired extends boolean = true> {
|
|
15
|
+
/** Column on the local (base) table used for the join (string key or property accessor) */
|
|
16
|
+
localColumn: ColumnRef<TLocalSchema>;
|
|
17
|
+
/** Column on the foreign table used for the join (string key or property accessor) */
|
|
18
|
+
foreignColumn: ColumnRef<TForeignSchema>;
|
|
19
|
+
/** Name of the field that will hold the loaded object in the result */
|
|
20
|
+
as: TFieldName;
|
|
21
|
+
/** If true (default), uses INNER JOIN; if false, uses LEFT JOIN (result may be null) */
|
|
22
|
+
required?: TRequired;
|
|
23
|
+
/** Optional Knex query builder for the foreign table — auto-derived from foreignSchema's tableName if omitted */
|
|
24
|
+
foreignQuery?: Knex.QueryBuilder | {
|
|
25
|
+
toKnexQuery(): Knex.QueryBuilder;
|
|
26
|
+
};
|
|
27
|
+
/** Foreign schema for type inference */
|
|
28
|
+
foreignSchema: TForeignSchema;
|
|
29
|
+
/** Optional post-load value transformers per foreign column */
|
|
30
|
+
mappers?: Partial<Record<SchemaKeys<TForeignSchema>, ((value: any) => any) | string>>;
|
|
31
|
+
}
|
|
32
|
+
export interface JoinManySpec<TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TForeignSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TFieldName extends string = string> {
|
|
33
|
+
/** Column on the local (base) table used for the join (string key or property accessor) */
|
|
34
|
+
localColumn: ColumnRef<TLocalSchema>;
|
|
35
|
+
/** Column on the foreign table used for the join (string key or property accessor) */
|
|
36
|
+
foreignColumn: ColumnRef<TForeignSchema>;
|
|
37
|
+
/** Name of the field that will hold the loaded array in the result */
|
|
38
|
+
as: TFieldName;
|
|
39
|
+
/** Optional Knex query builder for the foreign table — auto-derived from foreignSchema's tableName if omitted */
|
|
40
|
+
foreignQuery?: Knex.QueryBuilder | {
|
|
41
|
+
toKnexQuery(): Knex.QueryBuilder;
|
|
42
|
+
};
|
|
43
|
+
/** Foreign schema for type inference */
|
|
44
|
+
foreignSchema: TForeignSchema;
|
|
45
|
+
/** Maximum number of related items to load per parent row */
|
|
46
|
+
limit?: number;
|
|
47
|
+
/** Number of related items to skip per parent row */
|
|
48
|
+
offset?: number;
|
|
49
|
+
/** Column to order the related items by (required for deterministic limit/offset) */
|
|
50
|
+
orderBy?: {
|
|
51
|
+
column: ColumnRef<TForeignSchema>;
|
|
52
|
+
direction?: 'asc' | 'desc';
|
|
53
|
+
};
|
|
54
|
+
/** Optional post-load value transformers per foreign column */
|
|
55
|
+
mappers?: Partial<Record<SchemaKeys<TForeignSchema>, ((value: any) => any) | string>>;
|
|
56
|
+
}
|
|
57
|
+
/** Adds a single joined object field to TBase */
|
|
58
|
+
export type WithJoinedOne<TBase, TFieldName extends string, TForeignSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>, TRequired extends boolean> = TBase & {
|
|
59
|
+
[K in TFieldName]: TRequired extends true ? InferType<TForeignSchema> : InferType<TForeignSchema> | null;
|
|
60
|
+
};
|
|
61
|
+
/** Adds a joined collection field to TBase */
|
|
62
|
+
export type WithJoinedMany<TBase, TFieldName extends string, TForeignSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>> = TBase & {
|
|
63
|
+
[K in TFieldName]: InferType<TForeignSchema>[];
|
|
64
|
+
};
|
|
65
|
+
export interface ValidatedJoinOneSpec {
|
|
66
|
+
localColumn: string;
|
|
67
|
+
foreignColumn: string;
|
|
68
|
+
as: string;
|
|
69
|
+
required: boolean;
|
|
70
|
+
foreignQuery: Knex.QueryBuilder;
|
|
71
|
+
mappers?: Record<string, ((value: any) => any) | string>;
|
|
72
|
+
}
|
|
73
|
+
export interface ValidatedJoinManySpec {
|
|
74
|
+
localColumn: string;
|
|
75
|
+
foreignColumn: string;
|
|
76
|
+
as: string;
|
|
77
|
+
foreignQuery: Knex.QueryBuilder;
|
|
78
|
+
limit: number | null;
|
|
79
|
+
offset: number | null;
|
|
80
|
+
orderBy: {
|
|
81
|
+
column: string;
|
|
82
|
+
direction: 'asc' | 'desc';
|
|
83
|
+
} | null;
|
|
84
|
+
mappers?: Record<string, ((value: any) => any) | string>;
|
|
85
|
+
}
|
|
86
|
+
export type ValidatedSpec = ({
|
|
87
|
+
type: 'one';
|
|
88
|
+
} & ValidatedJoinOneSpec) | ({
|
|
89
|
+
type: 'many';
|
|
90
|
+
} & ValidatedJoinManySpec);
|
|
91
|
+
export type InsertType<T extends ObjectSchemaBuilder<any, any, any, any, any, any, any>> = InferType<T>;
|
|
92
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ObjectSchemaBuilder } from '@cleverbrush/schema';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
import type { JoinManySpec, JoinOneSpec, ValidatedJoinManySpec, ValidatedJoinOneSpec } from './types.js';
|
|
4
|
+
export declare function validateJoinOne(spec: JoinOneSpec<any, any, any, any>, localSchema: ObjectSchemaBuilder<any, any, any, any, any, any, any>, knex: Knex): ValidatedJoinOneSpec;
|
|
5
|
+
export declare function validateJoinMany(spec: JoinManySpec<any, any, any>, localSchema: ObjectSchemaBuilder<any, any, any, any, any, any, any>, knex: Knex): ValidatedJoinManySpec;
|
|
6
|
+
export declare function validateUniqueFieldNames(specs: Array<{
|
|
7
|
+
as: string;
|
|
8
|
+
}>): void;
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "Andrew Zolotukhin <andrew_zol@cleverbrush.com>",
|
|
3
|
+
"bugs": {
|
|
4
|
+
"url": "https://github.com/cleverbrush/framework/issues",
|
|
5
|
+
"email": "andrew_zol@cleverbrush.com"
|
|
6
|
+
},
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@cleverbrush/schema": "0.0.0-beta-20260413145651"
|
|
9
|
+
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"knex": ">=3.1.0"
|
|
12
|
+
},
|
|
13
|
+
"description": "Type-safe schema-driven query builder for Knex using @cleverbrush/schema — strongly typed CRUD, eager loading, and column mapping for PostgreSQL",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://docs.cleverbrush.com/knex-schema",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"knex",
|
|
20
|
+
"query builder",
|
|
21
|
+
"schema",
|
|
22
|
+
"typescript",
|
|
23
|
+
"type-safe",
|
|
24
|
+
"postgresql",
|
|
25
|
+
"orm",
|
|
26
|
+
"eager loading",
|
|
27
|
+
"cleverbrush"
|
|
28
|
+
],
|
|
29
|
+
"license": "BSD 3-Clause",
|
|
30
|
+
"main": "./dist/index.js",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"import": "./dist/index.js"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"sideEffects": false,
|
|
38
|
+
"name": "@cleverbrush/knex-schema",
|
|
39
|
+
"readme": "https://github.com/cleverbrush/framework/tree/master/libs/knex-schema#readme",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "github:cleverbrush/framework"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"watch": "tsc --build tsconfig.build.json --watch",
|
|
46
|
+
"build": "tsup && tsc --project tsconfig.build.json --emitDeclarationOnly",
|
|
47
|
+
"clean": "rm -rf dist tsconfig.build.tsbuildinfo"
|
|
48
|
+
},
|
|
49
|
+
"type": "module",
|
|
50
|
+
"types": "./dist/index.d.ts",
|
|
51
|
+
"version": "0.0.0-beta-20260413145651"
|
|
52
|
+
}
|