@lakeql/query-builder 0.1.5 → 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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @lakeql/query-builder
2
2
 
3
- SQL query builder for Trino using Kysely, supporting dynamic filters (AND/OR), sorting, pagination, and field transformations.
3
+ SQL query builder using Kysely, supporting dynamic filters (AND/OR), sorting, pagination, and field transformations across adapters.
4
4
 
5
5
  ## Installation
6
6
 
package/dist/index.d.mts CHANGED
@@ -1,11 +1,47 @@
1
+ /**
2
+ * Special thanks goes to https://github.com/igalklebanov
3
+ * for solving our edge case issue with multiple schematas <3
4
+ * https://www.answeroverflow.com/m/1227929774144618598
5
+ * and also with helping to solve the type issues <3
6
+ * https://www.answeroverflow.com/m/1228457827572645908
7
+ */
1
8
  import { GraphQLResolveInfo } from "graphql";
2
- import { CompiledQuery, ExpressionBuilder, ExpressionWrapper, SelectExpression, SqlBool } from "kysely";
3
-
4
- //#region src/index.d.ts
9
+ import { DatabaseIntrospector, DialectAdapter, ExpressionBuilder, ExpressionWrapper, Kysely, QueryCompiler, RawBuilder, SelectExpression, SqlBool } from "kysely";
10
+ import { AdapterName, SourceConfig } from "@lakeql/datasource";
11
+ /**
12
+ * Engine-specific SQL generation strategy for Kysely.
13
+ *
14
+ * Each adapter provides a dialect that handles identifier quoting,
15
+ * pagination syntax, date functions, and sql-formatter language selection.
16
+ * The dialect is injected into the query builder — the query builder
17
+ * itself contains no adapter-specific SQL logic.
18
+ */
19
+ interface QueryDialect {
20
+ /** Open adapter name identifying the backend this dialect targets. */
21
+ readonly adapterName: AdapterName;
22
+ /** Creates the Kysely dialect adapter (e.g. PostgresAdapter, MssqlAdapter). */
23
+ createAdapter: () => DialectAdapter;
24
+ /** Creates the Kysely query compiler for the target backend. */
25
+ createQueryCompiler: () => QueryCompiler;
26
+ /** Creates the Kysely database introspector for the target backend. */
27
+ createIntrospector: (db: Kysely<unknown>) => DatabaseIntrospector;
28
+ /** Wraps a column name in the backend-specific timestamp-to-unix conversion function. */
29
+ toUnixTimestamp: (field: string) => RawBuilder<unknown>;
30
+ /** Returns a raw SQL fragment for limit/offset pagination. */
31
+ pagination: (limit: number, offset?: number) => RawBuilder<unknown>;
32
+ /**
33
+ * Backend-specific boolean "true" literal used for the record-present
34
+ * sentinel column in the `records` CTE. Trino uses `TRUE`; T-SQL backends
35
+ * (e.g. Fabric) have no boolean literal and use `1`.
36
+ */
37
+ trueLiteral: () => RawBuilder<unknown>;
38
+ /** Returns the fully-qualified table name with backend-specific quoting. */
39
+ qualifiedTable: (config: SourceConfig) => string;
40
+ }
5
41
  /**
6
42
  * Logical operators for combining filter conditions.
7
43
  */
8
- declare enum WhereOperator {
44
+ export declare enum WhereOperator {
9
45
  AND = "and",
10
46
  OR = "or"
11
47
  }
@@ -16,7 +52,7 @@ declare enum WhereOperator {
16
52
  * String operators compare the field value against the provided string.
17
53
  * Boolean operators (`is`/`isNot`) check for equality with `true`/`false`.
18
54
  */
19
- interface FieldOptions {
55
+ export interface FieldOptions {
20
56
  eq?: string;
21
57
  neq?: string;
22
58
  in?: string;
@@ -33,18 +69,22 @@ interface FieldOptions {
33
69
  /**
34
70
  * Defines the sort order for a query result.
35
71
  *
36
- * @template TableDefinition - The table type used to constrain the `field` to valid column names.
72
+ * @template TableDefinition - The table type used to constrain the `field` to valid column names. See [query-builder](/docs/packages/query-builder) for details.
37
73
  */
38
- interface SortInput<TableDefinition> {
39
- /** Column name to sort by. Constrained to valid column names from the table type. */
74
+ export interface SortInput<TableDefinition> {
75
+ /**
76
+ * Column name to sort by. Constrained to valid column names from the table type.
77
+ *
78
+ * @see {@link https://kysely-org.github.io/kysely-apidoc/types/SelectExpression.html | Kysely API Docs - SelectExpression}
79
+ */
40
80
  field: SelectExpression<KyselyDatabase<TableDefinition>, keyof KyselyDatabase<TableDefinition>>;
41
- /** Sort direction — `"asc"` for ascending, `"desc"` for descending. */
42
- direction: string;
81
+ /** Sort direction */
82
+ direction: "asc" | "desc";
43
83
  }
44
84
  /**
45
85
  * Controls offset-based pagination.
46
86
  */
47
- interface PagingInput {
87
+ export interface PagingInput {
48
88
  /**
49
89
  * Maximum number of rows to return.
50
90
  * @default 100
@@ -57,12 +97,12 @@ interface PagingInput {
57
97
  * A single field condition — a record where the key is the field name
58
98
  * and the value is a [FieldOptions](#field-options) object describing the comparison.
59
99
  */
60
- type Field = Record<string, FieldOptions>;
100
+ export type Field = Record<string, FieldOptions>;
61
101
  /**
62
102
  * A recursive filter structure that can contain AND/OR groups,
63
103
  * each holding field conditions or further nested groups.
64
104
  */
65
- type Where = Partial<Record<WhereOperator, (Where | Field)[]>>;
105
+ export type Where = Partial<Record<WhereOperator, (Where | Field)[]>>;
66
106
  /**
67
107
  * KyselyDatabase is our generic interface which simulates
68
108
  * the normal kysely table definition
@@ -71,19 +111,26 @@ interface KyselyDatabase<TableDefinition> {
71
111
  tablename: TableDefinition;
72
112
  }
73
113
  /**
74
- * Parameters for generating a Trino-compatible SQL query from GraphQL resolve info.
114
+ * Parameters for generating an adapter-aware SQL query from GraphQL resolve info.
75
115
  *
76
- * @template TableDefinition - The table type definition used by Kysely for type-safe column references.
116
+ * @template TableDefinition - The table type definition used by Kysely for type-safe column references. See [query-builder](/docs/packages/query-builder) for details.
77
117
  */
78
- interface GenerateQueryProps<TableDefinition> {
79
- /** The Trino catalog name (e.g. "hive"). */
118
+ export interface GenerateQueryProps<TableDefinition> {
119
+ /** The query dialect providing adapter-specific SQL generation. */
120
+ dialect: QueryDialect;
121
+ /** The catalog name (e.g. "hive"). */
80
122
  catalog: string;
81
- /** The Trino schema name (e.g. "sales"). */
123
+ /** The schema name (e.g. "sales"). */
82
124
  schema: string;
83
125
  /** The table name to query. */
84
126
  table: string;
85
- /** The columns to select, derived from GraphQL field selections. */
86
- selectFields: SelectExpression<KyselyDatabase<TableDefinition>, keyof KyselyDatabase<TableDefinition>>[];
127
+ /**
128
+ * The column names to select, derived from GraphQL field selections.
129
+ *
130
+ * These are plain field-name strings (as returned by {@link getSelectFields});
131
+ * they are resolved against the table definition when the query is built.
132
+ */
133
+ selectFields: readonly string[];
87
134
  /** The user-provided filter query (WHERE clause). */
88
135
  userQuery: Where;
89
136
  /** Pagination parameters (limit and offset). */
@@ -92,14 +139,21 @@ interface GenerateQueryProps<TableDefinition> {
92
139
  sorting: SortInput<TableDefinition>[];
93
140
  /** Maps GraphQL field names to database column names. */
94
141
  transformFields?: Record<string, string>;
95
- /** Fields that should be wrapped in `to_unixtime()` for date conversion. */
142
+ /** Fields that should be wrapped in adapter-specific timestamp conversion. */
96
143
  dateFields?: string[];
97
144
  }
98
145
  /**
99
146
  * Parameters for building a single field comparison expression.
147
+ *
148
+ * @template TableDefinition - The table type definition. See [query-builder](/docs/packages/query-builder) for details.
100
149
  */
101
- interface GetFieldQueryProps<TableDefinition> {
102
- /** The Kysely expression builder for constructing SQL expressions. */
150
+ export interface GetFieldQueryProps<TableDefinition> {
151
+ /**
152
+ * The Kysely expression builder for constructing SQL expressions.
153
+ *
154
+ * @see {@link https://kysely.dev/docs/recipes/expressions | Kysely Docs - Expressions}
155
+ * @see {@link https://kysely-org.github.io/kysely-apidoc/interfaces/ExpressionBuilder.html | Kysely API Docs - ExpressionBuilder}
156
+ */
103
157
  eb: ExpressionBuilder<KyselyDatabase<TableDefinition>, "tablename">;
104
158
  /** The column name to filter on. */
105
159
  fieldName: string;
@@ -112,14 +166,9 @@ interface GetFieldQueryProps<TableDefinition> {
112
166
  * Builds a single field comparison expression for use in WHERE clauses.
113
167
  *
114
168
  * @param props - The field query parameters.
115
- * @returns A Kysely expression wrapper representing the comparison.
169
+ * @returns A Kysely [ExpressionWrapper](https://kysely-org.github.io/kysely-apidoc/classes/ExpressionWrapper.html) representing the comparison.
116
170
  */
117
- declare function getFieldQuery<TableDefinition>({
118
- eb,
119
- fieldName,
120
- operator,
121
- value
122
- }: GetFieldQueryProps<TableDefinition>): ExpressionWrapper<KyselyDatabase<TableDefinition>, "tablename", SqlBool>;
171
+ export declare function getFieldQuery<TableDefinition>({ eb, fieldName, operator, value }: GetFieldQueryProps<TableDefinition>): ExpressionWrapper<KyselyDatabase<TableDefinition>, "tablename", SqlBool>;
123
172
  /**
124
173
  * Normalizes filter objects by ensuring each field is in its own object within and/or arrays.
125
174
  *
@@ -129,7 +178,7 @@ declare function getFieldQuery<TableDefinition>({
129
178
  * @param filter - The filter object to normalize.
130
179
  * @returns A normalized filter with individual field entries.
131
180
  */
132
- declare function normalizeFilter(filter: Where): Where;
181
+ export declare function normalizeFilter(filter: Where): Where;
133
182
  /**
134
183
  * Wraps bare field-level filters into an AND-rooted structure.
135
184
  *
@@ -139,57 +188,38 @@ declare function normalizeFilter(filter: Where): Where;
139
188
  * @param userQuery - The user-provided filter query.
140
189
  * @returns A normalized query with a logical operator at the root.
141
190
  */
142
- declare function normalizeUserQuery(userQuery: Where): Where;
191
+ export declare function normalizeUserQuery(userQuery: Where): Where;
143
192
  /**
144
- * Generates a compiled SQL query with pagination metadata for Trino.
193
+ * Generates a compiled SQL query with pagination metadata using the injected dialect.
145
194
  *
146
- * Returns a Kysely `CompiledQuery` containing the generated SQL and parameters.
147
195
  * The query uses two CTEs internally:
148
196
  * - `total_count` — provides `total_records` (total matching rows before paging)
149
197
  * - `records` — the actual rows based on `selectFields`, filtering, sorting, and paging
150
198
  *
151
- * The compiled query is executed by the Trino client which returns the row data.
199
+ * The compiled query is executed by the DataSource adapter which returns the row data.
152
200
  *
153
- * @returns A compiled SQL query ready for execution via the Trino client.
154
- */
155
- declare function generateQuery<TableDefinition>({
156
- catalog,
157
- schema,
158
- table,
159
- selectFields,
160
- userQuery,
161
- sorting,
162
- paging,
163
- transformFields,
164
- dateFields
165
- }: GenerateQueryProps<TableDefinition>): CompiledQuery<{
201
+ * @returns A [CompiledQuery](https://kysely-org.github.io/kysely-apidoc/interfaces/CompiledQuery.html) ready for execution via the DataSource adapter.
202
+ */
203
+ export declare function generateQuery<TableDefinition>({ dialect, catalog, schema, table, selectFields, userQuery, sorting, paging, transformFields, dateFields }: GenerateQueryProps<TableDefinition>): import("kysely").CompiledQuery<{
166
204
  total_records: number;
167
205
  }>;
168
- /**
169
- * Parameters for formatting a compiled SQL query.
170
- */
171
- interface FormatQueryProps<T> {
172
- /** The compiled Kysely query to format. */
173
- query: CompiledQuery<T>;
206
+ export interface GetSelectFieldProps {
207
+ /**
208
+ * The GraphQL resolve info from the resolver.
209
+ *
210
+ * @see {@link https://the-guild.dev/graphql/tools/docs/api/utils/src/interfaces/graphqlresolveinfo | GraphQL Tools - GraphQLResolveInfo}
211
+ */
212
+ graphqlInfo: GraphQLResolveInfo;
213
+ /**
214
+ * When true, looks inside the `nodes` selection (for Connection types).
215
+ * @default false
216
+ */
217
+ withNodes?: boolean;
174
218
  }
175
- /**
176
- * Formats a compiled SQL query for readability.
177
- *
178
- * Applies uppercase keywords, PostgreSQL dialect, and interpolates parameters.
179
- *
180
- * @param props - The format query parameters.
181
- * @returns The formatted SQL string with interpolated parameters.
182
- */
183
- declare function formatQuery<T>({
184
- query
185
- }: FormatQueryProps<T>): string;
186
219
  /**
187
220
  * Extracts selected field names from a GraphQL resolve info object.
188
221
  *
189
- * @param graphqlInfo - The GraphQL resolve info from the resolver.
190
- * @param withNodes - When true, looks inside the `nodes` selection (for Connection types).
191
222
  * @returns An array of field names to use as SELECT columns.
192
223
  */
193
- declare function getSelectFields<T>(graphqlInfo: GraphQLResolveInfo, withNodes?: boolean): GenerateQueryProps<T>["selectFields"];
194
- //#endregion
195
- export { Field, FieldOptions, FormatQueryProps, GenerateQueryProps, GetFieldQueryProps, PagingInput, SortInput, Where, WhereOperator, formatQuery, generateQuery, getFieldQuery, getSelectFields, normalizeFilter, normalizeUserQuery };
224
+ export declare function getSelectFields({ graphqlInfo, withNodes }: GetSelectFieldProps): string[];
225
+ export type { QueryDialect };
package/dist/index.mjs CHANGED
@@ -1 +1,5 @@
1
- import{GraphQLError as e}from"graphql";import{DummyDriver as t,Kysely as n,PostgresAdapter as r,PostgresIntrospector as i,PostgresQueryCompiler as a,sql as o}from"kysely";import{format as s}from"sql-formatter";const c=()=>new n({dialect:{createAdapter(){return new r},createDriver(){return new t},createIntrospector(e){return new i(e)},createQueryCompiler(){return new a}}});let l=function(e){return e.AND=`and`,e.OR=`or`,e}({});const u={eq:`=`,gt:`>`,gte:`>=`,in:`in`,is:`=`,isnot:`!=`,lt:`<`,lte:`<=`,neq:`!=`,notin:`not in`};function d({eb:e,fieldName:t,operator:n,value:r}){let i=t,a=n.toLowerCase();switch(a){case`eq`:case`neq`:case`lt`:case`lte`:case`gt`:case`gte`:case`is`:case`isnot`:return e(o.id(i),u[a]??`=`,r);case`in`:case`notin`:return e(o.id(i),u[a]??`=`,r);case`like`:return e(o.id(i),`like`,`%${r}%`);case`notlike`:return e.not(e(o.id(i),`like`,`%${r}%`));case`startswith`:return e(o.id(i),`like`,`${r}%`);case`notstartswith`:return e.not(e(o.id(i),`like`,`${r}%`));case`endswith`:return e(o.id(i),`like`,`%${r}`);case`notendswith`:return e.not(e(o.id(i),`like`,`%${r}`));default:return e(o.id(i),`=`,r)}}function f({eb:e,query:t,transformFields:n}){let r=[];for(let[i,a]of Object.entries(t))switch(i.toLowerCase()){case`and`:for(let t of a){let i=f({eb:e,query:t,transformFields:n});i!==void 0&&r.push(i)}return e.and(r);case`or`:for(let t of a){let i=f({eb:e,query:t,transformFields:n});i&&r.push(i)}return e.or(r);default:{let[t,r]=Object.entries(a).flat();return d({eb:e,fieldName:n?.[i]??i,operator:t,value:r})}}}function p(e){if(!e)return e;let t={...e};return t.and&&Array.isArray(t.and)&&(t.and=t.and.flatMap(e=>{let t=e,n=Object.keys(t),r=n.filter(e=>e===`and`||e===`or`),i=n.filter(e=>e!==`and`&&e!==`or`);if(i.length>0&&r.length>0){let e=i.map(e=>({[e]:t[e]})),n=r.map(e=>({[e]:p({[e]:t[e]})[e]}));return[...e,...n]}if(i.length>1&&r.length===0)return i.map(e=>({[e]:t[e]}));if(r.length>0){let e={...t};for(let n of r)e[n]=p({[n]:t[n]})[n];return e}return e})),t.or&&Array.isArray(t.or)&&(t.or=t.or.flatMap(e=>{let t=e,n=Object.keys(t),r=n.filter(e=>e===`and`||e===`or`),i=n.filter(e=>e!==`and`&&e!==`or`);if(i.length>0&&r.length>0){let e=i.map(e=>({[e]:t[e]})),n=r.map(e=>({[e]:p({[e]:t[e]})[e]}));return[...e,...n]}if(i.length>1&&r.length===0)return i.map(e=>({[e]:t[e]}));if(r.length>0){let e={...t};for(let n of r)e[n]=p({[n]:t[n]})[n];return e}return e})),t}function m(e){let t=Object.keys(e);return t.length===1&&(t[0]===`and`||t[0]===`or`)?e:{and:Object.entries(e).map(([e,t])=>({[e]:t}))}}function h({catalog:e,schema:t,table:n,selectFields:r,userQuery:i,sorting:a,paging:s,transformFields:l,dateFields:u=[]}){let d=c(),{ref:h}=d.dynamic;return d.with(`total_count`,r=>r.selectFrom(o.id(e,t,n)).select(({fn:e})=>e.countAll().as(`total_records`)).$if(Object.keys(i).length>0,e=>e.where(e=>f({eb:e,query:p(m(i)),transformFields:l})??e.and([])))).with(`records`,c=>{let d=c.selectFrom(o.id(e,t,n)).select(r.map(e=>u.includes(e)?l?.[e]?o.raw(`to_unixtime(${l[e]})`).as(l[e]):o.raw(`to_unixtime(${e})`).as(e):l?.[e]?o.id(l[e]).as(l[e]):typeof e==`string`?h(e):e)).$if(Object.keys(i).length>0,e=>e.where(e=>f({eb:e,query:p(m(i)),transformFields:l})??e.and([])));for(let e of a){let t=l?.[e.field]||e.field;d=d.orderBy(t,e.direction.toLowerCase())}return d=!s?.offset||s.offset<=0?d.modifyEnd(o.raw(`FETCH FIRST ${s?.limit??100} ROWS ONLY`)):d.offset(s.offset??100).modifyEnd(o.raw(`FETCH NEXT ${s.limit??100} ROWS ONLY`)),d}).selectFrom(`total_count`).selectAll().fullJoin(`records`,e=>e.onTrue()).compile()}function g({query:e}){let t={};for(let[n,r]of e.parameters.entries())t[n+1]=String(typeof r==`string`?`'${r}'`:r);return s(e.sql,{keywordCase:`upper`,language:`postgresql`,params:t,tabWidth:0,useTabs:!1})}function _(t,n=!1){return t.fieldNodes.flatMap(t=>{let r=t.selectionSet?.selections,i=[];if(n){let t=r.find(e=>e.name.value===`nodes`);if(!t)throw new e("No fields to return defined. Please specify at least one field inside `nodes`.");i=t.selectionSet?.selections??[]}else i=t.selectionSet?.selections??[];return i.flatMap(e=>e.name.value)})}export{l as WhereOperator,g as formatQuery,h as generateQuery,d as getFieldQuery,_ as getSelectFields,p as normalizeFilter,m as normalizeUserQuery};
1
+ import{GraphQLError as e}from"graphql";import{DummyDriver as t,Kysely as n,sql as r}from"kysely";const i=e=>new n({dialect:{...e,createDriver:()=>new t}});let a=/* @__PURE__ */ function(e){return e.AND=`and`,e.OR=`or`,e}({});const o={eq:`=`,gt:`>`,gte:`>=`,in:`in`,is:`=`,isnot:`!=`,lt:`<`,lte:`<=`,neq:`!=`,notin:`not in`};function s({eb:e,fieldName:t,operator:n,value:i}){let a=t,s=n.toLowerCase();switch(s){case`eq`:case`neq`:case`lt`:case`lte`:case`gt`:case`gte`:case`is`:case`isnot`:return e(r.id(a),o[s]??`=`,i);case`in`:case`notin`:return e(r.id(a),o[s]??`=`,i);case`like`:return e(r.id(a),`like`,`%${i}%`);case`notlike`:return e.not(e(r.id(a),`like`,`%${i}%`));case`startswith`:return e(r.id(a),`like`,`${i}%`);case`notstartswith`:return e.not(e(r.id(a),`like`,`${i}%`));case`endswith`:return e(r.id(a),`like`,`%${i}`);case`notendswith`:return e.not(e(r.id(a),`like`,`%${i}`));default:return e(r.id(a),`=`,i)}}function c({eb:e,query:t,transformFields:n}){let r=[];for(let[i,a]of Object.entries(t))switch(i.toLowerCase()){case`and`:for(let t of a){let i=c({eb:e,query:t,transformFields:n});i!==void 0&&r.push(i)}return e.and(r);case`or`:for(let t of a){let i=c({eb:e,query:t,transformFields:n});i&&r.push(i)}return e.or(r);default:{let[t,r]=Object.entries(a).flat();return s({eb:e,fieldName:n?.[i]??i,operator:t,value:r})}}}function l(e){if(!e)return e;let t={...e};return t.and&&Array.isArray(t.and)&&(t.and=t.and.flatMap(e=>{let t=e,n=Object.keys(t),r=n.filter(e=>e===`and`||e===`or`),i=n.filter(e=>e!==`and`&&e!==`or`);
2
+ /* c8 ignore next 6 */
3
+ if(i.length>0&&r.length>0){let e=i.map(e=>({[e]:t[e]})),n=r.map(e=>({[e]:l({[e]:t[e]})[e]}));return[...e,...n]}if(i.length>1&&r.length===0)return i.map(e=>({[e]:t[e]}));if(r.length>0){let e={...t};for(let n of r)e[n]=l({[n]:t[n]})[n];return e}return e})),t.or&&Array.isArray(t.or)&&(t.or=t.or.flatMap(e=>{let t=e,n=Object.keys(t),r=n.filter(e=>e===`and`||e===`or`),i=n.filter(e=>e!==`and`&&e!==`or`);
4
+ /* c8 ignore next 6 */
5
+ if(i.length>0&&r.length>0){let e=i.map(e=>({[e]:t[e]})),n=r.map(e=>({[e]:l({[e]:t[e]})[e]}));return[...e,...n]}if(i.length>1&&r.length===0)return i.map(e=>({[e]:t[e]}));if(r.length>0){let e={...t};for(let n of r)e[n]=l({[n]:t[n]})[n];return e}return e})),t}function u(e){let t=Object.keys(e);return t.length===1&&(t[0]===`and`||t[0]===`or`)?e:{and:Object.entries(e).map(([e,t])=>({[e]:t}))}}function d({dialect:e,catalog:t,schema:n,table:a,selectFields:o,userQuery:s,sorting:d,paging:f,transformFields:p,dateFields:m=[]}){let h=i(e),g=e.qualifiedTable({dataSource:``,adapter:e.adapterName,catalog:t,schema:n,tableName:a}),{ref:_}=h.dynamic;return h.with(`total_count`,e=>e.selectFrom(r.raw(g)).select(({fn:e})=>e.countAll().as(`total_records`)).$if(Object.keys(s).length>0,e=>e.where(e=>c({eb:e,query:l(u(s)),transformFields:p})??e.and([])))).with(`records`,t=>{let n=t.selectFrom(r.raw(g)).select(o.map(t=>{if(m.includes(t)){if(p?.[t]){let n=p[t];return e.toUnixTimestamp(n).as(n)}return e.toUnixTimestamp(t).as(t)}return p?.[t]?r.id(p[t]).as(p[t]):typeof t==`string`?_(t):t})).select(e.trueLiteral().as(`__lakeql_record_present`)).$if(Object.keys(s).length>0,e=>e.where(e=>c({eb:e,query:l(u(s)),transformFields:p})??e.and([])));for(let e of d){let t=p?.[e.field]||e.field;n=n.orderBy(t,e.direction.toLowerCase())}let i=f?.limit??100,a=f?.offset;return n=!a||a<=0?n.modifyEnd(e.pagination(i)):n.offset(a).modifyEnd(e.pagination(i,a)),n}).selectFrom(`total_count`).selectAll().fullJoin(`records`,e=>e.on(r`1=1`)).compile()}function f({graphqlInfo:t,withNodes:n=!1}){return t.fieldNodes.flatMap(t=>{let r=t.selectionSet?.selections,i=[];if(n){let t=r.find(e=>e.name.value===`nodes`);if(!t)throw new e("No fields to return defined. Please specify at least one field inside `nodes`.");i=t.selectionSet?.selections??[]}else i=t.selectionSet?.selections??[];return i.flatMap(e=>e.name.value)})}export{a as WhereOperator,d as generateQuery,s as getFieldQuery,f as getSelectFields,l as normalizeFilter,u as normalizeUserQuery};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lakeql/query-builder",
3
- "version": "0.1.5",
4
- "description": "Kysely-based SQL query builder that translates GraphQL queries into Trino SQL",
3
+ "version": "1.0.0",
4
+ "description": "Kysely-based SQL query builder that translates GraphQL queries into adapter SQL",
5
5
  "keywords": [
6
6
  "graphql",
7
7
  "kysely",
@@ -40,18 +40,18 @@
40
40
  }
41
41
  },
42
42
  "dependencies": {
43
- "date-fns": "4.4.0",
44
- "kysely": "0.29.2",
45
- "sql-formatter": "15.8.2"
43
+ "@lakeql/datasource": "1.0.0",
44
+ "kysely": "0.29.8"
46
45
  },
47
46
  "devDependencies": {
48
- "@pothos/core": "4.13.0",
49
- "@types/node": "24.13.2",
50
- "graphql": "16.14.2",
51
- "tsdown": "0.22.3",
47
+ "@lakeql/tsconfig": "0.1.0",
48
+ "@lakeql/vitest-config": "0.1.0",
49
+ "@pothos/core": "4.16.0",
50
+ "@types/node": "24.19.2",
51
+ "graphql": "17.1.0",
52
+ "tsdown": "0.23.7",
52
53
  "typescript": "6.0.3",
53
- "vitest": "4.1.9",
54
- "@lakeql/tsconfig": "0.1.0"
54
+ "vitest": "5.1.0"
55
55
  },
56
56
  "scripts": {
57
57
  "build": "tsdown",
@@ -59,6 +59,7 @@
59
59
  "clean:cache": "git clean -xdf .cache .turbo",
60
60
  "clean:dist": "git clean -xdf dist",
61
61
  "dev": "tsdown --watch",
62
+ "test": "vitest run",
62
63
  "typecheck": "tsc --noEmit"
63
64
  }
64
65
  }