UNPKG

@langchain/community

Version:
1 lines 14.8 kB
{"version":3,"file":"supabase.cjs","names":["BaseTranslator","Operators","Comparators","convertObjectFilterToStructuredQuery","ProxyParamsDuplicator"],"sources":["../../src/structured_query/supabase.ts"],"sourcesContent":["import {\n isFilterEmpty,\n isFloat,\n isInt,\n isObject,\n isString,\n BaseTranslator,\n Comparator,\n Comparators,\n Comparison,\n Operation,\n Operator,\n Operators,\n StructuredQuery,\n isBoolean,\n} from \"@langchain/core/structured_query\";\nimport type {\n SupabaseFilterRPCCall,\n SupabaseMetadata,\n SupabaseVectorStore,\n} from \"../vectorstores/supabase.js\";\nimport {\n ProxyParamsDuplicator,\n convertObjectFilterToStructuredQuery,\n} from \"./supabase_utils.js\";\n\n/**\n * Represents the possible values that can be used in a comparison in a\n * structured query. It can be a string or a number.\n */\ntype ValueType = {\n eq: string | number;\n ne: string | number;\n lt: string | number;\n lte: string | number;\n gt: string | number;\n gte: string | number;\n};\n\n/**\n * A specialized translator designed to work with Supabase, extending the\n * BaseTranslator class. It translates structured queries into a format\n * that can be understood by the Supabase database.\n * @example\n * ```typescript\n * const selfQueryRetriever = new SelfQueryRetriever({\n * llm: new ChatOpenAI({ model: \"gpt-4o-mini\" }),\n * vectorStore: new SupabaseVectorStore(),\n * documentContents: \"Brief summary of a movie\",\n * attributeInfo: [],\n * structuredQueryTranslator: new SupabaseTranslator(),\n * });\n *\n * const queryResult = await selfQueryRetriever.getRelevantDocuments(\n * \"Which movies are directed by Greta Gerwig?\",\n * );\n * ```\n */\nexport class SupabaseTranslator<\n T extends SupabaseVectorStore,\n> extends BaseTranslator<T> {\n declare VisitOperationOutput: SupabaseFilterRPCCall;\n\n declare VisitComparisonOutput: SupabaseFilterRPCCall;\n\n allowedOperators: Operator[] = [Operators.and, Operators.or];\n\n allowedComparators: Comparator[] = [\n Comparators.eq,\n Comparators.ne,\n Comparators.gt,\n Comparators.gte,\n Comparators.lt,\n Comparators.lte,\n ];\n\n formatFunction(): string {\n throw new Error(\"Not implemented\");\n }\n\n /**\n * Returns a function that applies the appropriate comparator operation on\n * the attribute and value provided. The function returned is used to\n * filter data in a Supabase database.\n * @param comparator The comparator to be used in the operation.\n * @returns A function that applies the comparator operation on the attribute and value provided.\n */\n getComparatorFunction<C extends Comparator>(\n comparator: Comparator\n ): (attr: string, value: ValueType[C]) => SupabaseFilterRPCCall {\n switch (comparator) {\n case Comparators.eq: {\n return (attr: string, value: ValueType[C]) => (rpc) =>\n rpc.eq(this.buildColumnName(attr, value), value);\n }\n case Comparators.ne: {\n return (attr: string, value: ValueType[C]) => (rpc) =>\n rpc.neq(this.buildColumnName(attr, value), value);\n }\n case Comparators.gt: {\n return (attr: string, value: ValueType[C]) => (rpc) =>\n rpc.gt(this.buildColumnName(attr, value), value);\n }\n case Comparators.gte: {\n return (attr: string, value: ValueType[C]) => (rpc) =>\n rpc.gte(this.buildColumnName(attr, value), value);\n }\n case Comparators.lt: {\n return (attr: string, value: ValueType[C]) => (rpc) =>\n rpc.lt(this.buildColumnName(attr, value), value);\n }\n case Comparators.lte: {\n return (attr: string, value: ValueType[C]) => (rpc) =>\n rpc.lte(this.buildColumnName(attr, value), value);\n }\n default: {\n throw new Error(\"Unknown comparator\");\n }\n }\n }\n\n /**\n * Builds a column name based on the attribute and value provided. The\n * column name is used in filtering data in a Supabase database.\n * @param attr The attribute to be used in the column name.\n * @param value The value to be used in the column name.\n * @param includeType Whether to include the data type in the column name.\n * @returns The built column name.\n */\n buildColumnName(attr: string, value: string | number, includeType = true) {\n let column = \"\";\n if (isString(value)) {\n column = `metadata->>${attr}`;\n } else if (isInt(value)) {\n column = `metadata->${attr}${includeType ? \"::int\" : \"\"}`;\n } else if (isFloat(value)) {\n column = `metadata->${attr}${includeType ? \"::float\" : \"\"}`;\n } else if (isBoolean(value)) {\n column = `metadata->${attr}${includeType ? \"::boolean\" : \"\"}`;\n } else {\n throw new Error(\"Data type not supported\");\n }\n\n return column;\n }\n\n /**\n * Visits an operation and returns a string representation of it. This is\n * used in translating a structured query into a format that can be\n * understood by Supabase.\n * @param operation The operation to be visited.\n * @returns A string representation of the operation.\n */\n visitOperationAsString(operation: Operation): string {\n const { args } = operation;\n if (!args) {\n return \"\";\n }\n return args\n ?.reduce((acc, arg) => {\n if (arg.exprName === \"Comparison\") {\n acc.push(this.visitComparisonAsString(arg as Comparison));\n } else if (arg.exprName === \"Operation\") {\n const { operator: innerOperator } = arg as Operation;\n acc.push(\n `${innerOperator}(${this.visitOperationAsString(arg as Operation)})`\n );\n }\n return acc;\n }, [] as string[])\n .join(\",\");\n }\n\n /**\n * Visits an operation and returns a function that applies the operation\n * on a Supabase database. This is used in translating a structured query\n * into a format that can be understood by Supabase.\n * @param operation The operation to be visited.\n * @returns A function that applies the operation on a Supabase database.\n */\n visitOperation(operation: Operation): this[\"VisitOperationOutput\"] {\n const { operator, args } = operation;\n if (this.allowedOperators.includes(operator)) {\n if (operator === Operators.and) {\n if (!args) {\n return (rpc) => rpc;\n }\n const filter: SupabaseFilterRPCCall = (rpc) =>\n args.reduce((acc, arg) => {\n const filter = arg.accept(this) as SupabaseFilterRPCCall;\n return filter(acc);\n }, rpc);\n return filter;\n } else if (operator === Operators.or) {\n return (rpc) => rpc.or(this.visitOperationAsString(operation));\n } else {\n throw new Error(\"Unknown operator\");\n }\n } else {\n throw new Error(\"Operator not allowed\");\n }\n }\n\n /**\n * Visits a comparison and returns a string representation of it. This is\n * used in translating a structured query into a format that can be\n * understood by Supabase.\n * @param comparison The comparison to be visited.\n * @returns A string representation of the comparison.\n */\n visitComparisonAsString(comparison: Comparison): string {\n let { value } = comparison;\n const { comparator: _comparator, attribute } = comparison;\n let comparator = _comparator as string;\n if (comparator === Comparators.ne) {\n comparator = \"neq\";\n }\n if (Array.isArray(value)) {\n value = `(${value\n .map((v) => {\n if (typeof v === \"string\" && /[,()]/.test(v)) return `\"${v}\"`;\n return v;\n })\n .join(\",\")})`;\n }\n return `${this.buildColumnName(\n attribute,\n value,\n false\n )}.${comparator}.${value}`;\n }\n\n /**\n * Visits a comparison and returns a function that applies the comparison\n * on a Supabase database. This is used in translating a structured query\n * into a format that can be understood by Supabase.\n * @param comparison The comparison to be visited.\n * @returns A function that applies the comparison on a Supabase database.\n */\n visitComparison(comparison: Comparison): this[\"VisitComparisonOutput\"] {\n const { comparator, attribute, value } = comparison;\n if (this.allowedComparators.includes(comparator)) {\n const comparatorFunction = this.getComparatorFunction(\n comparator as Comparator\n );\n return comparatorFunction(attribute, value);\n } else {\n throw new Error(\"Comparator not allowed\");\n }\n }\n\n /**\n * Visits a structured query and returns a function that applies the query\n * on a Supabase database. This is used in translating a structured query\n * into a format that can be understood by Supabase.\n * @param query The structured query to be visited.\n * @returns A function that applies the query on a Supabase database.\n */\n visitStructuredQuery(\n query: StructuredQuery\n ): this[\"VisitStructuredQueryOutput\"] {\n if (!query.filter) {\n return {};\n }\n const filterFunction = query.filter?.accept(this);\n return { filter: (filterFunction as SupabaseFilterRPCCall) ?? {} };\n }\n\n /**\n * Merges two filters into one. The merged filter can be used to filter\n * data in a Supabase database.\n * @param defaultFilter The default filter to be merged.\n * @param generatedFilter The generated filter to be merged.\n * @param mergeType The type of merge to be performed. It can be 'and', 'or', or 'replace'.\n * @returns The merged filter.\n */\n mergeFilters(\n defaultFilter: SupabaseFilterRPCCall | SupabaseMetadata | undefined,\n generatedFilter: SupabaseFilterRPCCall | undefined,\n mergeType = \"and\"\n ): SupabaseFilterRPCCall | SupabaseMetadata | undefined {\n if (isFilterEmpty(defaultFilter) && isFilterEmpty(generatedFilter)) {\n return undefined;\n }\n if (isFilterEmpty(defaultFilter) || mergeType === \"replace\") {\n if (isFilterEmpty(generatedFilter)) {\n return undefined;\n }\n return generatedFilter;\n }\n if (isFilterEmpty(generatedFilter)) {\n if (mergeType === \"and\") {\n return undefined;\n }\n return defaultFilter;\n }\n\n let myDefaultFilter = defaultFilter;\n if (isObject(defaultFilter)) {\n const { filter } = this.visitStructuredQuery(\n convertObjectFilterToStructuredQuery(defaultFilter)\n );\n\n // just in case the built filter is empty somehow\n if (isFilterEmpty(filter)) {\n if (isFilterEmpty(generatedFilter)) {\n return undefined;\n }\n return generatedFilter;\n }\n myDefaultFilter = filter;\n }\n // After this point, myDefaultFilter will always be SupabaseFilterRPCCall\n if (mergeType === \"or\") {\n return (rpc) => {\n const defaultFlattenedParams = ProxyParamsDuplicator.getFlattenedParams(\n rpc,\n myDefaultFilter as SupabaseFilterRPCCall\n );\n const generatedFlattenedParams =\n ProxyParamsDuplicator.getFlattenedParams(rpc, generatedFilter);\n return rpc.or(`${defaultFlattenedParams},${generatedFlattenedParams}`);\n };\n } else if (mergeType === \"and\") {\n return (rpc) =>\n generatedFilter((myDefaultFilter as SupabaseFilterRPCCall)(rpc));\n } else {\n throw new Error(\"Unknown merge type\");\n }\n }\n}\n"],"mappings":"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"}