@proofkit/fmodata
Version:
FileMaker OData API client
897 lines (896 loc) • 33.3 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import buildQuery from "odata-query";
import { validateSingleResponse, validateListResponse } from "../validation.js";
import { RecordCountMismatchError } from "../errors.js";
import { getTableIdentifiers, transformFieldName, transformOrderByField, transformFieldNamesArray, transformResponseFields } from "../transform.js";
class QueryBuilder {
constructor(config) {
__publicField(this, "queryOptions", {});
__publicField(this, "expandConfigs", []);
__publicField(this, "singleMode", false);
__publicField(this, "isCountMode", false);
__publicField(this, "occurrence");
__publicField(this, "tableName");
__publicField(this, "databaseName");
__publicField(this, "context");
__publicField(this, "isNavigate");
__publicField(this, "navigateRecordId");
__publicField(this, "navigateRelation");
__publicField(this, "navigateSourceTableName");
__publicField(this, "navigateBaseRelation");
__publicField(this, "databaseUseEntityIds");
this.occurrence = config.occurrence;
this.tableName = config.tableName;
this.databaseName = config.databaseName;
this.context = config.context;
this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;
}
/**
* Helper to merge database-level useEntityIds with per-request options
*/
mergeExecuteOptions(options) {
return {
...options,
useEntityIds: (options == null ? void 0 : options.useEntityIds) === void 0 ? this.databaseUseEntityIds : options.useEntityIds
};
}
/**
* Helper to conditionally strip OData annotations based on options
*/
stripODataAnnotationsIfNeeded(data, options) {
if ((options == null ? void 0 : options.includeODataAnnotations) === true) {
return data;
}
const { "@id": _id, "@editLink": _editLink, ...rest } = data;
return rest;
}
/**
* Gets the table ID (FMTID) if using entity IDs, otherwise returns the table name
* @param useEntityIds - Optional override for entity ID usage
*/
getTableId(useEntityIds) {
var _a, _b;
if (!this.occurrence) {
return this.tableName;
}
const contextDefault = ((_b = (_a = this.context)._getUseEntityIds) == null ? void 0 : _b.call(_a)) ?? false;
const shouldUseIds = useEntityIds ?? contextDefault;
if (shouldUseIds) {
const identifiers = getTableIdentifiers(this.occurrence);
if (!identifiers.id) {
throw new Error(
`useEntityIds is true but TableOccurrence "${identifiers.name}" does not have an fmtId defined`
);
}
return identifiers.id;
}
return this.occurrence.getTableName();
}
select(...fields) {
const uniqueFields = [...new Set(fields)];
const newBuilder = new QueryBuilder({
occurrence: this.occurrence,
tableName: this.tableName,
databaseName: this.databaseName,
context: this.context,
databaseUseEntityIds: this.databaseUseEntityIds
});
newBuilder.queryOptions = {
...this.queryOptions,
select: uniqueFields
};
newBuilder.expandConfigs = [...this.expandConfigs];
newBuilder.singleMode = this.singleMode;
newBuilder.isCountMode = this.isCountMode;
newBuilder.isNavigate = this.isNavigate;
newBuilder.navigateRecordId = this.navigateRecordId;
newBuilder.navigateRelation = this.navigateRelation;
newBuilder.navigateSourceTableName = this.navigateSourceTableName;
newBuilder.navigateBaseRelation = this.navigateBaseRelation;
return newBuilder;
}
/**
* Transforms our filter format to odata-query's expected format
* - Arrays of operators are converted to AND conditions
* - Single operator objects pass through as-is
* - Shorthand values are handled by odata-query
*/
transformFilter(filter) {
var _a;
if (typeof filter === "string") {
return filter;
}
if (Array.isArray(filter)) {
return filter.map((f) => this.transformFilter(f));
}
if ("and" in filter || "or" in filter || "not" in filter) {
const result2 = {};
if ("and" in filter && Array.isArray(filter.and)) {
result2.and = filter.and.map((f) => this.transformFilter(f));
}
if ("or" in filter && Array.isArray(filter.or)) {
result2.or = filter.or.map((f) => this.transformFilter(f));
}
if ("not" in filter && filter.not) {
result2.not = this.transformFilter(filter.not);
}
return result2;
}
const result = {};
const andConditions = [];
for (const [field, value] of Object.entries(filter)) {
const fieldId = ((_a = this.occurrence) == null ? void 0 : _a.baseTable) ? transformFieldName(field, this.occurrence.baseTable) : field;
if (Array.isArray(value)) {
if (value.length === 1) {
result[fieldId] = value[0];
} else {
for (const op of value) {
andConditions.push({ [fieldId]: op });
}
}
} else if (value && typeof value === "object" && !(value instanceof Date) && !Array.isArray(value)) {
const operatorKeys = [
"eq",
"ne",
"gt",
"ge",
"lt",
"le",
"contains",
"startswith",
"endswith",
"in"
];
const isOperatorObject = operatorKeys.some((key) => key in value);
if (isOperatorObject) {
result[fieldId] = value;
} else {
result[fieldId] = value;
}
} else {
result[fieldId] = value;
}
}
if (andConditions.length > 0) {
if (Object.keys(result).length > 0) {
return { and: [...andConditions, result] };
} else {
return { and: andConditions };
}
}
return result;
}
filter(filter) {
this.queryOptions.filter = this.transformFilter(filter);
return this;
}
orderBy(orderBy) {
var _a;
if (((_a = this.occurrence) == null ? void 0 : _a.baseTable) && orderBy) {
if (Array.isArray(orderBy)) {
this.queryOptions.orderBy = orderBy.map(
(field) => transformOrderByField(String(field), this.occurrence.baseTable)
);
} else {
this.queryOptions.orderBy = transformOrderByField(
String(orderBy),
this.occurrence.baseTable
);
}
} else {
this.queryOptions.orderBy = orderBy;
}
return this;
}
top(count) {
this.queryOptions.top = count;
return this;
}
skip(count) {
this.queryOptions.skip = count;
return this;
}
/**
* Formats select fields for use in query strings.
* - Transforms field names to FMFIDs if using entity IDs
* - Wraps "id" fields in double quotes
* - URL-encodes special characters but preserves spaces
*/
formatSelectFields(select, baseTable) {
if (!select) return "";
const selectFieldsArray = Array.isArray(select) ? select : [select];
const transformedFields = baseTable ? transformFieldNamesArray(
selectFieldsArray.map((f) => String(f)),
baseTable
) : selectFieldsArray.map((f) => String(f));
return transformedFields.map((field) => {
if (field === "id") return `"id"`;
const encodedField = encodeURIComponent(String(field));
return encodedField.replace(/%20/g, " ");
}).join(",");
}
/**
* Builds expand validation configs from internal expand configurations.
* These are used to validate expanded navigation properties.
*/
buildExpandValidationConfigs(configs) {
return configs.map((config) => {
var _a, _b, _c;
const targetOccurrence = (_a = this.occurrence) == null ? void 0 : _a.navigation[config.relation];
const targetSchema = (_b = targetOccurrence == null ? void 0 : targetOccurrence.baseTable) == null ? void 0 : _b.schema;
const selectedFields = ((_c = config.options) == null ? void 0 : _c.select) ? Array.isArray(config.options.select) ? config.options.select.map((f) => String(f)) : [String(config.options.select)] : void 0;
return {
relation: config.relation,
targetSchema,
targetOccurrence,
targetBaseTable: targetOccurrence == null ? void 0 : targetOccurrence.baseTable,
occurrence: targetOccurrence,
// Add occurrence for transformation
selectedFields,
nestedExpands: void 0
// TODO: Handle nested expands if needed
};
});
}
/**
* Builds OData expand query string from expand configurations.
* Handles nested expands recursively.
* Transforms relation names to FMTIDs if using entity IDs.
*/
buildExpandString(configs) {
if (configs.length === 0) {
return "";
}
return configs.map((config) => {
var _a;
const targetOccurrence = (_a = this.occurrence) == null ? void 0 : _a.navigation[config.relation];
const relationName = targetOccurrence && targetOccurrence.isUsingTableId() ? targetOccurrence.getTableId() : config.relation;
if (!config.options || Object.keys(config.options).length === 0) {
return relationName;
}
const parts = [];
if (config.options.select) {
const selectFields = this.formatSelectFields(
config.options.select,
targetOccurrence == null ? void 0 : targetOccurrence.baseTable
);
parts.push(`$select=${selectFields}`);
}
if (config.options.filter) {
const filterQuery = buildQuery({ filter: config.options.filter });
const filterMatch = filterQuery.match(/\$filter=([^&]+)/);
if (filterMatch) {
parts.push(`$filter=${filterMatch[1]}`);
}
}
if (config.options.orderBy) {
const orderByValue = Array.isArray(config.options.orderBy) ? config.options.orderBy.join(",") : config.options.orderBy;
parts.push(`$orderby=${String(orderByValue)}`);
}
if (config.options.top !== void 0) {
parts.push(`$top=${config.options.top}`);
}
if (config.options.skip !== void 0) {
parts.push(`$skip=${config.options.skip}`);
}
if (config.options.expand) {
if (typeof config.options.expand === "string") {
parts.push(`$expand=${config.options.expand}`);
}
}
if (parts.length === 0) {
return relationName;
}
return `${relationName}(${parts.join(";")})`;
}).join(",");
}
expand(relation, callback) {
var _a;
const targetOccurrence = (_a = this.occurrence) == null ? void 0 : _a.navigation[relation];
if (callback) {
const targetBuilder = new QueryBuilder({
occurrence: targetOccurrence,
tableName: (targetOccurrence == null ? void 0 : targetOccurrence.name) ?? relation,
databaseName: this.databaseName,
context: this.context,
databaseUseEntityIds: this.databaseUseEntityIds
});
const typedBuilder = targetBuilder;
const configuredBuilder = callback(typedBuilder);
const expandOptions = {
...configuredBuilder.queryOptions
};
if (configuredBuilder.expandConfigs.length > 0) {
const nestedExpandString = this.buildExpandString(
configuredBuilder.expandConfigs
);
if (nestedExpandString) {
expandOptions.expand = nestedExpandString;
}
}
const expandConfig = {
relation,
options: expandOptions
};
this.expandConfigs.push(expandConfig);
} else {
this.expandConfigs.push({ relation });
}
return this;
}
single() {
const newBuilder = new QueryBuilder({
occurrence: this.occurrence,
tableName: this.tableName,
databaseName: this.databaseName,
context: this.context,
databaseUseEntityIds: this.databaseUseEntityIds
});
newBuilder.queryOptions = { ...this.queryOptions };
newBuilder.expandConfigs = [...this.expandConfigs];
newBuilder.singleMode = "exact";
newBuilder.isCountMode = this.isCountMode;
newBuilder.isNavigate = this.isNavigate;
newBuilder.navigateRecordId = this.navigateRecordId;
newBuilder.navigateRelation = this.navigateRelation;
newBuilder.navigateSourceTableName = this.navigateSourceTableName;
newBuilder.navigateBaseRelation = this.navigateBaseRelation;
return newBuilder;
}
maybeSingle() {
const newBuilder = new QueryBuilder({
occurrence: this.occurrence,
tableName: this.tableName,
databaseName: this.databaseName,
context: this.context,
databaseUseEntityIds: this.databaseUseEntityIds
});
newBuilder.queryOptions = { ...this.queryOptions };
newBuilder.expandConfigs = [...this.expandConfigs];
newBuilder.singleMode = "maybe";
newBuilder.isCountMode = this.isCountMode;
newBuilder.isNavigate = this.isNavigate;
newBuilder.navigateRecordId = this.navigateRecordId;
newBuilder.navigateRelation = this.navigateRelation;
newBuilder.navigateSourceTableName = this.navigateSourceTableName;
newBuilder.navigateBaseRelation = this.navigateBaseRelation;
return newBuilder;
}
count() {
const newBuilder = new QueryBuilder({
occurrence: this.occurrence,
tableName: this.tableName,
databaseName: this.databaseName,
context: this.context,
databaseUseEntityIds: this.databaseUseEntityIds
});
newBuilder.queryOptions = { ...this.queryOptions, count: true };
newBuilder.expandConfigs = [...this.expandConfigs];
newBuilder.singleMode = this.singleMode;
newBuilder.isCountMode = true;
newBuilder.isNavigate = this.isNavigate;
newBuilder.navigateRecordId = this.navigateRecordId;
newBuilder.navigateRelation = this.navigateRelation;
newBuilder.navigateSourceTableName = this.navigateSourceTableName;
newBuilder.navigateBaseRelation = this.navigateBaseRelation;
return newBuilder;
}
async execute(options) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
const queryOptionsWithoutExpand = { ...this.queryOptions };
delete queryOptionsWithoutExpand.expand;
const mergedOptions = this.mergeExecuteOptions(options);
if (queryOptionsWithoutExpand.select) {
queryOptionsWithoutExpand.select = this.formatSelectFields(
queryOptionsWithoutExpand.select,
(_a = this.occurrence) == null ? void 0 : _a.baseTable
);
}
let queryString = buildQuery(queryOptionsWithoutExpand);
const expandString = this.buildExpandString(this.expandConfigs);
if (expandString) {
const separator = queryString.includes("?") ? "&" : "?";
queryString = `${queryString}${separator}$expand=${expandString}`;
}
if (this.isNavigate && this.navigateRecordId && this.navigateRelation && this.navigateSourceTableName) {
let url;
if (this.navigateBaseRelation) {
url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;
} else {
url = `/${this.databaseName}/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;
}
const result2 = await this.context._makeRequest(url, mergedOptions);
if (result2.error) {
return { data: void 0, error: result2.error };
}
let response2 = result2.data;
const shouldUseIds2 = mergedOptions.useEntityIds ?? false;
if (((_b = this.occurrence) == null ? void 0 : _b.baseTable) && shouldUseIds2) {
const expandValidationConfigs3 = this.buildExpandValidationConfigs(
this.expandConfigs
);
response2 = transformResponseFields(
response2,
this.occurrence.baseTable,
expandValidationConfigs3
);
}
if ((options == null ? void 0 : options.skipValidation) === true) {
const resp = response2;
if (this.singleMode !== false) {
const records = resp.value ?? [resp];
const count = Array.isArray(records) ? records.length : 1;
if (count > 1) {
return {
data: void 0,
error: new RecordCountMismatchError(
this.singleMode === "exact" ? "one" : "at-most-one",
count
)
};
}
if (count === 0) {
if (this.singleMode === "exact") {
return {
data: void 0,
error: new RecordCountMismatchError("one", 0)
};
}
return { data: null, error: void 0 };
}
const record = Array.isArray(records) ? records[0] : records;
const stripped = this.stripODataAnnotationsIfNeeded(record, options);
return { data: stripped, error: void 0 };
} else {
const records = resp.value ?? [];
const stripped = records.map(
(record) => this.stripODataAnnotationsIfNeeded(record, options)
);
return { data: stripped, error: void 0 };
}
}
const schema2 = (_d = (_c = this.occurrence) == null ? void 0 : _c.baseTable) == null ? void 0 : _d.schema;
const selectedFields2 = this.queryOptions.select;
const expandValidationConfigs2 = this.buildExpandValidationConfigs(
this.expandConfigs
);
if (this.singleMode !== false) {
const validation = await validateSingleResponse(
response2,
schema2,
selectedFields2,
expandValidationConfigs2,
this.singleMode
);
if (!validation.valid) {
return { data: void 0, error: validation.error };
}
const stripped = validation.data ? this.stripODataAnnotationsIfNeeded(validation.data, options) : null;
return { data: stripped, error: void 0 };
} else {
const validation = await validateListResponse(
response2,
schema2,
selectedFields2,
expandValidationConfigs2
);
if (!validation.valid) {
return { data: void 0, error: validation.error };
}
const stripped = validation.data.map(
(record) => this.stripODataAnnotationsIfNeeded(record, options)
);
return { data: stripped, error: void 0 };
}
}
if (this.isNavigate && !this.navigateRecordId && this.navigateRelation && this.navigateSourceTableName) {
const result2 = await this.context._makeRequest(
`/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}${queryString}`,
mergedOptions
);
if (result2.error) {
return { data: void 0, error: result2.error };
}
let response2 = result2.data;
const shouldUseIds2 = mergedOptions.useEntityIds ?? false;
if (((_e = this.occurrence) == null ? void 0 : _e.baseTable) && shouldUseIds2) {
const expandValidationConfigs3 = this.buildExpandValidationConfigs(
this.expandConfigs
);
response2 = transformResponseFields(
response2,
this.occurrence.baseTable,
expandValidationConfigs3
);
}
if ((options == null ? void 0 : options.skipValidation) === true) {
const resp = response2;
if (this.singleMode !== false) {
const records = resp.value ?? [resp];
const count = Array.isArray(records) ? records.length : 1;
if (count > 1) {
return {
data: void 0,
error: new RecordCountMismatchError(
this.singleMode === "exact" ? "one" : "at-most-one",
count
)
};
}
if (count === 0) {
if (this.singleMode === "exact") {
return {
data: void 0,
error: new RecordCountMismatchError("one", 0)
};
}
return { data: null, error: void 0 };
}
const record = Array.isArray(records) ? records[0] : records;
const stripped = this.stripODataAnnotationsIfNeeded(record, options);
return { data: stripped, error: void 0 };
} else {
const records = resp.value ?? [];
const stripped = records.map(
(record) => this.stripODataAnnotationsIfNeeded(record, options)
);
return { data: stripped, error: void 0 };
}
}
const schema2 = (_g = (_f = this.occurrence) == null ? void 0 : _f.baseTable) == null ? void 0 : _g.schema;
const selectedFields2 = this.queryOptions.select;
const expandValidationConfigs2 = this.buildExpandValidationConfigs(
this.expandConfigs
);
if (this.singleMode !== false) {
const validation = await validateSingleResponse(
response2,
schema2,
selectedFields2,
expandValidationConfigs2,
this.singleMode
);
if (!validation.valid) {
return { data: void 0, error: validation.error };
}
const stripped = validation.data ? this.stripODataAnnotationsIfNeeded(validation.data, options) : null;
return { data: stripped, error: void 0 };
} else {
const validation = await validateListResponse(
response2,
schema2,
selectedFields2,
expandValidationConfigs2
);
if (!validation.valid) {
return { data: void 0, error: validation.error };
}
const stripped = validation.data.map(
(record) => this.stripODataAnnotationsIfNeeded(record, options)
);
return { data: stripped, error: void 0 };
}
}
if (this.isCountMode) {
const tableId2 = this.getTableId(mergedOptions.useEntityIds);
const result2 = await this.context._makeRequest(
`/${this.databaseName}/${tableId2}/$count${queryString}`,
mergedOptions
);
if (result2.error) {
return { data: void 0, error: result2.error };
}
const count = typeof result2.data === "string" ? Number(result2.data) : result2.data;
return { data: count, error: void 0 };
}
const tableId = this.getTableId(mergedOptions.useEntityIds);
const result = await this.context._makeRequest(
`/${this.databaseName}/${tableId}${queryString}`,
mergedOptions
);
if (result.error) {
return { data: void 0, error: result.error };
}
let response = result.data;
const shouldUseIds = mergedOptions.useEntityIds ?? false;
if (((_h = this.occurrence) == null ? void 0 : _h.baseTable) && shouldUseIds) {
const expandValidationConfigs2 = this.buildExpandValidationConfigs(
this.expandConfigs
);
response = transformResponseFields(
response,
this.occurrence.baseTable,
expandValidationConfigs2
);
}
if ((options == null ? void 0 : options.skipValidation) === true) {
const resp = response;
if (this.singleMode !== false) {
const records = resp.value ?? [resp];
const count = Array.isArray(records) ? records.length : 1;
if (count > 1) {
return {
data: void 0,
error: new RecordCountMismatchError(
this.singleMode === "exact" ? "one" : "at-most-one",
count
)
};
}
if (count === 0) {
if (this.singleMode === "exact") {
return {
data: void 0,
error: new RecordCountMismatchError("one", 0)
};
}
return { data: null, error: void 0 };
}
const record = Array.isArray(records) ? records[0] : records;
const stripped = this.stripODataAnnotationsIfNeeded(record, options);
return { data: stripped, error: void 0 };
} else {
const records = resp.value ?? [];
const stripped = records.map(
(record) => this.stripODataAnnotationsIfNeeded(record, options)
);
return { data: stripped, error: void 0 };
}
}
const schema = (_j = (_i = this.occurrence) == null ? void 0 : _i.baseTable) == null ? void 0 : _j.schema;
const selectedFields = this.queryOptions.select;
const expandValidationConfigs = this.buildExpandValidationConfigs(
this.expandConfigs
);
if (this.singleMode !== false) {
const validation = await validateSingleResponse(
response,
schema,
selectedFields,
expandValidationConfigs,
this.singleMode
);
if (!validation.valid) {
return { data: void 0, error: validation.error };
}
const stripped = validation.data ? this.stripODataAnnotationsIfNeeded(validation.data, options) : null;
return {
data: stripped,
error: void 0
};
} else {
const validation = await validateListResponse(
response,
schema,
selectedFields,
expandValidationConfigs
);
if (!validation.valid) {
return { data: void 0, error: validation.error };
}
const stripped = validation.data.map(
(record) => this.stripODataAnnotationsIfNeeded(record, options)
);
return {
data: stripped,
error: void 0
};
}
}
getQueryString() {
var _a;
const queryOptionsWithoutExpand = { ...this.queryOptions };
delete queryOptionsWithoutExpand.expand;
if (queryOptionsWithoutExpand.select) {
queryOptionsWithoutExpand.select = this.formatSelectFields(
queryOptionsWithoutExpand.select,
(_a = this.occurrence) == null ? void 0 : _a.baseTable
);
}
let queryParams = buildQuery(queryOptionsWithoutExpand);
if (this.queryOptions.select) {
queryParams = queryParams.replace(
/\$select=([^&]*)/,
(match, selectValue) => {
return `$select=${selectValue.replace(/%20/g, " ")}`;
}
);
}
const expandString = this.buildExpandString(this.expandConfigs);
if (expandString) {
const separator = queryParams.includes("?") ? "&" : "?";
queryParams = `${queryParams}${separator}$expand=${expandString}`;
}
if (this.isNavigate && this.navigateRecordId && this.navigateRelation && this.navigateSourceTableName) {
let path;
if (this.navigateBaseRelation) {
path = `/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}`;
} else {
path = `/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}`;
}
return queryParams ? `${path}${queryParams}` : path;
}
if (this.isNavigate && !this.navigateRecordId && this.navigateRelation && this.navigateSourceTableName) {
const path = `/${this.navigateSourceTableName}/${this.navigateRelation}`;
return queryParams ? `${path}${queryParams}` : path;
}
return `/${this.tableName}${queryParams}`;
}
getRequestConfig() {
var _a;
const queryOptionsWithoutExpand = { ...this.queryOptions };
delete queryOptionsWithoutExpand.expand;
if (queryOptionsWithoutExpand.select) {
queryOptionsWithoutExpand.select = this.formatSelectFields(
queryOptionsWithoutExpand.select,
(_a = this.occurrence) == null ? void 0 : _a.baseTable
);
}
let queryString = buildQuery(queryOptionsWithoutExpand);
const expandString = this.buildExpandString(this.expandConfigs);
if (expandString) {
const separator = queryString.includes("?") ? "&" : "?";
queryString = `${queryString}${separator}$expand=${expandString}`;
}
let url;
if (this.isNavigate && this.navigateRecordId && this.navigateRelation && this.navigateSourceTableName) {
if (this.navigateBaseRelation) {
url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;
} else {
url = `/${this.databaseName}/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;
}
} else if (this.isNavigate && !this.navigateRecordId && this.navigateRelation && this.navigateSourceTableName) {
url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}${queryString}`;
} else if (this.isCountMode) {
url = `/${this.databaseName}/${this.tableName}/$count${queryString}`;
} else {
url = `/${this.databaseName}/${this.tableName}${queryString}`;
}
return {
method: "GET",
url
};
}
toRequest(baseUrl) {
const config = this.getRequestConfig();
const fullUrl = `${baseUrl}${config.url}`;
return new Request(fullUrl, {
method: config.method,
headers: {
"Content-Type": "application/json",
Accept: "application/json"
}
});
}
async processResponse(response, options) {
var _a, _b, _c;
if (response.status === 204) {
if (this.singleMode !== false) {
if (this.singleMode === "maybe") {
return { data: null, error: void 0 };
}
return {
data: void 0,
error: new RecordCountMismatchError("one", 0)
};
}
return { data: [], error: void 0 };
}
let rawData;
try {
rawData = await response.json();
} catch (err) {
if (err instanceof SyntaxError && response.status === 204) {
return { data: [], error: void 0 };
}
return {
data: void 0,
error: {
name: "ResponseParseError",
message: `Failed to parse response JSON: ${err instanceof Error ? err.message : "Unknown error"}`,
timestamp: /* @__PURE__ */ new Date()
}
};
}
if (!rawData) {
return {
data: void 0,
error: {
name: "ResponseError",
message: "Response body was empty or null",
timestamp: /* @__PURE__ */ new Date()
}
};
}
const shouldUseIds = (options == null ? void 0 : options.useEntityIds) ?? this.databaseUseEntityIds;
let transformedData = rawData;
if (((_a = this.occurrence) == null ? void 0 : _a.baseTable) && shouldUseIds) {
const expandValidationConfigs2 = this.buildExpandValidationConfigs(
this.expandConfigs
);
transformedData = transformResponseFields(
rawData,
this.occurrence.baseTable,
expandValidationConfigs2
);
}
if ((options == null ? void 0 : options.skipValidation) === true) {
const resp = transformedData;
if (this.singleMode !== false) {
const records = resp.value ?? [resp];
const count = Array.isArray(records) ? records.length : 1;
if (count > 1) {
return {
data: void 0,
error: new RecordCountMismatchError(
this.singleMode === "exact" ? "one" : "at-most-one",
count
)
};
}
if (count === 0) {
if (this.singleMode === "exact") {
return {
data: void 0,
error: new RecordCountMismatchError("one", 0)
};
}
return { data: null, error: void 0 };
}
const record = Array.isArray(records) ? records[0] : records;
const stripped2 = this.stripODataAnnotationsIfNeeded(record, options);
return { data: stripped2, error: void 0 };
} else {
const records = resp.value ?? [];
const stripped2 = records.map(
(record) => this.stripODataAnnotationsIfNeeded(record, options)
);
return { data: stripped2, error: void 0 };
}
}
const schema = (_c = (_b = this.occurrence) == null ? void 0 : _b.baseTable) == null ? void 0 : _c.schema;
const selectedFields = this.queryOptions.select;
const expandValidationConfigs = this.buildExpandValidationConfigs(
this.expandConfigs
);
if (this.singleMode !== false) {
const validation2 = await validateSingleResponse(
transformedData,
schema,
selectedFields,
expandValidationConfigs,
this.singleMode
);
if (!validation2.valid) {
return { data: void 0, error: validation2.error };
}
if (validation2.data === null) {
return { data: null, error: void 0 };
}
const stripped2 = this.stripODataAnnotationsIfNeeded(
validation2.data,
options
);
return { data: stripped2, error: void 0 };
}
const validation = await validateListResponse(
transformedData,
schema,
selectedFields,
expandValidationConfigs
);
if (!validation.valid) {
return { data: void 0, error: validation.error };
}
const stripped = validation.data.map(
(record) => this.stripODataAnnotationsIfNeeded(record, options)
);
return { data: stripped, error: void 0 };
}
}
export {
QueryBuilder
};
//# sourceMappingURL=query-builder.js.map