@fjell/core
Version:
Core Item and Key Framework for Fjell
856 lines (846 loc) • 25.2 kB
JavaScript
// src/logger.ts
import Logging from "@fjell/logging";
var LibLogger = Logging.getLogger("@fjell/core");
var logger_default = LibLogger;
// src/dictionary.ts
var logger = logger_default.get("Dictionary");
var Dictionary = class _Dictionary {
map = {};
hashFunction = (key) => JSON.stringify(key);
constructor(map, hashFunction) {
if (hashFunction) {
this.hashFunction = hashFunction;
}
if (map) {
Object.entries(map).forEach(([hashedKey, value]) => {
try {
const originalKey = JSON.parse(hashedKey);
this.map[hashedKey] = { originalKey, value };
} catch {
logger.warning("Cannot recover original key from legacy map entry", { hashedKey });
}
});
}
}
set(key, item) {
logger.trace("set", { key, item });
const hashedKey = this.hashFunction(key);
this.map[hashedKey] = { originalKey: key, value: item };
}
get(key) {
logger.trace("get", { key });
const hashedKey = this.hashFunction(key);
const entry = this.map[hashedKey];
return entry && this.keysEqual(entry.originalKey, key) ? entry.value : null;
}
keysEqual(key1, key2) {
return key1 === key2;
}
delete(key) {
logger.trace("delete", { key });
const hashedKey = this.hashFunction(key);
delete this.map[hashedKey];
}
keys() {
return Object.values(this.map).map((entry) => entry.originalKey);
}
values() {
return Object.values(this.map).map((entry) => entry.value);
}
includesKey(key) {
const hashedKey = this.hashFunction(key);
const entry = this.map[hashedKey];
return entry ? this.keysEqual(entry.originalKey, key) : false;
}
clone() {
const clonedMap = {};
Object.entries(this.map).forEach(([hashedKey, entry]) => {
clonedMap[hashedKey] = entry.value;
});
const clone = new _Dictionary(clonedMap, this.hashFunction);
clone.map = Object.assign({}, this.map);
return clone;
}
};
// src/item/IFactory.ts
import deepmerge from "deepmerge";
// src/key/KUtils.ts
var logger2 = logger_default.get("KUtils");
var normalizeKeyValue = (value) => {
return String(value);
};
var createNormalizedHashFunction = () => {
return (key) => {
if (typeof key === "object" && key !== null) {
const normalizedKey = JSON.parse(JSON.stringify(key));
if ("pk" in normalizedKey && (normalizedKey.pk !== void 0 && normalizedKey.pk !== null)) {
normalizedKey.pk = normalizeKeyValue(normalizedKey.pk);
}
if ("lk" in normalizedKey && (normalizedKey.lk !== void 0 && normalizedKey.lk !== null)) {
normalizedKey.lk = normalizeKeyValue(normalizedKey.lk);
}
if ("loc" in normalizedKey && Array.isArray(normalizedKey.loc)) {
normalizedKey.loc = normalizedKey.loc.map((locItem) => {
if (locItem && "lk" in locItem && (locItem.lk !== void 0 && locItem.lk !== null)) {
return { ...locItem, lk: normalizeKeyValue(locItem.lk) };
}
return locItem;
});
}
return JSON.stringify(normalizedKey);
}
return JSON.stringify(key);
};
};
var isPriKeyEqualNormalized = (a, b) => {
logger2.trace("isPriKeyEqualNormalized", { a, b });
return a && b && normalizeKeyValue(a.pk) === normalizeKeyValue(b.pk) && a.kt === b.kt;
};
var isLocKeyEqualNormalized = (a, b) => {
logger2.trace("isLocKeyEqualNormalized", { a, b });
return a && b && normalizeKeyValue(a.lk) === normalizeKeyValue(b.lk) && a.kt === b.kt;
};
var isComKeyEqualNormalized = (a, b) => {
logger2.trace("isComKeyEqualNormalized", { a, b });
if (a && b && isPriKeyEqualNormalized({ kt: a.kt, pk: a.pk }, { kt: b.kt, pk: b.pk })) {
if (a.loc.length === b.loc.length) {
for (let i = 0; i < a.loc.length; i++) {
if (!isLocKeyEqualNormalized(a.loc[i], b.loc[i])) {
return false;
}
}
return true;
} else {
return false;
}
} else {
return false;
}
};
var isItemKeyEqualNormalized = (a, b) => {
logger2.trace("isItemKeyEqualNormalized", { a, b });
if (isComKey(a) && isComKey(b)) {
return isComKeyEqualNormalized(a, b);
} else if (isPriKey(a) && isPriKey(b)) {
if (isComKey(a) || isComKey(b)) {
return false;
} else {
return isPriKeyEqualNormalized(a, b);
}
} else {
return false;
}
};
var isItemKeyEqual = (a, b) => {
logger2.trace("isKeyEqual", { a, b });
if (isComKey(a) && isComKey(b)) {
return isComKeyEqual(a, b);
} else if (isPriKey(a) && isPriKey(b)) {
if (isComKey(a) || isComKey(b)) {
return false;
} else {
return isPriKeyEqual(a, b);
}
} else {
return false;
}
};
var isPriKeyEqual = (a, b) => {
logger2.trace("isPriKeyEqual", { a, b });
return a && b && a.pk === b.pk && a.kt === b.kt;
};
var isLocKeyEqual = (a, b) => {
logger2.trace("isLocKeyEqual", { a, b });
return a && b && a.lk === b.lk && a.kt === b.kt;
};
var isComKeyEqual = (a, b) => {
logger2.trace("isComKeyEqual", { a, b });
if (a && b && isPriKeyEqual({ kt: a.kt, pk: a.pk }, { kt: b.kt, pk: b.pk })) {
if (a.loc.length === b.loc.length) {
for (let i = 0; i < a.loc.length; i++) {
if (!isLocKeyEqual(a.loc[i], b.loc[i])) {
return false;
}
}
return true;
} else {
return false;
}
} else {
return false;
}
};
var isItemKey = (key) => {
logger2.trace("isItemKey", { key });
return key !== void 0 && (isComKey(key) || isPriKey(key));
};
var isComKey = (key) => {
logger2.trace("isComKey", { key });
return key !== void 0 && (key.pk !== void 0 && key.kt !== void 0) && (key.loc !== void 0 && key.loc.length > 0);
};
var isPriKey = (key) => {
logger2.trace("isPriKey", { key });
return key !== void 0 && (key.pk !== void 0 && key.kt !== void 0) && (key.loc === void 0 || key.loc.length === 0);
};
var isLocKey = (key) => {
logger2.trace("isLocKey", { key });
return key !== void 0 && (key.lk !== void 0 && key.kt !== void 0);
};
var generateKeyArray = (key) => {
logger2.trace("generateKeyArray", { key });
const keys = [];
if (isComKey(key) || isPriKey(key)) {
if (isComKey(key)) {
const comKey = key;
keys.push({ pk: comKey.pk, kt: comKey.kt });
for (let i = 0; i < comKey.loc.length; i++) {
keys.push(comKey.loc[i]);
}
} else {
keys.push(key);
}
} else {
const locKeys = key;
for (let i = 0; i < locKeys.length; i++) {
keys.push(locKeys[i]);
}
}
return keys;
};
var constructPriKey = (pk, kt) => {
logger2.trace("constructPriKey", { pk, kt });
let pri;
if (typeof pk === "string" || typeof pk === "number") {
pri = { kt, pk };
} else {
pri = pk;
}
return pri;
};
var cPK = constructPriKey;
var toKeyTypeArray = (ik) => {
logger2.trace("toKeyTypeArray", { ik });
if (isComKey(ik)) {
const ck = ik;
return [ck.kt, ...ck.loc.map((l) => l.kt)];
} else {
return [ik.kt];
}
};
var abbrevIK = (ik) => {
logger2.trace("abbrevIK", { ik });
if (ik) {
if (isComKey(ik)) {
const ck = ik;
return `${ck.kt}:${ck.pk}:${ck.loc.map((l) => `${l.kt}:${l.lk}`).join(",")}`;
} else {
return `${ik.kt}:${ik.pk}`;
}
} else {
return "null IK";
}
};
var abbrevLKA = (keyArray) => {
logger2.trace("abbrevLKA", { keyArray });
if (keyArray === void 0 || keyArray === null) {
return "null LKA";
} else {
return keyArray.map((key) => {
if (key) {
return `${key.kt}:${key.lk}`;
} else {
return key;
}
}).join(",");
}
};
var primaryType = (ik) => {
logger2.trace("primaryType", { ik });
if (isComKey(ik)) {
return ik.kt;
} else {
return ik.kt;
}
};
var itemKeyToLocKeyArray = (ik) => {
logger2.trace("itemKeyToLocKeyArray", { ik: abbrevIK(ik) });
let lka = [];
if (isComKey(ik)) {
const ck = ik;
lka = [{ kt: ck.kt, lk: ck.pk }, ...ck.loc];
} else {
const pk = ik;
lka = [{ kt: pk.kt, lk: pk.pk }];
}
logger2.trace("itemKeyToLocKeyArray Results", { ik: abbrevIK(ik), lka: abbrevLKA(lka) });
return lka;
};
var ikToLKA = itemKeyToLocKeyArray;
var locKeyArrayToItemKey = (lka) => {
logger2.trace("locKeyArrayToItemKey", { lka: abbrevLKA(lka) });
if (lka && lka.length === 1) {
const priKey = cPK(lka[0].lk, lka[0].kt);
return priKey;
} else if (lka && lka.length > 1 && lka[0] !== void 0) {
const locs = lka.slice(1);
const priKey = cPK(lka[0].lk, lka[0].kt);
const comKey = { kt: priKey.kt, pk: priKey.pk, loc: locs };
return comKey;
} else {
throw new Error("locKeyArrayToItemKey: lka is undefined or empty");
}
};
var isValidPriKey = (key) => {
const valid = key !== void 0 && key !== null && (key.pk !== void 0 && key.pk !== null && key.pk !== "" && key.pk !== "null") && (key.kt !== void 0 && key.kt !== null && key.kt !== "" && key.kt !== "null");
return valid;
};
var isValidLocKey = (key) => {
const valid = key !== void 0 && key !== null && (key.lk !== void 0 && key.lk !== null && key.lk !== "" && key.lk !== "null") && (key.kt !== void 0 && key.kt !== null && key.kt !== "" && key.kt !== "null");
return valid;
};
var isValidLocKeyArray = (keyArray) => {
return keyArray !== void 0 && keyArray !== null && keyArray.every(isValidLocKey);
};
var isValidComKey = (key) => {
return key !== void 0 && key !== null && isValidPriKey(key) && isValidLocKeyArray(key.loc);
};
var isValidItemKey = (key) => {
return isComKey(key) && isValidComKey(key) || isPriKey(key) && isValidPriKey(key);
};
var lkaToIK = locKeyArrayToItemKey;
// src/item/IFactory.ts
var IFactory = class _IFactory {
item = {};
constructor(props = {}) {
this.item = deepmerge(this.item, props);
}
addRef(i, name) {
const ik = i.key;
const refName = name || primaryType(ik);
if (!this.item.refs) {
this.item.refs = {};
}
this.item.refs[refName] = ik;
return this;
}
static addRef(i, name) {
return new _IFactory().addRef(i, name);
}
addDefaultEvents() {
if (!this.item.events) {
this.item.events = {};
}
const now = /* @__PURE__ */ new Date();
if (!this.item.events.created) {
this.item.events.created = { at: now };
}
if (!this.item.events.updated) {
this.item.events.updated = { at: now };
}
if (!this.item.events.deleted) {
this.item.events.deleted = { at: null };
}
return this;
}
addEvent(name, at, by) {
if (!this.item.events) {
this.item.events = {};
}
this.item.events[name] = { at, by };
return this;
}
static addEvent(name, at, by) {
return new _IFactory().addEvent(name, at, by);
}
addProp(name, value) {
this.item[name] = value;
return this;
}
static addProp(name, value) {
return new _IFactory().addProp(name, value);
}
addProps(props) {
this.item = deepmerge(this.item, props);
return this;
}
static addProps(props) {
return new _IFactory().addProps(props);
}
toItem() {
return this.item;
}
};
// src/AItemService.ts
var AItemService = class {
pkType;
parentService = null;
constructor(pkType, parentService) {
this.pkType = pkType;
if (parentService) {
this.parentService = parentService;
}
}
getPkType = () => {
return this.pkType;
};
getKeyTypes = () => {
let keyTypes = [this.getPkType()];
if (this.parentService) {
keyTypes = keyTypes.concat(this.parentService.getKeyTypes());
}
return keyTypes;
};
};
// src/item/ItemQuery.ts
var isCondition = (condition) => {
return (typeof condition.column === "string" && (Array.isArray(condition.value) && condition.value.every((item) => typeof item === "string")) || Array.isArray(condition.value) && condition.value.every((item) => typeof item === "number") || typeof condition.value === "string" || typeof condition.value === "number" || typeof condition.value === "boolean" || condition.value instanceof Date) && (condition.operator ? typeof condition.operator === "string" : true);
};
// src/item/IQFactory.ts
var IQFactory = class _IQFactory {
query = {};
constructor(query = {}) {
this.query = query;
}
orderBy(field, direction = "asc") {
if (!this.query.orderBy) {
this.query.orderBy = [];
}
this.query.orderBy.push({ field, direction });
return this;
}
agg(name, query) {
if (!this.query.aggs) {
this.query.aggs = {};
}
this.query.aggs[name] = query;
return this;
}
event(name, query) {
if (!this.query.events) {
this.query.events = {};
}
this.query.events[name] = query;
return this;
}
conditions(conditions, compoundType = "AND") {
for (const condition of conditions) {
if (!isCondition(condition)) {
throw new Error(`Invalid condition: ${JSON.stringify(condition)}`);
}
}
if (!this.query.compoundCondition) {
this.query.compoundCondition = {
compoundType,
conditions
};
} else {
const compoundCondition = {
compoundType,
conditions
};
this.query.compoundCondition.conditions.push(compoundCondition);
}
return this;
}
limit(limit) {
this.query.limit = limit;
return this;
}
offset(offset) {
this.query.offset = offset;
return this;
}
// TODO: right now, we're only supporting PK refs for queries. Should add support for CKs
pk(kt, pk, name) {
if (!this.query.refs) {
this.query.refs = {};
}
const refName = name || kt;
this.query.refs[refName] = cPK(pk, kt);
return this;
}
condition(column, value, operator = "==") {
const condition = { column, value, operator };
if (isCondition(condition)) {
if (!this.query.compoundCondition) {
this.query.compoundCondition = {
compoundType: "AND",
conditions: []
};
}
this.query.compoundCondition.conditions.push(condition);
return this;
} else {
throw new Error(`Invalid condition: ${JSON.stringify(condition)}`);
}
}
static all() {
const iqFactory = new _IQFactory();
return iqFactory;
}
static orderBy(field, direction = "asc") {
const iqFactory = new _IQFactory();
return iqFactory.orderBy(field, direction);
}
static agg(name, query) {
const iqFactory = new _IQFactory();
return iqFactory.agg(name, query);
}
static event(name, query) {
const iqFactory = new _IQFactory();
return iqFactory.event(name, query);
}
static limit(limit) {
const iqFactory = new _IQFactory();
return iqFactory.limit(limit);
}
static offset(offset) {
const iqFactory = new _IQFactory();
return iqFactory.offset(offset);
}
static pk(kt, pk, name) {
const iqFactory = new _IQFactory();
return iqFactory.pk(kt, pk, name);
}
static condition(column, value, operator = "==") {
const iqFactory = new _IQFactory();
return iqFactory.condition(column, value, operator);
}
static conditions(conditions, compoundType = "AND") {
const iqFactory = new _IQFactory();
return iqFactory.conditions(conditions, compoundType);
}
toQuery() {
return this.query;
}
};
// src/item/IQUtils.ts
import * as luxon from "luxon";
var logger3 = logger_default.get("IQUtils");
var queryToParams = (query) => {
const params = {};
if (query.compoundCondition) {
params.compoundCondition = JSON.stringify(query.compoundCondition);
}
if (query.refs) {
params.refs = JSON.stringify(query.refs);
}
if (query.limit) {
params.limit = query.limit;
}
if (query.offset) {
params.offset = query.offset;
}
if (query.aggs) {
params.aggs = JSON.stringify(query.aggs);
}
if (query.events) {
params.events = JSON.stringify(query.events);
}
return params;
};
var dateTimeReviver = function(key, value) {
if (typeof value === "string") {
const parsedDate = luxon.DateTime.fromISO(value);
if (parsedDate.isValid) {
return parsedDate.toJSDate();
;
}
}
return value;
};
var paramsToQuery = (params) => {
const query = {};
if (params.compoundCondition) {
query.compoundCondition = JSON.parse(params.compoundCondition);
}
if (params.refs) {
query.refs = JSON.parse(params.refs);
}
if (params.limit) {
query.limit = Number(params.limit);
}
if (params.offset) {
query.offset = Number(params.offset);
}
if (params.aggs) {
query.aggs = JSON.parse(params.aggs);
}
if (params.events) {
query.events = JSON.parse(params.events, dateTimeReviver);
}
return query;
};
var isRefQueryMatch = (refKey, queryRef, references) => {
logger3.trace("doesRefMatch", { queryRef, references });
logger3.debug("Comparing Ref", { refKey, itemRef: references[refKey], queryRef });
return isItemKeyEqual(queryRef, references[refKey]);
};
var isCompoundConditionQueryMatch = (queryCondition, item) => {
if (queryCondition.compoundType === "AND") {
return queryCondition.conditions.every(
(condition) => isCondition(condition) ? isConditionQueryMatch(condition, item) : isCompoundConditionQueryMatch(condition, item)
);
} else {
return queryCondition.conditions.some(
(condition) => isCondition(condition) ? isConditionQueryMatch(condition, item) : isCompoundConditionQueryMatch(condition, item)
);
}
};
var isConditionQueryMatch = (queryCondition, item) => {
const propKey = queryCondition.column;
logger3.trace("doesConditionMatch", { propKey, queryCondition, item });
if (item[propKey] === void 0) {
logger3.debug("Item does not contain prop under key", { propKey, item });
return false;
}
logger3.debug("Comparing Condition", { propKey, itemProp: item[propKey], queryCondition });
let result = false;
switch (queryCondition.operator) {
case "==":
result = item[propKey] === queryCondition.value;
break;
case "!=":
result = item[propKey] !== queryCondition.value;
break;
case ">":
result = item[propKey] > queryCondition.value;
break;
case ">=":
result = item[propKey] >= queryCondition.value;
break;
case "<":
result = item[propKey] < queryCondition.value;
break;
case "<=":
result = item[propKey] <= queryCondition.value;
break;
case "in":
result = queryCondition.value.includes(item[propKey]);
break;
case "not-in":
result = !queryCondition.value.includes(item[propKey]);
break;
case "array-contains":
result = item[propKey].includes(queryCondition.value);
break;
case "array-contains-any":
result = queryCondition.value.some((value) => item[propKey].includes(value));
break;
}
return result;
};
var isAggQueryMatch = (aggKey, aggQuery, agg) => {
const aggItem = agg.item;
logger3.debug("Comparing Agg", { aggKey, aggItem, aggQuery });
return isQueryMatch(aggItem, aggQuery);
};
var isEventQueryMatch = (eventKey, eventQuery, item) => {
if (!item.events[eventKey]) {
logger3.debug("Item does not contain event under key", { eventKey, events: item.events });
return false;
} else {
const itemEvent = item.events[eventKey];
if (itemEvent.at !== null) {
if (eventQuery.start && !(eventQuery.start.getTime() <= itemEvent.at.getTime())) {
logger3.debug("Item date before event start query", { eventQuery, itemEvent });
return false;
}
if (eventQuery.end && !(eventQuery.end.getTime() > itemEvent.at.getTime())) {
logger3.debug("Item date after event end query", { eventQuery, itemEvent });
return false;
}
} else {
logger3.debug("Item event does contains a null at", { itemEvent });
return false;
}
return true;
}
};
var isQueryMatch = (item, query) => {
logger3.trace("isMatch", { item, query });
if (query.refs && item.refs) {
for (const key in query.refs) {
const queryRef = query.refs[key];
if (!isRefQueryMatch(key, queryRef, item.refs)) return false;
}
} else if (query.refs && !item.refs) {
logger3.debug("Query contains refs but item does not have refs", { query, item });
return false;
}
if (query.compoundCondition && item) {
if (!isCompoundConditionQueryMatch(query.compoundCondition, item)) return false;
}
if (query.events && item.events) {
for (const key in query.events) {
const queryEvent = query.events[key];
if (!isEventQueryMatch(key, queryEvent, item)) return false;
}
return true;
}
if (query.aggs && item.aggs) {
for (const key in query.aggs) {
const aggQuery = query.aggs[key];
if (item.aggs[key] && !isAggQueryMatch(key, aggQuery, item.aggs[key])) return false;
}
}
if (query.aggs && !item.aggs) {
logger3.debug("Query contains aggs but item does not have aggs", { query, item });
return false;
}
return true;
};
var abbrevQuery = (query) => {
const abbrev = ["IQ"];
if (query) {
if (query.refs) {
for (const key in query.refs) {
const ref = abbrevRef(key, query.refs[key]);
abbrev.push(ref);
}
}
if (query.compoundCondition) {
const props = abbrevCompoundCondition(query.compoundCondition);
abbrev.push(props);
}
if (query.aggs) {
for (const key in query.aggs) {
const agg = abbrevAgg(key, query.aggs[key]);
abbrev.push(agg);
}
}
if (query.events) {
const events = `(E${Object.keys(query.events).join(",")})`;
abbrev.push(events);
}
if (query.limit) {
abbrev.push(`L${query.limit}`);
}
if (query.offset) {
abbrev.push(`O${query.offset}`);
}
} else {
abbrev.push("(empty)");
}
return abbrev.join(" ");
};
var abbrevRef = (key, ref) => {
if (isPriKey(ref)) {
const priKey = ref;
return `R(${key},${priKey.kt},${priKey.pk})`;
} else {
const comKey = ref;
return `R(${key},${JSON.stringify(comKey)})`;
}
};
var abbrevAgg = (key, agg) => {
return `A(${key},${abbrevQuery(agg)})`;
};
var abbrevCompoundCondition = (compoundCondition) => {
return `CC(${compoundCondition.compoundType},${compoundCondition.conditions ? compoundCondition.conditions.map(abbrevCondition).join(",") : "No Conditions"})`;
};
var abbrevCondition = (condition) => {
if (isCondition(condition)) {
return `(${condition.column},${condition.value},${condition.operator})`;
} else {
return abbrevCompoundCondition(condition);
}
};
// src/item/IUtils.ts
var logger4 = logger_default.get("IUtils");
var validatePKForItem = (item, pkType) => {
if (!item) {
logger4.error("Validating PK, Item is undefined", { item });
throw new Error("Validating PK, Item is undefined");
}
if (!item.key) {
logger4.error("Validating PK, Item does not have a key", { item });
throw new Error("Validating PK, Item does not have a key");
}
const keyTypeArray = toKeyTypeArray(item.key);
if (keyTypeArray[0] !== pkType) {
logger4.error("Key Type Array Mismatch", { keyTypeArray, pkType });
throw new Error(`Item does not have the correct primary key type. Expected ${pkType}, got ${keyTypeArray[0]}`);
}
return item;
};
var validatePK = (input, pkType) => {
logger4.trace("Checking Return Type", { input });
if (Array.isArray(input)) {
return input.map((item) => validatePKForItem(item, pkType));
}
return validatePKForItem(input, pkType);
};
var validateKeys = (item, keyTypes) => {
logger4.trace("Checking Return Type", { item });
if (!item) {
throw new Error("validating keys, item is undefined");
}
if (!item.key) {
throw new Error("validating keys, item does not have a key: " + JSON.stringify(item));
}
const keyTypeArray = toKeyTypeArray(item.key);
if (keyTypeArray.length !== keyTypes.length) {
throw new Error(`Item does not have the correct number of keys. Expected ${keyTypes.length}, but got ${keyTypeArray.length}`);
}
const match = JSON.stringify(keyTypeArray) === JSON.stringify(keyTypes);
if (!match) {
logger4.error("Key Type Array Mismatch", { keyTypeArray, thisKeyTypes: keyTypes });
throw new Error(`Item does not have the correct key types. Expected [${keyTypes.join(", ")}], but got [${keyTypeArray.join(", ")}]`);
}
return item;
};
var isPriItem = (item) => {
return !!(item && item.key && isPriKey(item.key));
};
var isComItem = (item) => {
return !!(item && item.key && isComKey(item.key));
};
export {
AItemService,
Dictionary,
IFactory,
IQFactory,
abbrevAgg,
abbrevCompoundCondition,
abbrevCondition,
abbrevIK,
abbrevLKA,
abbrevQuery,
abbrevRef,
cPK,
constructPriKey,
createNormalizedHashFunction,
generateKeyArray,
ikToLKA,
isComItem,
isComKey,
isComKeyEqual,
isComKeyEqualNormalized,
isCondition,
isItemKey,
isItemKeyEqual,
isItemKeyEqualNormalized,
isLocKey,
isLocKeyEqual,
isLocKeyEqualNormalized,
isPriItem,
isPriKey,
isPriKeyEqual,
isPriKeyEqualNormalized,
isQueryMatch,
isValidComKey,
isValidItemKey,
isValidLocKey,
isValidLocKeyArray,
isValidPriKey,
itemKeyToLocKeyArray,
lkaToIK,
locKeyArrayToItemKey,
paramsToQuery,
primaryType,
queryToParams,
toKeyTypeArray,
validateKeys,
validatePK
};