shiro-orm
Version:
Access your RONIN database via TypeScript.
854 lines (845 loc) • 27.1 kB
JavaScript
import {
getProperty,
setProperty
} from "./chunk-NXXOROUL.js";
// src/utils/errors.ts
var InvalidResponseError = class extends Error {
message;
code;
constructor(details) {
super(details.message);
this.name = "InvalidResponseError";
this.message = details.message;
this.code = details.code;
}
};
var getResponseBody = async (response, options) => {
if (response.ok) return response.json();
const text = await response.text();
let json;
try {
json = JSON.parse(text);
} catch (_err) {
throw new InvalidResponseError({
message: `${options?.errorPrefix ? `${options.errorPrefix} ` : ""}${text}`,
code: "JSON_PARSE_ERROR"
});
}
if (json.error) {
json.error.message = `${options?.errorPrefix ? `${options.errorPrefix} ` : ""}${json.error.message}`;
throw new InvalidResponseError(json.error);
}
return json;
};
// src/storage.ts
var isStorableObject = (value) => typeof File !== "undefined" && value instanceof File || typeof ReadableStream !== "undefined" && value instanceof ReadableStream || typeof Blob !== "undefined" && value instanceof Blob || typeof ArrayBuffer !== "undefined" && value instanceof ArrayBuffer || typeof Buffer !== "undefined" && Buffer.isBuffer(value);
var extractStorableObjects = (queries) => queries.reduce(
(references, query, queryIndex) => {
return [
// biome-ignore lint/performance/noAccumulatingSpread: This code is too complex to refactor.
...references,
...Object.entries(query).reduce(
(references2, [queryType, query2]) => {
if (!["set", "add"].includes(queryType)) return references2;
return [
// biome-ignore lint/performance/noAccumulatingSpread: This code is too complex to refactor.
...references2,
...Object.entries(query2).reduce(
(references3, [schema, instructions]) => {
const fields = instructions[queryType === "set" ? "to" : "with"];
return [
// biome-ignore lint/performance/noAccumulatingSpread: This code is too complex to refactor.
...references3,
...Object.entries(fields || {}).reduce(
(references4, [name, value]) => {
if (!isStorableObject(value)) return references4;
const blobValue = value;
const storarableObject = {
query: {
index: queryIndex,
type: queryType
},
schema,
field: name,
value: blobValue
};
if ("type" in blobValue) {
storarableObject.contentType = blobValue.type;
}
if ("name" in blobValue) {
storarableObject.name = blobValue.name;
}
return [...references4, storarableObject];
},
[]
)
];
},
[]
)
];
},
[]
)
];
},
[]
);
var uploadStorableObjects = (storableObjects, options = {}) => {
const fetcher = typeof options?.fetch === "function" ? options.fetch : fetch;
const requests = storableObjects.map(
async ({ name, value, contentType }) => {
const headers = new Headers();
headers.set("Authorization", `Bearer ${options.token}`);
if (contentType) {
headers.set("Content-Type", contentType);
}
if (name) {
headers.set(
"Content-Disposition",
`form-data; filename="${encodeURIComponent(name)}"`
);
}
const request = new Request("https://storage.ronin.co/", {
method: "PUT",
body: value,
headers
});
const response = await fetcher(request);
return getResponseBody(response, {
errorPrefix: "An error occurred while uploading the binary objects included in the provided queries. Error:"
});
}
);
return Promise.all(requests);
};
var processStorableObjects = async (queries, upload) => {
const objects = extractStorableObjects(queries);
if (objects.length > 0) {
const storedObjects = await upload(objects);
for (let index = 0; index < objects.length; index++) {
const { query, schema, field } = objects[index];
const reference = storedObjects[index];
queries[query.index][query.type][schema][query.type === "set" ? "to" : "with"][field] = reference;
}
}
return queries;
};
// ../shiro-compiler/dist/index.js
var DML_QUERY_TYPES_READ = ["get", "count"];
var DML_QUERY_TYPES_WRITE = ["set", "add", "remove"];
var DML_QUERY_TYPES = [
...DML_QUERY_TYPES_READ,
...DML_QUERY_TYPES_WRITE
];
var DDL_QUERY_TYPES = ["list", "create", "alter", "drop"];
var QUERY_TYPES = [...DML_QUERY_TYPES, ...DDL_QUERY_TYPES];
var QUERY_SYMBOLS = {
// Represents a sub query.
QUERY: "__RONIN_QUERY",
// Represents an expression that should be evaluated.
EXPRESSION: "__RONIN_EXPRESSION",
// Represents the value of a field in the model.
FIELD: "__RONIN_FIELD_",
// Represents the value of a field in the model of a parent query.
FIELD_PARENT: "__RONIN_FIELD_PARENT_",
// Represents a value provided to a query preset.
VALUE: "__RONIN_VALUE"
};
var RONIN_MODEL_FIELD_REGEX = new RegExp(
`${QUERY_SYMBOLS.FIELD}[_a-zA-Z0-9.]+`,
"g"
);
var CURRENT_TIME_EXPRESSION = {
[QUERY_SYMBOLS.EXPRESSION]: `strftime('%Y-%m-%dT%H:%M:%f', 'now') || 'Z'`
};
var SINGLE_QUOTE_REGEX = /'/g;
var DOUBLE_QUOTE_REGEX = /"/g;
var AMPERSAND_REGEX = /\s*&+\s*/g;
var SPECIAL_CHARACTERS_REGEX = /[^\w\s-]+/g;
var SPLIT_REGEX = /(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|[\s.\-_]+/;
var sanitize = (str) => {
if (!str || str.length === 0) return "";
return str.replace(SINGLE_QUOTE_REGEX, "").replace(DOUBLE_QUOTE_REGEX, "").replace(AMPERSAND_REGEX, " and ").replace(SPECIAL_CHARACTERS_REGEX, " ").trim();
};
var convertToSnakeCase = (str) => {
if (!str || str.length === 0) return "";
return sanitize(str).split(SPLIT_REGEX).map((part) => part.toLowerCase()).join("_");
};
var omit = (obj, properties) => Object.fromEntries(
Object.entries(obj).filter(([key]) => !properties.includes(key))
);
var conjunctions = [
"for",
"and",
"nor",
"but",
"or",
"yet",
"so"
];
var articles = [
"a",
"an",
"the"
];
var prepositions = [
"aboard",
"about",
"above",
"across",
"after",
"against",
"along",
"amid",
"among",
"anti",
"around",
"as",
"at",
"before",
"behind",
"below",
"beneath",
"beside",
"besides",
"between",
"beyond",
"but",
"by",
"concerning",
"considering",
"despite",
"down",
"during",
"except",
"excepting",
"excluding",
"following",
"for",
"from",
"in",
"inside",
"into",
"like",
"minus",
"near",
"of",
"off",
"on",
"onto",
"opposite",
"over",
"past",
"per",
"plus",
"regarding",
"round",
"save",
"since",
"than",
"through",
"to",
"toward",
"towards",
"under",
"underneath",
"unlike",
"until",
"up",
"upon",
"versus",
"via",
"with",
"within",
"without"
];
var lowerCase = /* @__PURE__ */ new Set([
...conjunctions,
...articles,
...prepositions
]);
var specials = [
"ZEIT",
"ZEIT Inc.",
"Vercel",
"Vercel Inc.",
"CLI",
"API",
"HTTP",
"HTTPS",
"JSX",
"DNS",
"URL",
"now.sh",
"now.json",
"vercel.app",
"vercel.json",
"CI",
"CD",
"CDN",
"package.json",
"package.lock",
"yarn.lock",
"GitHub",
"GitLab",
"CSS",
"Sass",
"JS",
"JavaScript",
"TypeScript",
"HTML",
"WordPress",
"Next.js",
"Node.js",
"Webpack",
"Docker",
"Bash",
"Kubernetes",
"SWR",
"TinaCMS",
"UI",
"UX",
"TS",
"TSX",
"iPhone",
"iPad",
"watchOS",
"iOS",
"iPadOS",
"macOS",
"PHP",
"composer.json",
"composer.lock",
"CMS",
"SQL",
"C",
"C#",
"GraphQL",
"GraphiQL",
"JWT",
"JWTs"
];
var word = `[^\\s'\u2019\\(\\)!?;:"-]`;
var regex = new RegExp(`(?:(?:(\\s?(?:^|[.\\(\\)!?;:"-])\\s*)(${word}))|(${word}))(${word}*[\u2019']*${word}*)`, "g");
var convertToRegExp = (specials2) => specials2.map((s) => [new RegExp(`\\b${s}\\b`, "gi"), s]);
function parseMatch(match) {
const firstCharacter = match[0];
if (/\s/.test(firstCharacter)) {
return match.slice(1);
}
if (/[\(\)]/.test(firstCharacter)) {
return null;
}
return match;
}
var src_default = (str, options = {}) => {
str = str.toLowerCase().replace(regex, (m, lead = "", forced, lower, rest, offset, string) => {
const isLastWord = m.length + offset >= string.length;
const parsedMatch = parseMatch(m);
if (!parsedMatch) {
return m;
}
if (!forced) {
const fullLower = lower + rest;
if (lowerCase.has(fullLower) && !isLastWord) {
return parsedMatch;
}
}
return lead + (lower || forced).toUpperCase() + rest;
});
const customSpecials = options.special || [];
const replace = [...specials, ...customSpecials];
const replaceRegExp = convertToRegExp(replace);
replaceRegExp.forEach(([pattern, s]) => {
str = str.replace(pattern, s);
});
return str;
};
var slugToName = (slug) => {
const name = slug.replace(/([a-z])([A-Z])/g, "$1 $2");
return src_default(name);
};
var VOWELS = ["a", "e", "i", "o", "u"];
var pluralize = (word2) => {
const lastLetter = word2.slice(-1).toLowerCase();
const secondLastLetter = word2.slice(-2, -1).toLowerCase();
if (lastLetter === "y" && !VOWELS.includes(secondLastLetter)) {
return `${word2.slice(0, -1)}ies`;
}
if (lastLetter === "s" || word2.slice(-2).toLowerCase() === "ch" || word2.slice(-2).toLowerCase() === "sh" || word2.slice(-2).toLowerCase() === "ex") {
return `${word2}es`;
}
return `${word2}s`;
};
var modelAttributes = [
["pluralSlug", "slug", pluralize, true],
["name", "slug", slugToName, false],
["pluralName", "pluralSlug", slugToName, false],
["idPrefix", "slug", (slug) => slug.slice(0, 3).toLowerCase(), false],
["table", "pluralSlug", convertToSnakeCase, true]
];
var getRecordIdentifier = (prefix) => {
return `${prefix}_${Array.from(crypto.getRandomValues(new Uint8Array(12))).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16).toLowerCase()}`;
};
var addDefaultModelAttributes = (model, isNew) => {
const copiedModel = { ...model };
if (isNew && !copiedModel.id) copiedModel.id = getRecordIdentifier("mod");
for (const [setting, base, generator, mustRegenerate] of modelAttributes) {
if (!(isNew || mustRegenerate)) continue;
if (copiedModel[setting] || !copiedModel[base]) continue;
copiedModel[setting] = generator(copiedModel[base]);
}
const newFields = copiedModel.fields || [];
if (isNew || Object.keys(newFields).length > 0) {
if (!copiedModel.identifiers) copiedModel.identifiers = {};
if (!copiedModel.identifiers.name) {
const suitableField = Object.entries(newFields).find(
([fieldSlug, field]) => field.type === "string" && field.required === true && ["name"].includes(fieldSlug)
);
copiedModel.identifiers.name = suitableField?.[0] || "id";
}
if (!copiedModel.identifiers.slug) {
const suitableField = Object.entries(newFields).find(
([fieldSlug, field]) => field.type === "string" && field.unique === true && field.required === true && ["slug", "handle"].includes(fieldSlug)
);
copiedModel.identifiers.slug = suitableField?.[0] || "id";
}
}
return copiedModel;
};
var ROOT_MODEL = {
slug: "roninModel",
identifiers: {
name: "name",
slug: "slug"
},
// The default ID prefix would be `ron_` based on the slug, but we want `mod_`.
idPrefix: "mod",
// This name mimics the `sqlite_schema` table in SQLite.
table: "ronin_schema",
// Indicates that the model was automatically generated by RONIN.
system: { model: "root" },
fields: {
name: { type: "string" },
pluralName: { type: "string" },
slug: { type: "string" },
pluralSlug: { type: "string" },
idPrefix: { type: "string" },
table: { type: "string" },
"identifiers.name": { type: "string" },
"identifiers.slug": { type: "string" },
// Providing an empty object as a default value allows us to use `json_insert`
// without needing to fall back to an empty object in the insertion statement,
// which makes the statement shorter.
fields: { type: "json", defaultValue: {} },
indexes: { type: "json", defaultValue: {} },
presets: { type: "json", defaultValue: {} }
}
};
var ROOT_MODEL_WITH_ATTRIBUTES = addDefaultModelAttributes(ROOT_MODEL, true);
var PLURAL_MODEL_ENTITIES = {
field: "fields",
index: "indexes",
preset: "presets"
};
var PLURAL_MODEL_ENTITIES_VALUES = Object.values(PLURAL_MODEL_ENTITIES);
var CLEAN_ROOT_MODEL = omit(ROOT_MODEL, ["system"]);
// src/utils/helpers.ts
var SPLIT_REGEX2 = /(?=[A-Z])|[.\-\s_]/;
var toDashCase = (string) => {
const capitalize = (str) => {
const lower = str.toLowerCase();
return lower.substring(0, 1).toUpperCase() + lower.substring(1, lower.length);
};
const parts = string?.replace(/([A-Z])+/g, capitalize)?.split(SPLIT_REGEX2).map((x) => x.toLowerCase()) ?? [];
if (parts.length === 0) return "";
if (parts.length === 1) return parts[0];
return parts.reduce((acc, part) => `${acc}-${part.toLowerCase()}`);
};
var formatDateFields = (record, dateFields) => {
for (const field of dateFields) {
const value = getProperty(record, field);
if (typeof value === "undefined" || value === null) continue;
setProperty(record, field, new Date(value));
}
};
var mergeOptions = (...options) => {
return options.reduce((acc, opt) => {
const resolvedOpt = typeof opt === "function" ? opt() : opt;
Object.assign(acc, resolvedOpt);
return acc;
}, {});
};
// src/utils/constants.ts
var WRITE_QUERY_TYPES = [
...DML_QUERY_TYPES_WRITE,
...DDL_QUERY_TYPES.filter((item) => item !== "list")
];
// src/utils/triggers.ts
var EMPTY = Symbol("empty");
var getModel = (instruction) => {
const key = Object.keys(instruction)[0];
let model = String(key);
let multipleRecords = false;
if (model.endsWith("s")) {
model = model.substring(0, model.length - 1);
multipleRecords = true;
}
return {
key,
// Convert camel case (e.g. `subscriptionItems`) into slugs
// (e.g. `subscription-items`).
model: toDashCase(model),
multipleRecords
};
};
var getMethodName = (triggerType, queryType) => {
const capitalizedQueryType = queryType[0].toUpperCase() + queryType.slice(1);
return triggerType === "during" ? queryType : triggerType + capitalizedQueryType;
};
var normalizeResults = (result) => {
const value = Array.isArray(result) ? result : result === EMPTY ? [] : [result];
return structuredClone(value);
};
var invokeTriggers = async (triggerType, definition, options) => {
const { triggers } = options;
const { query } = definition;
const queryType = Object.keys(query)[0];
let queryModel;
let queryModelDashed;
let multipleRecords;
let oldInstruction;
if (DDL_QUERY_TYPES.includes(queryType)) {
queryModel = queryModelDashed = "model";
multipleRecords = false;
oldInstruction = query[queryType];
} else {
const queryInstructions = query[queryType];
({
key: queryModel,
model: queryModelDashed,
multipleRecords
} = getModel(queryInstructions));
oldInstruction = queryInstructions[queryModel];
}
const triggerFile = options.database ? "sink" : queryModelDashed;
const triggersForModel = triggers[triggerFile];
const triggerName = getMethodName(triggerType, queryType);
const queryInstruction = oldInstruction ? structuredClone(oldInstruction) : {};
if (triggersForModel && triggerName in triggersForModel) {
const implicit = definition.implicit ?? false;
const trigger = triggersForModel[triggerName];
const triggerOptions = triggerFile === "sink" ? { model: queryModel, database: options.database, implicit } : { implicit };
const triggerResult = await (triggerType === "following" ? trigger(
queryInstruction,
multipleRecords,
normalizeResults(definition.resultBefore),
normalizeResults(definition.resultAfter),
triggerOptions
) : trigger(
queryInstruction,
multipleRecords,
triggerOptions
));
if (triggerType === "before") {
return { queries: triggerResult };
}
if (triggerType === "during") {
const result = triggerResult;
let newQuery = query;
if (result && QUERY_TYPES.some((type) => type in result)) {
newQuery = result;
} else {
newQuery = {
[queryType]: {
[queryModel]: result
}
};
}
return { queries: [newQuery] };
}
if (triggerType === "after") {
return { queries: triggerResult };
}
if (triggerType === "resolving") {
const result = triggerResult;
return { queries: [], result };
}
}
return { queries: [], result: EMPTY };
};
var runQueriesWithTriggers = async (queries, options = {}) => {
const { triggers, waitUntil } = options;
if (!triggers) return runQueries(queries, options);
if (typeof process === "undefined" && !waitUntil) {
let message = 'In the case that the "shiro-orm" package receives a value for';
message += " its `triggers` option, it must also receive a value for its";
message += " `waitUntil` option. This requirement only applies when using";
message += " an edge runtime and ensures that the edge worker continues to";
message += ' execute until all "following" triggers have been executed.';
throw new Error(message);
}
let queryList = queries.map(({ query, database }) => ({ query, result: EMPTY, database }));
await Promise.all(
queryList.map(async ({ query, database, implicit }, index) => {
const triggerResults = await invokeTriggers(
"before",
{ query, implicit },
{ triggers, database }
);
const queriesToInsert = triggerResults.queries.map((query2) => ({
query: query2,
result: EMPTY,
database,
implicit: true
}));
queryList.splice(index, 0, ...queriesToInsert);
})
);
await Promise.all(
queryList.map(async ({ query, database, implicit }, index) => {
const triggerResults = await invokeTriggers(
"during",
{ query, implicit },
{ triggers, database }
);
if (triggerResults.queries && triggerResults.queries.length > 0) {
queryList[index].query = triggerResults.queries[0];
}
})
);
await Promise.all(
queryList.map(async ({ query, database, implicit }, index) => {
const triggerResults = await invokeTriggers(
"after",
{ query, implicit },
{ triggers, database }
);
const queriesToInsert = triggerResults.queries.map((query2) => ({
query: query2,
result: EMPTY,
database,
implicit: true
}));
queryList.splice(index + 1, 0, ...queriesToInsert);
})
);
queryList = queryList.flatMap((details, index) => {
const { query, database } = details;
if (query.set || query.alter) {
let newQuery;
if (query.set) {
const modelSlug = Object.keys(query.set)[0];
newQuery = {
get: {
[modelSlug]: {
with: query.set[modelSlug].with
}
}
};
} else {
newQuery = {
list: {
model: query.alter.model
}
};
}
const diffQuery = {
query: newQuery,
diffForIndex: index + 1,
result: EMPTY,
database
};
return [diffQuery, details];
}
return [details];
});
await Promise.all(
queryList.map(async ({ query, database, implicit }, index) => {
const triggerResults = await invokeTriggers(
"resolving",
{ query, implicit },
{ triggers, database }
);
queryList[index].result = triggerResults.result;
})
);
const queriesWithoutResults = queryList.map((query, index) => ({ ...query, index })).filter((query) => query.result === EMPTY);
if (queriesWithoutResults.length > 0) {
const resultsFromDatabase = await runQueries(queriesWithoutResults, options);
for (let index = 0; index < resultsFromDatabase.length; index++) {
const query = queriesWithoutResults[index];
const result = resultsFromDatabase[index].result;
queryList[query.index].result = result;
}
}
for (let index = 0; index < queryList.length; index++) {
const { query, result, database, implicit } = queryList[index];
const queryType = Object.keys(query)[0];
if (!WRITE_QUERY_TYPES.includes(queryType)) continue;
const diffMatch = queryList.find((item) => item.diffForIndex === index);
let resultBefore = diffMatch ? diffMatch.result : EMPTY;
let resultAfter = result;
if (queryType === "remove" || queryType === "drop") {
resultBefore = result;
resultAfter = EMPTY;
}
const promise = invokeTriggers(
"following",
{ query, resultBefore, resultAfter, implicit },
{ triggers, database }
);
const clearPromise = promise.then(
() => {
},
(error) => Promise.reject(error)
);
if (waitUntil) waitUntil(clearPromise);
}
return queryList.filter(
(query) => typeof query.diffForIndex === "undefined" && typeof query.implicit === "undefined"
).map(({ result, database }) => ({
result,
database
}));
};
// src/queries.ts
var runQueries = async (queries, options = {}) => {
let hasWriteQuery = null;
let hasSingleQuery = true;
const operations = queries.reduce(
(acc, details) => {
const { database = "default" } = details;
if (!acc[database]) acc[database] = {};
if (database !== "default") hasSingleQuery = false;
if ("query" in details) {
const { query } = details;
if (!acc[database].queries) acc[database].queries = [];
acc[database].queries.push(query);
const queryType = Object.keys(query)[0];
hasWriteQuery = hasWriteQuery || WRITE_QUERY_TYPES.includes(queryType);
return acc;
}
const { statement } = details;
if (!acc[database].nativeQueries) acc[database].nativeQueries = [];
acc[database].nativeQueries.push({
query: statement.statement,
values: statement.params
});
return acc;
},
{}
);
const requestBody = hasSingleQuery ? operations.default : operations;
const hasCachingSupport = "cache" in new Request("https://ronin.co");
const request = new Request("https://data.ronin.co", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${options.token}`
},
body: JSON.stringify(requestBody),
// Disable cache if write queries are performed, as those must be
// guaranteed to reach RONIN.
...hasWriteQuery && hasCachingSupport ? { cache: "no-store" } : {},
// Allow for passing custom `fetch` options (e.g. in Next.js).
...typeof options?.fetch === "object" ? options.fetch : {}
});
const fetcher = typeof options?.fetch === "function" ? options.fetch : fetch;
const response = await fetcher(request);
const responseResults = await getResponseBody(response);
const startFormatting = performance.now();
const formattedResults = [];
if ("results" in responseResults) {
const usableResults = responseResults.results;
const finalResults = formatResults(usableResults);
formattedResults.push(...finalResults.map((result) => ({ result })));
} else {
for (const [database, { results }] of Object.entries(responseResults)) {
const finalResults = formatResults(results);
formattedResults.push(...finalResults.map((result) => ({ result, database })));
}
}
const endFormatting = performance.now();
const VERBOSE_LOGGING = typeof process !== "undefined" && process?.env && process.env.__RENDER_DEBUG_LEVEL === "verbose" || typeof import.meta?.env !== "undefined" && import.meta.env.__RENDER_DEBUG_LEVEL === "verbose";
if (VERBOSE_LOGGING) {
console.log(`Formatting took ${endFormatting - startFormatting}ms`);
}
return formattedResults;
};
async function runQueriesWithStorageAndTriggers(queries, options = {}) {
const singleDatabase = Array.isArray(queries);
const normalizedQueries = singleDatabase ? { default: queries } : queries;
const queriesWithReferences = (await Promise.all(
Object.entries(normalizedQueries).map(async ([database, queries2]) => {
const populatedQueries = await processStorableObjects(queries2, (objects) => {
return uploadStorableObjects(objects, options);
});
return populatedQueries.map((query) => ({
query,
database: database === "default" ? void 0 : database
}));
})
)).flat();
const results = await runQueriesWithTriggers(queriesWithReferences, options);
if (singleDatabase)
return results.filter(({ database }) => !database).map(({ result }) => result);
return results.reduce(
(acc, { result, database = "default" }) => {
if (!acc[database]) acc[database] = [];
acc[database].push(result);
return acc;
},
{}
);
}
var formatIndividualResult = (result) => {
if ("amount" in result && typeof result.amount !== "undefined" && result.amount !== null) {
return Number(result.amount);
}
const dateFields = "modelFields" in result ? Object.entries(result.modelFields).filter(([, type]) => type === "date").map(([slug]) => slug) : [];
if ("record" in result) {
if (result.record === null) return null;
formatDateFields(result.record, dateFields);
return result.record;
}
if ("records" in result) {
for (const record of result.records) {
formatDateFields(record, dateFields);
}
const formattedRecords = result.records;
if (typeof result.moreBefore !== "undefined")
formattedRecords.moreBefore = result.moreBefore;
if (typeof result.moreAfter !== "undefined")
formattedRecords.moreAfter = result.moreAfter;
return formattedRecords;
}
return result;
};
var formatResults = (results) => {
const formattedResults = [];
for (const result of results) {
if ("models" in result) {
formattedResults.push(
Object.fromEntries(
Object.entries(result.models).map(([model, result2]) => {
return [model, formatIndividualResult(result2)];
})
)
);
continue;
}
formattedResults.push(formatIndividualResult(result));
}
return formattedResults;
};
export {
InvalidResponseError,
isStorableObject,
processStorableObjects,
QUERY_SYMBOLS,
mergeOptions,
runQueries,
runQueriesWithStorageAndTriggers
};