/// /// /// /** * @file Manages query for records in Salesforce * @author Shinichi Tomita */ import { EventEmitter } from 'events'; import { Logger } from './util/logger'; import { Serializable } from './record-stream'; import Connection from './connection'; import { QueryConfig as SOQLQueryConfig, SortDir } from './soql-builder'; import { Record, Optional, Schema, SObjectNames, ChildRelationshipNames, ChildRelationshipSObjectName, FieldProjectionConfig, FieldPathSpecifier, FieldPathScopedProjection, SObjectRecord, SObjectInputRecord, SaveResult, DateString, SObjectChildRelationshipProp, SObjectFieldNames } from './types'; import { Readable } from 'stream'; import SfDate from './date'; /** * */ export type QueryField, FP extends FieldPathSpecifier = FieldPathSpecifier> = FP | FP[] | string | string[] | { [field: string]: number | boolean; }; /** * */ type CValue = T extends DateString ? SfDate : T extends string | number | boolean ? T : never; type CondOp = ['$eq', CValue | null] | ['$ne', CValue | null] | ['$gt', CValue] | ['$gte', CValue] | ['$lt', CValue] | ['$lte', CValue] | ['$like', T extends string ? T : never] | ['$nlike', T extends string ? T : never] | ['$in', Array>] | ['$nin', Array>] | ['$includes', T extends string ? T[] : never] | ['$excludes', T extends string ? T[] : never] | ['$exists', boolean]; type CondValueObj[0]> = Op extends CondOp[0] ? Op extends string ? { [K in Op]: Extract, [Op, any]>[1]; } : never : never; type CondValue = CValue | Array> | null | CondValueObj; type ConditionSet = { [K in keyof R]?: CondValue; }; export type QueryCondition> = { $or: Array>; } | { $and: Array>; } | ConditionSet>; export type QuerySort, R extends SObjectRecord = SObjectRecord> = { [K in keyof R]?: SortDir; } | Array<[keyof R, SortDir]>; /** * */ export type QueryConfig, FP extends FieldPathSpecifier = FieldPathSpecifier> = { fields?: QueryField; includes?: { [CRN in ChildRelationshipNames]?: QueryConfig>; }; table?: string; conditions?: QueryCondition; sort?: QuerySort; limit?: number; offset?: number; }; export type QueryOptions = { headers: { [name: string]: string; }; maxFetch: number; autoFetch: boolean; scanAll: boolean; responseTarget: QueryResponseTarget; }; export type QueryResult = { done: boolean; totalSize: number; records: R[]; nextRecordsUrl?: string; }; export type QueryExplainResult = { plans: Array<{ cardinality: number; fields: string[]; leadingOperationType: 'Index' | 'Other' | 'Sharing' | 'TableScan'; notes: Array<{ description: string; fields: string[]; tableEnumOrId: string; }>; relativeCost: number; sobjectCardinality: number; sobjectType: string; }>; }; declare const ResponseTargetValues: readonly ["QueryResult", "Records", "SingleRecord", "Count"]; export type QueryResponseTarget = typeof ResponseTargetValues[number]; export declare const ResponseTargets: { [K in QueryResponseTarget]: K; }; export type QueryResponse = QRT extends 'QueryResult' ? QueryResult : QRT extends 'Records' ? R[] : QRT extends 'SingleRecord' ? R | null : number; export type BulkApiVersion = 1 | 2; export type QueryDestroyOptions = { allowBulk?: boolean; bulkThreshold?: number; bulkApiVersion?: BulkApiVersion; }; export type QueryUpdateOptions = { allowBulk?: boolean; bulkThreshold?: number; bulkApiVersion?: BulkApiVersion; /** * Skip record template evaluation. */ skipRecordTemplateEval?: boolean; }; /** * Query */ export declare class Query, R extends Record = Record, QRT extends QueryResponseTarget = QueryResponseTarget> extends EventEmitter { static _logger: Logger; _conn: Connection; _logger: Logger; _soql: Optional; _locator: Optional; _config: SOQLQueryConfig; _children: Array>; _options: QueryOptions; _executed: boolean; _finished: boolean; _chaining: boolean; _promise: Promise>; _stream: Serializable; totalSize: number; totalFetched: number; records: R[]; /** * */ constructor(conn: Connection, config: string | QueryConfig | { locator: string; }, options?: Partial); /** * Select fields to include in the returning result */ select = FieldPathSpecifier, FPC extends FieldProjectionConfig = FieldPathScopedProjection, R2 extends SObjectRecord = SObjectRecord>(fields?: QueryField): Query; /** * Set query conditions to filter the result records */ where(conditions: QueryCondition | string): this; /** * Limit the returning result */ limit(limit: number): this; /** * Skip records */ skip(offset: number): this; /** * Synonym of Query#skip() */ offset: (offset: number) => this; /** * Set query sort with direction */ sort(sort: QuerySort | string): this; sort(sort: SObjectFieldNames | string, dir: SortDir): this; /** * Synonym of Query#sort() */ orderby: typeof Query.prototype.sort; /** * Include child relationship query and move down to the child query context */ include, CN extends ChildRelationshipSObjectName, CFP extends FieldPathSpecifier = FieldPathSpecifier, CFPC extends FieldProjectionConfig = FieldPathScopedProjection, CR extends Record = SObjectRecord>(childRelName: CRN, conditions?: Optional>, fields?: Optional>, options?: { limit?: number; offset?: number; sort?: QuerySort; }): SubQuery; include, CN extends SObjectNames, CR extends Record = SObjectRecord>(childRelName: string, conditions?: Optional>, fields?: Optional>, options?: { limit?: number; offset?: number; sort?: QuerySort; }): SubQuery; /** * Include child relationship queries, but not moving down to the children context */ includeChildren(includes: { [CRN in ChildRelationshipNames]?: QueryConfig>; }): this; /** * Setting maxFetch query option */ maxFetch(maxFetch: number): this; /** * Switching auto fetch mode */ autoFetch(autoFetch: boolean): this; /** * Set flag to scan all records including deleted and archived. */ scanAll(scanAll: boolean): this; /** * */ setResponseTarget(responseTarget: QRT1): Query; /** * Execute query and fetch records from server. */ execute(options_?: Partial & { responseTarget?: QRT1; }): Query; /** * Synonym of Query#execute() */ exec: (options_?: Partial & { responseTarget?: QRT1 | undefined; }) => Query; /** * Synonym of Query#execute() */ run: (options_?: Partial & { responseTarget?: QRT1 | undefined; }) => Query; private locatorToUrl; private urlToLocator; private constructResponse; /** * @private */ _execute(options: QueryOptions): Promise>; /** * Obtain readable stream instance */ stream(type: 'record'): Serializable; stream(type: 'csv'): Readable; /** * Pipe the queried records to another stream * This is for backward compatibility; Query is not a record stream instance anymore in 2.0. * If you want a record stream instance, use `Query#stream('record')`. */ pipe(stream: NodeJS.WritableStream): NodeJS.WritableStream; /** * @protected */ _expandFields(sobject_?: string): Promise; /** * */ _findRelationObject(relName: string): Promise; /** * */ _expandAsteriskFields(sobject: string, fields: string[]): Promise; /** * */ _expandAsteriskField(sobject: string, field: string): Promise; /** * Explain plan for executing query */ explain(): Promise; /** * Return SOQL expression for the query */ toSOQL(): Promise; /** * Promise/A+ interface * http://promises-aplus.github.io/promises-spec/ * * Delegate to deferred promise, return promise instance for query result */ then(onResolve?: ((qr: QueryResponse) => U | Promise) | null | undefined, onReject?: ((err: Error) => V | Promise) | null | undefined): Promise; catch(onReject: (err: Error) => QueryResponse | Promise>): Promise>; promise(): Promise>; /** * Bulk delete queried records */ destroy(options?: QueryDestroyOptions): Promise; destroy(type: N, options?: QueryDestroyOptions): Promise; /** * Synonym of Query#destroy() */ delete: { (options?: QueryDestroyOptions | undefined): Promise; (type: N, options?: QueryDestroyOptions | undefined): Promise; }; /** * Synonym of Query#destroy() */ del: { (options?: QueryDestroyOptions | undefined): Promise; (type: N, options?: QueryDestroyOptions | undefined): Promise; }; /** * Bulk update queried records, using given mapping function/object */ update>(mapping: ((rec: R) => UR) | UR, type: N, options?: QueryUpdateOptions): Promise; update>(mapping: ((rec: R) => UR) | UR, options?: QueryUpdateOptions): Promise; private mapBulkV2ResultsToSaveResults; /** * Fetches all records for a subquery field by following nextRecordsUrl * @private */ private _fetchAllSubqueryRecords; } /** * SubQuery object for representing child relationship query */ export declare class SubQuery, PR extends Record, PQRT extends QueryResponseTarget, CRN extends ChildRelationshipNames = ChildRelationshipNames, CN extends SObjectNames = ChildRelationshipSObjectName, CR extends Record = Record> { _relName: CRN; _query: Query; _parent: Query; /** * */ constructor(conn: Connection, relName: CRN, config: QueryConfig, parent: Query); /** * */ select = FieldPathSpecifier, FPC extends FieldProjectionConfig = FieldPathScopedProjection>(fields: QueryField): SubQuery>; /** * */ where(conditions: QueryCondition | string): this; /** * Limit the returning result */ limit(limit: number): this; /** * Skip records */ skip(offset: number): this; /** * Synonym of SubQuery#skip() */ offset: (offset: number) => this; /** * Set query sort with direction */ sort(sort: QuerySort): this; sort(sort: string | SObjectFieldNames, dir: SortDir): this; /** * Synonym of SubQuery#sort() */ orderby: typeof SubQuery.prototype.sort; /** * */ _expandFields(): Promise; /** * Back the context to parent query object */ end = SObjectChildRelationshipProp, PR1 extends Record = PR & CRP>(): Query; } export default Query;