/** * Query configuration for loading objects from the Lime CRM database. * * A {@link Query} defines what data to retrieve, how to filter it, and how to format * the response. Used primarily with {@link QueryService} to execute complex queries * with filtering, sorting, pagination, and aggregation. * * The query system supports: * - Complex filter expressions with AND/OR/NOT logic * - Multiple sort orders * - Pagination via limit/offset * - Aggregate calculations (COUNT, SUM, AVG, etc.) * * Define the query inline or with `satisfies Query` to keep the literal * `responseFormat` that {@link QueryResponse} infers the response shape from. * * @example Get active deals * ```ts * import { Operator, Query } from '@limetech/lime-web-components'; * * const query = { * limetype: 'deal', * filter: { * key: 'status', * op: Operator.EQUALS, * exp: 'active', * }, * responseFormat: { * object: { name: null, value: null }, * }, * } satisfies Query; * ``` * * @example Get high-value deals with pagination * ```ts * import { Operator, Query } from '@limetech/lime-web-components'; * * const secondPage = { * limetype: 'deal', * limit: 25, * offset: 25, * filter: { * key: 'value', * op: Operator.GREATER_OR_EQUAL, * exp: 100_000, * }, * orderBy: [{ name: 'value', direction: 'DESC' }], * responseFormat: { * object: { name: null, value: null }, * }, * } satisfies Query; * ``` * * @public * @group Query * @see {@link QueryService} for executing queries * @see {@link Expression} for building filter conditions * @see {@link LoadOptions} for similar filtering in LimeObjectRepository */ export interface Query { /** * Name of the limetype to query. */ limetype: string; /** * Maximum number of objects to return. */ limit?: number; /** * Number of objects to skip before starting to return results. */ offset?: number; /** * Properties to sort by with their sort direction. */ orderBy?: PropertyOrder[]; /** * Filter expression to limit which objects are returned. * * @see {@link Expression} for building filter conditions */ filter?: Expression; /** * Defines what data to include in the response. */ responseFormat: QueryResponseFormat; } /** * A single aggregate column within an {@link AggregateGroup}. The `op` * determines which aggregate is computed for the column, and `key` is the * property the operation is applied to. * * Every operation operates on a property and therefore requires a `key`, except * `COUNT`, which counts rows and takes none. A `GROUP` column groups the result * by `key`, producing one response row per distinct value. * * @public * @group Query * @see {@link AggregateOperator} for the available operations */ export type AggregateColumn = { op: 'COUNT'; } | { op: Exclude; key: string; }; /** * A named group of {@link AggregateColumn}s. Each key is the column name that * the computed value is returned under in the {@link QueryResponse}. * * @public * @group Query */ export type AggregateGroup = Record; /** * Shape describing which fields a {@link Query} should return. * * @public * @group Query */ export interface QueryResponseFormat { /** * Object properties to include in the response. Each key names a property * to return. */ object?: Record; /** * Aggregate calculations to perform, keyed by group name. */ aggregates?: Record; } /** * The shape of the response from executing a {@link Query}. * * Contains the objects that matched the query filter along with any requested * aggregate calculations. Each aggregate group is returned as an array with one * row per distinct combination of its `GROUP` columns, or a single row when the * group has none. * * When the query's `responseFormat` is known at compile time (defined inline or * with `satisfies Query`), the `objects` and `aggregates` shapes are inferred * from it. Otherwise it falls back to `unknown`. * * Aggregate values are typed by operator: `COUNT` is `number`, `SUM` and `AVG` * are `number | null`, and `MIN` and `MAX` are `number | string | null` (a date * or text column returns a string, and an empty result returns null). A `GROUP` * column returns the grouped property's value (a string, number, boolean, or * null). * * @example Read objects and aggregates from a response * ```ts * import { * AggregateOperator, * PlatformServiceName, * Query, * } from '@limetech/lime-web-components'; * * const queryService = platform.get(PlatformServiceName.Query); * * const query = { * limetype: 'deal', * responseFormat: { * object: { name: null, value: null }, * aggregates: { * totals: { * total_value: { op: AggregateOperator.Sum, key: 'value' }, * }, * }, * }, * } satisfies Query; * * const response = await queryService.execute(query); * * console.log(`Found ${response.objects.length} objects`); * for (const deal of response.objects) { * console.log(`Deal: ${deal.name}, Value: ${deal.value}`); * } * * const [totals] = response.aggregates.totals; * console.log(`Total value: ${totals?.total_value}`); * ``` * * @public * @group Query * @see {@link QueryService.execute} for running queries * @see {@link Query} for query configuration */ export type QueryResponse = { objects: Q['responseFormat'] extends { object: infer O; } ? Array<{ -readonly [K in keyof O]: unknown; }> : unknown[]; aggregates: Q['responseFormat'] extends { aggregates: infer A; } ? { -readonly [G in keyof A]: Array<{ -readonly [C in keyof A[G]]: A[G][C] extends { op: 'COUNT'; } ? number : A[G][C] extends { op: 'GROUP'; } ? string | number | boolean | null : A[G][C] extends { op: 'SUM' | 'AVG'; } ? number | null : number | string | null; }>; } : unknown; }; /** * Defines an ordering on a property when executing a {@link Query} or * {@link LoadOptions} against a repository. * * @public * @group Query */ export interface PropertyOrder { /** * Name of the property to sort on */ name: string; /** * The direction to order the property by */ direction: 'ASC' | 'DESC'; } /** * Filter expression for querying objects in Lime CRM. * * An {@link Expression} defines filtering criteria to limit which objects are returned * from queries. Expressions support complex logic with AND/OR/NOT operators, comparison * operators, and IN operators for checking multiple values or filter results. * * Expression types: * - {@link BasicExpression} - Simple property comparisons (equals, greater than, like, etc.) * - {@link AndOrExpression} - Combine multiple expressions with AND/OR logic * - {@link NotExpression} - Negate an expression * - {@link InExpression} - Check if property matches any value in a list * - {@link InFilterExpression} - Check if property matches results from another filter * * Used in: * - {@link Query.filter} for QueryService * - {@link LoadOptions.filter} for LimeObjectRepository * - {@link Filter.filter} for saved filter definitions * * @example Simple expression, status equals 'active' * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const statusIsActive: BasicExpression = { * key: 'status', * op: Operator.EQUALS, * exp: 'active', * }; * ``` * * @example AND expression, active deals worth over $50k * ```ts * import { AndOrExpression, Operator } from '@limetech/lime-web-components'; * * const activeAndWorthOver50k: AndOrExpression = { * op: Operator.AND, * exp: [ * { key: 'status', op: Operator.EQUALS, exp: 'active' }, * { key: 'value', op: Operator.GREATER, exp: 50_000 }, * ], * }; * ``` * * @example Complex nested expression, high priority open tickets * ```ts * import { Expression, Operator } from '@limetech/lime-web-components'; * * const highPriorityOpenTickets: Expression = { * op: Operator.AND, * exp: [ * { * key: 'status', * op: Operator.IN, * exp: ['open', 'in_progress', 'waiting'], * }, * { * op: Operator.OR, * exp: [ * { key: 'priority', op: Operator.EQUALS, exp: 'urgent' }, * { key: 'priority', op: Operator.EQUALS, exp: 'high' }, * ], * }, * ], * }; * ``` * * @example NOT expression, exclude closed deals * ```ts * import { NotExpression, Operator } from '@limetech/lime-web-components'; * * const notClosed: NotExpression = { * op: Operator.NOT, * exp: { key: 'status', op: Operator.EQUALS, exp: 'closed' }, * }; * ``` * * @example IN filter expression, deals owned by users matching a filter * ```ts * import { InFilterExpression, Operator } from '@limetech/lime-web-components'; * * const ownedBySalesTeam: InFilterExpression = { * type: 'filter', * key: 'owner', * op: Operator.IN, * exp: 'sales_team', * }; * ``` * * @public * @group Query * @see {@link LoadOptions} for using expressions with LimeObjectRepository * @see {@link Query} for using expressions with QueryService * @see {@link Filter} for saved filter definitions */ export type Expression = AndOrExpression | NotExpression | InFilterExpression | InExpression | BasicExpression; /** * Logical AND or OR expression combining multiple filter conditions. * * Combines multiple {@link Expression}s with either AND or OR logic: * - AND: All sub-expressions must be true for the object to match * - OR: At least one sub-expression must be true for the object to match * * AND/OR expressions can be nested to create complex filtering logic. * Use AND when all conditions must be met, OR when any condition can match. * * @example AND, find active deals with value over $50k * ```ts * import { AndOrExpression, Operator } from '@limetech/lime-web-components'; * * const activeAndWorthOver50k: AndOrExpression = { * op: Operator.AND, * exp: [ * { key: 'status', op: Operator.EQUALS, exp: 'active' }, * { key: 'value', op: Operator.GREATER, exp: 50_000 }, * ], * }; * ``` * * @example OR, find deals that are either urgent or high value * ```ts * import { AndOrExpression, Operator } from '@limetech/lime-web-components'; * * const urgentOrHighValue: AndOrExpression = { * op: Operator.OR, * exp: [ * { key: 'priority', op: Operator.EQUALS, exp: 'urgent' }, * { key: 'value', op: Operator.GREATER, exp: 1_000_000 }, * ], * }; * ``` * * @example Nested, (status='open' OR status='waiting') AND priority='high' * ```ts * import { AndOrExpression, Operator } from '@limetech/lime-web-components'; * * const waitingOrOpenAndHighPriority: AndOrExpression = { * op: Operator.AND, * exp: [ * { * op: Operator.OR, * exp: [ * { key: 'status', op: Operator.EQUALS, exp: 'open' }, * { key: 'status', op: Operator.EQUALS, exp: 'waiting' }, * ], * }, * { key: 'priority', op: Operator.EQUALS, exp: 'high' }, * ], * }; * ``` * * @public * @group Query * @see {@link Expression} for the main expression type * @see {@link Operator.AND} and {@link Operator.OR} */ export type AndOrExpression = { /** * Logical operator: AND requires all expressions to match, OR requires at least one. */ op: Operator.AND | Operator.OR; /** * Array of expressions to combine with the logical operator. */ exp: Expression[]; }; /** * Negation expression that inverts the result of another expression. * * Matches objects that do NOT match the contained expression. Use this to * exclude objects based on certain criteria, such as "not closed" or * "not in a specific list of values". * * The NOT operator can be applied to any type of expression, including * basic comparisons, AND/OR combinations, and IN expressions. * * @example Find all deals that are NOT closed * ```ts * import { NotExpression, Operator } from '@limetech/lime-web-components'; * * const notClosed: NotExpression = { * op: Operator.NOT, * exp: { key: 'status', op: Operator.EQUALS, exp: 'closed' }, * }; * ``` * * @example Find companies that are NOT in specific industries * ```ts * import { NotExpression, Operator } from '@limetech/lime-web-components'; * * const notInExcludedIndustries: NotExpression = { * op: Operator.NOT, * exp: { * key: 'industry', * op: Operator.IN, * exp: ['retail', 'hospitality', 'construction'], * }, * }; * ``` * * @example Complex, NOT (status is closed AND value under 1000) * ```ts * import { NotExpression, Operator } from '@limetech/lime-web-components'; * * const notSmallAndClosed: NotExpression = { * op: Operator.NOT, * exp: { * op: Operator.AND, * exp: [ * { key: 'status', op: Operator.EQUALS, exp: 'closed' }, * { key: 'value', op: Operator.LESS, exp: 1000 }, * ], * }, * }; * ``` * * @public * @group Query * @see {@link Expression} for the main expression type * @see {@link Operator.NOT} */ export type NotExpression = { /** * Negation operator. */ op: Operator.NOT; /** * Expression to negate. */ exp: Expression; }; /** * IN expression that checks if a property matches any object from a saved filter. * * Tests whether a property's value matches any object returned by executing * a named {@link Filter}. This is useful for filtering based on dynamic criteria * defined in saved filters, such as "deals owned by anyone in the sales team" * where the sales team is defined by a filter. * * The referenced filter is executed first, and the results are used as the * set of valid values for the IN comparison. * * @example Find deals owned by users matching the 'sales_team' filter * ```ts * import { InFilterExpression, Operator } from '@limetech/lime-web-components'; * * const ownedBySalesTeam: InFilterExpression = { * type: 'filter', * key: 'owner', * op: Operator.IN, * exp: 'sales_team', * }; * ``` * * @example Find companies related to deals matching a filter * ```ts * import { InFilterExpression, Operator } from '@limetech/lime-web-components'; * * const relatedToLargeActiveDeals: InFilterExpression = { * type: 'filter', * key: 'company', * op: Operator.IN, * exp: 'large_active_deals', * }; * ``` * * @example Complex, find contacts at companies in specific regions * ```ts * import { Expression, Operator } from '@limetech/lime-web-components'; * * const europeanDecisionMakers: Expression = { * op: Operator.AND, * exp: [ * { * type: 'filter', * key: 'company', * op: Operator.IN, * exp: 'european_companies', * }, * { key: 'role', op: Operator.EQUALS, exp: 'decision_maker' }, * ], * }; * ``` * * @public * @group Query * @see {@link Expression} for the main expression type * @see {@link InExpression} for checking against a static list of values * @see {@link Filter} for saved filter definitions * @see {@link Operator.IN} */ export type InFilterExpression = { /** * Discriminator identifying this as a filter-based IN expression. */ type: 'filter'; /** * Name of the property to check. */ key: string; /** * IN operator. */ op: Operator.IN; /** * Name of the saved filter whose results define the valid values. */ exp: string; }; /** * IN expression that checks if a property matches any value in a list. * * Tests whether a property's value equals any value in an array of possible values. * This is more efficient than using multiple OR expressions when checking against * multiple possible values. * * Equivalent to SQL's `WHERE property IN (value1, value2, value3)` or multiple * OR conditions like `property = value1 OR property = value2 OR property = value3`. * * @example Find deals in multiple status values * ```ts * import { InExpression, Operator } from '@limetech/lime-web-components'; * * const stillInProgress: InExpression = { * key: 'status', * op: Operator.IN, * exp: ['open', 'in_progress', 'waiting_for_approval'], * }; * ``` * * @example Find companies in specific cities * ```ts * import { InExpression, Operator } from '@limetech/lime-web-components'; * * const inMajorCities: InExpression = { * key: 'city', * op: Operator.IN, * exp: ['Stockholm', 'Gothenburg', 'Malmö'], * }; * ``` * * @example Find objects with specific IDs * ```ts * import { InExpression, Operator } from '@limetech/lime-web-components'; * * const specificIds: InExpression = { * key: 'id', * op: Operator.IN, * exp: [123, 456, 789], * }; * ``` * * @example Combine with AND, active deals owned by specific users * ```ts * import { Expression, Operator } from '@limetech/lime-web-components'; * * const activeAndOwnedBySpecificUsers: Expression = { * op: Operator.AND, * exp: [ * { key: 'status', op: Operator.EQUALS, exp: 'active' }, * { key: 'owner', op: Operator.IN, exp: [101, 102, 103] }, * ], * }; * ``` * * @public * @group Query * @see {@link Expression} for the main expression type * @see {@link InFilterExpression} for checking against filter results * @see {@link Operator.IN} * @see {@link ExpressionValue} for allowed value types */ export type InExpression = { /** * Name of the property to check. */ key: string; /** * IN operator. */ op: Operator.IN; /** * Array of possible values to match against. */ exp: ExpressionValue[]; }; /** * Basic comparison expression for filtering on a single property. * * Compares a property's value against a constant value using comparison operators * like equals, greater than, less than, or text matching operators like LIKE and BEGINS. * * This is the most common expression type, used for simple filters like "status = 'active'" * or "value > 10000". Can be combined with {@link AndOrExpression} to build complex filters. * * @example Equality check * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const statusIsActive: BasicExpression = { * key: 'status', * op: Operator.EQUALS, * exp: 'active', * }; * ``` * * @example Numeric comparison * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const worthAtLeast50k: BasicExpression = { * key: 'value', * op: Operator.GREATER_OR_EQUAL, * exp: 50_000, * }; * ``` * * @example Text contains a fragment, pass it on its own * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const nameContainsAcme: BasicExpression = { * key: 'name', * op: Operator.LIKE, * exp: 'Acme', * }; * ``` * * @example Starts with text * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const supportAddress: BasicExpression = { * key: 'email', * op: Operator.BEGINS, * exp: 'support@', * }; * ``` * * @example Boolean check * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const isActive: BasicExpression = { * key: 'is_active', * op: Operator.EQUALS, * exp: true, * }; * ``` * * @example Null check * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const notYetClosed: BasicExpression = { * key: 'closed_date', * op: Operator.EQUALS, * exp: null, * }; * ``` * * @public * @group Query * @see {@link Expression} for the main expression type * @see {@link BasicOperator} for available comparison operators * @see {@link ExpressionValue} for allowed value types */ export type BasicExpression = { /** * Name of the property to compare. */ key: string; /** * Comparison operator to use. */ op: BasicOperator; /** * Value to compare against. */ exp: ExpressionValue; }; /** * Comparison operators for {@link BasicExpression}. * * Defines the set of operators that can be used in basic property comparisons. * Includes numeric comparisons (`=`, `!=`, `<`, `>`, `<=`, `>=`) and text matching operators * (BEGINS, LIKE, ENDS). * * @public * @group Query * @see {@link BasicExpression} for usage examples * @see {@link Operator} for the full operator enum */ export type BasicOperator = Operator.EQUALS | Operator.NOT_EQUALS | Operator.GREATER | Operator.LESS | Operator.BEGINS | Operator.LIKE | Operator.LESS_OR_EQUAL | Operator.GREATER_OR_EQUAL | Operator.ENDS; /** * Allowed value types for expression comparisons. * * Property values in expressions can be strings, numbers, booleans, or null. * The type must match the property's data type in the limetype schema. * * @example The four allowed value types * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const stringValue: BasicExpression = { * key: 'status', * op: Operator.EQUALS, * exp: 'active', * }; * * const numberValue: BasicExpression = { * key: 'value', * op: Operator.GREATER, * exp: 50_000, * }; * * const booleanValue: BasicExpression = { * key: 'is_archived', * op: Operator.EQUALS, * exp: false, * }; * * const nullValue: BasicExpression = { * key: 'closed_date', * op: Operator.EQUALS, * exp: null, * }; * ``` * * @public * @group Query * @see {@link BasicExpression} * @see {@link InExpression} */ export type ExpressionValue = string | number | boolean | null; /** * Operators for building filter expressions in Lime CRM queries. * * The {@link Operator} enum defines all available operators for constructing * {@link Expression}s. Operators are divided into four categories: * * 1. **Logical operators** - Combine multiple expressions (AND, OR, NOT) * 2. **Comparison operators** - Compare property values (`=`, `!=`, `<`, `>`, `<=`, `>=`) * 3. **Text operators** - Match part of a text value (BEGINS, LIKE, ENDS) * 4. **Membership operator** - Check against multiple values (IN) * * The same operators are used in filters the server evaluates, such as * {@link Query.filter} and {@link LoadOptions.filter}, and in filters the web * client evaluates locally against an object it has already loaded. The two do * not compare text the same way. The client ignores case, while the server * compares as the database does. Treat case sensitivity as unspecified and do * not build logic that depends on it. * * Each operator carries its own example below. This one shows what a single * member cannot, how the categories combine into one filter. * * @example Complex real-world example, find high-priority open deals * ```ts * import { Expression, Operator } from '@limetech/lime-web-components'; * * const highPriorityOpenDeals: Expression = { * op: Operator.AND, * exp: [ * { * op: Operator.OR, * exp: [ * { key: 'status', op: Operator.EQUALS, exp: 'open' }, * { key: 'status', op: Operator.EQUALS, exp: 'in_progress' }, * ], * }, * { key: 'value', op: Operator.GREATER_OR_EQUAL, exp: 100_000 }, * { key: 'company.name', op: Operator.LIKE, exp: 'Tech' }, * { * op: Operator.NOT, * exp: { key: 'is_archived', op: Operator.EQUALS, exp: true }, * }, * ], * }; * ``` * * @public * @group Query * @see {@link Expression} for building filter expressions * @see {@link BasicExpression} for simple comparisons * @see {@link AndOrExpression} for combining expressions * @see {@link NotExpression} for negation * @see {@link InExpression} for list membership */ export declare enum Operator { /** * Logical AND: All sub-expressions must be true. * * Used in {@link AndOrExpression} to require all conditions to match. * * @example Active deals worth over $50k * ```ts * import { AndOrExpression, Operator } from '@limetech/lime-web-components'; * * const activeAndWorthOver50k: AndOrExpression = { * op: Operator.AND, * exp: [ * { key: 'status', op: Operator.EQUALS, exp: 'active' }, * { key: 'value', op: Operator.GREATER, exp: 50_000 }, * ], * }; * ``` */ AND = "AND", /** * Logical OR: At least one sub-expression must be true. * * Used in {@link AndOrExpression} to match if any condition is true. * * @example Urgent or high priority * ```ts * import { AndOrExpression, Operator } from '@limetech/lime-web-components'; * * const urgentOrHighPriority: AndOrExpression = { * op: Operator.OR, * exp: [ * { key: 'priority', op: Operator.EQUALS, exp: 'urgent' }, * { key: 'priority', op: Operator.EQUALS, exp: 'high' }, * ], * }; * ``` */ OR = "OR", /** * Logical NOT: Inverts the result of an expression. * * Used in {@link NotExpression} to exclude matching objects. The `exp` must * be another expression. To negate a single comparison, use * {@link Operator.NOT_EQUALS} rather than wrapping it in a NOT. * * @example Exclude closed deals * ```ts * import { NotExpression, Operator } from '@limetech/lime-web-components'; * * const notClosed: NotExpression = { * op: Operator.NOT, * exp: { key: 'status', op: Operator.EQUALS, exp: 'closed' }, * }; * ``` */ NOT = "!", /** * Equality operator: Property equals value. * * Matches objects where the property equals the specified value. Works with * strings, numbers, booleans, and null. * * When the web client evaluates the filter and the property holds several * values, such as a relation, the comparison matches if any one of them * equals the value. * * @example Status equals 'active' * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const statusIsActive: BasicExpression = { * key: 'status', * op: Operator.EQUALS, * exp: 'active', * }; * ``` */ EQUALS = "=", /** * Inequality operator: Property does not equal value. * * Matches objects where the property is not equal to the specified value. * * @example Status is not 'closed' * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const statusIsNotClosed: BasicExpression = { * key: 'status', * op: Operator.NOT_EQUALS, * exp: 'closed', * }; * ``` */ NOT_EQUALS = "!=", /** * Greater than operator: Property is greater than value. * * Matches objects where the property value is strictly greater than * the specified value. Works with numbers and with dates. * * @example Value over 50000 * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const worthOver50k: BasicExpression = { * key: 'value', * op: Operator.GREATER, * exp: 50_000, * }; * ``` */ GREATER = ">", /** * Less than operator: Property is less than value. * * Matches objects where the property value is strictly less than * the specified value. Works with numbers and with dates. * * @example Value under 1000 * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const worthUnder1k: BasicExpression = { * key: 'value', * op: Operator.LESS, * exp: 1000, * }; * ``` */ LESS = "<", /** * Membership operator: Property matches any value in a list or filter. * * Used in {@link InExpression} to check if property equals any value * in an array, or in {@link InFilterExpression} to check against * results from a saved filter. Each value in the list is compared the same * way {@link Operator.EQUALS} compares one. * * @example Check against a value list or against a filter * ```ts * import { * InExpression, * InFilterExpression, * Operator, * } from '@limetech/lime-web-components'; * * const inValueList: InExpression = { * key: 'status', * op: Operator.IN, * exp: ['open', 'in_progress', 'waiting'], * }; * * const inFilterResult: InFilterExpression = { * type: 'filter', * key: 'owner', * op: Operator.IN, * exp: 'sales_team_filter', * }; * ``` */ IN = "IN", /** * Text operator: Property begins with value. * * Matches objects where the text property starts with the specified value. * The operator already decides where the value has to appear, so pass the * fragment on its own rather than a pattern. * * @example Email starts with a support prefix * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const supportAddress: BasicExpression = { * key: 'email', * op: Operator.BEGINS, * exp: 'support@', * }; * ``` */ BEGINS = "=?", /** * Text operator: Property contains value. * * Matches objects where the text property contains the specified value * anywhere in the string. The operator already decides where the value has * to appear, so pass the fragment on its own rather than a pattern. * * @example Name contains 'Acme' * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const nameContainsAcme: BasicExpression = { * key: 'name', * op: Operator.LIKE, * exp: 'Acme', * }; * ``` */ LIKE = "?", /** * Less than or equal operator: Property is less than or equal to value. * * Matches objects where the property value is less than or equal to * the specified value. * * @example Age up to 30 * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const upToThirty: BasicExpression = { * key: 'age', * op: Operator.LESS_OR_EQUAL, * exp: 30, * }; * ``` */ LESS_OR_EQUAL = "<=", /** * Greater than or equal operator: Property is greater than or equal to value. * * Matches objects where the property value is greater than or equal to * the specified value. * * @example Value of at least 50000 * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const worthAtLeast50k: BasicExpression = { * key: 'value', * op: Operator.GREATER_OR_EQUAL, * exp: 50_000, * }; * ``` */ GREATER_OR_EQUAL = ">=", /** * Text operator: Property ends with value. * * Matches objects where the text property ends with the specified value. * The operator already decides where the value has to appear, so pass the * fragment on its own rather than a pattern. * * @example Email ends with the acme.com domain * ```ts * import { BasicExpression, Operator } from '@limetech/lime-web-components'; * * const acmeAddress: BasicExpression = { * key: 'email', * op: Operator.ENDS, * exp: '@acme.com', * }; * ``` */ ENDS = "=$" } /** * Saved filter definition for a limetype. * * A {@link Filter} represents a named, reusable filter that can be applied to objects * of a specific limetype. Filters are typically created by users or administrators * and can be referenced by name in {@link InFilterExpression}s or used directly * to query objects. * * Filters have multi-language names and descriptions, and can be either system-wide * or user-specific (when iduser is set). * * @example Filter definition, active high-value deals * ```ts * import { Filter, Operator } from '@limetech/lime-web-components'; * * const highValueDeals: Filter = { * id: 'high_value_deals', * limetype: 'deal', * name: { en: 'High Value Deals', sv: 'Höga affärer' }, * description: { en: 'Active deals worth more than $100,000' }, * filter: { * op: Operator.AND, * exp: [ * { key: 'status', op: Operator.EQUALS, exp: 'active' }, * { key: 'value', op: Operator.GREATER_OR_EQUAL, exp: 100_000 }, * ], * }, * }; * ``` * * @example Using a filter in an IN expression * ```ts * import { InFilterExpression, Operator } from '@limetech/lime-web-components'; * * const ownedBySalesTeam: InFilterExpression = { * type: 'filter', * key: 'owner', * op: Operator.IN, * exp: 'sales_team', * }; * ``` * * @public * @group Query * @see {@link Expression} for filter expressions * @see {@link InFilterExpression} for referencing filters in queries */ export interface Filter { /** * Unique identifier for this filter. */ id: string; /** * Name of the limetype this filter applies to. */ limetype: string; /** * Display name in different languages. * * Keys are language codes (e.g., 'en', 'sv'), values are translated names. */ name: { [language: string]: string; }; /** * Filter expression that defines the matching criteria. * * @see {@link Expression} */ filter: Expression; /** * Optional description in different languages. * * Keys are language codes (e.g., 'en', 'sv'), values are translated descriptions. */ description?: { [language: string]: string; }; /** * Optional user ID if this is a personal filter. * * If set, this filter is private to a specific user. If undefined, * the filter is available system-wide. */ iduser?: number; } /** * Aggregate operators for calculating summary statistics on object collections. * * The {@link AggregateOperator} object defines operators for aggregating numeric * property values across multiple objects. These are used in queries to calculate * totals, averages, counts, and min/max values. * * Available operators: * - **Group** - Group the result by a property * - **Count** - Count the number of objects * - **Sum** - Sum all values * - **Average** - Calculate mean value * - **Maximum** - Find highest value * - **Minimum** - Find lowest value * * Used in: * - {@link QueryResponseFormat.aggregates} for QueryService * - {@link AggregateProperty} for LimeObjectRepository * * @example Count total number of deals * ```ts * import { * AggregateOperator, * PlatformServiceName, * Query, * } from '@limetech/lime-web-components'; * * const queryService = platform.get(PlatformServiceName.Query); * * const query = { * limetype: 'deal', * responseFormat: { * aggregates: { * totals: { total_count: { op: AggregateOperator.Count } }, * }, * }, * } satisfies Query; * * const response = await queryService.execute(query); * const [totals] = response.aggregates.totals; * * console.log(`${totals?.total_count} deals`); * ``` * * @example Calculate total and average deal value * ```ts * import { * AggregateOperator, * Operator, * PlatformServiceName, * Query, * } from '@limetech/lime-web-components'; * * const queryService = platform.get(PlatformServiceName.Query); * * const query = { * limetype: 'deal', * filter: { key: 'status', op: Operator.EQUALS, exp: 'active' }, * responseFormat: { * aggregates: { * totals: { * total_value: { op: AggregateOperator.Sum, key: 'value' }, * average_value: { op: AggregateOperator.Average, key: 'value' }, * }, * }, * }, * } satisfies Query; * * const response = await queryService.execute(query); * * const [totals] = response.aggregates.totals; * console.log(totals?.total_value); * console.log(totals?.average_value); * ``` * * @example One row per deal status, with its highest and lowest value * ```ts * import { * AggregateOperator, * PlatformServiceName, * Query, * } from '@limetech/lime-web-components'; * * const queryService = platform.get(PlatformServiceName.Query); * * const query = { * limetype: 'deal', * responseFormat: { * aggregates: { * by_status: { * status: { op: AggregateOperator.Group, key: 'dealstatus' }, * highest_deal: { op: AggregateOperator.Maximum, key: 'value' }, * lowest_deal: { op: AggregateOperator.Minimum, key: 'value' }, * }, * }, * }, * } satisfies Query; * * const response = await queryService.execute(query); * * for (const row of response.aggregates.by_status) { * console.log(`${row.status}: ${row.lowest_deal} - ${row.highest_deal}`); * } * ``` * * @public * @group Query * @see {@link Query} for query configuration * @see {@link AggregateColumn} for the shape of a single aggregate column * @see {@link AggregateProperty} for aggregate properties in LoadOptions */ export declare const AggregateOperator: { /** * Group the result by a property. * * Produces one response row per distinct value of the grouped property, * instead of a single row for the whole result. */ readonly Group: "GROUP"; /** * Count the number of objects. * * Returns the total count of objects matching the query filter. */ readonly Count: "COUNT"; /** * Sum all values of a numeric property. * * Calculates the sum of all values for the specified property * across all matching objects. */ readonly Sum: "SUM"; /** * Calculate average (mean) value of a numeric property. * * Computes the arithmetic mean of the property values * across all matching objects. */ readonly Average: "AVG"; /** * Find the maximum value of a numeric property. * * Returns the highest value found for the specified property * among all matching objects. */ readonly Maximum: "MAX"; /** * Find the minimum value of a numeric property. * * Returns the lowest value found for the specified property * among all matching objects. */ readonly Minimum: "MIN"; }; /** * Type representing valid aggregate operator values. * * @public * @group Query * @see {@link AggregateOperator} for the operator definitions */ export type AggregateOperator = (typeof AggregateOperator)[keyof typeof AggregateOperator];