Skip to content
← Public packages

@kody/salesforce

Salesforce REST helpers for identity, SOQL, multi-org routing, and error investigation.

src/query.ts

72 lines · 2.3 KB · TypeScript
import { salesforceJson } from './request.ts'
import type { JsonRecord } from './types.ts'
import { optionalString, requireRecord, requireString } from './types.ts'

export type QueryInput = {
	/** SOQL query string. */
	q: string
	/** Continue a previous query from `nextRecordsUrl` or a query locator path. */
	nextRecordsUrl?: string
	instanceUrl?: string
	apiVersion?: string
	/** Saved OAuth integration name. Defaults to `salesforce`. */
	integrationName?: string
}

export type QueryResult = {
	totalSize: number
	done: boolean
	nextRecordsUrl?: string
	records: JsonRecord[]
	[key: string]: unknown
}

/**
 * Run a SOQL query or continue pagination with `nextRecordsUrl`.
 * @param input.q - SOQL query string.
 * @param input.nextRecordsUrl - Optional pagination URL from a prior page.
 * @returns Query page with records and pagination fields.
 * @example
 * import query from 'kody:@kody/salesforce/query'
 * const page = await query({
 *   q: 'SELECT Id, Name FROM Account ORDER BY LastModifiedDate DESC LIMIT 20',
 * })
 */
export async function query(input: QueryInput): Promise<QueryResult> {
	const nextRecordsUrl = optionalString(input.nextRecordsUrl, 'nextRecordsUrl')
	if (nextRecordsUrl) {
		return salesforceJson<QueryResult>({
			path: nextRecordsUrl,
			method: 'GET',
			instanceUrl: optionalString(input.instanceUrl, 'instanceUrl'),
			apiVersion: optionalString(input.apiVersion, 'apiVersion'),
			integrationName: optionalString(input.integrationName, 'integrationName'),
		})
	}

	const q = requireString(input.q, 'q')
	return salesforceJson<QueryResult>({
		path: 'query',
		method: 'GET',
		query: { q },
		instanceUrl: optionalString(input.instanceUrl, 'instanceUrl'),
		apiVersion: optionalString(input.apiVersion, 'apiVersion'),
		integrationName: optionalString(input.integrationName, 'integrationName'),
	})
}

/**
 * Run a SOQL query or continue pagination with `nextRecordsUrl`.
 * @example
 * import query from 'kody:@kody/salesforce/query'
 * const page = await query({
 *   q: 'SELECT Id, Name FROM Account ORDER BY LastModifiedDate DESC LIMIT 20',
 * })
 */
export default async function queryEntrypoint(
	params: Partial<QueryInput> & Record<string, unknown> = {},
) {
	const input = requireRecord(params, 'query') as QueryInput
	if (!input.nextRecordsUrl) requireString(input.q, 'q')
	return query(input)
}