@langchain/core
Version:
Core LangChain.js abstractions and schemas
237 lines (236 loc) • 9.03 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.FunctionalTranslator = void 0;
const ir_js_1 = require("./ir.cjs");
const base_js_1 = require("./base.cjs");
const utils_js_1 = require("./utils.cjs");
/**
* A class that extends `BaseTranslator` to translate structured queries
* into functional filters.
* @example
* ```typescript
* const functionalTranslator = new FunctionalTranslator();
* const relevantDocuments = await functionalTranslator.getRelevantDocuments(
* "Which movies are rated higher than 8.5?",
* );
* ```
*/
class FunctionalTranslator extends base_js_1.BaseTranslator {
constructor() {
super(...arguments);
Object.defineProperty(this, "allowedOperators", {
enumerable: true,
configurable: true,
writable: true,
value: [ir_js_1.Operators.and, ir_js_1.Operators.or]
});
Object.defineProperty(this, "allowedComparators", {
enumerable: true,
configurable: true,
writable: true,
value: [
ir_js_1.Comparators.eq,
ir_js_1.Comparators.ne,
ir_js_1.Comparators.gt,
ir_js_1.Comparators.gte,
ir_js_1.Comparators.lt,
ir_js_1.Comparators.lte,
]
});
}
formatFunction() {
throw new Error("Not implemented");
}
/**
* Returns the allowed comparators for a given data type.
* @param input The input value to get the allowed comparators for.
* @returns An array of allowed comparators for the input data type.
*/
getAllowedComparatorsForType(inputType) {
switch (inputType) {
case "string": {
return [
ir_js_1.Comparators.eq,
ir_js_1.Comparators.ne,
ir_js_1.Comparators.gt,
ir_js_1.Comparators.gte,
ir_js_1.Comparators.lt,
ir_js_1.Comparators.lte,
];
}
case "number": {
return [
ir_js_1.Comparators.eq,
ir_js_1.Comparators.ne,
ir_js_1.Comparators.gt,
ir_js_1.Comparators.gte,
ir_js_1.Comparators.lt,
ir_js_1.Comparators.lte,
];
}
case "boolean": {
return [ir_js_1.Comparators.eq, ir_js_1.Comparators.ne];
}
default: {
throw new Error(`Unsupported data type: ${inputType}`);
}
}
}
/**
* Returns a function that performs a comparison based on the provided
* comparator.
* @param comparator The comparator to base the comparison function on.
* @returns A function that takes two arguments and returns a boolean based on the comparison.
*/
getComparatorFunction(comparator) {
switch (comparator) {
case ir_js_1.Comparators.eq: {
return (a, b) => a === b;
}
case ir_js_1.Comparators.ne: {
return (a, b) => a !== b;
}
case ir_js_1.Comparators.gt: {
return (a, b) => a > b;
}
case ir_js_1.Comparators.gte: {
return (a, b) => a >= b;
}
case ir_js_1.Comparators.lt: {
return (a, b) => a < b;
}
case ir_js_1.Comparators.lte: {
return (a, b) => a <= b;
}
default: {
throw new Error("Unknown comparator");
}
}
}
/**
* Returns a function that performs an operation based on the provided
* operator.
* @param operator The operator to base the operation function on.
* @returns A function that takes two boolean arguments and returns a boolean based on the operation.
*/
getOperatorFunction(operator) {
switch (operator) {
case ir_js_1.Operators.and: {
return (a, b) => a && b;
}
case ir_js_1.Operators.or: {
return (a, b) => a || b;
}
default: {
throw new Error("Unknown operator");
}
}
}
/**
* Visits the operation part of a structured query and translates it into
* a functional filter.
* @param operation The operation part of a structured query.
* @returns A function that takes a `Document` as an argument and returns a boolean based on the operation.
*/
visitOperation(operation) {
const { operator, args } = operation;
if (this.allowedOperators.includes(operator)) {
const operatorFunction = this.getOperatorFunction(operator);
return (document) => {
if (!args) {
return true;
}
return args.reduce((acc, arg) => {
const result = arg.accept(this);
if (typeof result === "function") {
return operatorFunction(acc, result(document));
}
else {
throw new Error("Filter is not a function");
}
}, true);
};
}
else {
throw new Error("Operator not allowed");
}
}
/**
* Visits the comparison part of a structured query and translates it into
* a functional filter.
* @param comparison The comparison part of a structured query.
* @returns A function that takes a `Document` as an argument and returns a boolean based on the comparison.
*/
visitComparison(comparison) {
const { comparator, attribute, value } = comparison;
const undefinedTrue = [ir_js_1.Comparators.ne];
if (this.allowedComparators.includes(comparator)) {
if (!this.getAllowedComparatorsForType(typeof value).includes(comparator)) {
throw new Error(`'${comparator}' comparator not allowed to be used with ${typeof value}`);
}
const comparatorFunction = this.getComparatorFunction(comparator);
return (document) => {
const documentValue = document.metadata[attribute];
if (documentValue === undefined) {
if (undefinedTrue.includes(comparator)) {
return true;
}
return false;
}
return comparatorFunction(documentValue, (0, utils_js_1.castValue)(value));
};
}
else {
throw new Error("Comparator not allowed");
}
}
/**
* Visits a structured query and translates it into a functional filter.
* @param query The structured query to translate.
* @returns An object containing a `filter` property, which is a function that takes a `Document` as an argument and returns a boolean based on the structured query.
*/
visitStructuredQuery(query) {
if (!query.filter) {
return {};
}
const filterFunction = query.filter?.accept(this);
if (typeof filterFunction !== "function") {
throw new Error("Structured query filter is not a function");
}
return { filter: filterFunction };
}
/**
* Merges two filters into one, based on the specified merge type.
* @param defaultFilter The default filter function.
* @param generatedFilter The generated filter function.
* @param mergeType The type of merge to perform. Can be 'and', 'or', or 'replace'. Default is 'and'.
* @returns A function that takes a `Document` as an argument and returns a boolean based on the merged filters, or `undefined` if both filters are empty.
*/
mergeFilters(defaultFilter, generatedFilter, mergeType = "and") {
if ((0, utils_js_1.isFilterEmpty)(defaultFilter) && (0, utils_js_1.isFilterEmpty)(generatedFilter)) {
return undefined;
}
if ((0, utils_js_1.isFilterEmpty)(defaultFilter) || mergeType === "replace") {
if ((0, utils_js_1.isFilterEmpty)(generatedFilter)) {
return undefined;
}
return generatedFilter;
}
if ((0, utils_js_1.isFilterEmpty)(generatedFilter)) {
if (mergeType === "and") {
return undefined;
}
return defaultFilter;
}
if (mergeType === "and") {
return (document) => defaultFilter(document) && generatedFilter(document);
}
else if (mergeType === "or") {
return (document) => defaultFilter(document) || generatedFilter(document);
}
else {
throw new Error("Unknown merge type");
}
}
}
exports.FunctionalTranslator = FunctionalTranslator;
;