@pythia-software/query-table-codegen 0.5.0 → 0.7.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.
package/README.md CHANGED
@@ -38,3 +38,11 @@ path with `--go-import` when using a fork or a vendored module.
38
38
 
39
39
  The package also exports `generateTypeScript` and `generateGo` for build-tool
40
40
  integrations.
41
+
42
+ ## SQLite
43
+
44
+ Pass `--dialect sqlite` with `--go` (or `{ dialect: "sqlite" }` to `generateGo`)
45
+ to read `bindings.sqlite`. The default remains `postgres`; neither dialect falls
46
+ back to the other's expressions. SQLite bindings support `datetimeFormat`:
47
+ `rfc3339`, `utc-millis`, `unix-seconds`, and `unix-millis`. The frontend projection
48
+ continues to omit backend SQL. See [the SQLite guide](../../docs/backend-sqlite.md).
@@ -43,7 +43,8 @@ function asObject(value, label) {
43
43
  return value;
44
44
  }
45
45
  function requiredString(value, label) {
46
- if (typeof value !== "string" || !value) throw new Error(`${label} must be a non-empty string`);
46
+ if (typeof value !== "string" || !value)
47
+ throw new Error(`${label} must be a non-empty string`);
47
48
  return value;
48
49
  }
49
50
  function goString(value) {
@@ -65,8 +66,12 @@ function orderTerms(value, label, fieldNames) {
65
66
  return value.map((item, index) => {
66
67
  const raw = asObject(item, `${label}[${index}]`);
67
68
  const field = requiredString(raw.field, `${label}[${index}].field`);
68
- if (!fieldNames.has(field)) throw new Error(`${label}[${index}] references unknown field ${JSON.stringify(field)}`);
69
- if (raw.dir !== "asc" && raw.dir !== "desc") throw new Error(`${label}[${index}].dir must be "asc" or "desc"`);
69
+ if (!fieldNames.has(field))
70
+ throw new Error(
71
+ `${label}[${index}] references unknown field ${JSON.stringify(field)}`
72
+ );
73
+ if (raw.dir !== "asc" && raw.dir !== "desc")
74
+ throw new Error(`${label}[${index}].dir must be "asc" or "desc"`);
70
75
  const term = { field, dir: raw.dir };
71
76
  if (raw.nulls != null) {
72
77
  if (raw.nulls !== "first" && raw.nulls !== "last") {
@@ -76,9 +81,12 @@ function orderTerms(value, label, fieldNames) {
76
81
  }
77
82
  if (raw.extract != null) {
78
83
  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`);
84
+ if (typeof extract.regex !== "string")
85
+ throw new Error(`${label}[${index}].extract.regex must be a string`);
80
86
  if (extract.regex.length > 1e4) {
81
- throw new Error(`${label}[${index}].extract.regex exceeds 10000 characters`);
87
+ throw new Error(
88
+ `${label}[${index}].extract.regex exceeds 10000 characters`
89
+ );
82
90
  }
83
91
  term.extract = { regex: extract.regex };
84
92
  }
@@ -94,28 +102,52 @@ function renderOrderTerms(terms) {
94
102
  });
95
103
  return `[]querytable.OrderBy{${members.join(", ")}}`;
96
104
  }
97
- function projectGoFields(doc) {
98
- if (!Array.isArray(doc.fields)) throw new Error("schema.fields must be an array");
99
- const rawFields = doc.fields.map((field, index) => asObject(field, `schema.fields[${index}]`));
105
+ function projectGoFields(doc, dialect) {
106
+ if (!Array.isArray(doc.fields))
107
+ throw new Error("schema.fields must be an array");
108
+ const rawFields = doc.fields.map(
109
+ (field, index) => asObject(field, `schema.fields[${index}]`)
110
+ );
100
111
  const exprByName = /* @__PURE__ */ new Map();
101
112
  for (const [index, field] of rawFields.entries()) {
102
113
  const name = requiredString(field.name, `schema.fields[${index}].name`);
103
114
  if (field.bindings == null) continue;
104
- const bindings = asObject(field.bindings, `schema.fields[${index}].bindings`);
105
- if (bindings.postgres == null) continue;
106
- const postgres = asObject(bindings.postgres, `schema.fields[${index}].bindings.postgres`);
107
- exprByName.set(name, requiredString(postgres.expr, `schema.fields[${index}].bindings.postgres.expr`));
115
+ const bindings = asObject(
116
+ field.bindings,
117
+ `schema.fields[${index}].bindings`
118
+ );
119
+ if (bindings[dialect] == null) continue;
120
+ const binding = asObject(
121
+ bindings[dialect],
122
+ `schema.fields[${index}].bindings.${dialect}`
123
+ );
124
+ exprByName.set(
125
+ name,
126
+ requiredString(
127
+ binding.expr,
128
+ `schema.fields[${index}].bindings.${dialect}.expr`
129
+ )
130
+ );
108
131
  }
109
132
  const fields = [];
110
133
  for (const [index, field] of rawFields.entries()) {
111
134
  const name = requiredString(field.name, `schema.fields[${index}].name`);
112
135
  const expr = exprByName.get(name);
113
136
  if (!expr) continue;
114
- const bindings = asObject(field.bindings, `schema.fields[${index}].bindings`);
115
- const postgres = asObject(bindings.postgres, `schema.fields[${index}].bindings.postgres`);
116
- const kindName = typeof postgres.kind === "string" ? postgres.kind : requiredString(field.type, `schema.fields[${index}].type`);
137
+ const bindings = asObject(
138
+ field.bindings,
139
+ `schema.fields[${index}].bindings`
140
+ );
141
+ const binding = asObject(
142
+ bindings[dialect],
143
+ `schema.fields[${index}].bindings.${dialect}`
144
+ );
145
+ const kindName = typeof binding.kind === "string" ? binding.kind : requiredString(field.type, `schema.fields[${index}].type`);
117
146
  const kind = GO_KINDS[kindName];
118
- if (!kind) throw new Error(`field ${JSON.stringify(name)} has unknown postgres kind ${JSON.stringify(kindName)}`);
147
+ if (!kind)
148
+ throw new Error(
149
+ `field ${JSON.stringify(name)} has unknown ${dialect} kind ${JSON.stringify(kindName)}`
150
+ );
119
151
  let arrayCaseSensitive = false;
120
152
  let serverFilter = true;
121
153
  let filterOps;
@@ -123,37 +155,69 @@ function projectGoFields(doc) {
123
155
  const filter = asObject(field.filter, `schema.fields[${index}].filter`);
124
156
  arrayCaseSensitive = filter.arrayCaseSensitive === true;
125
157
  if (typeof filter.enabled === "boolean") serverFilter = filter.enabled;
126
- if (typeof filter.pushdown === "boolean") serverFilter = serverFilter && filter.pushdown;
158
+ if (typeof filter.pushdown === "boolean")
159
+ serverFilter = serverFilter && filter.pushdown;
127
160
  if (filter.ops != null) {
128
161
  if (!Array.isArray(filter.ops) || !filter.ops.every((op) => typeof op === "string")) {
129
- throw new Error(`schema.fields[${index}].filter.ops must be an array of strings`);
162
+ throw new Error(
163
+ `schema.fields[${index}].filter.ops must be an array of strings`
164
+ );
130
165
  }
131
166
  filterOps = [...filter.ops];
132
167
  }
133
168
  }
134
169
  let sortable = true;
135
170
  let sortExpr = expr;
171
+ let sqliteSortField;
136
172
  if (field.sort != null) {
137
173
  const sort = asObject(field.sort, `schema.fields[${index}].sort`);
138
174
  if (typeof sort.enabled === "boolean") sortable = sort.enabled;
139
175
  if (typeof sort.field === "string") {
140
176
  const referencedExpr = exprByName.get(sort.field);
141
177
  if (!referencedExpr) {
142
- throw new Error(`field ${JSON.stringify(name)} sort target ${JSON.stringify(sort.field)} has no postgres binding`);
178
+ throw new Error(
179
+ `field ${JSON.stringify(name)} sort target ${JSON.stringify(sort.field)} has no ${dialect} binding`
180
+ );
143
181
  }
144
182
  sortExpr = referencedExpr;
183
+ if (dialect === "sqlite") sqliteSortField = sort.field;
145
184
  }
146
185
  }
147
186
  const projected = {
148
187
  name,
149
188
  kind,
150
189
  expr,
151
- synthetic: postgres.synthetic === true,
190
+ synthetic: binding.synthetic === true,
152
191
  serverFilter,
153
192
  arrayCaseSensitive,
154
193
  sortable,
155
- sortExpr
194
+ sortExpr,
195
+ expressionNumeric: binding.expressionNumeric === true
156
196
  };
197
+ if (sqliteSortField !== void 0) projected.sqliteSortField = sqliteSortField;
198
+ if (dialect === "sqlite" && binding.datetimeFormat != null) {
199
+ if (kindName !== "datetime" || !["rfc3339", "utc-millis", "unix-seconds", "unix-millis"].includes(
200
+ String(binding.datetimeFormat)
201
+ ))
202
+ throw new Error(`field ${JSON.stringify(name)} has invalid SQLite datetimeFormat`);
203
+ projected.datetimeFormat = String(binding.datetimeFormat);
204
+ }
205
+ if (field.aggregate != null) {
206
+ const aggregate = asObject(
207
+ field.aggregate,
208
+ `schema.fields[${index}].aggregate`
209
+ );
210
+ if (typeof aggregate.groupable === "boolean")
211
+ projected.groupable = aggregate.groupable;
212
+ if (aggregate.measure === false) projected.aggregateOps = [];
213
+ else if (aggregate.ops != null) {
214
+ if (!Array.isArray(aggregate.ops) || !aggregate.ops.every((op) => typeof op === "string"))
215
+ throw new Error(
216
+ `schema.fields[${index}].aggregate.ops must be an array of strings`
217
+ );
218
+ projected.aggregateOps = [...aggregate.ops];
219
+ }
220
+ }
157
221
  if (filterOps !== void 0) projected.filterOps = filterOps;
158
222
  fields.push(projected);
159
223
  }
@@ -177,24 +241,44 @@ function generateGo(input, options) {
177
241
  const doc = asObject(input, "schema");
178
242
  const name = requiredString(doc.name, "schema.name");
179
243
  const idField = requiredString(doc.idField, "schema.idField");
180
- const fields = projectGoFields(doc);
244
+ const dialect = options.dialect ?? "postgres";
245
+ if (dialect !== "postgres" && dialect !== "sqlite") throw new Error("invalid SQL dialect");
246
+ const fields = projectGoFields(doc, dialect);
181
247
  if (!fields.some((field) => field.name === idField)) {
182
- throw new Error(`id field ${JSON.stringify(idField)} has no postgres binding`);
248
+ throw new Error(
249
+ `id field ${JSON.stringify(idField)} has no ${dialect} binding`
250
+ );
183
251
  }
184
- const fieldNames = new Set(doc.fields.map((field) => requiredString(field.name, "schema field name")));
185
- const defaultSort = orderTerms(doc.defaultSort, "schema.defaultSort", fieldNames);
186
- const tiebreakSort = orderTerms(doc.tiebreakSort, "schema.tiebreakSort", fieldNames);
252
+ const fieldNames = new Set(
253
+ doc.fields.map(
254
+ (field) => requiredString(field.name, "schema field name")
255
+ )
256
+ );
257
+ const defaultSort = orderTerms(
258
+ doc.defaultSort,
259
+ "schema.defaultSort",
260
+ fieldNames
261
+ );
262
+ const tiebreakSort = orderTerms(
263
+ doc.tiebreakSort,
264
+ "schema.tiebreakSort",
265
+ fieldNames
266
+ );
187
267
  const importPath = options.importPath ?? DEFAULT_GO_IMPORT;
188
- if (!importPath || /[\s\x00-\x1f\x7f"]/u.test(importPath)) throw new Error("invalid Go import path");
189
- const longestFieldKey = Math.max(0, ...fields.map((field) => goString(field.name).length));
190
- const fieldLines = fields.map(
191
- (field) => {
192
- const key = goString(field.name);
193
- const spacing = " ".repeat(longestFieldKey - key.length + 1);
194
- const filterOps = field.filterOps ? `, FilterOps: []string{${field.filterOps.map(goString).join(", ")}}` : "";
195
- return ` ${key}:${spacing}{Name: ${goString(field.name)}, Kind: querytable.${field.kind}, Expr: ${goString(field.expr)}, Synthetic: ${field.synthetic}, ServerFilter: ${field.serverFilter}${filterOps}${field.arrayCaseSensitive ? ", ArrayCaseSensitive: true" : ""}, Sortable: ${field.sortable}, SortExpr: ${goString(field.sortExpr)}},`;
196
- }
268
+ if (!importPath || /[\s\x00-\x1f\x7f"]/u.test(importPath))
269
+ throw new Error("invalid Go import path");
270
+ const longestFieldKey = Math.max(
271
+ 0,
272
+ ...fields.map((field) => goString(field.name).length)
197
273
  );
274
+ const fieldLines = fields.map((field) => {
275
+ const key = goString(field.name);
276
+ const spacing = " ".repeat(longestFieldKey - key.length + 1);
277
+ const filterOps = field.filterOps ? `, FilterOps: []string{${field.filterOps.map(goString).join(", ")}}` : "";
278
+ const aggregateOps = field.aggregateOps !== void 0 ? `, AggregateOps: []string{${field.aggregateOps.map(goString).join(", ")}}` : "";
279
+ const groupable = field.groupable !== void 0 ? `, Groupable: func() *bool { v := ${field.groupable}; return &v }()` : "";
280
+ return ` ${key}:${spacing}{Name: ${goString(field.name)}, Kind: querytable.${field.kind}, Expr: ${goString(field.expr)}, Synthetic: ${field.synthetic}${field.sqliteSortField ? `, SQLiteSortField: ${goString(field.sqliteSortField)}` : ""}${field.expressionNumeric ? ", ExpressionNumeric: true" : ""}${field.datetimeFormat ? `, SQLiteDatetimeFormat: ${goString(field.datetimeFormat)}` : ""}${aggregateOps}${groupable}, ServerFilter: ${field.serverFilter}${filterOps}${field.arrayCaseSensitive ? ", ArrayCaseSensitive: true" : ""}, Sortable: ${field.sortable}, SortExpr: ${goString(field.sortExpr)}},`;
281
+ });
198
282
  return [
199
283
  "// Code generated by query-table-codegen. DO NOT EDIT.",
200
284
  `package ${options.packageName}`,
@@ -220,4 +304,4 @@ export {
220
304
  generateTypeScript,
221
305
  generateGo
222
306
  };
223
- //# sourceMappingURL=chunk-YQ663BVQ.js.map
307
+ //# sourceMappingURL=chunk-ZQZDDNVV.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 dialect?: \"postgres\" | \"sqlite\";\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 arrayCaseSensitive: boolean;\n filterOps?: string[];\n sortable: boolean;\n sortExpr: string;\n sqliteSortField?: string;\n expressionNumeric: boolean;\n datetimeFormat?: string;\n aggregateOps?: string[];\n groupable?: boolean;\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)\n 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)\n .replace(/\\u2028/g, \"\\\\u2028\")\n .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 =\n parts.map((part) => part[0]!.toUpperCase() + part.slice(1)).join(\"\") ||\n \"Generated\";\n return `${/^\\d/.test(base) ? `Schema${base}` : base}Schema`;\n}\n\nfunction validateGoPackage(packageName: string): void {\n if (\n !/^[A-Za-z_][A-Za-z0-9_]*$/.test(packageName) ||\n GO_KEYWORDS.has(packageName)\n ) {\n throw new Error(`invalid Go package name ${JSON.stringify(packageName)}`);\n }\n}\n\nfunction orderTerms(\n value: unknown,\n label: string,\n fieldNames: Set<string>,\n): 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))\n throw new Error(\n `${label}[${index}] references unknown field ${JSON.stringify(field)}`,\n );\n if (raw.dir !== \"asc\" && raw.dir !== \"desc\")\n 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\")\n throw new Error(`${label}[${index}].extract.regex must be a string`);\n if (extract.regex.length > 10_000) {\n throw new Error(\n `${label}[${index}].extract.regex exceeds 10000 characters`,\n );\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, dialect: \"postgres\" | \"sqlite\"): GoField[] {\n if (!Array.isArray(doc.fields))\n throw new Error(\"schema.fields must be an array\");\n const rawFields = doc.fields.map((field, index) =>\n asObject(field, `schema.fields[${index}]`),\n );\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(\n field.bindings,\n `schema.fields[${index}].bindings`,\n );\n if (bindings[dialect] == null) continue;\n const binding = asObject(\n bindings[dialect],\n `schema.fields[${index}].bindings.${dialect}`,\n );\n exprByName.set(\n name,\n requiredString(\n binding.expr,\n `schema.fields[${index}].bindings.${dialect}.expr`,\n ),\n );\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(\n field.bindings,\n `schema.fields[${index}].bindings`,\n );\n const binding = asObject(\n bindings[dialect],\n `schema.fields[${index}].bindings.${dialect}`,\n );\n const kindName =\n typeof binding.kind === \"string\"\n ? binding.kind\n : requiredString(field.type, `schema.fields[${index}].type`);\n const kind = GO_KINDS[kindName];\n if (!kind)\n throw new Error(\n `field ${JSON.stringify(name)} has unknown ${dialect} kind ${JSON.stringify(kindName)}`,\n );\n\n let arrayCaseSensitive = false;\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 arrayCaseSensitive = filter.arrayCaseSensitive === true;\n if (typeof filter.enabled === \"boolean\") serverFilter = filter.enabled;\n if (typeof filter.pushdown === \"boolean\")\n serverFilter = serverFilter && filter.pushdown;\n if (filter.ops != null) {\n if (\n !Array.isArray(filter.ops) ||\n !filter.ops.every((op) => typeof op === \"string\")\n ) {\n throw new Error(\n `schema.fields[${index}].filter.ops must be an array of strings`,\n );\n }\n filterOps = [...filter.ops] as string[];\n }\n }\n\n let sortable = true;\n let sortExpr = expr;\n let sqliteSortField: string | undefined;\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(\n `field ${JSON.stringify(name)} sort target ${JSON.stringify(sort.field)} has no ${dialect} binding`,\n );\n }\n sortExpr = referencedExpr;\n if (dialect === \"sqlite\") sqliteSortField = sort.field;\n }\n }\n\n const projected: GoField = {\n name,\n kind,\n expr,\n synthetic: binding.synthetic === true,\n serverFilter,\n arrayCaseSensitive,\n sortable,\n sortExpr,\n expressionNumeric: binding.expressionNumeric === true,\n };\n if (sqliteSortField !== undefined) projected.sqliteSortField = sqliteSortField;\n if (dialect === \"sqlite\" && binding.datetimeFormat != null) {\n if (\n kindName !== \"datetime\" ||\n ![\"rfc3339\", \"utc-millis\", \"unix-seconds\", \"unix-millis\"].includes(\n String(binding.datetimeFormat),\n )\n )\n throw new Error(`field ${JSON.stringify(name)} has invalid SQLite datetimeFormat`);\n projected.datetimeFormat = String(binding.datetimeFormat);\n }\n if (field.aggregate != null) {\n const aggregate = asObject(\n field.aggregate,\n `schema.fields[${index}].aggregate`,\n );\n if (typeof aggregate.groupable === \"boolean\")\n projected.groupable = aggregate.groupable;\n if (aggregate.measure === false) projected.aggregateOps = [];\n else if (aggregate.ops != null) {\n if (\n !Array.isArray(aggregate.ops) ||\n !aggregate.ops.every((op) => typeof op === \"string\")\n )\n throw new Error(\n `schema.fields[${index}].aggregate.ops must be an array of strings`,\n );\n projected.aggregateOps = [...aggregate.ops] as string[];\n }\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 =\n exportedName(schema.name)\n .replace(/Schema$/, \"\")\n .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(\n input: unknown,\n options: GoGenerationOptions,\n): 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 dialect = options.dialect ?? \"postgres\";\n if (dialect !== \"postgres\" && dialect !== \"sqlite\") throw new Error(\"invalid SQL dialect\");\n const fields = projectGoFields(doc, dialect);\n if (!fields.some((field) => field.name === idField)) {\n throw new Error(\n `id field ${JSON.stringify(idField)} has no ${dialect} binding`,\n );\n }\n const fieldNames = new Set(\n (doc.fields as JsonObject[]).map((field) =>\n requiredString(field.name, \"schema field name\"),\n ),\n );\n const defaultSort = orderTerms(\n doc.defaultSort,\n \"schema.defaultSort\",\n fieldNames,\n );\n const tiebreakSort = orderTerms(\n doc.tiebreakSort,\n \"schema.tiebreakSort\",\n fieldNames,\n );\n const importPath = options.importPath ?? DEFAULT_GO_IMPORT;\n if (!importPath || /[\\s\\x00-\\x1f\\x7f\"]/u.test(importPath))\n throw new Error(\"invalid Go import path\");\n\n const longestFieldKey = Math.max(\n 0,\n ...fields.map((field) => goString(field.name).length),\n );\n const fieldLines = fields.map((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 const aggregateOps =\n field.aggregateOps !== undefined\n ? `, AggregateOps: []string{${field.aggregateOps.map(goString).join(\", \")}}`\n : \"\";\n const groupable =\n field.groupable !== undefined\n ? `, Groupable: func() *bool { v := ${field.groupable}; return &v }()`\n : \"\";\n return `\\t\\t\\t${key}:${spacing}{Name: ${goString(field.name)}, Kind: querytable.${field.kind}, Expr: ${goString(field.expr)}, Synthetic: ${field.synthetic}${field.sqliteSortField ? `, SQLiteSortField: ${goString(field.sqliteSortField)}` : \"\"}${field.expressionNumeric ? \", ExpressionNumeric: true\" : \"\"}${field.datetimeFormat ? `, SQLiteDatetimeFormat: ${goString(field.datetimeFormat)}` : \"\"}${aggregateOps}${groupable}, ServerFilter: ${field.serverFilter}${filterOps}${field.arrayCaseSensitive ? \", ArrayCaseSensitive: true\" : \"\"}, Sortable: ${field.sortable}, SortExpr: ${goString(field.sortExpr)}},`;\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-YQ663BVQ.js";
5
+ } from "./chunk-ZQZDDNVV.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -18,6 +18,8 @@ Usage:
18
18
  query-table-codegen <schema.json> --ts <output.ts>
19
19
  query-table-codegen <schema.json> --go <output.go> --go-package <name> [--go-import <path>]
20
20
 
21
+ Use --dialect sqlite with --go to read bindings.sqlite (default: postgres).
22
+
21
23
  Both --ts and --go may be supplied in one invocation.
22
24
  `;
23
25
  function optionValue(args, index, flag) {
@@ -46,6 +48,13 @@ function parseArgs(args) {
46
48
  options.goPackage = optionValue(args, index, flag);
47
49
  index += 1;
48
50
  break;
51
+ case "--dialect": {
52
+ const value = optionValue(args, index, flag);
53
+ if (value !== "postgres" && value !== "sqlite") throw new Error("--dialect must be postgres or sqlite");
54
+ options.dialect = value;
55
+ index += 1;
56
+ break;
57
+ }
49
58
  case "--go-import":
50
59
  options.goImport = optionValue(args, index, flag);
51
60
  index += 1;
@@ -56,7 +65,7 @@ function parseArgs(args) {
56
65
  }
57
66
  if (!options.ts && !options.go) throw new Error("at least one of --ts or --go is required");
58
67
  if (options.go && !options.goPackage) throw new Error("--go-package is required with --go");
59
- if (!options.go && (options.goPackage || options.goImport)) throw new Error("--go-package/--go-import require --go");
68
+ if (!options.go && (options.goPackage || options.goImport || options.dialect)) throw new Error("--go-package/--go-import require --go");
60
69
  return options;
61
70
  }
62
71
  async function writeGenerated(path, contents) {
@@ -89,7 +98,7 @@ async function main() {
89
98
  if (tsPath && goPath && tsPath === goPath) throw new Error("--ts and --go must use different output paths");
90
99
  const tsOutput = options.ts ? generateTypeScript(document) : void 0;
91
100
  const goOptions = options.go ? options.goImport ? { packageName: options.goPackage, importPath: options.goImport } : { packageName: options.goPackage } : void 0;
92
- const goOutput = goOptions ? generateGo(document, goOptions) : void 0;
101
+ const goOutput = goOptions ? generateGo(document, { ...goOptions, ...options.dialect ? { dialect: options.dialect } : {} }) : void 0;
93
102
  await Promise.all([
94
103
  ...options.ts && tsOutput ? [writeGenerated(options.ts, tsOutput)] : [],
95
104
  ...options.go && goOutput ? [writeGenerated(options.go, goOutput)] : []
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { generateGo, generateTypeScript } from \"./generate\";\n\nconst packageManifest = JSON.parse(await readFile(new URL(\"../package.json\", import.meta.url), \"utf8\")) as {\n version?: unknown;\n};\nif (typeof packageManifest.version !== \"string\" || !packageManifest.version) {\n throw new Error(\"package.json does not contain a valid version\");\n}\nconst VERSION = packageManifest.version;\n\ninterface CliOptions {\n input: string;\n ts?: string;\n go?: string;\n goPackage?: string;\n goImport?: string;\n}\n\nconst HELP = `query-table-codegen ${VERSION}\n\nUsage:\n query-table-codegen <schema.json> --ts <output.ts>\n query-table-codegen <schema.json> --go <output.go> --go-package <name> [--go-import <path>]\n\nBoth --ts and --go may be supplied in one invocation.\n`;\n\nfunction optionValue(args: string[], index: number, flag: string): string {\n const value = args[index + 1];\n if (!value || value.startsWith(\"--\")) throw new Error(`${flag} requires a value`);\n return value;\n}\n\nfunction parseArgs(args: string[]): CliOptions | \"help\" | \"version\" {\n if (args.includes(\"--help\") || args.includes(\"-h\")) return \"help\";\n if (args.includes(\"--version\") || args.includes(\"-v\")) return \"version\";\n const input = args[0];\n if (!input || input.startsWith(\"--\")) throw new Error(\"a schema JSON path is required\");\n const options: CliOptions = { input };\n\n for (let index = 1; index < args.length; index += 1) {\n const flag = args[index]!;\n switch (flag) {\n case \"--ts\":\n options.ts = optionValue(args, index, flag);\n index += 1;\n break;\n case \"--go\":\n options.go = optionValue(args, index, flag);\n index += 1;\n break;\n case \"--go-package\":\n options.goPackage = optionValue(args, index, flag);\n index += 1;\n break;\n case \"--go-import\":\n options.goImport = optionValue(args, index, flag);\n index += 1;\n break;\n default:\n throw new Error(`unknown option ${flag}`);\n }\n }\n\n if (!options.ts && !options.go) throw new Error(\"at least one of --ts or --go is required\");\n if (options.go && !options.goPackage) throw new Error(\"--go-package is required with --go\");\n if (!options.go && (options.goPackage || options.goImport)) throw new Error(\"--go-package/--go-import require --go\");\n return options;\n}\n\nasync function writeGenerated(path: string, contents: string): Promise<void> {\n const output = resolve(path);\n await mkdir(dirname(output), { recursive: true });\n await writeFile(output, contents, \"utf8\");\n}\n\nasync function main(): Promise<void> {\n const options = parseArgs(process.argv.slice(2));\n if (options === \"help\") {\n process.stdout.write(HELP);\n return;\n }\n if (options === \"version\") {\n process.stdout.write(`${VERSION}\\n`);\n return;\n }\n\n const source = await readFile(resolve(options.input), \"utf8\");\n let document: unknown;\n try {\n document = JSON.parse(source);\n } catch (error) {\n throw new Error(`invalid JSON in ${options.input}: ${(error as Error).message}`);\n }\n\n const inputPath = resolve(options.input);\n const tsPath = options.ts ? resolve(options.ts) : undefined;\n const goPath = options.go ? resolve(options.go) : undefined;\n if (tsPath === inputPath || goPath === inputPath) throw new Error(\"an output path must not overwrite the input schema\");\n if (tsPath && goPath && tsPath === goPath) throw new Error(\"--ts and --go must use different output paths\");\n\n const tsOutput = options.ts ? generateTypeScript(document) : undefined;\n const goOptions = options.go\n ? options.goImport\n ? { packageName: options.goPackage!, importPath: options.goImport }\n : { packageName: options.goPackage! }\n : undefined;\n const goOutput = goOptions ? generateGo(document, goOptions) : undefined;\n\n await Promise.all([\n ...(options.ts && tsOutput ? [writeGenerated(options.ts, tsOutput)] : []),\n ...(options.go && goOutput ? [writeGenerated(options.go, goOutput)] : []),\n ]);\n}\n\nvoid main().catch((error: unknown) => {\n process.stderr.write(`query-table-codegen: ${(error as Error).message}\\n`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { generateGo, generateTypeScript } from \"./generate\";\n\nconst packageManifest = JSON.parse(await readFile(new URL(\"../package.json\", import.meta.url), \"utf8\")) as {\n version?: unknown;\n};\nif (typeof packageManifest.version !== \"string\" || !packageManifest.version) {\n throw new Error(\"package.json does not contain a valid version\");\n}\nconst VERSION = packageManifest.version;\n\ninterface CliOptions {\n input: string;\n ts?: string;\n go?: string;\n goPackage?: string;\n goImport?: string;\n dialect?: \"postgres\" | \"sqlite\";\n}\n\nconst HELP = `query-table-codegen ${VERSION}\n\nUsage:\n query-table-codegen <schema.json> --ts <output.ts>\n query-table-codegen <schema.json> --go <output.go> --go-package <name> [--go-import <path>]\n\nUse --dialect sqlite with --go to read bindings.sqlite (default: postgres).\n\nBoth --ts and --go may be supplied in one invocation.\n`;\n\nfunction optionValue(args: string[], index: number, flag: string): string {\n const value = args[index + 1];\n if (!value || value.startsWith(\"--\")) throw new Error(`${flag} requires a value`);\n return value;\n}\n\nfunction parseArgs(args: string[]): CliOptions | \"help\" | \"version\" {\n if (args.includes(\"--help\") || args.includes(\"-h\")) return \"help\";\n if (args.includes(\"--version\") || args.includes(\"-v\")) return \"version\";\n const input = args[0];\n if (!input || input.startsWith(\"--\")) throw new Error(\"a schema JSON path is required\");\n const options: CliOptions = { input };\n\n for (let index = 1; index < args.length; index += 1) {\n const flag = args[index]!;\n switch (flag) {\n case \"--ts\":\n options.ts = optionValue(args, index, flag);\n index += 1;\n break;\n case \"--go\":\n options.go = optionValue(args, index, flag);\n index += 1;\n break;\n case \"--go-package\":\n options.goPackage = optionValue(args, index, flag);\n index += 1;\n break;\n case \"--dialect\": {\n const value = optionValue(args, index, flag);\n if (value !== \"postgres\" && value !== \"sqlite\") throw new Error(\"--dialect must be postgres or sqlite\");\n options.dialect = value;\n index += 1;\n break;\n }\n case \"--go-import\":\n options.goImport = optionValue(args, index, flag);\n index += 1;\n break;\n default:\n throw new Error(`unknown option ${flag}`);\n }\n }\n\n if (!options.ts && !options.go) throw new Error(\"at least one of --ts or --go is required\");\n if (options.go && !options.goPackage) throw new Error(\"--go-package is required with --go\");\n if (!options.go && (options.goPackage || options.goImport || options.dialect)) throw new Error(\"--go-package/--go-import require --go\");\n return options;\n}\n\nasync function writeGenerated(path: string, contents: string): Promise<void> {\n const output = resolve(path);\n await mkdir(dirname(output), { recursive: true });\n await writeFile(output, contents, \"utf8\");\n}\n\nasync function main(): Promise<void> {\n const options = parseArgs(process.argv.slice(2));\n if (options === \"help\") {\n process.stdout.write(HELP);\n return;\n }\n if (options === \"version\") {\n process.stdout.write(`${VERSION}\\n`);\n return;\n }\n\n const source = await readFile(resolve(options.input), \"utf8\");\n let document: unknown;\n try {\n document = JSON.parse(source);\n } catch (error) {\n throw new Error(`invalid JSON in ${options.input}: ${(error as Error).message}`);\n }\n\n const inputPath = resolve(options.input);\n const tsPath = options.ts ? resolve(options.ts) : undefined;\n const goPath = options.go ? resolve(options.go) : undefined;\n if (tsPath === inputPath || goPath === inputPath) throw new Error(\"an output path must not overwrite the input schema\");\n if (tsPath && goPath && tsPath === goPath) throw new Error(\"--ts and --go must use different output paths\");\n\n const tsOutput = options.ts ? generateTypeScript(document) : undefined;\n const goOptions = options.go\n ? options.goImport\n ? { packageName: options.goPackage!, importPath: options.goImport }\n : { packageName: options.goPackage! }\n : undefined;\n const goOutput = goOptions ? generateGo(document, { ...goOptions, ...(options.dialect ? { dialect: options.dialect } : {}) }) : undefined;\n\n await Promise.all([\n ...(options.ts && tsOutput ? [writeGenerated(options.ts, tsOutput)] : []),\n ...(options.go && goOutput ? [writeGenerated(options.go, goOutput)] : []),\n ]);\n}\n\nvoid main().catch((error: unknown) => {\n process.stderr.write(`query-table-codegen: ${(error as Error).message}\\n`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  interface GoGenerationOptions {
2
2
  packageName: string;
3
3
  importPath?: string;
4
+ dialect?: "postgres" | "sqlite";
4
5
  }
5
6
  /** Generate the frontend projection. SQL bindings are deliberately omitted. */
6
7
  declare function generateTypeScript(input: unknown): string;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  generateGo,
3
3
  generateTypeScript
4
- } from "./chunk-YQ663BVQ.js";
4
+ } from "./chunk-ZQZDDNVV.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.5.0",
3
+ "version": "0.7.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",
@@ -34,6 +34,6 @@
34
34
  "typecheck": "tsc --noEmit"
35
35
  },
36
36
  "dependencies": {
37
- "@pythia-software/query-table-core": "0.5.0"
37
+ "@pythia-software/query-table-core": "0.7.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 arrayCaseSensitive: 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 arrayCaseSensitive = false;\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 arrayCaseSensitive = filter.arrayCaseSensitive === true;\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 arrayCaseSensitive,\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}${field.arrayCaseSensitive ? \", ArrayCaseSensitive: true\" : \"\"}, 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":[]}