@proofkit/fmodata
Version:
FileMaker OData API client
194 lines (193 loc) • 7.26 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 { EntitySet } from "./entity-set.js";
import { BatchBuilder } from "./batch-builder.js";
import { SchemaManager } from "./schema-manager.js";
class Database {
constructor(databaseName, context, config) {
__publicField(this, "occurrenceMap");
__publicField(this, "_useEntityIds", false);
__publicField(this, "schema");
this.databaseName = databaseName;
this.context = context;
this.occurrenceMap = /* @__PURE__ */ new Map();
if (config == null ? void 0 : config.occurrences) {
const occurrencesWithIds = [];
const occurrencesWithoutIds = [];
for (const occ of config.occurrences) {
this.occurrenceMap.set(occ.name, occ);
const hasTableId = occ.isUsingTableId();
const hasFieldIds = occ.baseTable.isUsingFieldIds();
if (hasTableId && hasFieldIds) {
occurrencesWithIds.push(occ.name);
} else if (!hasTableId && !hasFieldIds) {
occurrencesWithoutIds.push(occ.name);
} else {
throw new Error(
`TableOccurrence "${occ.name}" has inconsistent entity ID configuration. Both fmtId (${hasTableId ? "present" : "missing"}) and fmfIds (${hasFieldIds ? "present" : "missing"}) must be defined together.`
);
}
}
const allOccurrencesUseEntityIds = occurrencesWithIds.length > 0 && occurrencesWithoutIds.length === 0;
const hasMixedUsage = occurrencesWithIds.length > 0 && occurrencesWithoutIds.length > 0;
if (config.useEntityIds !== void 0) {
if (config.useEntityIds === false) {
this._useEntityIds = false;
} else if (config.useEntityIds === true) {
if (hasMixedUsage || occurrencesWithoutIds.length > 0) {
throw new Error(
`useEntityIds is set to true but some occurrences do not use entity IDs. Occurrences without entity IDs: [${occurrencesWithoutIds.join(", ")}]. Either set useEntityIds to false or configure all occurrences with entity IDs.`
);
}
this._useEntityIds = true;
}
} else {
if (hasMixedUsage) {
throw new Error(
`Cannot mix TableOccurrence instances with and without entity IDs in the same database. Occurrences with entity IDs: [${occurrencesWithIds.join(", ")}]. Occurrences without entity IDs: [${occurrencesWithoutIds.join(", ")}]. Either all table occurrences must use entity IDs (fmtId + fmfIds), none should, or explicitly set useEntityIds to false.`
);
}
this._useEntityIds = allOccurrencesUseEntityIds;
}
} else {
this._useEntityIds = (config == null ? void 0 : config.useEntityIds) ?? false;
}
if (this.context._setUseEntityIds) {
this.context._setUseEntityIds(this._useEntityIds);
}
this.schema = new SchemaManager(this.databaseName, this.context);
}
/**
* Returns true if any table occurrence in this database is using entity IDs.
*/
isUsingEntityIds() {
return this._useEntityIds;
}
/**
* Gets a table occurrence by name.
* @internal
*/
getOccurrence(name) {
return this.occurrenceMap.get(name);
}
from(name) {
const occurrence = this.occurrenceMap.get(name);
if (occurrence) {
return EntitySet.create({
occurrence,
tableName: name,
databaseName: this.databaseName,
context: this.context,
database: this
});
} else {
return new EntitySet({
tableName: name,
databaseName: this.databaseName,
context: this.context,
database: this
});
}
}
async getMetadata(args) {
const result = await this.context._makeRequest(`/${this.databaseName}/$metadata`, {
headers: {
Accept: (args == null ? void 0 : args.format) === "xml" ? "application/xml" : "application/json"
}
});
if (result.error) {
throw result.error;
}
if ((args == null ? void 0 : args.format) === "json") {
const data = result.data;
const metadata = data[this.databaseName];
if (!metadata) {
throw new Error(
`Metadata for database "${this.databaseName}" not found in response`
);
}
return metadata;
}
return result.data;
}
/**
* Lists all available tables (entity sets) in this database.
* @returns Promise resolving to an array of table names
*/
async listTableNames() {
const result = await this.context._makeRequest(`/${this.databaseName}`);
if (result.error) {
throw result.error;
}
if (result.data.value && Array.isArray(result.data.value)) {
return result.data.value.map((item) => item.name);
}
return [];
}
/**
* Executes a FileMaker script.
* @param scriptName - The name of the script to execute (must be valid according to OData rules)
* @param options - Optional script parameter and result schema
* @returns Promise resolving to script execution result
*/
async runScript(scriptName, options) {
const body = {};
if ((options == null ? void 0 : options.scriptParam) !== void 0) {
body.scriptParameterValue = options.scriptParam;
}
const result = await this.context._makeRequest(`/${this.databaseName}/Script.${scriptName}`, {
method: "POST",
body: Object.keys(body).length > 0 ? JSON.stringify(body) : void 0
});
if (result.error) {
throw result.error;
}
const response = result.data;
if ((options == null ? void 0 : options.resultSchema) && response.scriptResult !== void 0) {
const validationResult = options.resultSchema["~standard"].validate(
response.scriptResult.resultParameter
);
const result2 = validationResult instanceof Promise ? await validationResult : validationResult;
if (result2.issues) {
throw new Error(
`Script result validation failed: ${JSON.stringify(result2.issues)}`
);
}
return {
resultCode: response.scriptResult.code,
result: result2.value
};
}
return {
resultCode: response.scriptResult.code,
result: response.scriptResult.resultParameter
};
}
/**
* Create a batch operation builder that allows multiple queries to be executed together
* in a single atomic request. All operations succeed or fail together (transactional).
*
* @param builders - Array of executable query builders to batch
* @returns A BatchBuilder that can be executed
* @example
* ```ts
* const result = await db.batch([
* db.from('contacts').list().top(5),
* db.from('users').list().top(5),
* db.from('contacts').insert({ name: 'John' })
* ]).execute();
*
* if (result.data) {
* const [contacts, users, insertResult] = result.data;
* }
* ```
*/
batch(builders) {
return new BatchBuilder(builders, this.databaseName, this.context);
}
}
export {
Database
};
//# sourceMappingURL=database.js.map