@shellicar/cosmos-query-builder 1.0.0-preview.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +252 -0
- package/dist/esm/index.d.ts +252 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Stephen Hellicar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @shellicar/cosmos-query-builder
|
|
2
|
+
|
|
3
|
+
> A type-safe query builder for [Azure Cosmos DB for NoSQL](https://docs.microsoft.com/en-us/azure/cosmos-db/nosql/)
|
|
4
|
+
|
|
5
|
+
> **Note**: This library is for Azure Cosmos DB for NoSQL (formerly SQL API). For MongoDB API, see [Azure Cosmos DB for MongoDB](https://docs.microsoft.com/en-us/azure/cosmos-db/mongodb/).
|
|
6
|
+
|
|
7
|
+
## Installation & Quick Start
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm i --save @shellicar/cosmos-query-builder
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
pnpm add @shellicar/cosmos-query-builder
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Example
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { createCosmosQueryBuilder, SortDirection } from '@shellicar/cosmos-query-builder';
|
|
21
|
+
|
|
22
|
+
const builder = createCosmosQueryBuilder<Person>();
|
|
23
|
+
|
|
24
|
+
builder.where('type', 'eq', 'Person');
|
|
25
|
+
builder.where('age', 'gt', 18);
|
|
26
|
+
builder.orderBy('created', SortDirection.Desc);
|
|
27
|
+
builder.limit(50);
|
|
28
|
+
|
|
29
|
+
const results = await builder.getAll(container);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
For a complete working example, see [examples/simple/src/main.ts](../../examples/simple/src/main.ts).
|
|
33
|
+
|
|
34
|
+
## Documentation
|
|
35
|
+
|
|
36
|
+
For full documentation, visit the [GitHub repository](https://github.com/shellicar/cosmos-query-builder).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=Object.defineProperty,t=(t,s)=>e(t,"name",{value:s,configurable:!0}),s=class{static{t(this,"ILogger")}},r=class{static{t(this,"ICosmosQueryBuilder")}},i={eq:"=",ne:"!=",ge:">=",gt:">",le:"<=",lt:"<"},n=class extends s{static{t(this,"DefaultLogger")}debug(e,...t){}info(e,...t){}error(e,...t){}warn(e,...t){}verbose(e,...t){}},o=class extends r{static{t(this,"CosmosQueryBuilder")}_orderBy;_select="*";_groupBy=null;_join="";_from="c";_queries=[];_parameters=[];_limit;_logger;constructor(e){super(),this._logger=e?.logger??new n}get queries(){return this._queries}set queries(e){this._queries=e}get parameters(){return this._parameters}set parameters(e){this._parameters=e}handleStringFilter(e,t){return this.handleFilterObject(e,t)}handleUuidFilter(e,t){return this.handleFilterObject(e,t)}handleInstantFilter(e,t){return this.handleFilterObject(e,t)}handleFilterObject(e,t){const{__typeInfo:s,...r}=t;for(const[t,s]of Object.entries(r).filter(e=>void 0!==e[1])){const r=e,n=`@p${this._parameters.length}`,o=i[t],u=`(${r} ?? null)`;if(null!=o)this._queries.push(`${u} ${o} ${n}`);else if("ieq"===t)this._queries.push(`StringEquals(${u}, ${n}, true)`);else if("ine"===t)this._queries.push(`Not(StringEquals(${u}, ${n}, true))`);else if("like"===t)this._queries.push(`Contains(${u}, ${n}, true)`);else{if("in"!==t)throw new Error(`Unknown operator ${t}`);this._queries.push(`ARRAY_CONTAINS(${n}, ${u})`)}this._parameters.push({name:n,value:s})}}_buildQuery(e,t="c"){if(null!=e){const{__typeInfo:s,...r}=e,i=Object.keys(r);for(const s of i){const r=e[s],i=r.__typeInfo??null,n=`${t}.${s}`;if("object"!=typeof r||null==r)throw new Error(`Unhandled type ${i}`);"StringFilter"===i?this.handleStringFilter(n,r):"InstantFilter"===i?this.handleInstantFilter(n,r):"UUIDFilter"===i?this.handleUuidFilter(n,r):this._buildQuery(r,n)}}}buildQuery(e,t="c"){this._buildQuery(e,t)}orderBy(e,t){this._orderBy=null==e||null==t?void 0:`\nORDER BY\n c.${e} ${t}`}groupBy(e){this._groupBy=`\nGROUP BY\n ${e}`}select(e){this._select=e}parameter(e,t){this._parameters.push({name:e,value:t})}limit(e){this._limit=e}join(e,t){this._join=`${e} IN c.${t}`}whereFuzzy(e,t){const s=`@p${this._parameters.length}`,r=[];for(const e of t){const t=`Contains(c.${e}, ${s}, true)`;r.push(t)}const i=`(${r.join(" OR ")})`;this._queries.push(i),this._parameters.push({name:s,value:e})}whereRaw(e,t,s){const r=`@p${this._parameters.length}`,n=i[t];this._queries.push(`${e} ${n} ${r}`),this._parameters.push({name:r,value:s})}whereOr(e){const t=[];for(const s of e){const{field:e,operator:r,value:n}=s,o=`@p${this._parameters.length}`;if("isNull"===r)t.push(`(c.${e} ?? null) = null`);else if("contains"===r)t.push(`ARRAY_CONTAINS(c.${e}, ${o})`);else if("in"===r)t.push(`ARRAY_CONTAINS(${o}, c.${e})`);else{const s=i[r];null!=s&&void 0!==n&&(t.push(`c.${e} ${s} ${o}`),this._parameters.push({name:o,value:n}))}}t.length>0&&this._queries.push(`(${t.join(" OR ")})`)}where(e,t,s){const r=`@p${this._parameters.length}`;if("isNull"===t){const t=`(c.${e} ?? null) = null`;this._queries.push(t)}else if("contains"===t){if(void 0!==s){const t=`ARRAY_CONTAINS(c.${e}, ${r})`;this._queries.push(t),this._parameters.push({name:r,value:s})}}else if("in"===t){if(void 0!==s){const t=`ARRAY_CONTAINS(${r}, c.${e})`;this._queries.push(t),this._parameters.push({name:r,value:s})}}else{const n=i[t];null!=n&&void 0!==s&&(this._queries.push(`c.${e} ${n} ${r}`),this._parameters.push({name:r,value:s}))}}filter(e){const t=`@p${this._parameters.length}`;this._queries.push(e.clause.replace("@",t)),null!=e.parameter&&this._parameters.push({name:t,value:e.parameter})}query(){const e=[];if(e.push(`SELECT\n ${this._select}`),e.push(`FROM\n ${this._from}`),""!==this._join&&e.push(`JOIN\n ${this._join}`),this._queries.length>0){e.push("WHERE");const t=this._queries.join("\n AND ");e.push(t)}null!=this._orderBy&&e.push(this._orderBy),null!=this._groupBy&&e.push(this._groupBy),null!=this._limit&&(e.push("OFFSET 0"),e.push(`LIMIT ${this._limit}`));const t={query:e.join("\n"),parameters:this.parameters};return this._logger.verbose("Cosmos Query",t),t}async getOne(e){const t=this.query(),s=e.items.query(t),r=await s.fetchNext();return this._logger.verbose("Cosmos Result",{result:r}),r.resources?.[0]??null}async getAll(e,t,s){const r=this.query(),i=e.items.query(r,{continuationToken:s??void 0,maxItemCount:t??void 0});let n;try{n=await i.fetchAll()}catch(e){throw this._logger.error("Cosmos Query Error",e),e}this._logger.verbose("Cosmos Result",{result:n}),this.select("VALUE COUNT(1)"),this.orderBy();const o=this.query(),u=e.items.query(o);let l;try{l=await u.fetchAll()}catch(e){throw this._logger.error("Cosmos Count Query Error",e),e}const h=l.resources?.[0]??0;return{continuationToken:n.continuationToken,count:n.resources?.length??0,items:n.resources??[],hasMoreResults:n.hasMoreResults,totalCount:h}}patch(...e){return{operations:e.map(e=>{if("remove"===e.op)return{op:e.op,path:e.path};if(void 0!==e.value)return{op:e.op,path:e.path,value:e.value};throw new Error(`Value is required for operation: ${e.op}`)})}}};function u(e){return new o(e)}t(u,"createCosmosQueryBuilder");var l=(e=>(e.Asc="ASC",e.Desc="DESC",e))(l||{});exports.ILogger=s,exports.SortDirection=l,exports.createCosmosQueryBuilder=u;//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/public/interfaces.ts","../../src/private/consts.ts","../../src/private/DefaultLogger.ts","../../src/private/CosmosQueryBuilder.ts","../../src/public/createCosmosQueryBuilder.ts","../../src/public/enums.ts"],"names":["SortDirection"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { JSONValue, PatchRequestBody, SqlQuerySpec } from '@azure/cosmos';\nimport type { ExtractPatchPathExpressions, ExtractPathExpressions, PatchPathValue, PathValue } from '../private/types';\nimport type { SortDirection } from './enums';\nimport type { BasicOpCode, Container, ExtendedOpCode, FetchResult, InstantFilter, StringFilter, UUIDFilter } from './types';\n\nexport abstract class ILogger {\n public abstract debug(message?: any, ...optionalParams: any[]): void;\n public abstract info(message?: any, ...optionalParams: any[]): void;\n public abstract error(message?: any, ...optionalParams: any[]): void;\n public abstract warn(message?: any, ...optionalParams: any[]): void;\n public abstract verbose(message?: any, ...optionalParams: any[]): void;\n}\n\nexport abstract class ICosmosQueryBuilder<T extends Record<string, any>> {\n /**\n * Sets the maximum number of items to return\n * @param limit Maximum number of items\n * @example\n * ```typescript\n * builder.limit(100);\n * ```\n */\n public abstract limit(limit: number): void;\n\n /**\n * Adds a JOIN clause to the query\n * @param value JOIN alias\n * @param statement Field path to join on\n * @example\n * ```typescript\n * builder.join('b', 'bones');\n * ```\n */\n public abstract join<P extends ExtractPathExpressions<T>>(value: string, statement: P): void;\n\n /**\n * Sets the SELECT clause for the query\n * @param value SELECT clause string\n * @example\n * ```typescript\n * builder.select('COUNT(1) as count, UPPER(c.name.givenName) as name');\n * ```\n */\n public abstract select(value: string): void;\n\n /**\n * Sets the GROUP BY clause for the query\n * @param value GROUP BY expression\n * @example\n * ```typescript\n * builder.groupBy('UPPER(c.sex)');\n * ```\n */\n public abstract groupBy(value: string): void;\n\n /**\n * Performs fuzzy search across multiple fields\n * @param value Search term\n * @param fields Array of field paths to search in\n * @example\n * ```typescript\n * builder.whereFuzzy('steve', ['name.givenName', 'name.familyName', 'email']);\n * ```\n */\n public abstract whereFuzzy<P extends ExtractPathExpressions<T>>(value: string, fields: [P, ...P[]]): void;\n\n /**\n * Adds a raw WHERE clause with field, operator, and value\n * @param field Field name as string\n * @param operator SQL operator (excluding isNull, contains, in)\n * @param value Value to compare against\n * @example\n * ```typescript\n * builder.whereRaw('p.id', 'eq', 'some-id');\n * ```\n */\n public abstract whereRaw(field: string, operator: Exclude<ExtendedOpCode, 'isNull' | 'contains' | 'in'>, value: JSONValue): void;\n\n /**\n * Adds an OR clause to match items satisfying any of the given conditions\n * @param conditions Array of field/operator/value conditions\n * @example\n * ```typescript\n * builder.whereOr([\n * { field: 'name.givenName', operator: 'eq', value: 'John' },\n * { field: 'name.familyName', operator: 'eq', value: 'Smith' }\n * ]);\n * ```\n */\n public abstract whereOr(conditions: Array<{ field: string; operator: ExtendedOpCode; value: JSONValue }>): void;\n\n /**\n * Creates a JSON patch document for Cosmos DB patch operations\n * @param operations Array of patch operations (set, add, replace, remove)\n * @returns Patch request body for Cosmos DB\n * @example\n * ```typescript\n * const operations = builder.patch({\n * op: 'replace',\n * path: '/name/givenName',\n * value: 'Smith',\n * });\n * const item = container.item('id', 'partitionKey');\n * await item.patch<Person>(operations);\n * ```\n */\n public abstract patch<P extends ExtractPatchPathExpressions<T>>(...operations: Array<{ path: P; op: 'set' | 'add' | 'replace'; value: PatchPathValue<T, P> } | { path: P; op: 'remove' }>): PatchRequestBody;\n\n /**\n * Builds query conditions from a structured object with type filters\n * Supports {@link StringFilter}, {@link UUIDFilter}, and {@link InstantFilter} types\n * @param query Query object with nested field filters containing __typeInfo\n * @param prefix Path prefix for nested queries (defaults to 'c')\n * @example\n * ```typescript\n * type PersonFilter = {\n * name?: {\n * givenName?: StringFilter;\n * };\n * };\n * const filter = {\n * name: {\n * givenName: { __typeInfo: 'StringFilter', eq: 'John' }\n * },\n * } satisfies PersonFilter;\n * builder.buildQuery(filter);\n * ```\n */\n public abstract buildQuery(query: Record<string, any> | undefined | null, prefix?: string): void;\n\n /**\n * Adds a WHERE clause with type-safe field access and operators\n * @param field Type-safe field path\n * @param operator SQL operator\n * @example\n * ```typescript\n * builder.where('name.givenName', 'eq', 'John');\n * builder.where('age', 'gt', 18);\n * builder.where('bones', 'contains', 'arm');\n * builder.where('name.givenName', 'in', ['John', 'Jane']);\n * builder.where('deletedAt', 'isNull');\n * ```\n */\n public abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'isNull'): void;\n public abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'in', value: readonly PathValue<T, P>[]): void;\n public abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'contains', value: PathValue<T, P>[number]): void;\n public abstract where<P extends ExtractPathExpressions<T>, V extends PathValue<T, P>>(field: P, operator: BasicOpCode, value: V): void;\n\n /**\n * Clears any existing ordering\n */\n public abstract orderBy(): void;\n\n /**\n * Sets ordering by field and direction\n * @param field Field path to order by\n * @param direction Sort direction (ASC/DESC)\n */\n public abstract orderBy<P extends ExtractPathExpressions<T>>(field: P, direction: SortDirection): void;\n\n /**\n * Builds and returns the final SQL query specification\n * @returns SQL query specification with parameters\n */\n public abstract query(): SqlQuerySpec;\n\n /**\n * Executes the query and returns the first result\n * @param container Cosmos DB container to query\n * @returns First matching item or null\n */\n public abstract getOne<TSelect = T>(container: Container): Promise<TSelect | null>;\n\n /**\n * Executes the query and returns paginated results with total count\n * @param container Cosmos DB container to query\n * @param limit Maximum number of items per page\n * @param cursor Continuation token for pagination\n * @returns Paginated results with metadata\n */\n public abstract getAll<TSelect = T>(container: Container, limit?: number | null | undefined, cursor?: string | null | undefined): Promise<FetchResult<TSelect>>;\n}\n","export const operators: Record<string, string | undefined> = {\n eq: '=',\n ne: '!=',\n ge: '>=',\n gt: '>',\n le: '<=',\n lt: '<',\n} as const;\n","import { ILogger } from '../public/interfaces';\n\nexport class DefaultLogger extends ILogger {\n public debug(_message?: any, ..._optionalParams: any[]): void {}\n public info(_message?: any, ..._optionalParams: any[]): void {}\n public error(_message?: any, ..._optionalParams: any[]): void {}\n public warn(_message?: any, ..._optionalParams: any[]): void {}\n public verbose(_message?: any, ..._optionalParams: any[]): void {}\n}\n","import type { JSONValue, PatchRequestBody, SqlParameter, SqlQuerySpec } from '@azure/cosmos';\nimport type { SortDirection } from '../public/enums';\nimport { ICosmosQueryBuilder, type ILogger } from '../public/interfaces';\nimport type { BasicOpCode, Container, CosmosQueryBuilderOptions, ExtendedOpCode, FeedResponse, FetchResult, InstantFilter, StringFilter, UUIDFilter } from '../public/types';\nimport { operators } from './consts';\nimport { DefaultLogger } from './DefaultLogger';\nimport type { ExtractPatchPathExpressions, ExtractPathExpressions, PatchPathValue, PathValue, StringFilterData } from './types';\n\nexport class CosmosQueryBuilder<T extends Record<string, any>> extends ICosmosQueryBuilder<T> {\n private _orderBy?: string;\n private _select = '*';\n private _groupBy: string | null = null;\n private _join = '';\n private _from = 'c';\n private _queries: string[] = [];\n private _parameters: SqlParameter[] = [];\n private _limit: number | undefined;\n private _logger: ILogger;\n\n public constructor(options?: CosmosQueryBuilderOptions) {\n super();\n this._logger = options?.logger ?? new DefaultLogger();\n }\n\n public get queries(): string[] {\n return this._queries;\n }\n\n public set queries(value: string[]) {\n this._queries = value;\n }\n\n public get parameters(): SqlParameter[] {\n return this._parameters;\n }\n\n public set parameters(value: SqlParameter[]) {\n this._parameters = value;\n }\n\n private handleStringFilter(prefix: string, value: StringFilter) {\n return this.handleFilterObject(prefix, value);\n }\n\n private handleUuidFilter(prefix: string, value: UUIDFilter) {\n return this.handleFilterObject(prefix, value);\n }\n\n private handleInstantFilter(prefix: string, value: InstantFilter) {\n return this.handleFilterObject(prefix, value);\n }\n\n private handleFilterObject(prefix: string, value: StringFilterData & { __typeInfo: string }) {\n const { __typeInfo, ...rest } = value;\n for (const [key, value2] of Object.entries(rest).filter((x) => x[1] !== undefined)) {\n const path = prefix;\n const parameterName = `@p${this._parameters.length}`;\n const operator = operators[key];\n\n // Default to null to allow null comparison when parent object is not defined\n const queryKey = `(${path} ?? null)`;\n if (operator != null) {\n this._queries.push(`${queryKey} ${operator} ${parameterName}`);\n } else {\n if (key === 'ieq') {\n this._queries.push(`StringEquals(${queryKey}, ${parameterName}, true)`);\n } else if (key === 'ine') {\n this._queries.push(`Not(StringEquals(${queryKey}, ${parameterName}, true))`);\n } else if (key === 'like') {\n this._queries.push(`Contains(${queryKey}, ${parameterName}, true)`);\n } else if (key === 'in') {\n this._queries.push(`ARRAY_CONTAINS(${parameterName}, ${queryKey})`);\n } else {\n throw new Error(`Unknown operator ${key}`);\n }\n }\n this._parameters.push({ name: parameterName, value: value2 });\n }\n }\n\n private _buildQuery(query: Record<string, any> | null | undefined, prefix = 'c'): void {\n if (query != null) {\n const { __typeInfo, ...rest } = query;\n const queryKeys = Object.keys(rest);\n\n for (const key of queryKeys) {\n const value = query[key];\n const type: string | null = value.__typeInfo ?? null;\n const subPath = `${prefix}.${key}`;\n\n if (typeof value === 'object' && value != null) {\n if (type === 'StringFilter') {\n this.handleStringFilter(subPath, value);\n } else if (type === 'InstantFilter') {\n this.handleInstantFilter(subPath, value);\n } else if (type === 'UUIDFilter') {\n this.handleUuidFilter(subPath, value);\n } else {\n this._buildQuery(value, subPath);\n }\n } else {\n throw new Error(`Unhandled type ${type}`);\n }\n }\n }\n }\n\n public override buildQuery(query: Record<string, any> | undefined | null, prefix = 'c'): void {\n this._buildQuery(query, prefix);\n }\n\n public override orderBy(): void;\n public override orderBy<P extends ExtractPathExpressions<T>>(field: P, direction: SortDirection): void;\n public override orderBy<P extends ExtractPathExpressions<T>>(field?: P, direction?: SortDirection) {\n if (field == null || direction == null) {\n this._orderBy = undefined;\n } else {\n this._orderBy = `\\nORDER BY\\n c.${field} ${direction}`;\n }\n }\n\n public override groupBy(value: string): void {\n this._groupBy = `\\nGROUP BY\\n ${value}`;\n }\n\n public override select(value: string): void {\n this._select = value;\n }\n\n private parameter(name: string, value: JSONValue): void {\n this._parameters.push({\n name,\n value,\n });\n }\n\n public override limit(limit: number): void {\n this._limit = limit;\n }\n\n public override join<P extends ExtractPathExpressions<T>>(value: string, statement: P): void {\n this._join = `${value} IN c.${statement}`;\n }\n\n public override whereFuzzy<P extends ExtractPathExpressions<T>>(value: string, fields: [P, ...P[]]): void {\n const parameterName = `@p${this._parameters.length}`;\n const lines: string[] = [];\n for (const field of fields) {\n const clause = `Contains(c.${field}, ${parameterName}, true)`;\n lines.push(clause);\n }\n const queryLine = `(${lines.join(' OR ')})`;\n this._queries.push(queryLine);\n this._parameters.push({ name: parameterName, value });\n }\n\n public override whereRaw(field: string, operator: Exclude<ExtendedOpCode, 'isNull' | 'contains' | 'in'>, value: JSONValue): void {\n const parameterName = `@p${this._parameters.length}`;\n const sqlOperator = operators[operator];\n this._queries.push(`${field} ${sqlOperator} ${parameterName}`);\n this._parameters.push({ name: parameterName, value });\n }\n\n public override whereOr(conditions: Array<{ field: string; operator: ExtendedOpCode; value: JSONValue }>): void {\n const orClauses: string[] = [];\n for (const condition of conditions) {\n const { field, operator, value } = condition;\n const parameterName = `@p${this._parameters.length}`;\n\n if (operator === 'isNull') {\n orClauses.push(`(c.${field} ?? null) = null`);\n } else if (operator === 'contains') {\n orClauses.push(`ARRAY_CONTAINS(c.${field}, ${parameterName})`);\n } else if (operator === 'in') {\n orClauses.push(`ARRAY_CONTAINS(${parameterName}, c.${field})`);\n } else {\n const sqlOperator = operators[operator];\n if (sqlOperator != null && value !== undefined) {\n orClauses.push(`c.${field} ${sqlOperator} ${parameterName}`);\n this._parameters.push({ name: parameterName, value });\n }\n }\n }\n\n if (orClauses.length > 0) {\n this._queries.push(`(${orClauses.join(' OR ')})`);\n }\n }\n\n public override where<P extends ExtractPathExpressions<T>>(field: P, operator: 'isNull'): void;\n public override where<P extends ExtractPathExpressions<T>>(field: P, operator: 'in', value: readonly PathValue<T, P>[]): void;\n public override where<P extends ExtractPathExpressions<T>>(field: P, operator: 'contains', value: PathValue<T, P>[number]): void;\n public override where<P extends ExtractPathExpressions<T>, V extends PathValue<T, P>>(field: P, operator: BasicOpCode, value: V): void;\n public override where<P extends ExtractPathExpressions<T>, V extends PathValue<T, P>>(field: P, operator: ExtendedOpCode, value?: V | readonly V[]): void {\n const parameterName = `@p${this._parameters.length}`;\n\n if (operator === 'isNull') {\n const clause = `(c.${field} ?? null) = null`;\n this._queries.push(clause);\n } else if (operator === 'contains') {\n if (value !== undefined) {\n const clause = `ARRAY_CONTAINS(c.${field}, ${parameterName})`;\n this._queries.push(clause);\n this._parameters.push({ name: parameterName, value });\n }\n } else if (operator === 'in') {\n // Handle 'IN' operator\n if (value !== undefined) {\n const clause = `ARRAY_CONTAINS(${parameterName}, c.${field})`;\n this._queries.push(clause);\n this._parameters.push({ name: parameterName, value });\n }\n } else {\n const sqlOperator = operators[operator];\n if (sqlOperator != null && value !== undefined) {\n this._queries.push(`c.${field} ${sqlOperator} ${parameterName}`);\n this._parameters.push({ name: parameterName, value });\n }\n }\n }\n\n public filter(x: { clause: string; parameter?: JSONValue }): void {\n const paramName = `@p${this._parameters.length}`;\n this._queries.push(x.clause.replace('@', paramName));\n if (x.parameter != null) {\n this._parameters.push({\n name: paramName,\n value: x.parameter,\n });\n }\n }\n\n public override query(): SqlQuerySpec {\n const lines: string[] = [];\n lines.push(`SELECT\\n ${this._select}`);\n lines.push(`FROM\\n ${this._from}`);\n if (this._join !== '') {\n lines.push(`JOIN\\n ${this._join}`);\n }\n\n if (this._queries.length > 0) {\n lines.push('WHERE');\n const where = this._queries.join('\\n AND ');\n lines.push(where);\n }\n\n if (this._orderBy != null) {\n lines.push(this._orderBy);\n }\n if (this._groupBy != null) {\n lines.push(this._groupBy);\n }\n if (this._limit != null) {\n lines.push('OFFSET 0');\n lines.push(`LIMIT ${this._limit}`);\n }\n\n const queryText = lines.join('\\n');\n const result = {\n query: queryText,\n parameters: this.parameters,\n };\n this._logger.verbose('Cosmos Query', result);\n return result;\n }\n\n public override async getOne<TSelect = T>(container: Container): Promise<TSelect | null> {\n const itemsQuery = this.query();\n const itemsIterator = container.items.query<TSelect>(itemsQuery);\n const items = await itemsIterator.fetchNext();\n this._logger.verbose('Cosmos Result', { result: items });\n return items.resources?.[0] ?? null;\n }\n\n public override async getAll<TSelect>(container: Container, limit?: number | null | undefined, cursor?: string | null | undefined): Promise<FetchResult<TSelect>> {\n const itemsQuery = this.query();\n const itemsIterator = container.items.query<TSelect>(itemsQuery, {\n continuationToken: cursor ?? undefined,\n maxItemCount: limit ?? undefined,\n });\n let items: FeedResponse<TSelect>;\n try {\n items = await itemsIterator.fetchAll();\n } catch (err) {\n this._logger.error('Cosmos Query Error', err);\n throw err;\n }\n this._logger.verbose('Cosmos Result', { result: items });\n\n this.select('VALUE COUNT(1)');\n this.orderBy();\n\n const countQuery = this.query();\n const countIterator = container.items.query<number>(countQuery);\n\n let count: FeedResponse<number>;\n try {\n count = await countIterator.fetchAll();\n } catch (err) {\n this._logger.error('Cosmos Count Query Error', err);\n throw err;\n }\n\n const totalCount = count.resources?.[0] ?? 0;\n\n const result: FetchResult<TSelect> = {\n continuationToken: items.continuationToken,\n count: items.resources?.length ?? 0,\n items: items.resources ?? [],\n hasMoreResults: items.hasMoreResults,\n totalCount,\n };\n return result;\n }\n\n public override patch<P extends ExtractPatchPathExpressions<T>>(...operations: Array<{ path: P; op: 'set' | 'add' | 'replace'; value: PatchPathValue<T, P> } | { path: P; op: 'remove' }>): PatchRequestBody {\n const patchOperations = operations.map((opDef) => {\n if (opDef.op === 'remove') {\n return { op: opDef.op, path: opDef.path };\n }\n\n if (opDef.value !== undefined) {\n return { op: opDef.op, path: opDef.path, value: opDef.value };\n }\n\n throw new Error(`Value is required for operation: ${opDef.op}`);\n });\n\n return { operations: patchOperations };\n }\n}\n","import { CosmosQueryBuilder } from '../private/CosmosQueryBuilder';\nimport type { ICosmosQueryBuilder } from './interfaces';\nimport type { CosmosQueryBuilderOptions } from './types';\n\nexport function createCosmosQueryBuilder<T extends Record<string, any>>(options?: CosmosQueryBuilderOptions): ICosmosQueryBuilder<T> {\n return new CosmosQueryBuilder<T>(options);\n}\n","export enum SortDirection {\n Asc = 'ASC',\n Desc = 'DESC',\n}\n"]}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { SqlQuerySpec, JSONValue, PatchRequestBody } from '@azure/cosmos';
|
|
2
|
+
|
|
3
|
+
type ArrayElement<T> = T extends (infer U)[] ? U : never;
|
|
4
|
+
type PathBuilder<T, Sep extends string, K extends keyof T = keyof T> = K extends string ? T[K] extends Record<string, any> | null ? T[K] extends ArrayLike<any> ? K | `${K}[${number}]` | `${K}[${number}]${Sep}${PathBuilder<NonNullable<ArrayElement<T[K]>>, Sep>}` : K | `${K}${Sep}${PathBuilder<NonNullable<T[K]>, Sep>}` : K : never;
|
|
5
|
+
type DotPath<T> = PathBuilder<T, '.'>;
|
|
6
|
+
type SlashPathCore<T> = PathBuilder<T, '/'>;
|
|
7
|
+
type ExtractPathExpressions<T> = DotPath<T>;
|
|
8
|
+
type ExtractPatchPathExpressions<T> = `/${SlashPathCore<T>}` | `/${SlashPathCore<T>}/-`;
|
|
9
|
+
type PathValueResolver<T, P extends string, Sep extends string> = P extends `${infer K}${Sep}${infer Rest}` ? K extends keyof T ? PathValueResolver<NonNullable<T[K]>, Rest, Sep> : never : P extends `${infer K}[${infer _Index}]${infer Rest}` ? K extends keyof T ? T[K] extends (infer R)[] | null ? Rest extends '' ? NonNullable<R> : Rest extends `${Sep}${infer More}` ? PathValueResolver<NonNullable<R>, More, Sep> : never : never : never : P extends keyof T ? T[P] : T extends Record<string, any> ? T[keyof T] : never;
|
|
10
|
+
type PathValue<T, P extends string> = PathValueResolver<T, P, '.'>;
|
|
11
|
+
type PatchPathValue<T, P extends string> = P extends `/${infer Rest}` ? PathValueResolver<T, Rest, '/'> : never;
|
|
12
|
+
|
|
13
|
+
declare enum SortDirection {
|
|
14
|
+
Asc = "ASC",
|
|
15
|
+
Desc = "DESC"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type UUIDFilter = {
|
|
19
|
+
__typeInfo: 'UUIDFilter';
|
|
20
|
+
eq?: string;
|
|
21
|
+
ne?: string;
|
|
22
|
+
};
|
|
23
|
+
type InstantFilter = {
|
|
24
|
+
__typeInfo: 'InstantFilter';
|
|
25
|
+
eq?: string;
|
|
26
|
+
ieq?: string;
|
|
27
|
+
in?: string;
|
|
28
|
+
ine?: string;
|
|
29
|
+
like?: string;
|
|
30
|
+
ne?: string;
|
|
31
|
+
};
|
|
32
|
+
type StringFilter = {
|
|
33
|
+
__typeInfo: 'StringFilter';
|
|
34
|
+
eq?: string;
|
|
35
|
+
ieq?: string;
|
|
36
|
+
in?: string;
|
|
37
|
+
ine?: string;
|
|
38
|
+
like?: string;
|
|
39
|
+
ne?: string;
|
|
40
|
+
};
|
|
41
|
+
type ExtendedOpCode = BasicOpCode | 'contains' | 'in' | 'isNull';
|
|
42
|
+
type BasicOpCode = 'eq' | 'gt' | 'lt' | 'ge' | 'le' | 'ne';
|
|
43
|
+
type FetchResult<T> = {
|
|
44
|
+
items: T[];
|
|
45
|
+
continuationToken: string;
|
|
46
|
+
hasMoreResults: boolean;
|
|
47
|
+
totalCount: number;
|
|
48
|
+
count: number;
|
|
49
|
+
};
|
|
50
|
+
type CosmosQueryBuilderOptions = {
|
|
51
|
+
/**
|
|
52
|
+
* Custom implementation for logger.
|
|
53
|
+
* @defaultValue undefined (no logging)
|
|
54
|
+
*/
|
|
55
|
+
logger?: ILogger;
|
|
56
|
+
};
|
|
57
|
+
type FeedOptions = {
|
|
58
|
+
continuationToken?: string | null;
|
|
59
|
+
maxItemCount?: number | null;
|
|
60
|
+
};
|
|
61
|
+
interface FeedResponse<TResource> {
|
|
62
|
+
readonly resources?: TResource[];
|
|
63
|
+
readonly hasMoreResults: boolean;
|
|
64
|
+
get continuationToken(): string;
|
|
65
|
+
}
|
|
66
|
+
interface QueryIterator<TResource> {
|
|
67
|
+
fetchNext(): Promise<FeedResponse<TResource>>;
|
|
68
|
+
fetchAll(): Promise<FeedResponse<TResource>>;
|
|
69
|
+
}
|
|
70
|
+
interface Container {
|
|
71
|
+
items: {
|
|
72
|
+
query<TResource>(querySpec: SqlQuerySpec, options?: FeedOptions): QueryIterator<TResource>;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
declare abstract class ILogger {
|
|
77
|
+
abstract debug(message?: any, ...optionalParams: any[]): void;
|
|
78
|
+
abstract info(message?: any, ...optionalParams: any[]): void;
|
|
79
|
+
abstract error(message?: any, ...optionalParams: any[]): void;
|
|
80
|
+
abstract warn(message?: any, ...optionalParams: any[]): void;
|
|
81
|
+
abstract verbose(message?: any, ...optionalParams: any[]): void;
|
|
82
|
+
}
|
|
83
|
+
declare abstract class ICosmosQueryBuilder<T extends Record<string, any>> {
|
|
84
|
+
/**
|
|
85
|
+
* Sets the maximum number of items to return
|
|
86
|
+
* @param limit Maximum number of items
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* builder.limit(100);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
abstract limit(limit: number): void;
|
|
93
|
+
/**
|
|
94
|
+
* Adds a JOIN clause to the query
|
|
95
|
+
* @param value JOIN alias
|
|
96
|
+
* @param statement Field path to join on
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* builder.join('b', 'bones');
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
abstract join<P extends ExtractPathExpressions<T>>(value: string, statement: P): void;
|
|
103
|
+
/**
|
|
104
|
+
* Sets the SELECT clause for the query
|
|
105
|
+
* @param value SELECT clause string
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* builder.select('COUNT(1) as count, UPPER(c.name.givenName) as name');
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
abstract select(value: string): void;
|
|
112
|
+
/**
|
|
113
|
+
* Sets the GROUP BY clause for the query
|
|
114
|
+
* @param value GROUP BY expression
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* builder.groupBy('UPPER(c.sex)');
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
abstract groupBy(value: string): void;
|
|
121
|
+
/**
|
|
122
|
+
* Performs fuzzy search across multiple fields
|
|
123
|
+
* @param value Search term
|
|
124
|
+
* @param fields Array of field paths to search in
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* builder.whereFuzzy('steve', ['name.givenName', 'name.familyName', 'email']);
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
abstract whereFuzzy<P extends ExtractPathExpressions<T>>(value: string, fields: [P, ...P[]]): void;
|
|
131
|
+
/**
|
|
132
|
+
* Adds a raw WHERE clause with field, operator, and value
|
|
133
|
+
* @param field Field name as string
|
|
134
|
+
* @param operator SQL operator (excluding isNull, contains, in)
|
|
135
|
+
* @param value Value to compare against
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* builder.whereRaw('p.id', 'eq', 'some-id');
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
abstract whereRaw(field: string, operator: Exclude<ExtendedOpCode, 'isNull' | 'contains' | 'in'>, value: JSONValue): void;
|
|
142
|
+
/**
|
|
143
|
+
* Adds an OR clause to match items satisfying any of the given conditions
|
|
144
|
+
* @param conditions Array of field/operator/value conditions
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* builder.whereOr([
|
|
148
|
+
* { field: 'name.givenName', operator: 'eq', value: 'John' },
|
|
149
|
+
* { field: 'name.familyName', operator: 'eq', value: 'Smith' }
|
|
150
|
+
* ]);
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
abstract whereOr(conditions: Array<{
|
|
154
|
+
field: string;
|
|
155
|
+
operator: ExtendedOpCode;
|
|
156
|
+
value: JSONValue;
|
|
157
|
+
}>): void;
|
|
158
|
+
/**
|
|
159
|
+
* Creates a JSON patch document for Cosmos DB patch operations
|
|
160
|
+
* @param operations Array of patch operations (set, add, replace, remove)
|
|
161
|
+
* @returns Patch request body for Cosmos DB
|
|
162
|
+
* @example
|
|
163
|
+
* ```typescript
|
|
164
|
+
* const operations = builder.patch({
|
|
165
|
+
* op: 'replace',
|
|
166
|
+
* path: '/name/givenName',
|
|
167
|
+
* value: 'Smith',
|
|
168
|
+
* });
|
|
169
|
+
* const item = container.item('id', 'partitionKey');
|
|
170
|
+
* await item.patch<Person>(operations);
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
abstract patch<P extends ExtractPatchPathExpressions<T>>(...operations: Array<{
|
|
174
|
+
path: P;
|
|
175
|
+
op: 'set' | 'add' | 'replace';
|
|
176
|
+
value: PatchPathValue<T, P>;
|
|
177
|
+
} | {
|
|
178
|
+
path: P;
|
|
179
|
+
op: 'remove';
|
|
180
|
+
}>): PatchRequestBody;
|
|
181
|
+
/**
|
|
182
|
+
* Builds query conditions from a structured object with type filters
|
|
183
|
+
* Supports {@link StringFilter}, {@link UUIDFilter}, and {@link InstantFilter} types
|
|
184
|
+
* @param query Query object with nested field filters containing __typeInfo
|
|
185
|
+
* @param prefix Path prefix for nested queries (defaults to 'c')
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* type PersonFilter = {
|
|
189
|
+
* name?: {
|
|
190
|
+
* givenName?: StringFilter;
|
|
191
|
+
* };
|
|
192
|
+
* };
|
|
193
|
+
* const filter = {
|
|
194
|
+
* name: {
|
|
195
|
+
* givenName: { __typeInfo: 'StringFilter', eq: 'John' }
|
|
196
|
+
* },
|
|
197
|
+
* } satisfies PersonFilter;
|
|
198
|
+
* builder.buildQuery(filter);
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
abstract buildQuery(query: Record<string, any> | undefined | null, prefix?: string): void;
|
|
202
|
+
/**
|
|
203
|
+
* Adds a WHERE clause with type-safe field access and operators
|
|
204
|
+
* @param field Type-safe field path
|
|
205
|
+
* @param operator SQL operator
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* builder.where('name.givenName', 'eq', 'John');
|
|
209
|
+
* builder.where('age', 'gt', 18);
|
|
210
|
+
* builder.where('bones', 'contains', 'arm');
|
|
211
|
+
* builder.where('name.givenName', 'in', ['John', 'Jane']);
|
|
212
|
+
* builder.where('deletedAt', 'isNull');
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'isNull'): void;
|
|
216
|
+
abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'in', value: readonly PathValue<T, P>[]): void;
|
|
217
|
+
abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'contains', value: PathValue<T, P>[number]): void;
|
|
218
|
+
abstract where<P extends ExtractPathExpressions<T>, V extends PathValue<T, P>>(field: P, operator: BasicOpCode, value: V): void;
|
|
219
|
+
/**
|
|
220
|
+
* Clears any existing ordering
|
|
221
|
+
*/
|
|
222
|
+
abstract orderBy(): void;
|
|
223
|
+
/**
|
|
224
|
+
* Sets ordering by field and direction
|
|
225
|
+
* @param field Field path to order by
|
|
226
|
+
* @param direction Sort direction (ASC/DESC)
|
|
227
|
+
*/
|
|
228
|
+
abstract orderBy<P extends ExtractPathExpressions<T>>(field: P, direction: SortDirection): void;
|
|
229
|
+
/**
|
|
230
|
+
* Builds and returns the final SQL query specification
|
|
231
|
+
* @returns SQL query specification with parameters
|
|
232
|
+
*/
|
|
233
|
+
abstract query(): SqlQuerySpec;
|
|
234
|
+
/**
|
|
235
|
+
* Executes the query and returns the first result
|
|
236
|
+
* @param container Cosmos DB container to query
|
|
237
|
+
* @returns First matching item or null
|
|
238
|
+
*/
|
|
239
|
+
abstract getOne<TSelect = T>(container: Container): Promise<TSelect | null>;
|
|
240
|
+
/**
|
|
241
|
+
* Executes the query and returns paginated results with total count
|
|
242
|
+
* @param container Cosmos DB container to query
|
|
243
|
+
* @param limit Maximum number of items per page
|
|
244
|
+
* @param cursor Continuation token for pagination
|
|
245
|
+
* @returns Paginated results with metadata
|
|
246
|
+
*/
|
|
247
|
+
abstract getAll<TSelect = T>(container: Container, limit?: number | null | undefined, cursor?: string | null | undefined): Promise<FetchResult<TSelect>>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
declare function createCosmosQueryBuilder<T extends Record<string, any>>(options?: CosmosQueryBuilderOptions): ICosmosQueryBuilder<T>;
|
|
251
|
+
|
|
252
|
+
export { type BasicOpCode, type CosmosQueryBuilderOptions, type FetchResult, ICosmosQueryBuilder, ILogger, type InstantFilter, type ExtendedOpCode as OpCode, SortDirection, type StringFilter, type UUIDFilter, createCosmosQueryBuilder };
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { SqlQuerySpec, JSONValue, PatchRequestBody } from '@azure/cosmos';
|
|
2
|
+
|
|
3
|
+
type ArrayElement<T> = T extends (infer U)[] ? U : never;
|
|
4
|
+
type PathBuilder<T, Sep extends string, K extends keyof T = keyof T> = K extends string ? T[K] extends Record<string, any> | null ? T[K] extends ArrayLike<any> ? K | `${K}[${number}]` | `${K}[${number}]${Sep}${PathBuilder<NonNullable<ArrayElement<T[K]>>, Sep>}` : K | `${K}${Sep}${PathBuilder<NonNullable<T[K]>, Sep>}` : K : never;
|
|
5
|
+
type DotPath<T> = PathBuilder<T, '.'>;
|
|
6
|
+
type SlashPathCore<T> = PathBuilder<T, '/'>;
|
|
7
|
+
type ExtractPathExpressions<T> = DotPath<T>;
|
|
8
|
+
type ExtractPatchPathExpressions<T> = `/${SlashPathCore<T>}` | `/${SlashPathCore<T>}/-`;
|
|
9
|
+
type PathValueResolver<T, P extends string, Sep extends string> = P extends `${infer K}${Sep}${infer Rest}` ? K extends keyof T ? PathValueResolver<NonNullable<T[K]>, Rest, Sep> : never : P extends `${infer K}[${infer _Index}]${infer Rest}` ? K extends keyof T ? T[K] extends (infer R)[] | null ? Rest extends '' ? NonNullable<R> : Rest extends `${Sep}${infer More}` ? PathValueResolver<NonNullable<R>, More, Sep> : never : never : never : P extends keyof T ? T[P] : T extends Record<string, any> ? T[keyof T] : never;
|
|
10
|
+
type PathValue<T, P extends string> = PathValueResolver<T, P, '.'>;
|
|
11
|
+
type PatchPathValue<T, P extends string> = P extends `/${infer Rest}` ? PathValueResolver<T, Rest, '/'> : never;
|
|
12
|
+
|
|
13
|
+
declare enum SortDirection {
|
|
14
|
+
Asc = "ASC",
|
|
15
|
+
Desc = "DESC"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type UUIDFilter = {
|
|
19
|
+
__typeInfo: 'UUIDFilter';
|
|
20
|
+
eq?: string;
|
|
21
|
+
ne?: string;
|
|
22
|
+
};
|
|
23
|
+
type InstantFilter = {
|
|
24
|
+
__typeInfo: 'InstantFilter';
|
|
25
|
+
eq?: string;
|
|
26
|
+
ieq?: string;
|
|
27
|
+
in?: string;
|
|
28
|
+
ine?: string;
|
|
29
|
+
like?: string;
|
|
30
|
+
ne?: string;
|
|
31
|
+
};
|
|
32
|
+
type StringFilter = {
|
|
33
|
+
__typeInfo: 'StringFilter';
|
|
34
|
+
eq?: string;
|
|
35
|
+
ieq?: string;
|
|
36
|
+
in?: string;
|
|
37
|
+
ine?: string;
|
|
38
|
+
like?: string;
|
|
39
|
+
ne?: string;
|
|
40
|
+
};
|
|
41
|
+
type ExtendedOpCode = BasicOpCode | 'contains' | 'in' | 'isNull';
|
|
42
|
+
type BasicOpCode = 'eq' | 'gt' | 'lt' | 'ge' | 'le' | 'ne';
|
|
43
|
+
type FetchResult<T> = {
|
|
44
|
+
items: T[];
|
|
45
|
+
continuationToken: string;
|
|
46
|
+
hasMoreResults: boolean;
|
|
47
|
+
totalCount: number;
|
|
48
|
+
count: number;
|
|
49
|
+
};
|
|
50
|
+
type CosmosQueryBuilderOptions = {
|
|
51
|
+
/**
|
|
52
|
+
* Custom implementation for logger.
|
|
53
|
+
* @defaultValue undefined (no logging)
|
|
54
|
+
*/
|
|
55
|
+
logger?: ILogger;
|
|
56
|
+
};
|
|
57
|
+
type FeedOptions = {
|
|
58
|
+
continuationToken?: string | null;
|
|
59
|
+
maxItemCount?: number | null;
|
|
60
|
+
};
|
|
61
|
+
interface FeedResponse<TResource> {
|
|
62
|
+
readonly resources?: TResource[];
|
|
63
|
+
readonly hasMoreResults: boolean;
|
|
64
|
+
get continuationToken(): string;
|
|
65
|
+
}
|
|
66
|
+
interface QueryIterator<TResource> {
|
|
67
|
+
fetchNext(): Promise<FeedResponse<TResource>>;
|
|
68
|
+
fetchAll(): Promise<FeedResponse<TResource>>;
|
|
69
|
+
}
|
|
70
|
+
interface Container {
|
|
71
|
+
items: {
|
|
72
|
+
query<TResource>(querySpec: SqlQuerySpec, options?: FeedOptions): QueryIterator<TResource>;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
declare abstract class ILogger {
|
|
77
|
+
abstract debug(message?: any, ...optionalParams: any[]): void;
|
|
78
|
+
abstract info(message?: any, ...optionalParams: any[]): void;
|
|
79
|
+
abstract error(message?: any, ...optionalParams: any[]): void;
|
|
80
|
+
abstract warn(message?: any, ...optionalParams: any[]): void;
|
|
81
|
+
abstract verbose(message?: any, ...optionalParams: any[]): void;
|
|
82
|
+
}
|
|
83
|
+
declare abstract class ICosmosQueryBuilder<T extends Record<string, any>> {
|
|
84
|
+
/**
|
|
85
|
+
* Sets the maximum number of items to return
|
|
86
|
+
* @param limit Maximum number of items
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* builder.limit(100);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
abstract limit(limit: number): void;
|
|
93
|
+
/**
|
|
94
|
+
* Adds a JOIN clause to the query
|
|
95
|
+
* @param value JOIN alias
|
|
96
|
+
* @param statement Field path to join on
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* builder.join('b', 'bones');
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
abstract join<P extends ExtractPathExpressions<T>>(value: string, statement: P): void;
|
|
103
|
+
/**
|
|
104
|
+
* Sets the SELECT clause for the query
|
|
105
|
+
* @param value SELECT clause string
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* builder.select('COUNT(1) as count, UPPER(c.name.givenName) as name');
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
abstract select(value: string): void;
|
|
112
|
+
/**
|
|
113
|
+
* Sets the GROUP BY clause for the query
|
|
114
|
+
* @param value GROUP BY expression
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* builder.groupBy('UPPER(c.sex)');
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
abstract groupBy(value: string): void;
|
|
121
|
+
/**
|
|
122
|
+
* Performs fuzzy search across multiple fields
|
|
123
|
+
* @param value Search term
|
|
124
|
+
* @param fields Array of field paths to search in
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* builder.whereFuzzy('steve', ['name.givenName', 'name.familyName', 'email']);
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
abstract whereFuzzy<P extends ExtractPathExpressions<T>>(value: string, fields: [P, ...P[]]): void;
|
|
131
|
+
/**
|
|
132
|
+
* Adds a raw WHERE clause with field, operator, and value
|
|
133
|
+
* @param field Field name as string
|
|
134
|
+
* @param operator SQL operator (excluding isNull, contains, in)
|
|
135
|
+
* @param value Value to compare against
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* builder.whereRaw('p.id', 'eq', 'some-id');
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
abstract whereRaw(field: string, operator: Exclude<ExtendedOpCode, 'isNull' | 'contains' | 'in'>, value: JSONValue): void;
|
|
142
|
+
/**
|
|
143
|
+
* Adds an OR clause to match items satisfying any of the given conditions
|
|
144
|
+
* @param conditions Array of field/operator/value conditions
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* builder.whereOr([
|
|
148
|
+
* { field: 'name.givenName', operator: 'eq', value: 'John' },
|
|
149
|
+
* { field: 'name.familyName', operator: 'eq', value: 'Smith' }
|
|
150
|
+
* ]);
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
abstract whereOr(conditions: Array<{
|
|
154
|
+
field: string;
|
|
155
|
+
operator: ExtendedOpCode;
|
|
156
|
+
value: JSONValue;
|
|
157
|
+
}>): void;
|
|
158
|
+
/**
|
|
159
|
+
* Creates a JSON patch document for Cosmos DB patch operations
|
|
160
|
+
* @param operations Array of patch operations (set, add, replace, remove)
|
|
161
|
+
* @returns Patch request body for Cosmos DB
|
|
162
|
+
* @example
|
|
163
|
+
* ```typescript
|
|
164
|
+
* const operations = builder.patch({
|
|
165
|
+
* op: 'replace',
|
|
166
|
+
* path: '/name/givenName',
|
|
167
|
+
* value: 'Smith',
|
|
168
|
+
* });
|
|
169
|
+
* const item = container.item('id', 'partitionKey');
|
|
170
|
+
* await item.patch<Person>(operations);
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
abstract patch<P extends ExtractPatchPathExpressions<T>>(...operations: Array<{
|
|
174
|
+
path: P;
|
|
175
|
+
op: 'set' | 'add' | 'replace';
|
|
176
|
+
value: PatchPathValue<T, P>;
|
|
177
|
+
} | {
|
|
178
|
+
path: P;
|
|
179
|
+
op: 'remove';
|
|
180
|
+
}>): PatchRequestBody;
|
|
181
|
+
/**
|
|
182
|
+
* Builds query conditions from a structured object with type filters
|
|
183
|
+
* Supports {@link StringFilter}, {@link UUIDFilter}, and {@link InstantFilter} types
|
|
184
|
+
* @param query Query object with nested field filters containing __typeInfo
|
|
185
|
+
* @param prefix Path prefix for nested queries (defaults to 'c')
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* type PersonFilter = {
|
|
189
|
+
* name?: {
|
|
190
|
+
* givenName?: StringFilter;
|
|
191
|
+
* };
|
|
192
|
+
* };
|
|
193
|
+
* const filter = {
|
|
194
|
+
* name: {
|
|
195
|
+
* givenName: { __typeInfo: 'StringFilter', eq: 'John' }
|
|
196
|
+
* },
|
|
197
|
+
* } satisfies PersonFilter;
|
|
198
|
+
* builder.buildQuery(filter);
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
abstract buildQuery(query: Record<string, any> | undefined | null, prefix?: string): void;
|
|
202
|
+
/**
|
|
203
|
+
* Adds a WHERE clause with type-safe field access and operators
|
|
204
|
+
* @param field Type-safe field path
|
|
205
|
+
* @param operator SQL operator
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* builder.where('name.givenName', 'eq', 'John');
|
|
209
|
+
* builder.where('age', 'gt', 18);
|
|
210
|
+
* builder.where('bones', 'contains', 'arm');
|
|
211
|
+
* builder.where('name.givenName', 'in', ['John', 'Jane']);
|
|
212
|
+
* builder.where('deletedAt', 'isNull');
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'isNull'): void;
|
|
216
|
+
abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'in', value: readonly PathValue<T, P>[]): void;
|
|
217
|
+
abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'contains', value: PathValue<T, P>[number]): void;
|
|
218
|
+
abstract where<P extends ExtractPathExpressions<T>, V extends PathValue<T, P>>(field: P, operator: BasicOpCode, value: V): void;
|
|
219
|
+
/**
|
|
220
|
+
* Clears any existing ordering
|
|
221
|
+
*/
|
|
222
|
+
abstract orderBy(): void;
|
|
223
|
+
/**
|
|
224
|
+
* Sets ordering by field and direction
|
|
225
|
+
* @param field Field path to order by
|
|
226
|
+
* @param direction Sort direction (ASC/DESC)
|
|
227
|
+
*/
|
|
228
|
+
abstract orderBy<P extends ExtractPathExpressions<T>>(field: P, direction: SortDirection): void;
|
|
229
|
+
/**
|
|
230
|
+
* Builds and returns the final SQL query specification
|
|
231
|
+
* @returns SQL query specification with parameters
|
|
232
|
+
*/
|
|
233
|
+
abstract query(): SqlQuerySpec;
|
|
234
|
+
/**
|
|
235
|
+
* Executes the query and returns the first result
|
|
236
|
+
* @param container Cosmos DB container to query
|
|
237
|
+
* @returns First matching item or null
|
|
238
|
+
*/
|
|
239
|
+
abstract getOne<TSelect = T>(container: Container): Promise<TSelect | null>;
|
|
240
|
+
/**
|
|
241
|
+
* Executes the query and returns paginated results with total count
|
|
242
|
+
* @param container Cosmos DB container to query
|
|
243
|
+
* @param limit Maximum number of items per page
|
|
244
|
+
* @param cursor Continuation token for pagination
|
|
245
|
+
* @returns Paginated results with metadata
|
|
246
|
+
*/
|
|
247
|
+
abstract getAll<TSelect = T>(container: Container, limit?: number | null | undefined, cursor?: string | null | undefined): Promise<FetchResult<TSelect>>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
declare function createCosmosQueryBuilder<T extends Record<string, any>>(options?: CosmosQueryBuilderOptions): ICosmosQueryBuilder<T>;
|
|
251
|
+
|
|
252
|
+
export { type BasicOpCode, type CosmosQueryBuilderOptions, type FetchResult, ICosmosQueryBuilder, ILogger, type InstantFilter, type ExtendedOpCode as OpCode, SortDirection, type StringFilter, type UUIDFilter, createCosmosQueryBuilder };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=Object.defineProperty,t=(t,s)=>e(t,"name",{value:s,configurable:!0}),s=class{static{t(this,"ILogger")}},r=class{static{t(this,"ICosmosQueryBuilder")}},i={eq:"=",ne:"!=",ge:">=",gt:">",le:"<=",lt:"<"},n=class extends s{static{t(this,"DefaultLogger")}debug(e,...t){}info(e,...t){}error(e,...t){}warn(e,...t){}verbose(e,...t){}},u=class extends r{static{t(this,"CosmosQueryBuilder")}_orderBy;_select="*";_groupBy=null;_join="";_from="c";_queries=[];_parameters=[];_limit;_logger;constructor(e){super(),this._logger=e?.logger??new n}get queries(){return this._queries}set queries(e){this._queries=e}get parameters(){return this._parameters}set parameters(e){this._parameters=e}handleStringFilter(e,t){return this.handleFilterObject(e,t)}handleUuidFilter(e,t){return this.handleFilterObject(e,t)}handleInstantFilter(e,t){return this.handleFilterObject(e,t)}handleFilterObject(e,t){const{__typeInfo:s,...r}=t;for(const[t,s]of Object.entries(r).filter(e=>void 0!==e[1])){const r=e,n=`@p${this._parameters.length}`,u=i[t],o=`(${r} ?? null)`;if(null!=u)this._queries.push(`${o} ${u} ${n}`);else if("ieq"===t)this._queries.push(`StringEquals(${o}, ${n}, true)`);else if("ine"===t)this._queries.push(`Not(StringEquals(${o}, ${n}, true))`);else if("like"===t)this._queries.push(`Contains(${o}, ${n}, true)`);else{if("in"!==t)throw new Error(`Unknown operator ${t}`);this._queries.push(`ARRAY_CONTAINS(${n}, ${o})`)}this._parameters.push({name:n,value:s})}}_buildQuery(e,t="c"){if(null!=e){const{__typeInfo:s,...r}=e,i=Object.keys(r);for(const s of i){const r=e[s],i=r.__typeInfo??null,n=`${t}.${s}`;if("object"!=typeof r||null==r)throw new Error(`Unhandled type ${i}`);"StringFilter"===i?this.handleStringFilter(n,r):"InstantFilter"===i?this.handleInstantFilter(n,r):"UUIDFilter"===i?this.handleUuidFilter(n,r):this._buildQuery(r,n)}}}buildQuery(e,t="c"){this._buildQuery(e,t)}orderBy(e,t){this._orderBy=null==e||null==t?void 0:`\nORDER BY\n c.${e} ${t}`}groupBy(e){this._groupBy=`\nGROUP BY\n ${e}`}select(e){this._select=e}parameter(e,t){this._parameters.push({name:e,value:t})}limit(e){this._limit=e}join(e,t){this._join=`${e} IN c.${t}`}whereFuzzy(e,t){const s=`@p${this._parameters.length}`,r=[];for(const e of t){const t=`Contains(c.${e}, ${s}, true)`;r.push(t)}const i=`(${r.join(" OR ")})`;this._queries.push(i),this._parameters.push({name:s,value:e})}whereRaw(e,t,s){const r=`@p${this._parameters.length}`,n=i[t];this._queries.push(`${e} ${n} ${r}`),this._parameters.push({name:r,value:s})}whereOr(e){const t=[];for(const s of e){const{field:e,operator:r,value:n}=s,u=`@p${this._parameters.length}`;if("isNull"===r)t.push(`(c.${e} ?? null) = null`);else if("contains"===r)t.push(`ARRAY_CONTAINS(c.${e}, ${u})`);else if("in"===r)t.push(`ARRAY_CONTAINS(${u}, c.${e})`);else{const s=i[r];null!=s&&void 0!==n&&(t.push(`c.${e} ${s} ${u}`),this._parameters.push({name:u,value:n}))}}t.length>0&&this._queries.push(`(${t.join(" OR ")})`)}where(e,t,s){const r=`@p${this._parameters.length}`;if("isNull"===t){const t=`(c.${e} ?? null) = null`;this._queries.push(t)}else if("contains"===t){if(void 0!==s){const t=`ARRAY_CONTAINS(c.${e}, ${r})`;this._queries.push(t),this._parameters.push({name:r,value:s})}}else if("in"===t){if(void 0!==s){const t=`ARRAY_CONTAINS(${r}, c.${e})`;this._queries.push(t),this._parameters.push({name:r,value:s})}}else{const n=i[t];null!=n&&void 0!==s&&(this._queries.push(`c.${e} ${n} ${r}`),this._parameters.push({name:r,value:s}))}}filter(e){const t=`@p${this._parameters.length}`;this._queries.push(e.clause.replace("@",t)),null!=e.parameter&&this._parameters.push({name:t,value:e.parameter})}query(){const e=[];if(e.push(`SELECT\n ${this._select}`),e.push(`FROM\n ${this._from}`),""!==this._join&&e.push(`JOIN\n ${this._join}`),this._queries.length>0){e.push("WHERE");const t=this._queries.join("\n AND ");e.push(t)}null!=this._orderBy&&e.push(this._orderBy),null!=this._groupBy&&e.push(this._groupBy),null!=this._limit&&(e.push("OFFSET 0"),e.push(`LIMIT ${this._limit}`));const t={query:e.join("\n"),parameters:this.parameters};return this._logger.verbose("Cosmos Query",t),t}async getOne(e){const t=this.query(),s=e.items.query(t),r=await s.fetchNext();return this._logger.verbose("Cosmos Result",{result:r}),r.resources?.[0]??null}async getAll(e,t,s){const r=this.query(),i=e.items.query(r,{continuationToken:s??void 0,maxItemCount:t??void 0});let n;try{n=await i.fetchAll()}catch(e){throw this._logger.error("Cosmos Query Error",e),e}this._logger.verbose("Cosmos Result",{result:n}),this.select("VALUE COUNT(1)"),this.orderBy();const u=this.query(),o=e.items.query(u);let l;try{l=await o.fetchAll()}catch(e){throw this._logger.error("Cosmos Count Query Error",e),e}const h=l.resources?.[0]??0;return{continuationToken:n.continuationToken,count:n.resources?.length??0,items:n.resources??[],hasMoreResults:n.hasMoreResults,totalCount:h}}patch(...e){return{operations:e.map(e=>{if("remove"===e.op)return{op:e.op,path:e.path};if(void 0!==e.value)return{op:e.op,path:e.path,value:e.value};throw new Error(`Value is required for operation: ${e.op}`)})}}};function o(e){return new u(e)}t(o,"createCosmosQueryBuilder");var l=(e=>(e.Asc="ASC",e.Desc="DESC",e))(l||{});export{s as ILogger,l as SortDirection,o as createCosmosQueryBuilder};//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/public/interfaces.ts","../../src/private/consts.ts","../../src/private/DefaultLogger.ts","../../src/private/CosmosQueryBuilder.ts","../../src/public/createCosmosQueryBuilder.ts","../../src/public/enums.ts"],"names":["SortDirection"],"mappings":"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","file":"index.js","sourcesContent":["import type { JSONValue, PatchRequestBody, SqlQuerySpec } from '@azure/cosmos';\nimport type { ExtractPatchPathExpressions, ExtractPathExpressions, PatchPathValue, PathValue } from '../private/types';\nimport type { SortDirection } from './enums';\nimport type { BasicOpCode, Container, ExtendedOpCode, FetchResult, InstantFilter, StringFilter, UUIDFilter } from './types';\n\nexport abstract class ILogger {\n public abstract debug(message?: any, ...optionalParams: any[]): void;\n public abstract info(message?: any, ...optionalParams: any[]): void;\n public abstract error(message?: any, ...optionalParams: any[]): void;\n public abstract warn(message?: any, ...optionalParams: any[]): void;\n public abstract verbose(message?: any, ...optionalParams: any[]): void;\n}\n\nexport abstract class ICosmosQueryBuilder<T extends Record<string, any>> {\n /**\n * Sets the maximum number of items to return\n * @param limit Maximum number of items\n * @example\n * ```typescript\n * builder.limit(100);\n * ```\n */\n public abstract limit(limit: number): void;\n\n /**\n * Adds a JOIN clause to the query\n * @param value JOIN alias\n * @param statement Field path to join on\n * @example\n * ```typescript\n * builder.join('b', 'bones');\n * ```\n */\n public abstract join<P extends ExtractPathExpressions<T>>(value: string, statement: P): void;\n\n /**\n * Sets the SELECT clause for the query\n * @param value SELECT clause string\n * @example\n * ```typescript\n * builder.select('COUNT(1) as count, UPPER(c.name.givenName) as name');\n * ```\n */\n public abstract select(value: string): void;\n\n /**\n * Sets the GROUP BY clause for the query\n * @param value GROUP BY expression\n * @example\n * ```typescript\n * builder.groupBy('UPPER(c.sex)');\n * ```\n */\n public abstract groupBy(value: string): void;\n\n /**\n * Performs fuzzy search across multiple fields\n * @param value Search term\n * @param fields Array of field paths to search in\n * @example\n * ```typescript\n * builder.whereFuzzy('steve', ['name.givenName', 'name.familyName', 'email']);\n * ```\n */\n public abstract whereFuzzy<P extends ExtractPathExpressions<T>>(value: string, fields: [P, ...P[]]): void;\n\n /**\n * Adds a raw WHERE clause with field, operator, and value\n * @param field Field name as string\n * @param operator SQL operator (excluding isNull, contains, in)\n * @param value Value to compare against\n * @example\n * ```typescript\n * builder.whereRaw('p.id', 'eq', 'some-id');\n * ```\n */\n public abstract whereRaw(field: string, operator: Exclude<ExtendedOpCode, 'isNull' | 'contains' | 'in'>, value: JSONValue): void;\n\n /**\n * Adds an OR clause to match items satisfying any of the given conditions\n * @param conditions Array of field/operator/value conditions\n * @example\n * ```typescript\n * builder.whereOr([\n * { field: 'name.givenName', operator: 'eq', value: 'John' },\n * { field: 'name.familyName', operator: 'eq', value: 'Smith' }\n * ]);\n * ```\n */\n public abstract whereOr(conditions: Array<{ field: string; operator: ExtendedOpCode; value: JSONValue }>): void;\n\n /**\n * Creates a JSON patch document for Cosmos DB patch operations\n * @param operations Array of patch operations (set, add, replace, remove)\n * @returns Patch request body for Cosmos DB\n * @example\n * ```typescript\n * const operations = builder.patch({\n * op: 'replace',\n * path: '/name/givenName',\n * value: 'Smith',\n * });\n * const item = container.item('id', 'partitionKey');\n * await item.patch<Person>(operations);\n * ```\n */\n public abstract patch<P extends ExtractPatchPathExpressions<T>>(...operations: Array<{ path: P; op: 'set' | 'add' | 'replace'; value: PatchPathValue<T, P> } | { path: P; op: 'remove' }>): PatchRequestBody;\n\n /**\n * Builds query conditions from a structured object with type filters\n * Supports {@link StringFilter}, {@link UUIDFilter}, and {@link InstantFilter} types\n * @param query Query object with nested field filters containing __typeInfo\n * @param prefix Path prefix for nested queries (defaults to 'c')\n * @example\n * ```typescript\n * type PersonFilter = {\n * name?: {\n * givenName?: StringFilter;\n * };\n * };\n * const filter = {\n * name: {\n * givenName: { __typeInfo: 'StringFilter', eq: 'John' }\n * },\n * } satisfies PersonFilter;\n * builder.buildQuery(filter);\n * ```\n */\n public abstract buildQuery(query: Record<string, any> | undefined | null, prefix?: string): void;\n\n /**\n * Adds a WHERE clause with type-safe field access and operators\n * @param field Type-safe field path\n * @param operator SQL operator\n * @example\n * ```typescript\n * builder.where('name.givenName', 'eq', 'John');\n * builder.where('age', 'gt', 18);\n * builder.where('bones', 'contains', 'arm');\n * builder.where('name.givenName', 'in', ['John', 'Jane']);\n * builder.where('deletedAt', 'isNull');\n * ```\n */\n public abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'isNull'): void;\n public abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'in', value: readonly PathValue<T, P>[]): void;\n public abstract where<P extends ExtractPathExpressions<T>>(field: P, operator: 'contains', value: PathValue<T, P>[number]): void;\n public abstract where<P extends ExtractPathExpressions<T>, V extends PathValue<T, P>>(field: P, operator: BasicOpCode, value: V): void;\n\n /**\n * Clears any existing ordering\n */\n public abstract orderBy(): void;\n\n /**\n * Sets ordering by field and direction\n * @param field Field path to order by\n * @param direction Sort direction (ASC/DESC)\n */\n public abstract orderBy<P extends ExtractPathExpressions<T>>(field: P, direction: SortDirection): void;\n\n /**\n * Builds and returns the final SQL query specification\n * @returns SQL query specification with parameters\n */\n public abstract query(): SqlQuerySpec;\n\n /**\n * Executes the query and returns the first result\n * @param container Cosmos DB container to query\n * @returns First matching item or null\n */\n public abstract getOne<TSelect = T>(container: Container): Promise<TSelect | null>;\n\n /**\n * Executes the query and returns paginated results with total count\n * @param container Cosmos DB container to query\n * @param limit Maximum number of items per page\n * @param cursor Continuation token for pagination\n * @returns Paginated results with metadata\n */\n public abstract getAll<TSelect = T>(container: Container, limit?: number | null | undefined, cursor?: string | null | undefined): Promise<FetchResult<TSelect>>;\n}\n","export const operators: Record<string, string | undefined> = {\n eq: '=',\n ne: '!=',\n ge: '>=',\n gt: '>',\n le: '<=',\n lt: '<',\n} as const;\n","import { ILogger } from '../public/interfaces';\n\nexport class DefaultLogger extends ILogger {\n public debug(_message?: any, ..._optionalParams: any[]): void {}\n public info(_message?: any, ..._optionalParams: any[]): void {}\n public error(_message?: any, ..._optionalParams: any[]): void {}\n public warn(_message?: any, ..._optionalParams: any[]): void {}\n public verbose(_message?: any, ..._optionalParams: any[]): void {}\n}\n","import type { JSONValue, PatchRequestBody, SqlParameter, SqlQuerySpec } from '@azure/cosmos';\nimport type { SortDirection } from '../public/enums';\nimport { ICosmosQueryBuilder, type ILogger } from '../public/interfaces';\nimport type { BasicOpCode, Container, CosmosQueryBuilderOptions, ExtendedOpCode, FeedResponse, FetchResult, InstantFilter, StringFilter, UUIDFilter } from '../public/types';\nimport { operators } from './consts';\nimport { DefaultLogger } from './DefaultLogger';\nimport type { ExtractPatchPathExpressions, ExtractPathExpressions, PatchPathValue, PathValue, StringFilterData } from './types';\n\nexport class CosmosQueryBuilder<T extends Record<string, any>> extends ICosmosQueryBuilder<T> {\n private _orderBy?: string;\n private _select = '*';\n private _groupBy: string | null = null;\n private _join = '';\n private _from = 'c';\n private _queries: string[] = [];\n private _parameters: SqlParameter[] = [];\n private _limit: number | undefined;\n private _logger: ILogger;\n\n public constructor(options?: CosmosQueryBuilderOptions) {\n super();\n this._logger = options?.logger ?? new DefaultLogger();\n }\n\n public get queries(): string[] {\n return this._queries;\n }\n\n public set queries(value: string[]) {\n this._queries = value;\n }\n\n public get parameters(): SqlParameter[] {\n return this._parameters;\n }\n\n public set parameters(value: SqlParameter[]) {\n this._parameters = value;\n }\n\n private handleStringFilter(prefix: string, value: StringFilter) {\n return this.handleFilterObject(prefix, value);\n }\n\n private handleUuidFilter(prefix: string, value: UUIDFilter) {\n return this.handleFilterObject(prefix, value);\n }\n\n private handleInstantFilter(prefix: string, value: InstantFilter) {\n return this.handleFilterObject(prefix, value);\n }\n\n private handleFilterObject(prefix: string, value: StringFilterData & { __typeInfo: string }) {\n const { __typeInfo, ...rest } = value;\n for (const [key, value2] of Object.entries(rest).filter((x) => x[1] !== undefined)) {\n const path = prefix;\n const parameterName = `@p${this._parameters.length}`;\n const operator = operators[key];\n\n // Default to null to allow null comparison when parent object is not defined\n const queryKey = `(${path} ?? null)`;\n if (operator != null) {\n this._queries.push(`${queryKey} ${operator} ${parameterName}`);\n } else {\n if (key === 'ieq') {\n this._queries.push(`StringEquals(${queryKey}, ${parameterName}, true)`);\n } else if (key === 'ine') {\n this._queries.push(`Not(StringEquals(${queryKey}, ${parameterName}, true))`);\n } else if (key === 'like') {\n this._queries.push(`Contains(${queryKey}, ${parameterName}, true)`);\n } else if (key === 'in') {\n this._queries.push(`ARRAY_CONTAINS(${parameterName}, ${queryKey})`);\n } else {\n throw new Error(`Unknown operator ${key}`);\n }\n }\n this._parameters.push({ name: parameterName, value: value2 });\n }\n }\n\n private _buildQuery(query: Record<string, any> | null | undefined, prefix = 'c'): void {\n if (query != null) {\n const { __typeInfo, ...rest } = query;\n const queryKeys = Object.keys(rest);\n\n for (const key of queryKeys) {\n const value = query[key];\n const type: string | null = value.__typeInfo ?? null;\n const subPath = `${prefix}.${key}`;\n\n if (typeof value === 'object' && value != null) {\n if (type === 'StringFilter') {\n this.handleStringFilter(subPath, value);\n } else if (type === 'InstantFilter') {\n this.handleInstantFilter(subPath, value);\n } else if (type === 'UUIDFilter') {\n this.handleUuidFilter(subPath, value);\n } else {\n this._buildQuery(value, subPath);\n }\n } else {\n throw new Error(`Unhandled type ${type}`);\n }\n }\n }\n }\n\n public override buildQuery(query: Record<string, any> | undefined | null, prefix = 'c'): void {\n this._buildQuery(query, prefix);\n }\n\n public override orderBy(): void;\n public override orderBy<P extends ExtractPathExpressions<T>>(field: P, direction: SortDirection): void;\n public override orderBy<P extends ExtractPathExpressions<T>>(field?: P, direction?: SortDirection) {\n if (field == null || direction == null) {\n this._orderBy = undefined;\n } else {\n this._orderBy = `\\nORDER BY\\n c.${field} ${direction}`;\n }\n }\n\n public override groupBy(value: string): void {\n this._groupBy = `\\nGROUP BY\\n ${value}`;\n }\n\n public override select(value: string): void {\n this._select = value;\n }\n\n private parameter(name: string, value: JSONValue): void {\n this._parameters.push({\n name,\n value,\n });\n }\n\n public override limit(limit: number): void {\n this._limit = limit;\n }\n\n public override join<P extends ExtractPathExpressions<T>>(value: string, statement: P): void {\n this._join = `${value} IN c.${statement}`;\n }\n\n public override whereFuzzy<P extends ExtractPathExpressions<T>>(value: string, fields: [P, ...P[]]): void {\n const parameterName = `@p${this._parameters.length}`;\n const lines: string[] = [];\n for (const field of fields) {\n const clause = `Contains(c.${field}, ${parameterName}, true)`;\n lines.push(clause);\n }\n const queryLine = `(${lines.join(' OR ')})`;\n this._queries.push(queryLine);\n this._parameters.push({ name: parameterName, value });\n }\n\n public override whereRaw(field: string, operator: Exclude<ExtendedOpCode, 'isNull' | 'contains' | 'in'>, value: JSONValue): void {\n const parameterName = `@p${this._parameters.length}`;\n const sqlOperator = operators[operator];\n this._queries.push(`${field} ${sqlOperator} ${parameterName}`);\n this._parameters.push({ name: parameterName, value });\n }\n\n public override whereOr(conditions: Array<{ field: string; operator: ExtendedOpCode; value: JSONValue }>): void {\n const orClauses: string[] = [];\n for (const condition of conditions) {\n const { field, operator, value } = condition;\n const parameterName = `@p${this._parameters.length}`;\n\n if (operator === 'isNull') {\n orClauses.push(`(c.${field} ?? null) = null`);\n } else if (operator === 'contains') {\n orClauses.push(`ARRAY_CONTAINS(c.${field}, ${parameterName})`);\n } else if (operator === 'in') {\n orClauses.push(`ARRAY_CONTAINS(${parameterName}, c.${field})`);\n } else {\n const sqlOperator = operators[operator];\n if (sqlOperator != null && value !== undefined) {\n orClauses.push(`c.${field} ${sqlOperator} ${parameterName}`);\n this._parameters.push({ name: parameterName, value });\n }\n }\n }\n\n if (orClauses.length > 0) {\n this._queries.push(`(${orClauses.join(' OR ')})`);\n }\n }\n\n public override where<P extends ExtractPathExpressions<T>>(field: P, operator: 'isNull'): void;\n public override where<P extends ExtractPathExpressions<T>>(field: P, operator: 'in', value: readonly PathValue<T, P>[]): void;\n public override where<P extends ExtractPathExpressions<T>>(field: P, operator: 'contains', value: PathValue<T, P>[number]): void;\n public override where<P extends ExtractPathExpressions<T>, V extends PathValue<T, P>>(field: P, operator: BasicOpCode, value: V): void;\n public override where<P extends ExtractPathExpressions<T>, V extends PathValue<T, P>>(field: P, operator: ExtendedOpCode, value?: V | readonly V[]): void {\n const parameterName = `@p${this._parameters.length}`;\n\n if (operator === 'isNull') {\n const clause = `(c.${field} ?? null) = null`;\n this._queries.push(clause);\n } else if (operator === 'contains') {\n if (value !== undefined) {\n const clause = `ARRAY_CONTAINS(c.${field}, ${parameterName})`;\n this._queries.push(clause);\n this._parameters.push({ name: parameterName, value });\n }\n } else if (operator === 'in') {\n // Handle 'IN' operator\n if (value !== undefined) {\n const clause = `ARRAY_CONTAINS(${parameterName}, c.${field})`;\n this._queries.push(clause);\n this._parameters.push({ name: parameterName, value });\n }\n } else {\n const sqlOperator = operators[operator];\n if (sqlOperator != null && value !== undefined) {\n this._queries.push(`c.${field} ${sqlOperator} ${parameterName}`);\n this._parameters.push({ name: parameterName, value });\n }\n }\n }\n\n public filter(x: { clause: string; parameter?: JSONValue }): void {\n const paramName = `@p${this._parameters.length}`;\n this._queries.push(x.clause.replace('@', paramName));\n if (x.parameter != null) {\n this._parameters.push({\n name: paramName,\n value: x.parameter,\n });\n }\n }\n\n public override query(): SqlQuerySpec {\n const lines: string[] = [];\n lines.push(`SELECT\\n ${this._select}`);\n lines.push(`FROM\\n ${this._from}`);\n if (this._join !== '') {\n lines.push(`JOIN\\n ${this._join}`);\n }\n\n if (this._queries.length > 0) {\n lines.push('WHERE');\n const where = this._queries.join('\\n AND ');\n lines.push(where);\n }\n\n if (this._orderBy != null) {\n lines.push(this._orderBy);\n }\n if (this._groupBy != null) {\n lines.push(this._groupBy);\n }\n if (this._limit != null) {\n lines.push('OFFSET 0');\n lines.push(`LIMIT ${this._limit}`);\n }\n\n const queryText = lines.join('\\n');\n const result = {\n query: queryText,\n parameters: this.parameters,\n };\n this._logger.verbose('Cosmos Query', result);\n return result;\n }\n\n public override async getOne<TSelect = T>(container: Container): Promise<TSelect | null> {\n const itemsQuery = this.query();\n const itemsIterator = container.items.query<TSelect>(itemsQuery);\n const items = await itemsIterator.fetchNext();\n this._logger.verbose('Cosmos Result', { result: items });\n return items.resources?.[0] ?? null;\n }\n\n public override async getAll<TSelect>(container: Container, limit?: number | null | undefined, cursor?: string | null | undefined): Promise<FetchResult<TSelect>> {\n const itemsQuery = this.query();\n const itemsIterator = container.items.query<TSelect>(itemsQuery, {\n continuationToken: cursor ?? undefined,\n maxItemCount: limit ?? undefined,\n });\n let items: FeedResponse<TSelect>;\n try {\n items = await itemsIterator.fetchAll();\n } catch (err) {\n this._logger.error('Cosmos Query Error', err);\n throw err;\n }\n this._logger.verbose('Cosmos Result', { result: items });\n\n this.select('VALUE COUNT(1)');\n this.orderBy();\n\n const countQuery = this.query();\n const countIterator = container.items.query<number>(countQuery);\n\n let count: FeedResponse<number>;\n try {\n count = await countIterator.fetchAll();\n } catch (err) {\n this._logger.error('Cosmos Count Query Error', err);\n throw err;\n }\n\n const totalCount = count.resources?.[0] ?? 0;\n\n const result: FetchResult<TSelect> = {\n continuationToken: items.continuationToken,\n count: items.resources?.length ?? 0,\n items: items.resources ?? [],\n hasMoreResults: items.hasMoreResults,\n totalCount,\n };\n return result;\n }\n\n public override patch<P extends ExtractPatchPathExpressions<T>>(...operations: Array<{ path: P; op: 'set' | 'add' | 'replace'; value: PatchPathValue<T, P> } | { path: P; op: 'remove' }>): PatchRequestBody {\n const patchOperations = operations.map((opDef) => {\n if (opDef.op === 'remove') {\n return { op: opDef.op, path: opDef.path };\n }\n\n if (opDef.value !== undefined) {\n return { op: opDef.op, path: opDef.path, value: opDef.value };\n }\n\n throw new Error(`Value is required for operation: ${opDef.op}`);\n });\n\n return { operations: patchOperations };\n }\n}\n","import { CosmosQueryBuilder } from '../private/CosmosQueryBuilder';\nimport type { ICosmosQueryBuilder } from './interfaces';\nimport type { CosmosQueryBuilderOptions } from './types';\n\nexport function createCosmosQueryBuilder<T extends Record<string, any>>(options?: CosmosQueryBuilderOptions): ICosmosQueryBuilder<T> {\n return new CosmosQueryBuilder<T>(options);\n}\n","export enum SortDirection {\n Asc = 'ASC',\n Desc = 'DESC',\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shellicar/cosmos-query-builder",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "1.0.0-preview.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Stephen Hellicar",
|
|
8
|
+
"description": "A type-safe query builder for Azure Cosmos DB for NoSQL",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"query",
|
|
11
|
+
"builder",
|
|
12
|
+
"azure",
|
|
13
|
+
"cosmos",
|
|
14
|
+
"db",
|
|
15
|
+
"cosmosdb",
|
|
16
|
+
"nosql",
|
|
17
|
+
"typescript"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/shellicar/cosmos-query-builder.git"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/shellicar/cosmos-query-builder/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/shellicar/cosmos-query-builder#readme",
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"main": "./dist/cjs/index.cjs",
|
|
31
|
+
"module": "./dist/esm/index.js",
|
|
32
|
+
"types": "./dist/esm/index.d.ts",
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/cjs/index.d.cts",
|
|
37
|
+
"default": "./dist/cjs/index.cjs"
|
|
38
|
+
},
|
|
39
|
+
"import": {
|
|
40
|
+
"types": "./dist/esm/index.d.ts",
|
|
41
|
+
"default": "./dist/esm/index.js"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"dist"
|
|
47
|
+
],
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@azure/cosmos": "^4.5.1",
|
|
50
|
+
"@shellicar/build-clean": "^1.0.0",
|
|
51
|
+
"@tsconfig/node20": "^20.1.6",
|
|
52
|
+
"@tsconfig/node22": "^22.0.2",
|
|
53
|
+
"@types/node": "^24.3.0",
|
|
54
|
+
"terser": "^5.43.1",
|
|
55
|
+
"tsup": "^8.5.0",
|
|
56
|
+
"typescript": "^5.9.2",
|
|
57
|
+
"vitest": "^3.2.4"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"@azure/cosmos": ">=4.0.0 <5.0.0"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"build": "tsup-node",
|
|
64
|
+
"dev": "tsup-node --watch",
|
|
65
|
+
"type-check": "tsc -p tsconfig.check.json"
|
|
66
|
+
}
|
|
67
|
+
}
|