@lakeql/schema-generator 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,134 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/endpoint-schema.d.ts
4
+ /**
5
+ * Regex pattern for field names: alphanumeric + underscore, no leading digit, max 64 chars.
6
+ */
7
+ declare const fieldNamePattern: RegExp;
8
+ /**
9
+ * Regex pattern for metadata fields (tableName, catalog, schema): alphanumeric + underscore,
10
+ * no leading digit, max 128 chars.
11
+ */
12
+ declare const metadataFieldPattern: RegExp;
13
+ /**
14
+ * Supported load strategies for the mutation write pipeline.
15
+ */
16
+ declare const loadStrategies: readonly ["full_load", "full_load_append", "append"];
17
+ type LoadStrategy = (typeof loadStrategies)[number];
18
+ /**
19
+ * Mutation pipeline configuration for an endpoint.
20
+ */
21
+ interface MutationConfig {
22
+ /** Load strategy for the write pipeline. */
23
+ loadStrategy: LoadStrategy;
24
+ /** S3 base path for endpoint data. */
25
+ basePath: string;
26
+ }
27
+ /**
28
+ * Zod schema for the mutation configuration object.
29
+ */
30
+ declare const mutationConfigSchema: z.ZodObject<{
31
+ loadStrategy: z.ZodEnum<{
32
+ full_load: "full_load";
33
+ full_load_append: "full_load_append";
34
+ append: "append";
35
+ }>;
36
+ basePath: z.ZodString;
37
+ }, z.core.$strip>;
38
+ /**
39
+ * Zod schema for the mutation field: either `false` (disabled) or a config object (enabled).
40
+ */
41
+ declare const mutationSchema: z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
42
+ loadStrategy: z.ZodEnum<{
43
+ full_load: "full_load";
44
+ full_load_append: "full_load_append";
45
+ append: "append";
46
+ }>;
47
+ basePath: z.ZodString;
48
+ }, z.core.$strip>]>;
49
+ /**
50
+ * Supported primitive types for field definitions.
51
+ */
52
+ declare const primitiveTypes: readonly ["String", "Integer", "Float", "Boolean", "Date", "DateTime"];
53
+ type PrimitiveType = (typeof primitiveTypes)[number];
54
+ /**
55
+ * Field-level validation refinement types.
56
+ */
57
+ type FieldValidation = {
58
+ type: "email";
59
+ } | {
60
+ type: "url";
61
+ } | {
62
+ type: "uuid";
63
+ } | {
64
+ type: "min";
65
+ value: number;
66
+ } | {
67
+ type: "max";
68
+ value: number;
69
+ } | {
70
+ type: "regex";
71
+ pattern: string;
72
+ };
73
+ /**
74
+ * Field-level options for mutation input validation.
75
+ */
76
+ interface FieldOptions {
77
+ /** Whether the field is required in mutation input. Default: false. */
78
+ required?: boolean;
79
+ /** Validation refinements to apply via Zod. */
80
+ validations?: FieldValidation[];
81
+ }
82
+ /**
83
+ * Zod schema for field validation refinements.
84
+ */
85
+ declare const fieldValidationSchema: z.ZodType<FieldValidation>;
86
+ /**
87
+ * Zod schema for field-level options.
88
+ */
89
+ declare const fieldOptionsSchema: z.ZodType<FieldOptions>;
90
+ interface ArrayItemDefinition {
91
+ type: PrimitiveType | "Object";
92
+ fields?: FieldDefinition[];
93
+ }
94
+ interface FieldDefinition {
95
+ name: string;
96
+ type: PrimitiveType | "Object" | "Array";
97
+ fields?: FieldDefinition[];
98
+ items?: ArrayItemDefinition;
99
+ options?: FieldOptions;
100
+ }
101
+ /**
102
+ * Zod schema for field definitions using a discriminated union on "type".
103
+ * Supports recursive nesting via z.lazy for Object fields and Array items.
104
+ */
105
+ declare const fieldDefinitionSchema: z.ZodType<FieldDefinition>;
106
+ /**
107
+ * Zod schema for the complete endpoint definition format.
108
+ */
109
+ declare const endpointDefinitionSchema: z.ZodObject<{
110
+ version: z.ZodLiteral<"1.0">;
111
+ tableName: z.ZodString;
112
+ catalog: z.ZodString;
113
+ schema: z.ZodString;
114
+ fields: z.ZodArray<z.ZodType<FieldDefinition, unknown, z.core.$ZodTypeInternals<FieldDefinition, unknown>>>;
115
+ mutation: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
116
+ loadStrategy: z.ZodEnum<{
117
+ full_load: "full_load";
118
+ full_load_append: "full_load_append";
119
+ append: "append";
120
+ }>;
121
+ basePath: z.ZodString;
122
+ }, z.core.$strip>]>>;
123
+ }, z.core.$strip>;
124
+ type EndpointDefinitionFormat = z.infer<typeof endpointDefinitionSchema>;
125
+ /**
126
+ * Checks for duplicate field names at the same nesting level within a list of field definitions.
127
+ * Returns an array of objects describing each duplicate found, including the field name and path.
128
+ */
129
+ declare function findDuplicateFieldNames(fields: FieldDefinition[], path?: string[]): {
130
+ name: string;
131
+ path: string[];
132
+ }[];
133
+ //#endregion
134
+ export { ArrayItemDefinition, EndpointDefinitionFormat, FieldDefinition, FieldOptions, FieldValidation, LoadStrategy, MutationConfig, PrimitiveType, endpointDefinitionSchema, fieldDefinitionSchema, fieldNamePattern, fieldOptionsSchema, fieldValidationSchema, findDuplicateFieldNames, loadStrategies, metadataFieldPattern, mutationConfigSchema, mutationSchema, primitiveTypes };
@@ -0,0 +1 @@
1
+ import{z as e}from"zod";const t=/^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/u,n=/^[a-zA-Z_][a-zA-Z0-9_]{0,127}$/u,r=[`full_load`,`full_load_append`,`append`],i=e.object({loadStrategy:e.enum(r),basePath:e.string().min(1)}),a=e.union([e.literal(!1),i]),o=[`String`,`Integer`,`Float`,`Boolean`,`Date`,`DateTime`],s=e.union([e.object({type:e.literal(`email`)}),e.object({type:e.literal(`url`)}),e.object({type:e.literal(`uuid`)}),e.object({type:e.literal(`min`),value:e.number()}),e.object({type:e.literal(`max`),value:e.number()}),e.object({type:e.literal(`regex`),pattern:e.string()})]),c=e.object({required:e.boolean().optional(),validations:e.array(s).optional()}),l=e.lazy(()=>e.discriminatedUnion(`type`,[e.object({name:e.string().regex(t),type:e.literal(`String`),options:c.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Integer`),options:c.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Float`),options:c.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Boolean`),options:c.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Date`),options:c.optional()}),e.object({name:e.string().regex(t),type:e.literal(`DateTime`),options:c.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Object`),fields:e.array(l).min(1),options:c.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Array`),items:e.union([e.object({type:e.enum(o)}),e.object({type:e.literal(`Object`),fields:e.array(l).min(1)})]),options:c.optional()})])),u=e.object({version:e.literal(`1.0`),tableName:e.string().regex(n),catalog:e.string().regex(n),schema:e.string().regex(n),fields:e.array(l),mutation:a.optional()});function d(e,t=[]){let n=[],r=new Set;for(let i of e)r.has(i.name)?n.push({name:i.name,path:t}):r.add(i.name),i.type===`Object`&&i.fields&&n.push(...d(i.fields,[...t,i.name])),i.type===`Array`&&i.items?.type===`Object`&&i.items.fields&&n.push(...d(i.items.fields,[...t,i.name,`items`]));return n}export{u as endpointDefinitionSchema,l as fieldDefinitionSchema,t as fieldNamePattern,c as fieldOptionsSchema,s as fieldValidationSchema,d as findDuplicateFieldNames,r as loadStrategies,n as metadataFieldPattern,i as mutationConfigSchema,a as mutationSchema,o as primitiveTypes};
@@ -1,7 +1,24 @@
1
+ import { FieldDefinition } from "./endpoint-schema.mjs";
1
2
  import { t as JSONSchema7 } from "./index-CGZiTFRE.mjs";
2
3
  import { JSONType } from "json-column-parser/lib/common/types/type.common";
3
4
 
4
5
  //#region src/json-schema.d.ts
5
6
  declare function generateJsonSchema(parsedColumns: Record<string, JSONType>): JSONSchema7;
7
+ /**
8
+ * Converts an array of FieldDefinitions to a complete JSON Schema Draft-07 document.
9
+ *
10
+ * The root schema has `$schema`, `type: "object"`, `properties`, and `additionalProperties: false`.
11
+ * Each field is recursively mapped according to the type mapping rules:
12
+ * - String → {type: "string"}
13
+ * - Integer → {type: "integer"}
14
+ * - Float → {type: "number"}
15
+ * - Boolean → {type: "boolean"}
16
+ * - Date → {type: "string", format: "date"}
17
+ * - DateTime → {type: "string", format: "date-time"}
18
+ * - Object → {type: "object", properties: {...}, additionalProperties: false}
19
+ * - Array (primitive) → {type: "array", items: {primitive schema}}
20
+ * - Array (object) → {type: "array", items: {type: "object", properties: {...}, additionalProperties: false}}
21
+ */
22
+ declare function generateJsonSchemaFromFields(fields: FieldDefinition[]): JSONSchema7;
6
23
  //#endregion
7
- export { generateJsonSchema };
24
+ export { generateJsonSchema, generateJsonSchemaFromFields };
@@ -1 +1 @@
1
- import{isObject as e}from"@lakeql/helpers/object-helper";import{createRegExp as t,global as n,not as r}from"magic-regexp";function i(e){return{$schema:`https://json-schema.org/draft-07/schema#`,...s(e),additionalProperties:!1}}function a(e){let i=t(r.letter,[n]),a=e.toString().replace(i,``);switch(a){case`varchar`:return{type:`string`};case`decimal`:case`double`:case`float`:return{type:`number`};case`integer`:case`bigint`:return{type:`integer`};case`boolean`:return{type:`boolean`};case`timestamp`:return{format:`date-time`,type:`string`};case`date`:return{format:`date`,type:`string`};default:throw Error(`Type ${a.toString()} is unknown.`)}}function o(t){if(t.length>1)throw Error("We expect that an array has only one element ( e.g. a primitive like `varchar` or an object like `row()`.");if(Array.isArray(t[0]))throw TypeError(`We currently do not support 'array of array'. Feel free to raise an issue.`);if(typeof t[0]==`string`)return{items:a(t[0]),type:`array`};if(e(t[0]))return{items:s(t[0]),type:`array`};throw Error("Unexpected case in `json-generator.handleArray`")}function s(t){let n={additionalProperties:!1,properties:{},type:`object`};for(let[r,i]of Object.entries(t)){if(typeof i==`string`)try{n.properties[r]=a(i)}catch(e){console.log(e)}if(Array.isArray(i))try{n.properties[r]=o(i)}catch(e){console.log(e)}if(e(i))try{n.properties[r]=s(i)}catch(e){console.log(e)}}return n}export{i as generateJsonSchema};
1
+ import{isObject as e}from"@lakeql/helpers/object-helper";import{createRegExp as t,global as n,not as r}from"magic-regexp";function i(e){return{$schema:`https://json-schema.org/draft-07/schema#`,...s(e),additionalProperties:!1}}function a(e){let i=t(r.letter,[n]),a=e.toString().replace(i,``);switch(a){case`varchar`:return{type:`string`};case`decimal`:case`double`:case`float`:return{type:`number`};case`integer`:case`bigint`:return{type:`integer`};case`boolean`:return{type:`boolean`};case`timestamp`:return{format:`date-time`,type:`string`};case`date`:return{format:`date`,type:`string`};default:throw Error(`Type ${a.toString()} is unknown.`)}}function o(t){if(t.length>1)throw Error("We expect that an array has only one element ( e.g. a primitive like `varchar` or an object like `row()`.");if(Array.isArray(t[0]))throw TypeError(`We currently do not support 'array of array'. Feel free to raise an issue.`);if(typeof t[0]==`string`)return{items:a(t[0]),type:`array`};if(e(t[0]))return{items:s(t[0]),type:`array`};throw Error("Unexpected case in `json-generator.handleArray`")}function s(t){let n={additionalProperties:!1,properties:{},type:`object`};for(let[r,i]of Object.entries(t))typeof i==`string`&&(n.properties[r]=a(i)),Array.isArray(i)&&(n.properties[r]=o(i)),e(i)&&(n.properties[r]=s(i));return n}function c(e){switch(e){case`String`:return{type:`string`};case`Integer`:return{type:`integer`};case`Float`:return{type:`number`};case`Boolean`:return{type:`boolean`};case`Date`:return{type:`string`,format:`date`};case`DateTime`:return{type:`string`,format:`date-time`};default:return{type:`string`}}}function l(e){return e.type===`Object`&&e.fields?{type:`object`,properties:d(e.fields),additionalProperties:!1}:c(e.type)}function u(e){switch(e.type){case`Object`:return{type:`object`,properties:d(e.fields??[]),additionalProperties:!1};case`Array`:return{type:`array`,items:e.items?l(e.items):{type:`string`}};default:return c(e.type)}}function d(e){let t={};for(let n of e)t[n.name]=u(n);return t}function f(e){return{$schema:`https://json-schema.org/draft-07/schema#`,type:`object`,properties:d(e),additionalProperties:!1}}export{i as generateJsonSchema,f as generateJsonSchemaFromFields};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lakeql/schema-generator",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "Generates GraphQL schemas, Hive table definitions, and JSON schemas from Trino metadata",
5
5
  "keywords": [
6
6
  "codegen",
@@ -33,6 +33,10 @@
33
33
  "type": "module",
34
34
  "sideEffects": false,
35
35
  "exports": {
36
+ "./endpoint-schema": {
37
+ "types": "./dist/endpoint-schema.d.mts",
38
+ "import": "./dist/endpoint-schema.mjs"
39
+ },
36
40
  "./graphql-schema": {
37
41
  "types": "./dist/graphql-schema.d.mts",
38
42
  "import": "./dist/graphql-schema.mjs"
@@ -50,12 +54,14 @@
50
54
  "kysely": "0.29.2",
51
55
  "lodash-es": "4.18.1",
52
56
  "magic-regexp": "0.11.0",
57
+ "zod": "4.4.3",
53
58
  "@lakeql/helpers": "0.1.2"
54
59
  },
55
60
  "devDependencies": {
56
61
  "@types/json-schema": "7.0.15",
57
62
  "@types/lodash-es": "4.17.12",
58
63
  "@types/node": "24.13.2",
64
+ "fast-check": "^4.8.0",
59
65
  "json-column-parser": "2.0.0",
60
66
  "tsdown": "0.22.2",
61
67
  "typescript": "6.0.3",
@@ -68,6 +74,7 @@
68
74
  "clean:cache": "git clean -xdf .cache .turbo",
69
75
  "clean:dist": "git clean -xdf dist",
70
76
  "dev": "tsdown --watch",
77
+ "test": "vitest run",
71
78
  "typecheck": "tsc --noEmit"
72
79
  }
73
80
  }