Kysoql
Reference

Schema and result types

Understand generated Salesforce metadata and infer query result types.

For application code, prefer a schema generated by @kysoql/codegen. It reflects the objects, fields, relationships, and capabilities visible to the Salesforce identity used during generation.

Use the generated schema

import { Kysoql } from "@kysoql/core";
import type { SalesforceSchema } from "./kysoql/salesforce.generated";

export const db = new Kysoql<SalesforceSchema>();

The schema is a TypeScript snapshot, not a live permission check. Regenerate it when the Salesforce shape you rely on changes.

Handwritten schemas

Handwritten schemas are useful for small examples and isolated tests:

import {
  Kysoql,
  type SalesforceField,
  type SalesforceObject,
} from "@kysoql/core";

interface DemoSchema {
  readonly Account: SalesforceObject<{
    readonly Id: SalesforceField<string, {
      readonly salesforceType: "id";
      readonly nullable: false;
      readonly filterable: true;
      readonly sortable: true;
      readonly groupable: true;
      readonly aggregatable: true;
    }>;
    readonly Name: SalesforceField<string, {
      readonly salesforceType: "string";
      readonly nullable: false;
      readonly filterable: true;
      readonly sortable: true;
      readonly groupable: true;
    }>;
  }>;
}

const db = new Kysoql<DemoSchema>();
const query = db.selectFrom("Account").select(["Id", "Name"]).limit(10);

console.log(query.compile().soql);

Do not copy guessed capabilities into a production schema. A field marked filterable or groupable in TypeScript can still be rejected by Salesforce if the metadata is wrong or stale.

Field metadata

SalesforceField<Value, Metadata> carries the field value type plus the capabilities Kysoql needs while building a query.

PropertyWhat it controls
salesforceTypeSalesforce field type such as id, currency, or datetime
nullableWhether the value can be null
filterableUse in typed WHERE expressions
sortableUse in ORDER BY
groupableUse in GROUP BY
aggregatableUse with supported aggregate functions
customStandard or custom grouping for FIELDS(...)
polymorphicSupported polymorphic relationship paths
referenceTo, relationshipNameParent relationship metadata
activePicklistValueActive multipicklist values used by typed filters

Codegen maps Salesforce values to useful TypeScript types. Numeric fields become number, booleans become boolean, common text and temporal fields become string, and geolocation uses SalesforceGeolocation. Nullability is added from the field metadata.

Object metadata

SalesforceObject also carries relationship and object-level capabilities such as scopes, Knowledge data categories, MRU support, Data 360 options, and whether the generated field list is complete.

A schema generated with an explicit field rule marks that object as incomplete. Kysoql then disables selectFields(...) for the object because Salesforce expands FIELDS(...) from live metadata, not from your generated subset. Explicit .select(...) calls continue to work normally.

Useful exported types

TypeUse
SalesforceFieldValue<Field>Returned field value with nullability
SalesforceFieldFilterValue<Field>Value accepted by typed filters
SalesforceRow<Object>All direct fields on an object
SalesforceQueryResult<Row>Salesforce query envelope with records and paging metadata
SalesforceGeolocation{ latitude, longitude }
CompiledQuery<Output>Compiled SOQL with a type-only output carrier

Infer result types from the query

Avoid maintaining a second interface for selected rows when TypeScript can infer it from the query itself:

import { db } from "./db";

export function loadAccountNames() {
  return db.selectFrom("Account").select(["Id", "Name"]).limit(100).execute();
}

export type AccountNames = Awaited<ReturnType<typeof loadAccountNames>>;
export type AccountName = AccountNames[number];

The inferred type describes the expected result shape. It does not deeply validate or freeze values returned by an external transport at runtime.

On this page