@pythia-software/query-table-codegen 0.1.0 → 0.3.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.
@@ -74,6 +74,14 @@ function orderTerms(value, label, fieldNames) {
74
74
  }
75
75
  term.nulls = raw.nulls;
76
76
  }
77
+ if (raw.extract != null) {
78
+ const extract = asObject(raw.extract, `${label}[${index}].extract`);
79
+ if (typeof extract.regex !== "string") throw new Error(`${label}[${index}].extract.regex must be a string`);
80
+ if (extract.regex.length > 1e4) {
81
+ throw new Error(`${label}[${index}].extract.regex exceeds 10000 characters`);
82
+ }
83
+ term.extract = { regex: extract.regex };
84
+ }
77
85
  return term;
78
86
  });
79
87
  }
@@ -81,7 +89,8 @@ function renderOrderTerms(terms) {
81
89
  if (terms.length === 0) return "nil";
82
90
  const members = terms.map((term) => {
83
91
  const nulls = term.nulls ? `, Nulls: ${goString(term.nulls)}` : "";
84
- return `{Field: ${goString(term.field)}, Dir: ${goString(term.dir)}${nulls}}`;
92
+ const extract = term.extract ? `, Extract: &querytable.RegexExtract{Regex: ${goString(term.extract.regex)}}` : "";
93
+ return `{Field: ${goString(term.field)}, Dir: ${goString(term.dir)}${nulls}${extract}}`;
85
94
  });
86
95
  return `[]querytable.OrderBy{${members.join(", ")}}`;
87
96
  }
@@ -108,10 +117,17 @@ function projectGoFields(doc) {
108
117
  const kind = GO_KINDS[kindName];
109
118
  if (!kind) throw new Error(`field ${JSON.stringify(name)} has unknown postgres kind ${JSON.stringify(kindName)}`);
110
119
  let serverFilter = true;
120
+ let filterOps;
111
121
  if (field.filter != null) {
112
122
  const filter = asObject(field.filter, `schema.fields[${index}].filter`);
113
123
  if (typeof filter.enabled === "boolean") serverFilter = filter.enabled;
114
124
  if (typeof filter.pushdown === "boolean") serverFilter = serverFilter && filter.pushdown;
125
+ if (filter.ops != null) {
126
+ if (!Array.isArray(filter.ops) || !filter.ops.every((op) => typeof op === "string")) {
127
+ throw new Error(`schema.fields[${index}].filter.ops must be an array of strings`);
128
+ }
129
+ filterOps = [...filter.ops];
130
+ }
115
131
  }
116
132
  let sortable = true;
117
133
  let sortExpr = expr;
@@ -126,7 +142,7 @@ function projectGoFields(doc) {
126
142
  sortExpr = referencedExpr;
127
143
  }
128
144
  }
129
- fields.push({
145
+ const projected = {
130
146
  name,
131
147
  kind,
132
148
  expr,
@@ -134,7 +150,9 @@ function projectGoFields(doc) {
134
150
  serverFilter,
135
151
  sortable,
136
152
  sortExpr
137
- });
153
+ };
154
+ if (filterOps !== void 0) projected.filterOps = filterOps;
155
+ fields.push(projected);
138
156
  }
139
157
  return fields;
140
158
  }
@@ -170,7 +188,8 @@ function generateGo(input, options) {
170
188
  (field) => {
171
189
  const key = goString(field.name);
172
190
  const spacing = " ".repeat(longestFieldKey - key.length + 1);
173
- return ` ${key}:${spacing}{Name: ${goString(field.name)}, Kind: querytable.${field.kind}, Expr: ${goString(field.expr)}, Synthetic: ${field.synthetic}, ServerFilter: ${field.serverFilter}, Sortable: ${field.sortable}, SortExpr: ${goString(field.sortExpr)}},`;
191
+ const filterOps = field.filterOps ? `, FilterOps: []string{${field.filterOps.map(goString).join(", ")}}` : "";
192
+ return ` ${key}:${spacing}{Name: ${goString(field.name)}, Kind: querytable.${field.kind}, Expr: ${goString(field.expr)}, Synthetic: ${field.synthetic}, ServerFilter: ${field.serverFilter}${filterOps}, Sortable: ${field.sortable}, SortExpr: ${goString(field.sortExpr)}},`;
174
193
  }
175
194
  );
176
195
  return [
@@ -198,4 +217,4 @@ export {
198
217
  generateTypeScript,
199
218
  generateGo
200
219
  };
201
- //# sourceMappingURL=chunk-RJYRZ372.js.map
220
+ //# sourceMappingURL=chunk-2SMI2V7J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/generate.ts"],"sourcesContent":["import { loadSchema } from \"@pythia-software/query-table-core\";\n\nexport interface GoGenerationOptions {\n packageName: string;\n importPath?: string;\n}\n\nconst DEFAULT_GO_IMPORT = \"github.com/Pythia-Software/query-table/backends/go\";\n\nconst GO_KINDS: Record<string, string> = {\n text: \"FieldText\",\n number: \"FieldNumber\",\n datetime: \"FieldDatetime\",\n bool: \"FieldBool\",\n enum: \"FieldEnum\",\n textarray: \"FieldTextArray\",\n};\n\nconst GO_KEYWORDS = new Set([\n \"break\",\n \"default\",\n \"func\",\n \"interface\",\n \"select\",\n \"case\",\n \"defer\",\n \"go\",\n \"map\",\n \"struct\",\n \"chan\",\n \"else\",\n \"goto\",\n \"package\",\n \"switch\",\n \"const\",\n \"fallthrough\",\n \"if\",\n \"range\",\n \"type\",\n \"continue\",\n \"for\",\n \"import\",\n \"return\",\n \"var\",\n]);\n\ntype JsonObject = Record<string, unknown>;\n\ninterface GoField {\n name: string;\n kind: string;\n expr: string;\n synthetic: boolean;\n serverFilter: boolean;\n filterOps?: string[];\n sortable: boolean;\n sortExpr: string;\n}\n\ninterface OrderTerm {\n field: string;\n dir: \"asc\" | \"desc\";\n nulls?: \"first\" | \"last\";\n extract?: { regex: string };\n}\n\nfunction asObject(value: unknown, label: string): JsonObject {\n if (value == null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`${label} must be an object`);\n }\n return value as JsonObject;\n}\n\nfunction requiredString(value: unknown, label: string): string {\n if (typeof value !== \"string\" || !value) throw new Error(`${label} must be a non-empty string`);\n return value;\n}\n\nfunction goString(value: string): string {\n return JSON.stringify(value).replace(/\\u2028/g, \"\\\\u2028\").replace(/\\u2029/g, \"\\\\u2029\");\n}\n\nfunction exportedName(name: string): string {\n const parts = name.split(/[^A-Za-z0-9]+/).filter(Boolean);\n const base = parts.map((part) => part[0]!.toUpperCase() + part.slice(1)).join(\"\") || \"Generated\";\n return `${/^\\d/.test(base) ? `Schema${base}` : base}Schema`;\n}\n\nfunction validateGoPackage(packageName: string): void {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(packageName) || GO_KEYWORDS.has(packageName)) {\n throw new Error(`invalid Go package name ${JSON.stringify(packageName)}`);\n }\n}\n\nfunction orderTerms(value: unknown, label: string, fieldNames: Set<string>): OrderTerm[] {\n if (value == null) return [];\n if (!Array.isArray(value)) throw new Error(`${label} must be an array`);\n return value.map((item, index) => {\n const raw = asObject(item, `${label}[${index}]`);\n const field = requiredString(raw.field, `${label}[${index}].field`);\n if (!fieldNames.has(field)) throw new Error(`${label}[${index}] references unknown field ${JSON.stringify(field)}`);\n if (raw.dir !== \"asc\" && raw.dir !== \"desc\") throw new Error(`${label}[${index}].dir must be \"asc\" or \"desc\"`);\n const term: OrderTerm = { field, dir: raw.dir };\n if (raw.nulls != null) {\n if (raw.nulls !== \"first\" && raw.nulls !== \"last\") {\n throw new Error(`${label}[${index}].nulls must be \"first\" or \"last\"`);\n }\n term.nulls = raw.nulls;\n }\n if (raw.extract != null) {\n const extract = asObject(raw.extract, `${label}[${index}].extract`);\n if (typeof extract.regex !== \"string\") throw new Error(`${label}[${index}].extract.regex must be a string`);\n if (extract.regex.length > 10_000) {\n throw new Error(`${label}[${index}].extract.regex exceeds 10000 characters`);\n }\n term.extract = { regex: extract.regex };\n }\n return term;\n });\n}\n\nfunction renderOrderTerms(terms: OrderTerm[]): string {\n if (terms.length === 0) return \"nil\";\n const members = terms.map((term) => {\n const nulls = term.nulls ? `, Nulls: ${goString(term.nulls)}` : \"\";\n const extract = term.extract\n ? `, Extract: &querytable.RegexExtract{Regex: ${goString(term.extract.regex)}}`\n : \"\";\n return `{Field: ${goString(term.field)}, Dir: ${goString(term.dir)}${nulls}${extract}}`;\n });\n return `[]querytable.OrderBy{${members.join(\", \")}}`;\n}\n\nfunction projectGoFields(doc: JsonObject): GoField[] {\n if (!Array.isArray(doc.fields)) throw new Error(\"schema.fields must be an array\");\n const rawFields = doc.fields.map((field, index) => asObject(field, `schema.fields[${index}]`));\n const exprByName = new Map<string, string>();\n\n for (const [index, field] of rawFields.entries()) {\n const name = requiredString(field.name, `schema.fields[${index}].name`);\n if (field.bindings == null) continue;\n const bindings = asObject(field.bindings, `schema.fields[${index}].bindings`);\n if (bindings.postgres == null) continue;\n const postgres = asObject(bindings.postgres, `schema.fields[${index}].bindings.postgres`);\n exprByName.set(name, requiredString(postgres.expr, `schema.fields[${index}].bindings.postgres.expr`));\n }\n\n const fields: GoField[] = [];\n for (const [index, field] of rawFields.entries()) {\n const name = requiredString(field.name, `schema.fields[${index}].name`);\n const expr = exprByName.get(name);\n if (!expr) continue;\n const bindings = asObject(field.bindings, `schema.fields[${index}].bindings`);\n const postgres = asObject(bindings.postgres, `schema.fields[${index}].bindings.postgres`);\n const kindName = typeof postgres.kind === \"string\" ? postgres.kind : requiredString(field.type, `schema.fields[${index}].type`);\n const kind = GO_KINDS[kindName];\n if (!kind) throw new Error(`field ${JSON.stringify(name)} has unknown postgres kind ${JSON.stringify(kindName)}`);\n\n let serverFilter = true;\n let filterOps: string[] | undefined;\n if (field.filter != null) {\n const filter = asObject(field.filter, `schema.fields[${index}].filter`);\n if (typeof filter.enabled === \"boolean\") serverFilter = filter.enabled;\n if (typeof filter.pushdown === \"boolean\") serverFilter = serverFilter && filter.pushdown;\n if (filter.ops != null) {\n if (!Array.isArray(filter.ops) || !filter.ops.every((op) => typeof op === \"string\")) {\n throw new Error(`schema.fields[${index}].filter.ops must be an array of strings`);\n }\n filterOps = [...filter.ops] as string[];\n }\n }\n\n let sortable = true;\n let sortExpr = expr;\n if (field.sort != null) {\n const sort = asObject(field.sort, `schema.fields[${index}].sort`);\n if (typeof sort.enabled === \"boolean\") sortable = sort.enabled;\n if (typeof sort.field === \"string\") {\n const referencedExpr = exprByName.get(sort.field);\n if (!referencedExpr) {\n throw new Error(`field ${JSON.stringify(name)} sort target ${JSON.stringify(sort.field)} has no postgres binding`);\n }\n sortExpr = referencedExpr;\n }\n }\n\n const projected: GoField = {\n name,\n kind,\n expr,\n synthetic: postgres.synthetic === true,\n serverFilter,\n sortable,\n sortExpr,\n };\n if (filterOps !== undefined) projected.filterOps = filterOps;\n fields.push(projected);\n }\n return fields;\n}\n\n/** Generate the frontend projection. SQL bindings are deliberately omitted. */\nexport function generateTypeScript(input: unknown): string {\n const schema = loadSchema(input);\n const constant = exportedName(schema.name).replace(/Schema$/, \"\").toUpperCase() + \"_SCHEMA\";\n return [\n \"// Code generated by query-table-codegen. DO NOT EDIT.\",\n 'import type { FieldSchema } from \"@pythia-software/query-table-core\";',\n \"\",\n `export const ${constant}: FieldSchema = ${JSON.stringify(schema, null, 2)};`,\n `export const ${constant.replace(/_SCHEMA$/, \"_FIELDS\")} = ${constant}.fields;`,\n \"\",\n ].join(\"\\n\");\n}\n\n/** Generate a direct Go Schema literal with no runtime JSON parsing. */\nexport function generateGo(input: unknown, options: GoGenerationOptions): string {\n validateGoPackage(options.packageName);\n loadSchema(input);\n const doc = asObject(input, \"schema\");\n const name = requiredString(doc.name, \"schema.name\");\n const idField = requiredString(doc.idField, \"schema.idField\");\n const fields = projectGoFields(doc);\n if (!fields.some((field) => field.name === idField)) {\n throw new Error(`id field ${JSON.stringify(idField)} has no postgres binding`);\n }\n const fieldNames = new Set((doc.fields as JsonObject[]).map((field) => requiredString(field.name, \"schema field name\")));\n const defaultSort = orderTerms(doc.defaultSort, \"schema.defaultSort\", fieldNames);\n const tiebreakSort = orderTerms(doc.tiebreakSort, \"schema.tiebreakSort\", fieldNames);\n const importPath = options.importPath ?? DEFAULT_GO_IMPORT;\n if (!importPath || /[\\s\\x00-\\x1f\\x7f\"]/u.test(importPath)) throw new Error(\"invalid Go import path\");\n\n const longestFieldKey = Math.max(0, ...fields.map((field) => goString(field.name).length));\n const fieldLines = fields.map(\n (field) => {\n const key = goString(field.name);\n const spacing = \" \".repeat(longestFieldKey - key.length + 1);\n const filterOps = field.filterOps\n ? `, FilterOps: []string{${field.filterOps.map(goString).join(\", \")}}`\n : \"\";\n return `\\t\\t\\t${key}:${spacing}{Name: ${goString(field.name)}, Kind: querytable.${field.kind}, Expr: ${goString(field.expr)}, Synthetic: ${field.synthetic}, ServerFilter: ${field.serverFilter}${filterOps}, Sortable: ${field.sortable}, SortExpr: ${goString(field.sortExpr)}},`;\n },\n );\n\n return [\n \"// Code generated by query-table-codegen. DO NOT EDIT.\",\n `package ${options.packageName}`,\n \"\",\n `import querytable ${goString(importPath)}`,\n \"\",\n `func ${exportedName(name)}() querytable.Schema {`,\n \"\\treturn querytable.Schema{\",\n `\\t\\tName: ${goString(name)},`,\n `\\t\\tIDField: ${goString(idField)},`,\n \"\\t\\tFields: map[string]querytable.FieldSpec{\",\n ...fieldLines,\n \"\\t\\t},\",\n `\\t\\tDefaultSort: ${renderOrderTerms(defaultSort)},`,\n `\\t\\tTiebreakSort: ${renderOrderTerms(tiebreakSort)},`,\n \"\\t}\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  generateGo,
4
4
  generateTypeScript
5
- } from "./chunk-RJYRZ372.js";
5
+ } from "./chunk-2SMI2V7J.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { mkdir, readFile, writeFile } from "fs/promises";
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  generateGo,
3
3
  generateTypeScript
4
- } from "./chunk-RJYRZ372.js";
4
+ } from "./chunk-2SMI2V7J.js";
5
5
  export {
6
6
  generateGo,
7
7
  generateTypeScript
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pythia-software/query-table-codegen",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Generate the TS catalog + Go schema from a query-table JSON schema document.",
5
5
  "keywords": ["codegen", "data-table", "json-schema", "typescript", "golang"],
6
6
  "license": "MIT",
@@ -25,7 +25,7 @@
25
25
  "default": "./dist/index.js"
26
26
  }
27
27
  },
28
- "bin": { "query-table-codegen": "./dist/cli.js" },
28
+ "bin": { "query-table-codegen": "dist/cli.js" },
29
29
  "files": ["dist", "README.md", "LICENSE"],
30
30
  "publishConfig": { "access": "public" },
31
31
  "scripts": {
@@ -34,6 +34,6 @@
34
34
  "typecheck": "tsc --noEmit"
35
35
  },
36
36
  "dependencies": {
37
- "@pythia-software/query-table-core": "0.1.0"
37
+ "@pythia-software/query-table-core": "0.3.0"
38
38
  }
39
39
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/generate.ts"],"sourcesContent":["import { loadSchema } from \"@pythia-software/query-table-core\";\n\nexport interface GoGenerationOptions {\n packageName: string;\n importPath?: string;\n}\n\nconst DEFAULT_GO_IMPORT = \"github.com/Pythia-Software/query-table/backends/go\";\n\nconst GO_KINDS: Record<string, string> = {\n text: \"FieldText\",\n number: \"FieldNumber\",\n datetime: \"FieldDatetime\",\n bool: \"FieldBool\",\n enum: \"FieldEnum\",\n textarray: \"FieldTextArray\",\n};\n\nconst GO_KEYWORDS = new Set([\n \"break\",\n \"default\",\n \"func\",\n \"interface\",\n \"select\",\n \"case\",\n \"defer\",\n \"go\",\n \"map\",\n \"struct\",\n \"chan\",\n \"else\",\n \"goto\",\n \"package\",\n \"switch\",\n \"const\",\n \"fallthrough\",\n \"if\",\n \"range\",\n \"type\",\n \"continue\",\n \"for\",\n \"import\",\n \"return\",\n \"var\",\n]);\n\ntype JsonObject = Record<string, unknown>;\n\ninterface GoField {\n name: string;\n kind: string;\n expr: string;\n synthetic: boolean;\n serverFilter: boolean;\n sortable: boolean;\n sortExpr: string;\n}\n\ninterface OrderTerm {\n field: string;\n dir: \"asc\" | \"desc\";\n nulls?: \"first\" | \"last\";\n}\n\nfunction asObject(value: unknown, label: string): JsonObject {\n if (value == null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`${label} must be an object`);\n }\n return value as JsonObject;\n}\n\nfunction requiredString(value: unknown, label: string): string {\n if (typeof value !== \"string\" || !value) throw new Error(`${label} must be a non-empty string`);\n return value;\n}\n\nfunction goString(value: string): string {\n return JSON.stringify(value).replace(/\\u2028/g, \"\\\\u2028\").replace(/\\u2029/g, \"\\\\u2029\");\n}\n\nfunction exportedName(name: string): string {\n const parts = name.split(/[^A-Za-z0-9]+/).filter(Boolean);\n const base = parts.map((part) => part[0]!.toUpperCase() + part.slice(1)).join(\"\") || \"Generated\";\n return `${/^\\d/.test(base) ? `Schema${base}` : base}Schema`;\n}\n\nfunction validateGoPackage(packageName: string): void {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(packageName) || GO_KEYWORDS.has(packageName)) {\n throw new Error(`invalid Go package name ${JSON.stringify(packageName)}`);\n }\n}\n\nfunction orderTerms(value: unknown, label: string, fieldNames: Set<string>): OrderTerm[] {\n if (value == null) return [];\n if (!Array.isArray(value)) throw new Error(`${label} must be an array`);\n return value.map((item, index) => {\n const raw = asObject(item, `${label}[${index}]`);\n const field = requiredString(raw.field, `${label}[${index}].field`);\n if (!fieldNames.has(field)) throw new Error(`${label}[${index}] references unknown field ${JSON.stringify(field)}`);\n if (raw.dir !== \"asc\" && raw.dir !== \"desc\") throw new Error(`${label}[${index}].dir must be \"asc\" or \"desc\"`);\n const term: OrderTerm = { field, dir: raw.dir };\n if (raw.nulls != null) {\n if (raw.nulls !== \"first\" && raw.nulls !== \"last\") {\n throw new Error(`${label}[${index}].nulls must be \"first\" or \"last\"`);\n }\n term.nulls = raw.nulls;\n }\n return term;\n });\n}\n\nfunction renderOrderTerms(terms: OrderTerm[]): string {\n if (terms.length === 0) return \"nil\";\n const members = terms.map((term) => {\n const nulls = term.nulls ? `, Nulls: ${goString(term.nulls)}` : \"\";\n return `{Field: ${goString(term.field)}, Dir: ${goString(term.dir)}${nulls}}`;\n });\n return `[]querytable.OrderBy{${members.join(\", \")}}`;\n}\n\nfunction projectGoFields(doc: JsonObject): GoField[] {\n if (!Array.isArray(doc.fields)) throw new Error(\"schema.fields must be an array\");\n const rawFields = doc.fields.map((field, index) => asObject(field, `schema.fields[${index}]`));\n const exprByName = new Map<string, string>();\n\n for (const [index, field] of rawFields.entries()) {\n const name = requiredString(field.name, `schema.fields[${index}].name`);\n if (field.bindings == null) continue;\n const bindings = asObject(field.bindings, `schema.fields[${index}].bindings`);\n if (bindings.postgres == null) continue;\n const postgres = asObject(bindings.postgres, `schema.fields[${index}].bindings.postgres`);\n exprByName.set(name, requiredString(postgres.expr, `schema.fields[${index}].bindings.postgres.expr`));\n }\n\n const fields: GoField[] = [];\n for (const [index, field] of rawFields.entries()) {\n const name = requiredString(field.name, `schema.fields[${index}].name`);\n const expr = exprByName.get(name);\n if (!expr) continue;\n const bindings = asObject(field.bindings, `schema.fields[${index}].bindings`);\n const postgres = asObject(bindings.postgres, `schema.fields[${index}].bindings.postgres`);\n const kindName = typeof postgres.kind === \"string\" ? postgres.kind : requiredString(field.type, `schema.fields[${index}].type`);\n const kind = GO_KINDS[kindName];\n if (!kind) throw new Error(`field ${JSON.stringify(name)} has unknown postgres kind ${JSON.stringify(kindName)}`);\n\n let serverFilter = true;\n if (field.filter != null) {\n const filter = asObject(field.filter, `schema.fields[${index}].filter`);\n if (typeof filter.enabled === \"boolean\") serverFilter = filter.enabled;\n if (typeof filter.pushdown === \"boolean\") serverFilter = serverFilter && filter.pushdown;\n }\n\n let sortable = true;\n let sortExpr = expr;\n if (field.sort != null) {\n const sort = asObject(field.sort, `schema.fields[${index}].sort`);\n if (typeof sort.enabled === \"boolean\") sortable = sort.enabled;\n if (typeof sort.field === \"string\") {\n const referencedExpr = exprByName.get(sort.field);\n if (!referencedExpr) {\n throw new Error(`field ${JSON.stringify(name)} sort target ${JSON.stringify(sort.field)} has no postgres binding`);\n }\n sortExpr = referencedExpr;\n }\n }\n\n fields.push({\n name,\n kind,\n expr,\n synthetic: postgres.synthetic === true,\n serverFilter,\n sortable,\n sortExpr,\n });\n }\n return fields;\n}\n\n/** Generate the frontend projection. SQL bindings are deliberately omitted. */\nexport function generateTypeScript(input: unknown): string {\n const schema = loadSchema(input);\n const constant = exportedName(schema.name).replace(/Schema$/, \"\").toUpperCase() + \"_SCHEMA\";\n return [\n \"// Code generated by query-table-codegen. DO NOT EDIT.\",\n 'import type { FieldSchema } from \"@pythia-software/query-table-core\";',\n \"\",\n `export const ${constant}: FieldSchema = ${JSON.stringify(schema, null, 2)};`,\n `export const ${constant.replace(/_SCHEMA$/, \"_FIELDS\")} = ${constant}.fields;`,\n \"\",\n ].join(\"\\n\");\n}\n\n/** Generate a direct Go Schema literal with no runtime JSON parsing. */\nexport function generateGo(input: unknown, options: GoGenerationOptions): string {\n validateGoPackage(options.packageName);\n loadSchema(input);\n const doc = asObject(input, \"schema\");\n const name = requiredString(doc.name, \"schema.name\");\n const idField = requiredString(doc.idField, \"schema.idField\");\n const fields = projectGoFields(doc);\n if (!fields.some((field) => field.name === idField)) {\n throw new Error(`id field ${JSON.stringify(idField)} has no postgres binding`);\n }\n const fieldNames = new Set((doc.fields as JsonObject[]).map((field) => requiredString(field.name, \"schema field name\")));\n const defaultSort = orderTerms(doc.defaultSort, \"schema.defaultSort\", fieldNames);\n const tiebreakSort = orderTerms(doc.tiebreakSort, \"schema.tiebreakSort\", fieldNames);\n const importPath = options.importPath ?? DEFAULT_GO_IMPORT;\n if (!importPath || /[\\s\\x00-\\x1f\\x7f\"]/u.test(importPath)) throw new Error(\"invalid Go import path\");\n\n const longestFieldKey = Math.max(0, ...fields.map((field) => goString(field.name).length));\n const fieldLines = fields.map(\n (field) => {\n const key = goString(field.name);\n const spacing = \" \".repeat(longestFieldKey - key.length + 1);\n return `\\t\\t\\t${key}:${spacing}{Name: ${goString(field.name)}, Kind: querytable.${field.kind}, Expr: ${goString(field.expr)}, Synthetic: ${field.synthetic}, ServerFilter: ${field.serverFilter}, Sortable: ${field.sortable}, SortExpr: ${goString(field.sortExpr)}},`;\n },\n );\n\n return [\n \"// Code generated by query-table-codegen. DO NOT EDIT.\",\n `package ${options.packageName}`,\n \"\",\n `import querytable ${goString(importPath)}`,\n \"\",\n `func ${exportedName(name)}() querytable.Schema {`,\n \"\\treturn querytable.Schema{\",\n `\\t\\tName: ${goString(name)},`,\n `\\t\\tIDField: ${goString(idField)},`,\n \"\\t\\tFields: map[string]querytable.FieldSpec{\",\n ...fieldLines,\n \"\\t\\t},\",\n `\\t\\tDefaultSort: ${renderOrderTerms(defaultSort)},`,\n `\\t\\tTiebreakSort: ${renderOrderTerms(tiebreakSort)},`,\n \"\\t}\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n"],"mappings":"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","names":[]}