rads-db 3.2.36 → 3.2.38
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/dist/config.cjs +91 -12
- package/dist/config.d.ts +21 -7
- package/dist/config.mjs +90 -12
- package/dist/index.d.ts +2 -2
- package/dist/{types-eb31ea63.d.ts → types-f64a81e8.d.ts} +1 -0
- package/package.json +2 -1
package/dist/config.cjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
4
|
const path = require('node:path');
|
|
5
|
+
const fg = require('fast-glob');
|
|
5
6
|
const typescript = require('typescript');
|
|
6
7
|
const _ = require('lodash');
|
|
7
8
|
|
|
@@ -9,6 +10,7 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
9
10
|
|
|
10
11
|
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
11
12
|
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
13
|
+
const fg__default = /*#__PURE__*/_interopDefaultCompat(fg);
|
|
12
14
|
const ___default = /*#__PURE__*/_interopDefaultCompat(_);
|
|
13
15
|
|
|
14
16
|
const supportedPrimitiveTypes = ["string", "number", "boolean", "Record<string, string>", "Record<string, any>"];
|
|
@@ -598,21 +600,98 @@ function verifyRelationFields(result) {
|
|
|
598
600
|
function defineRadsConfig(config) {
|
|
599
601
|
return config;
|
|
600
602
|
}
|
|
601
|
-
function
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
603
|
+
async function expandToDirectories(patterns) {
|
|
604
|
+
const dirs = [];
|
|
605
|
+
for (const p of patterns) {
|
|
606
|
+
if (fg__default.isDynamicPattern(p)) {
|
|
607
|
+
const matches = await fg__default(p, { onlyDirectories: true, absolute: true });
|
|
608
|
+
dirs.push(...matches);
|
|
609
|
+
} else {
|
|
610
|
+
dirs.push(path__default.resolve(p));
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return dirs;
|
|
614
|
+
}
|
|
615
|
+
async function resolveDirs(pathsArray) {
|
|
616
|
+
const resolvedDirs = [];
|
|
617
|
+
for (const p of pathsArray) {
|
|
618
|
+
if (fg__default.isDynamicPattern(p)) {
|
|
619
|
+
const matches = await fg__default(p, { onlyDirectories: true, absolute: true });
|
|
620
|
+
resolvedDirs.push(...matches);
|
|
621
|
+
} else {
|
|
622
|
+
const resolved = path__default.resolve(p);
|
|
623
|
+
if (!fs__default.existsSync(resolved))
|
|
624
|
+
await fs__default.promises.mkdir(resolved, { recursive: true });
|
|
625
|
+
resolvedDirs.push(resolved);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return resolvedDirs;
|
|
629
|
+
}
|
|
630
|
+
async function scanDirs(resolvedDirs) {
|
|
631
|
+
const entities = {};
|
|
632
|
+
const entityFilePaths = {};
|
|
633
|
+
const entityDirs = {};
|
|
634
|
+
for (const dir of resolvedDirs) {
|
|
635
|
+
const entries = await fs__default.promises.readdir(dir, { withFileTypes: true });
|
|
636
|
+
for (const entry of entries) {
|
|
637
|
+
if (!entry.isFile() || !entry.name.endsWith(".ts"))
|
|
609
638
|
continue;
|
|
610
|
-
|
|
639
|
+
const filePath = path__default.join(dir, entry.name);
|
|
640
|
+
const content = await fs__default.promises.readFile(filePath, "utf-8");
|
|
641
|
+
const stem = entry.name.slice(0, -3);
|
|
642
|
+
const hasEntity = content.includes("@entity");
|
|
643
|
+
if (hasEntity && entityFilePaths[stem]) {
|
|
644
|
+
throw new Error(
|
|
645
|
+
`Entity name collision: "${stem}" is defined in multiple locations:
|
|
646
|
+
${entityFilePaths[stem]}
|
|
647
|
+
${filePath}`
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
entities[stem] = content;
|
|
651
|
+
if (hasEntity) {
|
|
652
|
+
entityFilePaths[stem] = filePath;
|
|
653
|
+
entityDirs[stem] = dir;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return { entities, entityFilePaths, entityDirs };
|
|
658
|
+
}
|
|
659
|
+
async function validateEntityRules(entityFilePaths, entityDirs, entityRules) {
|
|
660
|
+
const resolvedRules = await Promise.all(
|
|
661
|
+
entityRules.map(async (rule) => {
|
|
662
|
+
const rulePaths = Array.isArray(rule.path) ? rule.path : [rule.path];
|
|
663
|
+
const dirs = await expandToDirectories(rulePaths);
|
|
664
|
+
return { rule, dirs };
|
|
665
|
+
})
|
|
666
|
+
);
|
|
667
|
+
for (const [stem, filePath] of Object.entries(entityFilePaths)) {
|
|
668
|
+
const entityDir = entityDirs[stem];
|
|
669
|
+
for (const { rule, dirs } of resolvedRules) {
|
|
670
|
+
const applies = dirs.some((d) => entityDir === d || entityDir.startsWith(d + path__default.sep));
|
|
671
|
+
if (!applies)
|
|
611
672
|
continue;
|
|
612
|
-
|
|
613
|
-
|
|
673
|
+
if (rule.namePrefix && !stem.startsWith(rule.namePrefix)) {
|
|
674
|
+
throw new Error(`Entity "${stem}" at "${filePath}" must have name prefix "${rule.namePrefix}"`);
|
|
675
|
+
}
|
|
676
|
+
if (rule.validate) {
|
|
677
|
+
const error = rule.validate(stem, filePath);
|
|
678
|
+
if (error)
|
|
679
|
+
throw new Error(error);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
function schemaFromFiles(paths, options) {
|
|
685
|
+
return async () => {
|
|
686
|
+
const pathsArray = Array.isArray(paths) ? paths : [paths];
|
|
687
|
+
const resolvedDirs = await resolveDirs(pathsArray);
|
|
688
|
+
const { entities, entityFilePaths, entityDirs } = await scanDirs(resolvedDirs);
|
|
689
|
+
if (options?.entityRules?.length) {
|
|
690
|
+
await validateEntityRules(entityFilePaths, entityDirs, options.entityRules);
|
|
614
691
|
}
|
|
615
|
-
|
|
692
|
+
const isSingleLiteralPath = pathsArray.length === 1 && !fg__default.isDynamicPattern(pathsArray[0]);
|
|
693
|
+
const entitiesDir = isSingleLiteralPath ? pathsArray[0] : void 0;
|
|
694
|
+
return { schema: parseSchema(entities), entitiesDir, entitiesDirs: resolvedDirs };
|
|
616
695
|
};
|
|
617
696
|
}
|
|
618
697
|
function schemaFromRadsApi(radsApiUrl) {
|
package/dist/config.d.ts
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
|
-
import { g as RadsConfig, T as TypeDefinition } from './types-
|
|
1
|
+
import { g as RadsConfig, T as TypeDefinition } from './types-f64a81e8.js';
|
|
2
2
|
import 'mssql';
|
|
3
3
|
import '_rads-db';
|
|
4
4
|
|
|
5
5
|
declare function defineRadsConfig(config: RadsConfig): RadsConfig;
|
|
6
|
+
interface SchemaFromFilesEntityRule {
|
|
7
|
+
/** Directory path(s) or glob pattern(s) this rule applies to */
|
|
8
|
+
path: string | string[];
|
|
9
|
+
/** Entity class name must start with this prefix */
|
|
10
|
+
namePrefix?: string;
|
|
11
|
+
/** Custom validator — return an error message to reject the entity, or throw */
|
|
12
|
+
validate?: (entityName: string, filePath: string) => string | void;
|
|
13
|
+
}
|
|
14
|
+
interface SchemaFromFilesOptions {
|
|
15
|
+
entityRules?: SchemaFromFilesEntityRule[];
|
|
16
|
+
}
|
|
6
17
|
/**
|
|
7
|
-
* Loads all typescript files
|
|
8
|
-
*
|
|
9
|
-
* @
|
|
18
|
+
* Loads all typescript files with @entity() decorated classes from the given path(s),
|
|
19
|
+
* parses them and outputs a merged schema.
|
|
20
|
+
* @param paths - path(s) from project root to folder(s) with entity files; may include glob patterns
|
|
21
|
+
* @param options - optional validation rules per path
|
|
22
|
+
* @returns schema loader function
|
|
10
23
|
*/
|
|
11
|
-
declare function schemaFromFiles(
|
|
24
|
+
declare function schemaFromFiles(paths: string | string[], options?: SchemaFromFilesOptions): () => Promise<{
|
|
12
25
|
schema: Record<string, TypeDefinition>;
|
|
13
|
-
entitiesDir: string;
|
|
26
|
+
entitiesDir: string | undefined;
|
|
27
|
+
entitiesDirs: string[];
|
|
14
28
|
}>;
|
|
15
29
|
/**
|
|
16
30
|
* Loads schema from the rads api.
|
|
@@ -21,4 +35,4 @@ declare function schemaFromRadsApi(radsApiUrl: string): () => Promise<{
|
|
|
21
35
|
schema: any;
|
|
22
36
|
}>;
|
|
23
37
|
|
|
24
|
-
export { defineRadsConfig, schemaFromFiles, schemaFromRadsApi };
|
|
38
|
+
export { SchemaFromFilesEntityRule, SchemaFromFilesOptions, defineRadsConfig, schemaFromFiles, schemaFromRadsApi };
|
package/dist/config.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import fg from 'fast-glob';
|
|
3
4
|
import { SyntaxKind, createSourceFile, ScriptTarget } from 'typescript';
|
|
4
5
|
import _ from 'lodash';
|
|
5
6
|
|
|
@@ -590,21 +591,98 @@ function verifyRelationFields(result) {
|
|
|
590
591
|
function defineRadsConfig(config) {
|
|
591
592
|
return config;
|
|
592
593
|
}
|
|
593
|
-
function
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
594
|
+
async function expandToDirectories(patterns) {
|
|
595
|
+
const dirs = [];
|
|
596
|
+
for (const p of patterns) {
|
|
597
|
+
if (fg.isDynamicPattern(p)) {
|
|
598
|
+
const matches = await fg(p, { onlyDirectories: true, absolute: true });
|
|
599
|
+
dirs.push(...matches);
|
|
600
|
+
} else {
|
|
601
|
+
dirs.push(path.resolve(p));
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return dirs;
|
|
605
|
+
}
|
|
606
|
+
async function resolveDirs(pathsArray) {
|
|
607
|
+
const resolvedDirs = [];
|
|
608
|
+
for (const p of pathsArray) {
|
|
609
|
+
if (fg.isDynamicPattern(p)) {
|
|
610
|
+
const matches = await fg(p, { onlyDirectories: true, absolute: true });
|
|
611
|
+
resolvedDirs.push(...matches);
|
|
612
|
+
} else {
|
|
613
|
+
const resolved = path.resolve(p);
|
|
614
|
+
if (!fs.existsSync(resolved))
|
|
615
|
+
await fs.promises.mkdir(resolved, { recursive: true });
|
|
616
|
+
resolvedDirs.push(resolved);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return resolvedDirs;
|
|
620
|
+
}
|
|
621
|
+
async function scanDirs(resolvedDirs) {
|
|
622
|
+
const entities = {};
|
|
623
|
+
const entityFilePaths = {};
|
|
624
|
+
const entityDirs = {};
|
|
625
|
+
for (const dir of resolvedDirs) {
|
|
626
|
+
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
627
|
+
for (const entry of entries) {
|
|
628
|
+
if (!entry.isFile() || !entry.name.endsWith(".ts"))
|
|
601
629
|
continue;
|
|
602
|
-
|
|
630
|
+
const filePath = path.join(dir, entry.name);
|
|
631
|
+
const content = await fs.promises.readFile(filePath, "utf-8");
|
|
632
|
+
const stem = entry.name.slice(0, -3);
|
|
633
|
+
const hasEntity = content.includes("@entity");
|
|
634
|
+
if (hasEntity && entityFilePaths[stem]) {
|
|
635
|
+
throw new Error(
|
|
636
|
+
`Entity name collision: "${stem}" is defined in multiple locations:
|
|
637
|
+
${entityFilePaths[stem]}
|
|
638
|
+
${filePath}`
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
entities[stem] = content;
|
|
642
|
+
if (hasEntity) {
|
|
643
|
+
entityFilePaths[stem] = filePath;
|
|
644
|
+
entityDirs[stem] = dir;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return { entities, entityFilePaths, entityDirs };
|
|
649
|
+
}
|
|
650
|
+
async function validateEntityRules(entityFilePaths, entityDirs, entityRules) {
|
|
651
|
+
const resolvedRules = await Promise.all(
|
|
652
|
+
entityRules.map(async (rule) => {
|
|
653
|
+
const rulePaths = Array.isArray(rule.path) ? rule.path : [rule.path];
|
|
654
|
+
const dirs = await expandToDirectories(rulePaths);
|
|
655
|
+
return { rule, dirs };
|
|
656
|
+
})
|
|
657
|
+
);
|
|
658
|
+
for (const [stem, filePath] of Object.entries(entityFilePaths)) {
|
|
659
|
+
const entityDir = entityDirs[stem];
|
|
660
|
+
for (const { rule, dirs } of resolvedRules) {
|
|
661
|
+
const applies = dirs.some((d) => entityDir === d || entityDir.startsWith(d + path.sep));
|
|
662
|
+
if (!applies)
|
|
603
663
|
continue;
|
|
604
|
-
|
|
605
|
-
|
|
664
|
+
if (rule.namePrefix && !stem.startsWith(rule.namePrefix)) {
|
|
665
|
+
throw new Error(`Entity "${stem}" at "${filePath}" must have name prefix "${rule.namePrefix}"`);
|
|
666
|
+
}
|
|
667
|
+
if (rule.validate) {
|
|
668
|
+
const error = rule.validate(stem, filePath);
|
|
669
|
+
if (error)
|
|
670
|
+
throw new Error(error);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
function schemaFromFiles(paths, options) {
|
|
676
|
+
return async () => {
|
|
677
|
+
const pathsArray = Array.isArray(paths) ? paths : [paths];
|
|
678
|
+
const resolvedDirs = await resolveDirs(pathsArray);
|
|
679
|
+
const { entities, entityFilePaths, entityDirs } = await scanDirs(resolvedDirs);
|
|
680
|
+
if (options?.entityRules?.length) {
|
|
681
|
+
await validateEntityRules(entityFilePaths, entityDirs, options.entityRules);
|
|
606
682
|
}
|
|
607
|
-
|
|
683
|
+
const isSingleLiteralPath = pathsArray.length === 1 && !fg.isDynamicPattern(pathsArray[0]);
|
|
684
|
+
const entitiesDir = isSingleLiteralPath ? pathsArray[0] : void 0;
|
|
685
|
+
return { schema: parseSchema(entities), entitiesDir, entitiesDirs: resolvedDirs };
|
|
608
686
|
};
|
|
609
687
|
}
|
|
610
688
|
function schemaFromRadsApi(radsApiUrl) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as EntityDecoratorArgs, U as UiDecoratorArgs, a as UiFieldDecoratorArgs, V as ValidateEntityDecoratorArgs, b as ValidateFieldDecoratorArgs, F as FieldDecoratorArgs, C as ComputedDecoratorArgs, S as Schema, D as DriverConstructor, c as Driver, d as ComputedContext, R as RadsRequestContext, e as CreateRadsDbArgs, f as CreateRadsDbClientArgs } from './types-
|
|
2
|
-
export { O as Change, x as ComputedContextGlobal, k as CreateRadsArgsDrivers, m as CreateRadsDbArgsNormalized, an as DeepKeys, ai as DeepPartial, af as DeepPartialArrayItem, ad as DeepPartialWithNulls, ae as DeepPartialWithNullsItem, ag as DeepPartialWithoutNulls, ah as DeepPartialWithoutNullsItem, ao as EntityMethods, w as EnumDefinition, v as FieldDefinition, J as FileSystemNode, u as FileUploadArgs, q as FileUploadDriver, p as FileUploadResult, H as GenerateClientNormalizedOptions, B as GenerateClientOptions, a9 as Get, $ as GetAggArgs, a0 as GetAggArgsAgg, a3 as GetAggArgsAny, a6 as GetAggResponse, _ as GetArgs, a2 as GetArgsAny, a5 as GetArgsInclude, Q as GetManyArgs, a1 as GetManyArgsAny, a7 as GetManyResponse, a8 as GetResponse, aa as GetResponseInclude, ab as GetResponseIncludeSelect, ac as GetResponseNoInclude, s as GetRestRoutesArgs, G as GetRestRoutesOptions, t as GetRestRoutesResponse, ak as InverseRelation, am as JsonPutOperations, M as MinimalDriver, al as Put, P as PutEffect, g as RadsConfig, h as RadsConfigDataSource, r as RadsDbInstance, N as RadsFeature, y as RadsHookDoc, L as RadsUiSlotDefinition, K as RadsUiSlotName, I as RadsVitePluginOptions, aj as Relation, i as RequiredFields, l as RestDriverOptions, A as RestFileUploadDriverOptions, n as SchemaLoadResult, o as SchemaValidators, z as SqlDriverOptions, T as TypeDefinition, j as ValidateStringDecoratorArgs, X as VerifyManyArgs, a4 as VerifyManyArgsAny, Y as VerifyManyResponse, Z as Where, W as WhereJsonContains } from './types-
|
|
1
|
+
import { E as EntityDecoratorArgs, U as UiDecoratorArgs, a as UiFieldDecoratorArgs, V as ValidateEntityDecoratorArgs, b as ValidateFieldDecoratorArgs, F as FieldDecoratorArgs, C as ComputedDecoratorArgs, S as Schema, D as DriverConstructor, c as Driver, d as ComputedContext, R as RadsRequestContext, e as CreateRadsDbArgs, f as CreateRadsDbClientArgs } from './types-f64a81e8.js';
|
|
2
|
+
export { O as Change, x as ComputedContextGlobal, k as CreateRadsArgsDrivers, m as CreateRadsDbArgsNormalized, an as DeepKeys, ai as DeepPartial, af as DeepPartialArrayItem, ad as DeepPartialWithNulls, ae as DeepPartialWithNullsItem, ag as DeepPartialWithoutNulls, ah as DeepPartialWithoutNullsItem, ao as EntityMethods, w as EnumDefinition, v as FieldDefinition, J as FileSystemNode, u as FileUploadArgs, q as FileUploadDriver, p as FileUploadResult, H as GenerateClientNormalizedOptions, B as GenerateClientOptions, a9 as Get, $ as GetAggArgs, a0 as GetAggArgsAgg, a3 as GetAggArgsAny, a6 as GetAggResponse, _ as GetArgs, a2 as GetArgsAny, a5 as GetArgsInclude, Q as GetManyArgs, a1 as GetManyArgsAny, a7 as GetManyResponse, a8 as GetResponse, aa as GetResponseInclude, ab as GetResponseIncludeSelect, ac as GetResponseNoInclude, s as GetRestRoutesArgs, G as GetRestRoutesOptions, t as GetRestRoutesResponse, ak as InverseRelation, am as JsonPutOperations, M as MinimalDriver, al as Put, P as PutEffect, g as RadsConfig, h as RadsConfigDataSource, r as RadsDbInstance, N as RadsFeature, y as RadsHookDoc, L as RadsUiSlotDefinition, K as RadsUiSlotName, I as RadsVitePluginOptions, aj as Relation, i as RequiredFields, l as RestDriverOptions, A as RestFileUploadDriverOptions, n as SchemaLoadResult, o as SchemaValidators, z as SqlDriverOptions, T as TypeDefinition, j as ValidateStringDecoratorArgs, X as VerifyManyArgs, a4 as VerifyManyArgsAny, Y as VerifyManyResponse, Z as Where, W as WhereJsonContains } from './types-f64a81e8.js';
|
|
3
3
|
import { RadsDb } from '_rads-db';
|
|
4
4
|
export { RadsDb } from '_rads-db';
|
|
5
5
|
import 'mssql';
|
|
@@ -287,6 +287,7 @@ type Schema = Record<string, TypeDefinition>;
|
|
|
287
287
|
interface SchemaLoadResult {
|
|
288
288
|
schema: Schema;
|
|
289
289
|
entitiesDir?: string;
|
|
290
|
+
entitiesDirs?: string[];
|
|
290
291
|
}
|
|
291
292
|
type SchemaValidators = Record<string, (item: any, oldDoc?: any) => any>;
|
|
292
293
|
interface TypeDefinition {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rads-db",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.38",
|
|
4
4
|
"description": "Say goodbye to boilerplate code and hello to efficient and elegant syntax.",
|
|
5
5
|
"author": "",
|
|
6
6
|
"license": "ISC",
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"@fastify/deepmerge": "^1.3.0",
|
|
85
85
|
"dataloader": "^2.2.2",
|
|
86
|
+
"fast-glob": "^3.3.3",
|
|
86
87
|
"ignore": "^5.2.4",
|
|
87
88
|
"jiti": "^2.4.2",
|
|
88
89
|
"klaw": "^4.1.0",
|