@lakeql/schema-generator 0.4.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,34 +1,28 @@
1
1
  import { z } from "zod";
2
- //#region src/endpoint-schema.d.ts
2
+ import { LoadStrategy, LoadStrategy as LoadStrategy$1 } from "@lakeql/datasource";
3
3
  /**
4
4
  * Regex pattern for field names: alphanumeric + underscore, no leading digit, max 64 chars.
5
5
  */
6
- declare const fieldNamePattern: RegExp;
6
+ export declare const fieldNamePattern: RegExp;
7
7
  /**
8
8
  * Regex pattern for metadata fields (tableName, catalog, schema): alphanumeric + underscore,
9
9
  * no leading digit, max 128 chars.
10
10
  */
11
- declare const metadataFieldPattern: RegExp;
11
+ export declare const metadataFieldPattern: RegExp;
12
12
  /**
13
13
  * Supported load strategies for the mutation write pipeline.
14
14
  */
15
- declare const loadStrategies: readonly ["full_load", "full_load_append", "append"];
16
- type LoadStrategy = (typeof loadStrategies)[number];
17
- /**
18
- * Supported storage adapter types.
19
- */
20
- declare const storageTypes: readonly ["s3", "minio"];
21
- type StorageType = (typeof storageTypes)[number];
15
+ export declare const loadStrategies: readonly ["full_load", "full_load_append", "append"];
22
16
  /**
23
17
  * Supported partitioning format granularities.
24
18
  */
25
- declare const partitioningFormats: readonly ["year", "year/month", "year/month/day"];
26
- type PartitioningFormat = (typeof partitioningFormats)[number];
19
+ export declare const partitioningFormats: readonly ["year", "year/month", "year/month/day"];
20
+ export type PartitioningFormat = (typeof partitioningFormats)[number];
27
21
  /**
28
22
  * Supported date components for custom partition format segments.
29
23
  */
30
- declare const partitioningComponents: readonly ["year", "month", "day", "hour", "minute", "second"];
31
- type PartitioningComponent = (typeof partitioningComponents)[number];
24
+ export declare const partitioningComponents: readonly ["year", "month", "day", "hour", "minute", "second"];
25
+ export type PartitioningComponent = (typeof partitioningComponents)[number];
32
26
  /**
33
27
  * Validates a custom partitioning format string.
34
28
  * - If the value contains no `/` and no `:`, it must match fieldNamePattern (legacy single-field mode).
@@ -39,33 +33,22 @@ type PartitioningComponent = (typeof partitioningComponents)[number];
39
33
  *
40
34
  * Returns null if valid, or an error message string if invalid.
41
35
  */
42
- declare function validatePartitioningFormat(value: string): string | null;
36
+ export declare function validatePartitioningFormat(value: string): string | null;
43
37
  /**
44
38
  * Partitioning configuration value:
45
39
  * - true: partition by write timestamp (default)
46
40
  * - false: no partitioning (flat layout)
47
41
  * - string: partition by named field
48
42
  */
49
- type PartitioningValue = boolean | string;
43
+ export type PartitioningValue = boolean | string;
50
44
  /**
51
45
  * Mutation pipeline configuration for an endpoint.
52
46
  */
53
- interface MutationConfig {
47
+ export interface MutationConfig {
54
48
  /** Load strategy for the write pipeline. */
55
- loadStrategy: LoadStrategy;
56
- /**
57
- * Storage adapter type.
58
- * @default "s3"
59
- */
60
- type: StorageType;
61
- /** S3/MinIO bucket name for endpoint data. */
62
- bucket: string;
49
+ loadStrategy: LoadStrategy$1;
63
50
  /** Base path for endpoint data. */
64
51
  basePath: string;
65
- /** Optional region override (falls back to AWS_DEFAULT_REGION env var for S3). */
66
- region?: string;
67
- /** Optional custom endpoint. Required for MinIO, optional for S3. */
68
- endpoint?: string;
69
52
  /**
70
53
  * Partitioning mode. `true` partitions by write timestamp, `false` disables partitioning, or a string for field-based/custom partitioning.
71
54
  * @default true
@@ -80,52 +63,38 @@ interface MutationConfig {
80
63
  /**
81
64
  * Zod schema for the mutation configuration object.
82
65
  */
83
- declare const mutationConfigSchema: z.ZodObject<{
66
+ export declare const mutationConfigSchema: z.ZodObject<{
84
67
  loadStrategy: z.ZodEnum<{
85
68
  full_load: "full_load";
86
69
  full_load_append: "full_load_append";
87
70
  append: "append";
88
71
  }>;
89
- type: z.ZodDefault<z.ZodEnum<{
90
- s3: "s3";
91
- minio: "minio";
92
- }>>;
93
- bucket: z.ZodString;
94
72
  basePath: z.ZodString;
95
- region: z.ZodOptional<z.ZodString>;
96
- endpoint: z.ZodOptional<z.ZodString>;
97
73
  partitioning: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>;
98
74
  partitioningFormat: z.ZodOptional<z.ZodString>;
99
75
  }, z.core.$strip>;
100
76
  /**
101
77
  * Zod schema for the mutation field: either `false` (disabled) or a config object (enabled).
102
78
  */
103
- declare const mutationSchema: z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
79
+ export declare const mutationSchema: z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
104
80
  loadStrategy: z.ZodEnum<{
105
81
  full_load: "full_load";
106
82
  full_load_append: "full_load_append";
107
83
  append: "append";
108
84
  }>;
109
- type: z.ZodDefault<z.ZodEnum<{
110
- s3: "s3";
111
- minio: "minio";
112
- }>>;
113
- bucket: z.ZodString;
114
85
  basePath: z.ZodString;
115
- region: z.ZodOptional<z.ZodString>;
116
- endpoint: z.ZodOptional<z.ZodString>;
117
86
  partitioning: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>;
118
87
  partitioningFormat: z.ZodOptional<z.ZodString>;
119
88
  }, z.core.$strip>]>;
120
89
  /**
121
90
  * Supported primitive types for field definitions.
122
91
  */
123
- declare const primitiveTypes: readonly ["String", "Integer", "Float", "Boolean", "Date", "DateTime"];
124
- type PrimitiveType = (typeof primitiveTypes)[number];
92
+ export declare const primitiveTypes: readonly ["String", "Integer", "Float", "Boolean", "Date", "DateTime"];
93
+ export type PrimitiveType = (typeof primitiveTypes)[number];
125
94
  /**
126
95
  * Field-level validation refinement types.
127
96
  */
128
- type FieldValidation = {
97
+ export type FieldValidation = {
129
98
  type: "email";
130
99
  } | {
131
100
  type: "url";
@@ -144,7 +113,7 @@ type FieldValidation = {
144
113
  /**
145
114
  * Field-level options for mutation input validation.
146
115
  */
147
- interface FieldOptions {
116
+ export interface FieldOptions {
148
117
  /**
149
118
  * Whether the field is required in mutation input.
150
119
  * @default false
@@ -164,16 +133,16 @@ interface FieldOptions {
164
133
  /**
165
134
  * Zod schema for field validation refinements.
166
135
  */
167
- declare const fieldValidationSchema: z.ZodType<FieldValidation>;
136
+ export declare const fieldValidationSchema: z.ZodType<FieldValidation>;
168
137
  /**
169
138
  * Zod schema for field-level options.
170
139
  */
171
- declare const fieldOptionsSchema: z.ZodType<FieldOptions>;
172
- interface ArrayItemDefinition {
140
+ export declare const fieldOptionsSchema: z.ZodType<FieldOptions>;
141
+ export interface ArrayItemDefinition {
173
142
  type: PrimitiveType | "Object";
174
143
  fields?: FieldDefinition[];
175
144
  }
176
- interface FieldDefinition {
145
+ export interface FieldDefinition {
177
146
  name: string;
178
147
  type: PrimitiveType | "Object" | "Array";
179
148
  fields?: FieldDefinition[];
@@ -184,15 +153,16 @@ interface FieldDefinition {
184
153
  * Zod schema for field definitions using a discriminated union on "type".
185
154
  * Supports recursive nesting via z.lazy for Object fields and Array items.
186
155
  */
187
- declare const fieldDefinitionSchema: z.ZodType<FieldDefinition>;
156
+ export declare const fieldDefinitionSchema: z.ZodType<FieldDefinition>;
188
157
  /**
189
158
  * Zod schema for the complete endpoint definition format.
190
159
  */
191
- declare const endpointDefinitionSchema: z.ZodObject<{
160
+ export declare const endpointDefinitionSchema: z.ZodObject<{
192
161
  version: z.ZodLiteral<"1.0">;
193
162
  tableName: z.ZodString;
194
163
  catalog: z.ZodString;
195
164
  schema: z.ZodString;
165
+ dataSource: z.ZodOptional<z.ZodString>;
196
166
  fields: z.ZodArray<z.ZodType<FieldDefinition, unknown, z.core.$ZodTypeInternals<FieldDefinition, unknown>>>;
197
167
  mutation: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
198
168
  loadStrategy: z.ZodEnum<{
@@ -200,26 +170,18 @@ declare const endpointDefinitionSchema: z.ZodObject<{
200
170
  full_load_append: "full_load_append";
201
171
  append: "append";
202
172
  }>;
203
- type: z.ZodDefault<z.ZodEnum<{
204
- s3: "s3";
205
- minio: "minio";
206
- }>>;
207
- bucket: z.ZodString;
208
173
  basePath: z.ZodString;
209
- region: z.ZodOptional<z.ZodString>;
210
- endpoint: z.ZodOptional<z.ZodString>;
211
174
  partitioning: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>;
212
175
  partitioningFormat: z.ZodOptional<z.ZodString>;
213
176
  }, z.core.$strip>]>>;
214
177
  }, z.core.$strip>;
215
- type EndpointDefinitionFormat = z.infer<typeof endpointDefinitionSchema>;
178
+ export type EndpointDefinitionFormat = z.infer<typeof endpointDefinitionSchema>;
216
179
  /**
217
180
  * Checks for duplicate field names at the same nesting level within a list of field definitions.
218
181
  * Returns an array of objects describing each duplicate found, including the field name and path.
219
182
  */
220
- declare function findDuplicateFieldNames(fields: FieldDefinition[], path?: string[]): {
183
+ export declare function findDuplicateFieldNames(fields: FieldDefinition[], path?: string[]): {
221
184
  name: string;
222
185
  path: string[];
223
186
  }[];
224
- //#endregion
225
- export { ArrayItemDefinition, EndpointDefinitionFormat, FieldDefinition, FieldOptions, FieldValidation, LoadStrategy, MutationConfig, PartitioningComponent, PartitioningFormat, PartitioningValue, PrimitiveType, StorageType, endpointDefinitionSchema, fieldDefinitionSchema, fieldNamePattern, fieldOptionsSchema, fieldValidationSchema, findDuplicateFieldNames, loadStrategies, metadataFieldPattern, mutationConfigSchema, mutationSchema, partitioningComponents, partitioningFormats, primitiveTypes, storageTypes, validatePartitioningFormat };
187
+ export type { LoadStrategy };
@@ -1 +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=[`s3`,`minio`],a=[`year`,`year/month`,`year/month/day`],o=[`year`,`month`,`day`,`hour`,`minute`,`second`];function s(e){if(!(e.includes(`/`)||e.includes(`:`)))return t.test(e)?null:`Invalid partition field name "${e}". Must match pattern: letters/underscores, no leading digit, max 64 chars.`;let n=e.split(`/`);for(let r of n){if(r===``)return`Invalid partition format: empty segment found in "${e}".`;if(r.includes(`:`)){let e=r.split(`:`);if(e.length!==2)return`Invalid partition segment "${r}": expected format "fieldname:component".`;let[n,i]=e;if(!t.test(n))return`Invalid field name "${n}" in partition segment "${r}".`;if(!o.includes(i))return`Invalid date component "${i}" in partition segment "${r}". Expected one of: ${o.join(`, `)}.`}else if(!t.test(r))return`Invalid field name "${r}" in partition format.`}return null}const c=e.object({loadStrategy:e.enum(r),type:e.enum(i).default(`s3`),bucket:e.string().min(1),basePath:e.string().min(1),region:e.string().optional(),endpoint:e.string().optional(),partitioning:e.union([e.boolean(),e.string().min(1)]).optional(),partitioningFormat:e.string().optional()}).superRefine((e,t)=>{if(e.type===`minio`&&!e.endpoint&&t.addIssue({code:`custom`,path:[`endpoint`],message:`Endpoint is required when storage type is 'minio'. Provide the MinIO server URL (e.g. http://minio:9000).`}),e.partitioning!==!1){if(typeof e.partitioning==`string`){let n=s(e.partitioning);if(n){t.addIssue({code:`custom`,path:[`partitioning`],message:n});return}if(e.partitioning.includes(`/`)||e.partitioning.includes(`:`))return}e.partitioningFormat!==void 0&&!a.includes(e.partitioningFormat)&&t.addIssue({code:`invalid_value`,values:[...a],path:[`partitioningFormat`],message:`Invalid partitioning format. Expected one of: ${a.join(`, `)}`})}}),l=e.union([e.literal(!1),c]),u=[`String`,`Integer`,`Float`,`Boolean`,`Date`,`DateTime`],d=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()})]),f=e.object({required:e.boolean().optional(),validations:e.array(d).optional(),readOnly:e.boolean().optional()}),p=e.lazy(()=>e.discriminatedUnion(`type`,[e.object({name:e.string().regex(t),type:e.literal(`String`),options:f.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Integer`),options:f.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Float`),options:f.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Boolean`),options:f.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Date`),options:f.optional()}),e.object({name:e.string().regex(t),type:e.literal(`DateTime`),options:f.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Object`),fields:e.array(p).min(1),options:f.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Array`),items:e.union([e.object({type:e.enum(u)}),e.object({type:e.literal(`Object`),fields:e.array(p).min(1)})]),options:f.optional()})])),m=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(p),mutation:l.optional()});function h(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(...h(i.fields,[...t,i.name])),i.type===`Array`&&i.items?.type===`Object`&&i.items.fields&&n.push(...h(i.items.fields,[...t,i.name,`items`]));return n}export{m as endpointDefinitionSchema,p as fieldDefinitionSchema,t as fieldNamePattern,f as fieldOptionsSchema,d as fieldValidationSchema,h as findDuplicateFieldNames,r as loadStrategies,n as metadataFieldPattern,c as mutationConfigSchema,l as mutationSchema,o as partitioningComponents,a as partitioningFormats,u as primitiveTypes,i as storageTypes,s as validatePartitioningFormat};
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=[`year`,`year/month`,`year/month/day`],a=[`year`,`month`,`day`,`hour`,`minute`,`second`];function o(e){if(!(e.includes(`/`)||e.includes(`:`)))return t.test(e)?null:`Invalid partition field name "${e}". Must match pattern: letters/underscores, no leading digit, max 64 chars.`;let n=e.split(`/`);for(let r of n){if(r===``)return`Invalid partition format: empty segment found in "${e}".`;if(r.includes(`:`)){let e=r.split(`:`);if(e.length!==2)return`Invalid partition segment "${r}": expected format "fieldname:component".`;let[n,i]=e;if(!t.test(n))return`Invalid field name "${n}" in partition segment "${r}".`;if(!a.includes(i))return`Invalid date component "${i}" in partition segment "${r}". Expected one of: ${a.join(`, `)}.`}else if(!t.test(r))return`Invalid field name "${r}" in partition format.`}return null}const s=e.object({loadStrategy:e.enum(r),basePath:e.string().min(1),partitioning:e.union([e.boolean(),e.string().min(1)]).optional(),partitioningFormat:e.string().optional()}).superRefine((e,t)=>{if(e.partitioning!==!1){if(typeof e.partitioning==`string`){let n=o(e.partitioning);if(n){t.addIssue({code:`custom`,path:[`partitioning`],message:n});return}if(e.partitioning.includes(`/`)||e.partitioning.includes(`:`))return}e.partitioningFormat!==void 0&&!i.includes(e.partitioningFormat)&&t.addIssue({code:`invalid_value`,values:[...i],path:[`partitioningFormat`],message:`Invalid partitioning format. Expected one of: ${i.join(`, `)}`})}}),c=e.union([e.literal(!1),s]),l=[`String`,`Integer`,`Float`,`Boolean`,`Date`,`DateTime`],u=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()})]),d=e.object({required:e.boolean().optional(),validations:e.array(u).optional(),readOnly:e.boolean().optional()}),f=e.lazy(()=>e.discriminatedUnion(`type`,[e.object({name:e.string().regex(t),type:e.literal(`String`),options:d.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Integer`),options:d.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Float`),options:d.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Boolean`),options:d.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Date`),options:d.optional()}),e.object({name:e.string().regex(t),type:e.literal(`DateTime`),options:d.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Object`),fields:e.array(f).min(1),options:d.optional()}),e.object({name:e.string().regex(t),type:e.literal(`Array`),items:e.union([e.object({type:e.enum(l)}),e.object({type:e.literal(`Object`),fields:e.array(f).min(1)})]),options:d.optional()})])),p=e.object({version:e.literal(`1.0`),tableName:e.string().regex(n),catalog:e.string().regex(n),schema:e.string().regex(n),dataSource:e.string().min(1).optional(),fields:e.array(f),mutation:c.optional()});function m(e,t=[]){let n=[],r=/* @__PURE__ */ 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(...m(i.fields,[...t,i.name])),i.type===`Array`&&i.items?.type===`Object`&&i.items.fields&&n.push(...m(i.items.fields,[...t,i.name,`items`]));return n}export{p as endpointDefinitionSchema,f as fieldDefinitionSchema,t as fieldNamePattern,d as fieldOptionsSchema,u as fieldValidationSchema,m as findDuplicateFieldNames,r as loadStrategies,n as metadataFieldPattern,s as mutationConfigSchema,c as mutationSchema,a as partitioningComponents,i as partitioningFormats,l as primitiveTypes,o as validatePartitioningFormat};
@@ -1,6 +1,5 @@
1
1
  import { JSONSchema7 } from "json-schema";
2
- //#region src/graphql-schema.d.ts
3
- interface CurrentModelResponse {
2
+ export interface CurrentModelResponse {
4
3
  name: string;
5
4
  rawFieldName: string;
6
5
  transformed: boolean;
@@ -12,7 +11,7 @@ interface CurrentModelResponse {
12
11
  nullable: boolean;
13
12
  filter: boolean;
14
13
  }
15
- interface ModelResponse {
14
+ export interface ModelResponse {
16
15
  root: boolean;
17
16
  modelName: string;
18
17
  interfaceName: string;
@@ -20,11 +19,11 @@ interface ModelResponse {
20
19
  transformFields: string[][];
21
20
  dateTimeFields: string[];
22
21
  }
23
- interface FilterFieldInput {
22
+ export interface FilterFieldInput {
24
23
  name: string;
25
24
  type: string;
26
25
  }
27
- type FieldDefinitionResponse = {
26
+ export type FieldDefinitionResponse = {
28
27
  graphqlType: string;
29
28
  graphqlTplType: string;
30
29
  interfaceType: string;
@@ -44,7 +43,7 @@ type FieldDefinitionResponse = {
44
43
  /**
45
44
  * Parameters for generateModel.
46
45
  */
47
- interface GenerateModelProps {
46
+ export interface GenerateModelProps {
48
47
  /** The JSON Schema source definition to generate a model from. */
49
48
  source: JSONSchema7;
50
49
  /** The name of the model being generated. */
@@ -59,15 +58,15 @@ interface GenerateModelProps {
59
58
  /**
60
59
  * Sanitizes a raw field name into a valid GraphQL/TypeScript identifier-like key.
61
60
  */
62
- declare function sanitizeFieldName(rawFieldName: string): string;
61
+ export declare function sanitizeFieldName(rawFieldName: string): string;
63
62
  /**
64
63
  * Generates a GraphQL model definition from JSON Schema.
65
64
  */
66
- declare const generateModel: ({ source, name, parent, models, isRoot }: GenerateModelProps) => Record<string, ModelResponse>;
65
+ export declare const generateModel: ({ source, name, parent, models, isRoot }: GenerateModelProps) => Record<string, ModelResponse>;
67
66
  /**
68
67
  * Parameters for generateFieldDefinition.
69
68
  */
70
- interface GenerateFieldDefinitionProps {
69
+ export interface GenerateFieldDefinitionProps {
71
70
  /** The sanitized field name. */
72
71
  fieldName: string;
73
72
  /** The original raw field name from the schema. */
@@ -80,6 +79,4 @@ interface GenerateFieldDefinitionProps {
80
79
  /**
81
80
  * Generates field definitions for a single model property.
82
81
  */
83
- declare const generateFieldDefinition: ({ fieldName, rawFieldName, fieldDefinition, parent }: GenerateFieldDefinitionProps) => FieldDefinitionResponse;
84
- //#endregion
85
- export { CurrentModelResponse, FieldDefinitionResponse, FilterFieldInput, GenerateFieldDefinitionProps, GenerateModelProps, ModelResponse, generateFieldDefinition, generateModel, sanitizeFieldName };
82
+ export declare const generateFieldDefinition: ({ fieldName, rawFieldName, fieldDefinition, parent }: GenerateFieldDefinitionProps) => FieldDefinitionResponse;
@@ -1 +1 @@
1
- import e from"@lakeql/helpers/special-characters";import{capitalize as t,omit as n}from"lodash-es";function r(t){let n=e(t).replaceAll(/[^a-zA-Z0-9_]/gu,`_`).replaceAll(/_+/gu,`_`).replaceAll(/^_+|_+$/gu,``);return n.length===0?`field`:n.replace(/^(?<digit>\d)/u,`_$<digit>`)}function i(e,t,n){if(!t.has(e))return t.add(e),e;throw Error(`Field name collision after normalization: "${n}" -> "${e}".`)}const a=({source:e,name:s,parent:c,models:l={},isRoot:u=!0})=>{let d=n(e,[`additionalProperties`]),f={...l},p=new Set,m={};for(let[e,t]of Object.entries(d.properties)){let n=i(r(e),p,e),l=o({fieldDefinition:t,fieldName:n,parent:c??s,rawFieldName:e});m[n]={filter:l.filter,graphqlTplType:l.graphqlTplType,graphqlType:l.graphqlType,interfaceName:l.interfaceName,interfaceType:l.interfaceType,isArray:l.isArray??!1,name:n,nullable:!0,rawFieldName:e,transformed:n!==e},l.subModel!==!1&&Object.assign(f,a({isRoot:!1,models:f,name:n,parent:c??s,source:l.subModel}))}let h=u?s:`${c}_${t(s)}`;return f[h]={dateTimeFields:Object.values(m).filter(e=>e.graphqlType===`DateTime`).map(e=>e.rawFieldName),fields:m,interfaceName:`${h}Interface`,modelName:h,root:u,transformFields:Object.values(m).filter(e=>e.transformed).map(e=>[e.name,e.rawFieldName])},f},o=({fieldName:e,rawFieldName:n,fieldDefinition:r,parent:i})=>{let a=t(e);switch(r.type){case`string`:switch(r.format){case`date`:return{filter:!0,graphqlTplType:`'Date'`,graphqlType:`Date`,interfaceType:`Date`,subModel:!1};case`date-time`:return{filter:!0,graphqlTplType:`'DateTime'`,graphqlType:`DateTime`,interfaceType:`Date`,subModel:!1};default:return{filter:!0,graphqlTplType:`'String'`,graphqlType:`String`,interfaceType:`string`,subModel:!1}}case`number`:return{filter:!0,graphqlTplType:`'Float'`,graphqlType:`Float`,interfaceType:`number`,subModel:!1};case`integer`:return{filter:!0,graphqlTplType:`'Int'`,graphqlType:`Int`,interfaceType:`number`,subModel:!1};case`boolean`:return{filter:!0,graphqlTplType:`'Boolean'`,graphqlType:`Boolean`,interfaceType:`boolean`,subModel:!1};case`array`:if(r.items.type!==`object`){let t=o({fieldDefinition:r.items,fieldName:e,rawFieldName:n});return{filter:!1,graphqlTplType:`['${t.graphqlType}']`,graphqlType:`[${t.graphqlType}]`,interfaceType:`${t.interfaceType}[]`,isArray:!0,subModel:!1}}return{filter:!1,graphqlTplType:`[${i}_${a}]`,graphqlType:`[${i}_${a}]`,interfaceName:`${i}_${a}Interface[]`,interfaceType:`${i}_${a}[]`,isArray:!0,subModel:r.items};case`object`:return{filter:!1,graphqlTplType:`${i}_${a}`,graphqlType:`${i}_${a}`,interfaceName:`${i}_${a}Interface`,interfaceType:`${i}_${a}`,subModel:r};default:return{filter:!1,graphqlTplType:`Null`,graphqlType:`Null`,interfaceType:`null`,subModel:!1}}};export{o as generateFieldDefinition,a as generateModel,r as sanitizeFieldName};
1
+ import e from"@lakeql/helpers/special-characters";import{toCapitalize as t}from"@lakeql/helpers/string-case";import{omit as n}from"es-toolkit";function r(t){let n=e(t).replaceAll(/[^a-zA-Z0-9_]/gu,`_`).replaceAll(/_+/gu,`_`).replaceAll(/^_+|_+$/gu,``);return n.length===0?`field`:n.replace(/^(?<digit>\d)/u,`_$<digit>`)}function i(e,t,n){if(!t.has(e))return t.add(e),e;throw Error(`Field name collision after normalization: "${n}" -> "${e}".`)}const a=({source:e,name:s,parent:c,models:l={},isRoot:u=!0})=>{let d=n(e,[`additionalProperties`]),f={...l},p=/* @__PURE__ */ new Set,m={};for(let[e,t]of Object.entries(d.properties)){let n=i(r(e),p,e),l=o({fieldDefinition:t,fieldName:n,parent:c??s,rawFieldName:e});m[n]={filter:l.filter,graphqlTplType:l.graphqlTplType,graphqlType:l.graphqlType,interfaceName:l.interfaceName,interfaceType:l.interfaceType,isArray:l.isArray??!1,name:n,nullable:!0,rawFieldName:e,transformed:n!==e},l.subModel!==!1&&Object.assign(f,a({isRoot:!1,models:f,name:n,parent:c??s,source:l.subModel}))}let h=u?s:`${c}_${t(s)}`;return f[h]={dateTimeFields:Object.values(m).filter(e=>e.graphqlType===`DateTime`).map(e=>e.rawFieldName),fields:m,interfaceName:`${h}Interface`,modelName:h,root:u,transformFields:Object.values(m).filter(e=>e.transformed).map(e=>[e.name,e.rawFieldName])},f},o=({fieldName:e,rawFieldName:n,fieldDefinition:r,parent:i})=>{let a=t(e);switch(r.type){case`string`:switch(r.format){case`date`:return{filter:!0,graphqlTplType:`'Date'`,graphqlType:`Date`,interfaceType:`Date`,subModel:!1};case`date-time`:return{filter:!0,graphqlTplType:`'DateTime'`,graphqlType:`DateTime`,interfaceType:`Date`,subModel:!1};default:return{filter:!0,graphqlTplType:`'String'`,graphqlType:`String`,interfaceType:`string`,subModel:!1}}case`number`:return{filter:!0,graphqlTplType:`'Float'`,graphqlType:`Float`,interfaceType:`number`,subModel:!1};case`integer`:return{filter:!0,graphqlTplType:`'Int'`,graphqlType:`Int`,interfaceType:`number`,subModel:!1};case`boolean`:return{filter:!0,graphqlTplType:`'Boolean'`,graphqlType:`Boolean`,interfaceType:`boolean`,subModel:!1};case`array`:if(r.items.type!==`object`){let t=o({fieldDefinition:r.items,fieldName:e,rawFieldName:n});return{filter:!1,graphqlTplType:`['${t.graphqlType}']`,graphqlType:`[${t.graphqlType}]`,interfaceType:`${t.interfaceType}[]`,isArray:!0,subModel:!1}}return{filter:!1,graphqlTplType:`[${i}_${a}]`,graphqlType:`[${i}_${a}]`,interfaceName:`${i}_${a}Interface[]`,interfaceType:`${i}_${a}[]`,isArray:!0,subModel:r.items};case`object`:return{filter:!1,graphqlTplType:`${i}_${a}`,graphqlType:`${i}_${a}`,interfaceName:`${i}_${a}Interface`,interfaceType:`${i}_${a}`,subModel:r};default:return{filter:!1,graphqlTplType:`Null`,graphqlType:`Null`,interfaceType:`null`,subModel:!1}}};export{o as generateFieldDefinition,a as generateModel,r as sanitizeFieldName};
@@ -1,5 +1,4 @@
1
1
  import { JSONSchema7 } from "json-schema";
2
- //#region src/hive-table.d.ts
3
2
  type SqlFieldDefinition = [string, string];
4
3
  interface SchemaDefinition {
5
4
  type: string;
@@ -15,29 +14,29 @@ type ParquetField = Record<string, string | [string, ParquetField] | [string, {
15
14
  /**
16
15
  * Parameters for generateSqlSchema.
17
16
  */
18
- interface GenerateSqlSchemaProps {
17
+ export interface GenerateSqlSchemaProps {
19
18
  /** The JSON Schema property definitions to generate SQL columns from. */
20
19
  definition: Record<string, SchemaDefinition>;
21
20
  }
22
21
  /**
23
22
  * Generates SQL column definitions from parsed columns.
24
23
  */
25
- declare function generateSqlSchema({ definition }: GenerateSqlSchemaProps): SqlFieldDefinition[];
24
+ export declare function generateSqlSchema({ definition }: GenerateSqlSchemaProps): SqlFieldDefinition[];
26
25
  /**
27
26
  * Parameters for parquetTransformer.
28
27
  */
29
- interface ParquetTransformerProps {
28
+ export interface ParquetTransformerProps {
30
29
  /** The JSON Schema property definitions to transform for Parquet format. */
31
30
  definition: Record<string, JSONSchema7>;
32
31
  }
33
32
  /**
34
33
  * Transforms column definitions for Parquet format.
35
34
  */
36
- declare function parquetTransformer({ definition }: ParquetTransformerProps): ParquetField;
35
+ export declare function parquetTransformer({ definition }: ParquetTransformerProps): ParquetField;
37
36
  /**
38
37
  * Parameters for generateCreateTableStatement.
39
38
  */
40
- interface GenerateCreateTableStatementProps {
39
+ export interface GenerateCreateTableStatementProps {
41
40
  /** The Hive schema name. */
42
41
  schema: string;
43
42
  /** The table name. */
@@ -52,6 +51,5 @@ interface GenerateCreateTableStatementProps {
52
51
  /**
53
52
  * Generates a full CREATE TABLE DDL statement.
54
53
  */
55
- declare function generateCreateTableStatement({ schema, tableName, bucketName, bucketPath, definition }: GenerateCreateTableStatementProps): string;
56
- //#endregion
57
- export { GenerateCreateTableStatementProps, GenerateSqlSchemaProps, ParquetTransformerProps, generateCreateTableStatement, generateSqlSchema, parquetTransformer };
54
+ export declare function generateCreateTableStatement({ schema, tableName, bucketName, bucketPath, definition }: GenerateCreateTableStatementProps): string;
55
+ export {};
@@ -1,8 +1,7 @@
1
1
  import { FieldDefinition } from "./endpoint-schema.mjs";
2
2
  import { JSONSchema7 } from "json-schema";
3
3
  import { JSONType } from "json-column-parser/lib/common/types/type.common";
4
- //#region src/json-schema.d.ts
5
- declare function generateJsonSchema(parsedColumns: Record<string, JSONType>): JSONSchema7;
4
+ export declare function generateJsonSchema(parsedColumns: Record<string, JSONType>): JSONSchema7;
6
5
  /**
7
6
  * Converts an array of FieldDefinitions to a complete JSON Schema Draft-07 document.
8
7
  *
@@ -18,6 +17,4 @@ declare function generateJsonSchema(parsedColumns: Record<string, JSONType>): JS
18
17
  * - Array (primitive) → {type: "array", items: {primitive schema}}
19
18
  * - Array (object) → {type: "array", items: {type: "object", properties: {...}, additionalProperties: false}}
20
19
  */
21
- declare function generateJsonSchemaFromFields(fields: FieldDefinition[]): JSONSchema7;
22
- //#endregion
23
- export { generateJsonSchema, generateJsonSchemaFromFields };
20
+ export declare function generateJsonSchemaFromFields(fields: FieldDefinition[]): JSONSchema7;
@@ -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))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};
1
+ import{isObject as e}from"@lakeql/helpers/object-helper";const t=/[^a-zA-Z]/gu;function n(e){return{$schema:`https://json-schema.org/draft-07/schema#`,...a(e),additionalProperties:!1}}function r(e){let n=e.toString().replaceAll(t,``);switch(n){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 ${n.toString()} is unknown.`)}}function i(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:r(t[0]),type:`array`};if(e(t[0]))return{items:a(t[0]),type:`array`};throw Error("Unexpected case in `json-generator.handleArray`")}function a(t){let n={additionalProperties:!1,properties:{},type:`object`};for(let[o,s]of Object.entries(t))typeof s==`string`&&(n.properties[o]=r(s)),Array.isArray(s)&&(n.properties[o]=i(s)),e(s)&&(n.properties[o]=a(s));return n}function o(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 s(e){return e.type===`Object`&&e.fields?{type:`object`,properties:l(e.fields),additionalProperties:!1}:o(e.type)}function c(e){switch(e.type){case`Object`:return{type:`object`,properties:l(e.fields??[]),additionalProperties:!1};case`Array`:return{type:`array`,items:e.items?s(e.items):{type:`string`}};default:return o(e.type)}}function l(e){let t={};for(let n of e)t[n.name]=c(n);return t}function u(e){return{$schema:`https://json-schema.org/draft-07/schema#`,type:`object`,properties:l(e),additionalProperties:!1}}export{n as generateJsonSchema,u as generateJsonSchemaFromFields};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lakeql/schema-generator",
3
- "version": "0.4.6",
4
- "description": "Generates GraphQL schemas, Hive table definitions, and JSON schemas from Trino metadata",
3
+ "version": "1.0.0",
4
+ "description": "Generates GraphQL schemas, Hive table definitions, and JSON schemas from data source metadata",
5
5
  "keywords": [
6
6
  "codegen",
7
7
  "graphql",
@@ -51,22 +51,21 @@
51
51
  }
52
52
  },
53
53
  "dependencies": {
54
- "kysely": "0.29.4",
55
- "lodash-es": "4.18.1",
56
- "magic-regexp": "0.11.0",
57
- "zod": "4.4.3",
58
- "@lakeql/helpers": "0.1.7"
54
+ "@lakeql/datasource": "1.0.0",
55
+ "@lakeql/helpers": "1.0.0",
56
+ "es-toolkit": "1.53.2",
57
+ "zod": "4.6.7"
59
58
  },
60
59
  "devDependencies": {
60
+ "@lakeql/tsconfig": "0.1.0",
61
+ "@lakeql/vitest-config": "0.1.0",
61
62
  "@types/json-schema": "7.0.15",
62
- "@types/lodash-es": "4.17.12",
63
- "@types/node": "24.13.3",
64
- "fast-check": "^4.9.0",
63
+ "@types/node": "24.19.2",
64
+ "fast-check": "4.10.2",
65
65
  "json-column-parser": "2.0.0",
66
- "tsdown": "0.22.13",
66
+ "tsdown": "0.23.7",
67
67
  "typescript": "6.0.3",
68
- "vitest": "4.1.10",
69
- "@lakeql/tsconfig": "0.1.0"
68
+ "vitest": "5.1.0"
70
69
  },
71
70
  "scripts": {
72
71
  "build": "tsdown",