UNPKG

@jsforce/jsforce-node

Version:

Salesforce API Library for JavaScript

342 lines (341 loc) 13.1 kB
/// <reference types="node" /> /// <reference types="node" /> /// <reference types="node" /> /** * @file Manages query for records in Salesforce * @author Shinichi Tomita <shinichi.tomita@gmail.com> */ 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<S extends Schema, N extends SObjectNames<S>, FP extends FieldPathSpecifier<S, N> = FieldPathSpecifier<S, N>> = FP | FP[] | string | string[] | { [field: string]: number | boolean; }; /** * */ type CValue<T> = T extends DateString ? SfDate : T extends string | number | boolean ? T : never; type CondOp<T> = ['$eq', CValue<T> | null] | ['$ne', CValue<T> | null] | ['$gt', CValue<T>] | ['$gte', CValue<T>] | ['$lt', CValue<T>] | ['$lte', CValue<T>] | ['$like', T extends string ? T : never] | ['$nlike', T extends string ? T : never] | ['$in', Array<CValue<T>>] | ['$nin', Array<CValue<T>>] | ['$includes', T extends string ? T[] : never] | ['$excludes', T extends string ? T[] : never] | ['$exists', boolean]; type CondValueObj<T, Op = CondOp<T>[0]> = Op extends CondOp<T>[0] ? Op extends string ? { [K in Op]: Extract<CondOp<T>, [Op, any]>[1]; } : never : never; type CondValue<T> = CValue<T> | Array<CValue<T>> | null | CondValueObj<T>; type ConditionSet<R extends Record> = { [K in keyof R]?: CondValue<R[K]>; }; export type QueryCondition<S extends Schema, N extends SObjectNames<S>> = { $or: Array<QueryCondition<S, N>>; } | { $and: Array<QueryCondition<S, N>>; } | ConditionSet<SObjectRecord<S, N>>; export type QuerySort<S extends Schema, N extends SObjectNames<S>, R extends SObjectRecord<S, N> = SObjectRecord<S, N>> = { [K in keyof R]?: SortDir; } | Array<[keyof R, SortDir]>; /** * */ export type QueryConfig<S extends Schema, N extends SObjectNames<S>, FP extends FieldPathSpecifier<S, N> = FieldPathSpecifier<S, N>> = { fields?: QueryField<S, N, FP>; includes?: { [CRN in ChildRelationshipNames<S, N>]?: QueryConfig<S, ChildRelationshipSObjectName<S, N, CRN>>; }; table?: string; conditions?: QueryCondition<S, N>; sort?: QuerySort<S, N>; limit?: number; offset?: number; }; export type QueryOptions = { headers: { [name: string]: string; }; maxFetch: number; autoFetch: boolean; scanAll: boolean; responseTarget: QueryResponseTarget; }; export type QueryResult<R extends Record> = { 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<R extends Record, QRT extends QueryResponseTarget = QueryResponseTarget> = QRT extends 'QueryResult' ? QueryResult<R> : 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<S extends Schema, N extends SObjectNames<S>, R extends Record = Record, QRT extends QueryResponseTarget = QueryResponseTarget> extends EventEmitter { static _logger: Logger; _conn: Connection<S>; _logger: Logger; _soql: Optional<string>; _locator: Optional<string>; _config: SOQLQueryConfig; _children: Array<SubQuery<S, N, R, QRT, any, any, any>>; _options: QueryOptions; _executed: boolean; _finished: boolean; _chaining: boolean; _promise: Promise<QueryResponse<R, QRT>>; _stream: Serializable<R>; totalSize: number; totalFetched: number; records: R[]; /** * */ constructor(conn: Connection<S>, config: string | QueryConfig<S, N> | { locator: string; }, options?: Partial<QueryOptions>); /** * Select fields to include in the returning result */ select<R extends Record = Record, FP extends FieldPathSpecifier<S, N> = FieldPathSpecifier<S, N>, FPC extends FieldProjectionConfig = FieldPathScopedProjection<S, N, FP>, R2 extends SObjectRecord<S, N, FPC, R> = SObjectRecord<S, N, FPC, R>>(fields?: QueryField<S, N, FP>): Query<S, N, R2, QRT>; /** * Set query conditions to filter the result records */ where(conditions: QueryCondition<S, N> | 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<S, N> | string): this; sort(sort: SObjectFieldNames<S, N> | 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<CRN extends ChildRelationshipNames<S, N>, CN extends ChildRelationshipSObjectName<S, N, CRN>, CFP extends FieldPathSpecifier<S, CN> = FieldPathSpecifier<S, CN>, CFPC extends FieldProjectionConfig = FieldPathScopedProjection<S, CN, CFP>, CR extends Record = SObjectRecord<S, CN, CFPC>>(childRelName: CRN, conditions?: Optional<QueryCondition<S, CN>>, fields?: Optional<QueryField<S, CN, CFP>>, options?: { limit?: number; offset?: number; sort?: QuerySort<S, CN>; }): SubQuery<S, N, R, QRT, CRN, CN, CR>; include<CRN extends ChildRelationshipNames<S, N>, CN extends SObjectNames<S>, CR extends Record = SObjectRecord<S, CN>>(childRelName: string, conditions?: Optional<QueryCondition<S, CN>>, fields?: Optional<QueryField<S, CN>>, options?: { limit?: number; offset?: number; sort?: QuerySort<S, CN>; }): SubQuery<S, N, R, QRT, CRN, CN, CR>; /** * Include child relationship queries, but not moving down to the children context */ includeChildren(includes: { [CRN in ChildRelationshipNames<S, N>]?: QueryConfig<S, ChildRelationshipSObjectName<S, N, CRN>>; }): 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<QRT1 extends QueryResponseTarget>(responseTarget: QRT1): Query<S, N, R, QRT1>; /** * Execute query and fetch records from server. */ execute<QRT1 extends QueryResponseTarget = QRT>(options_?: Partial<QueryOptions> & { responseTarget?: QRT1; }): Query<S, N, R, QRT1>; /** * Synonym of Query#execute() */ exec: <QRT1 extends "Records" | "QueryResult" | "SingleRecord" | "Count" = QRT>(options_?: Partial<QueryOptions> & { responseTarget?: QRT1 | undefined; }) => Query<S, N, R, QRT1>; /** * Synonym of Query#execute() */ run: <QRT1 extends "Records" | "QueryResult" | "SingleRecord" | "Count" = QRT>(options_?: Partial<QueryOptions> & { responseTarget?: QRT1 | undefined; }) => Query<S, N, R, QRT1>; private locatorToUrl; private urlToLocator; private constructResponse; /** * @private */ _execute(options: QueryOptions): Promise<QueryResponse<R>>; /** * Obtain readable stream instance */ stream(type: 'record'): Serializable<R>; 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<void>; /** * */ _findRelationObject(relName: string): Promise<string>; /** * */ _expandAsteriskFields(sobject: string, fields: string[]): Promise<string[]>; /** * */ _expandAsteriskField(sobject: string, field: string): Promise<string[]>; /** * Explain plan for executing query */ explain(): Promise<QueryExplainResult>; /** * Return SOQL expression for the query */ toSOQL(): Promise<string>; /** * Promise/A+ interface * http://promises-aplus.github.io/promises-spec/ * * Delegate to deferred promise, return promise instance for query result */ then<U, V>(onResolve?: ((qr: QueryResponse<R, QRT>) => U | Promise<U>) | null | undefined, onReject?: ((err: Error) => V | Promise<V>) | null | undefined): Promise<U | V>; catch(onReject: (err: Error) => QueryResponse<R, QRT> | Promise<QueryResponse<R, QRT>>): Promise<QueryResponse<R, QRT>>; promise(): Promise<QueryResponse<R, QRT>>; /** * Bulk delete queried records */ destroy(options?: QueryDestroyOptions): Promise<SaveResult[]>; destroy(type: N, options?: QueryDestroyOptions): Promise<SaveResult[]>; /** * Synonym of Query#destroy() */ delete: { (options?: QueryDestroyOptions | undefined): Promise<SaveResult[]>; (type: N, options?: QueryDestroyOptions | undefined): Promise<SaveResult[]>; }; /** * Synonym of Query#destroy() */ del: { (options?: QueryDestroyOptions | undefined): Promise<SaveResult[]>; (type: N, options?: QueryDestroyOptions | undefined): Promise<SaveResult[]>; }; /** * Bulk update queried records, using given mapping function/object */ update<UR extends SObjectInputRecord<S, N>>(mapping: ((rec: R) => UR) | UR, type: N, options?: QueryUpdateOptions): Promise<SaveResult[]>; update<UR extends SObjectInputRecord<S, N>>(mapping: ((rec: R) => UR) | UR, options?: QueryUpdateOptions): Promise<SaveResult[]>; private mapBulkV2ResultsToSaveResults; } /** * SubQuery object for representing child relationship query */ export declare class SubQuery<S extends Schema, PN extends SObjectNames<S>, PR extends Record, PQRT extends QueryResponseTarget, CRN extends ChildRelationshipNames<S, PN> = ChildRelationshipNames<S, PN>, CN extends SObjectNames<S> = ChildRelationshipSObjectName<S, PN, CRN>, CR extends Record = Record> { _relName: CRN; _query: Query<S, CN, CR>; _parent: Query<S, PN, PR, PQRT>; /** * */ constructor(conn: Connection<S>, relName: CRN, config: QueryConfig<S, CN>, parent: Query<S, PN, PR, PQRT>); /** * */ select<R extends Record = Record, FP extends FieldPathSpecifier<S, CN> = FieldPathSpecifier<S, CN>, FPC extends FieldProjectionConfig = FieldPathScopedProjection<S, CN, FP>>(fields: QueryField<S, CN, FP>): SubQuery<S, PN, PR, PQRT, CRN, CN, SObjectRecord<S, CN, FPC, R>>; /** * */ where(conditions: QueryCondition<S, CN> | 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<S, CN>): this; sort(sort: string | SObjectFieldNames<S, CN>, dir: SortDir): this; /** * Synonym of SubQuery#sort() */ orderby: typeof SubQuery.prototype.sort; /** * */ _expandFields(): Promise<void>; /** * Back the context to parent query object */ end<CRP extends SObjectChildRelationshipProp<CRN, CR> = SObjectChildRelationshipProp<CRN, CR>, PR1 extends Record = PR & CRP>(): Query<S, PN, PR1, PQRT>; } export default Query;