@baqhub/sdk
Version:
The official JavaScript SDK for the BAQ federated app platform.
278 lines (277 loc) • 10.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Query = void 0;
const tslib_1 = require("tslib");
const jsonpath_plus_1 = require("jsonpath-plus");
const flow_js_1 = tslib_1.__importDefault(require("lodash/flow.js"));
const isEqual_js_1 = tslib_1.__importDefault(require("lodash/isEqual.js"));
const isString_js_1 = tslib_1.__importDefault(require("lodash/isString.js"));
const orderBy_js_1 = tslib_1.__importDefault(require("lodash/orderBy.js"));
const uniqBy_js_1 = tslib_1.__importDefault(require("lodash/uniqBy.js"));
const constants_js_1 = require("../../constants.js");
const array_js_1 = require("../../helpers/array.js");
const string_js_1 = require("../../helpers/string.js");
const type_js_1 = require("../../helpers/type.js");
const record_js_1 = require("../records/record.js");
const recordKey_js_1 = require("../records/recordKey.js");
const pathHelpers_js_1 = require("./pathHelpers.js");
const queryDate_js_1 = require("./queryDate.js");
const queryFilter_js_1 = require("./queryFilter.js");
const querySort_js_1 = require("./querySort.js");
const includeLinkSpecialValues = [
"entity",
"standing",
"existential",
];
const defaultIncludeLinks = [
"entity",
"existential",
];
const defaultSources = [
record_js_1.RecordSource.SELF,
record_js_1.RecordSource.NOTIFICATION,
record_js_1.RecordSource.SUBSCRIPTION,
];
const defaultSortBy = [
querySort_js_1.QuerySortProperty.VERSION_RECEIVED_AT,
querySort_js_1.QuerySortDirection.DESCENDING,
];
//
// I/O.
//
function queryNew(query) {
return query;
}
function queryOfKey(key, baseQuery = {}) {
const { entity, recordId } = recordKey_js_1.RecordKey.toComponents(key);
return {
...baseQuery,
pageSize: 1,
filter: queryFilter_js_1.Q.and(queryFilter_js_1.Q.author(entity), queryFilter_js_1.Q.id(recordId)),
};
}
function querySingleToQueryString(query) {
if (!query) {
return "";
}
return paramsToString([
["include_links", includeLinksToString(query.includeLinks)],
["include_deleted", query.includeDeleted ? "true" : undefined],
["proxy_to", query.proxyTo],
]);
}
function queryToQueryString(query) {
const filterStrings = query.filter && queryFilter_js_1.QueryFilter.toListString(query.filter);
return paramsToString([
["sort", query.sort && querySort_js_1.QuerySort.toString(query.sort)],
["min", query.min && queryDate_js_1.QueryDate.toString(query.min)],
["max", query.max && queryDate_js_1.QueryDate.toString(query.max)],
["page_start", query.pageStart && queryDate_js_1.QueryDate.toString(query.pageStart)],
["page_size", (query.pageSize || constants_js_1.Constants.defaultPageSize).toString()],
["distinct", query.distinct && (0, pathHelpers_js_1.normalizePath)(query.distinct)],
["sources", query.sources?.join(",")],
...(filterStrings || []).map(f => ["filter", f]),
["include_links", includeLinksToString(query.includeLinks)],
["include_deleted", query.includeDeleted ? "true" : undefined],
["proxy_to", query.proxyTo],
]);
}
function queryToSync(query, boundary) {
return {
max: undefined,
min: boundary,
sort: querySort_js_1.QuerySort.syncDefault,
pageStart: undefined,
pageSize: 100,
distinct: undefined,
sources: query.sources,
filter: query.filter,
mode: query.mode,
includeLinks: query.includeLinks,
includeDeleted: true,
proxyTo: query.proxyTo,
};
}
function queryFindBoundary(query, record) {
const sort = query.sort || querySort_js_1.QuerySort.default;
return [querySort_js_1.QuerySort.findDateInRecord(record, sort), record.id];
}
function includeLinksToString(includeLinks) {
function includeLinkToString(link) {
if (includeLinkSpecialValues.includes(link)) {
return link;
}
return (0, pathHelpers_js_1.normalizePath)(link);
}
return includeLinks?.map(includeLinkToString).join(",");
}
function includeLinksIsSuperset(links1, links2) {
const l1 = links1 || defaultIncludeLinks;
const l2 = links2 || defaultIncludeLinks;
return array_js_1.Array.isSuperset(l1, l2);
}
function sourcesIsSuperset(sources1, sources2) {
const s1 = sources1 || defaultSources;
const s2 = sources2 || defaultSources;
return array_js_1.Array.isSuperset(s1, s2);
}
function paramsToString(params) {
const filteredParams = params
.map(p => ((0, type_js_1.isDefined)(p[1]) ? [p[0], p[1]] : undefined))
.filter(type_js_1.isDefined);
return string_js_1.Str.buildQuery(filteredParams);
}
function findQueryMaxDate(query, sortDirection) {
if (query.pageStart && sortDirection === querySort_js_1.QuerySortDirection.DESCENDING) {
return query.pageStart;
}
return query.max;
}
function findQueryMinDate(query, sortDirection) {
if (query.pageStart && sortDirection === querySort_js_1.QuerySortDirection.ASCENDING) {
return query.pageStart;
}
return query.min;
}
function queryFilter(query, records, { ignorePageSize, boundary } = {}) {
const sortBy = query.sort || defaultSortBy;
const sortDir = querySort_js_1.QuerySort.toDirection(sortBy);
const isAscending = sortDir === querySort_js_1.QuerySortDirection.ASCENDING;
const maxDate = findQueryMaxDate(query, sortDir);
const minDate = findQueryMinDate(query, sortDir);
function sort() {
const order = isAscending ? "asc" : "desc";
return (list) => {
return (0, orderBy_js_1.default)(list, r => querySort_js_1.QuerySort.findDateInRecord(r, sortBy), order);
};
}
function distinct() {
const { distinct } = query;
if (!distinct) {
return (list) => list;
}
const distinctValue = (record) => {
const recordValues = (0, jsonpath_plus_1.JSONPath)({
path: distinct,
json: record,
}).filter(type_js_1.isDefined);
if (recordValues.length === 0) {
return `null+${record.author.entity}+${record.id}`;
}
// TODO: Implement link detection for correct logic.
const valueToString = (value) => {
if ((0, isString_js_1.default)(value)) {
return `"${value}"`;
}
if ("versionHash" in value) {
return `${value.entity}+${value.recordId}+${value.versionHash}`;
}
if ("recordId" in value) {
return `${value.entity}+${value.recordId}`;
}
if ("entity" in value) {
return value.entity;
}
return String(value);
};
return recordValues.map(valueToString).join(":");
};
return (list) => (0, uniqBy_js_1.default)(list, distinctValue);
}
function filter() {
function isMatch(record) {
// Exclude deleted.
if ("noContent" in record) {
return false;
}
// Date boundaries.
const recordDate = querySort_js_1.QuerySort.findDateInRecord(record, sortBy);
const recordId = record.id;
if (queryDate_js_1.QueryDate.compare(recordDate, recordId, maxDate) > 0) {
return false;
}
if (queryDate_js_1.QueryDate.compare(recordDate, recordId, minDate) < 0) {
return false;
}
if (boundary) {
const result = queryDate_js_1.QueryDate.compare(recordDate, recordId, boundary);
if (isAscending ? result > 0 : result < 0) {
return false;
}
}
if (query.mode && record.mode !== query.mode) {
return false;
}
// Sources.
const sources = query.sources || defaultSources;
if (!sources.includes(record.source) &&
record.source !== record_js_1.RecordSource.PROXY) {
return false;
}
// Filter.
return !query.filter || queryFilter_js_1.QueryFilter.isMatch(record, query.filter);
}
return (list) => {
return list.filter(isMatch);
};
}
function pageSize() {
if (ignorePageSize) {
return list => list;
}
return list => {
return list.slice(0, query.pageSize || constants_js_1.Constants.defaultPageSize);
};
}
return (0, flow_js_1.default)(sort(), distinct(), filter(), pageSize())(records);
}
function queryIsMatch(query1, query2) {
const { ["filter"]: filter1, ...q1 } = query1;
const { ["filter"]: filter2, ...q2 } = query2;
if (!(0, isEqual_js_1.default)(q1, q2)) {
return false;
}
if (filter1 && filter2) {
return (queryFilter_js_1.QueryFilter.isSuperset(filter1, filter2) &&
queryFilter_js_1.QueryFilter.isSuperset(filter2, filter1));
}
return !filter1 && !filter2;
}
function queryIsSuperset(query1, query2) {
if (query1.distinct !== query2.distinct) {
return false;
}
return queryIsSyncSuperset(query1, query2);
}
function queryIsSyncSuperset(query1, query2) {
if (query1.mode !== query2.mode || query1.proxyTo !== query2.proxyTo) {
return false;
}
if (!includeLinksIsSuperset(query1.includeLinks, query2.includeLinks)) {
return false;
}
if (!sourcesIsSuperset(query1.sources, query2.sources)) {
return false;
}
if (query2.includeDeleted && !query1.includeDeleted) {
return false;
}
if (query1.filter && query2.filter) {
return queryFilter_js_1.QueryFilter.isSuperset(query1.filter, query2.filter);
}
return !query1.filter && !query2.filter;
}
exports.Query = {
new: queryNew,
ofKey: queryOfKey,
singleToQueryString: querySingleToQueryString,
toQueryString: queryToQueryString,
toSync: queryToSync,
findBoundary: queryFindBoundary,
filter: queryFilter,
isMatch: queryIsMatch,
isSuperset: queryIsSuperset,
isSyncSuperset: queryIsSyncSuperset,
defaultIncludeLinks,
defaultSources,
};