{"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":";;;;;;;;;;;;;;;;;;;;;;;;;AA0DA,IAAa,qBAAb,cAEUA,iCAAAA,eAAkB;CAK1B,mBAA+B,CAACC,iCAAAA,UAAU,KAAKA,iCAAAA,UAAU,GAAG;CAE5D,qBAAmC;EACjCC,iCAAAA,YAAY;EACZA,iCAAAA,YAAY;EACZA,iCAAAA,YAAY;EACZA,iCAAAA,YAAY;EACZA,iCAAAA,YAAY;EACZA,iCAAAA,YAAY;EACb;CAED,iBAAyB;AACvB,QAAM,IAAI,MAAM,kBAAkB;;;;;;;;;CAUpC,sBACE,YAC8D;AAC9D,UAAQ,YAAR;GACE,KAAKA,iCAAAA,YAAY,GACf,SAAQ,MAAc,WAAyB,QAC7C,IAAI,GAAG,KAAK,gBAAgB,MAAM,MAAM,EAAE,MAAM;GAEpD,KAAKA,iCAAAA,YAAY,GACf,SAAQ,MAAc,WAAyB,QAC7C,IAAI,IAAI,KAAK,gBAAgB,MAAM,MAAM,EAAE,MAAM;GAErD,KAAKA,iCAAAA,YAAY,GACf,SAAQ,MAAc,WAAyB,QAC7C,IAAI,GAAG,KAAK,gBAAgB,MAAM,MAAM,EAAE,MAAM;GAEpD,KAAKA,iCAAAA,YAAY,IACf,SAAQ,MAAc,WAAyB,QAC7C,IAAI,IAAI,KAAK,gBAAgB,MAAM,MAAM,EAAE,MAAM;GAErD,KAAKA,iCAAAA,YAAY,GACf,SAAQ,MAAc,WAAyB,QAC7C,IAAI,GAAG,KAAK,gBAAgB,MAAM,MAAM,EAAE,MAAM;GAEpD,KAAKA,iCAAAA,YAAY,IACf,SAAQ,MAAc,WAAyB,QAC7C,IAAI,IAAI,KAAK,gBAAgB,MAAM,MAAM,EAAE,MAAM;GAErD,QACE,OAAM,IAAI,MAAM,qBAAqB;;;;;;;;;;;CAa3C,gBAAgB,MAAc,OAAwB,cAAc,MAAM;EACxE,IAAI,SAAS;AACb,OAAA,GAAA,iCAAA,UAAa,MAAM,CACjB,UAAS,cAAc;uDACR,MAAM,CACrB,UAAS,aAAa,OAAO,cAAc,UAAU;yDACpC,MAAM,CACvB,UAAS,aAAa,OAAO,cAAc,YAAY;2DACpC,MAAM,CACzB,UAAS,aAAa,OAAO,cAAc,cAAc;MAEzD,OAAM,IAAI,MAAM,0BAA0B;AAG5C,SAAO;;;;;;;;;CAUT,uBAAuB,WAA8B;EACnD,MAAM,EAAE,SAAS;AACjB,MAAI,CAAC,KACH,QAAO;AAET,SAAO,MACH,QAAQ,KAAK,QAAQ;AACrB,OAAI,IAAI,aAAa,aACnB,KAAI,KAAK,KAAK,wBAAwB,IAAkB,CAAC;YAChD,IAAI,aAAa,aAAa;IACvC,MAAM,EAAE,UAAU,kBAAkB;AACpC,QAAI,KACF,GAAG,cAAc,GAAG,KAAK,uBAAuB,IAAiB,CAAC,GACnE;;AAEH,UAAO;KACN,EAAE,CAAa,CACjB,KAAK,IAAI;;;;;;;;;CAUd,eAAe,WAAoD;EACjE,MAAM,EAAE,UAAU,SAAS;AAC3B,MAAI,KAAK,iBAAiB,SAAS,SAAS,CAC1C,KAAI,aAAaD,iCAAAA,UAAU,KAAK;AAC9B,OAAI,CAAC,KACH,SAAQ,QAAQ;GAElB,MAAM,UAAiC,QACrC,KAAK,QAAQ,KAAK,QAAQ;AAExB,WADe,IAAI,OAAO,KAAK,CACjB,IAAI;MACjB,IAAI;AACT,UAAO;aACE,aAAaA,iCAAAA,UAAU,GAChC,SAAQ,QAAQ,IAAI,GAAG,KAAK,uBAAuB,UAAU,CAAC;MAE9D,OAAM,IAAI,MAAM,mBAAmB;MAGrC,OAAM,IAAI,MAAM,uBAAuB;;;;;;;;;CAW3C,wBAAwB,YAAgC;EACtD,IAAI,EAAE,UAAU;EAChB,MAAM,EAAE,YAAY,aAAa,cAAc;EAC/C,IAAI,aAAa;AACjB,MAAI,eAAeC,iCAAAA,YAAY,GAC7B,cAAa;AAEf,MAAI,MAAM,QAAQ,MAAM,CACtB,SAAQ,IAAI,MACT,KAAK,MAAM;AACV,OAAI,OAAO,MAAM,YAAY,QAAQ,KAAK,EAAE,CAAE,QAAO,IAAI,EAAE;AAC3D,UAAO;IACP,CACD,KAAK,IAAI,CAAC;AAEf,SAAO,GAAG,KAAK,gBACb,WACA,OACA,MACD,CAAC,GAAG,WAAW,GAAG;;;;;;;;;CAUrB,gBAAgB,YAAuD;EACrE,MAAM,EAAE,YAAY,WAAW,UAAU;AACzC,MAAI,KAAK,mBAAmB,SAAS,WAAW,CAI9C,QAH2B,KAAK,sBAC9B,WACD,CACyB,WAAW,MAAM;MAE3C,OAAM,IAAI,MAAM,yBAAyB;;;;;;;;;CAW7C,qBACE,OACoC;AACpC,MAAI,CAAC,MAAM,OACT,QAAO,EAAE;AAGX,SAAO,EAAE,QADc,MAAM,QAAQ,OAAO,KAAK,IACa,EAAE,EAAE;;;;;;;;;;CAWpE,aACE,eACA,iBACA,YAAY,OAC0C;AACtD,OAAA,GAAA,iCAAA,eAAkB,cAAc,KAAA,GAAA,iCAAA,eAAkB,gBAAgB,CAChE;AAEF,OAAA,GAAA,iCAAA,eAAkB,cAAc,IAAI,cAAc,WAAW;AAC3D,QAAA,GAAA,iCAAA,eAAkB,gBAAgB,CAChC;AAEF,UAAO;;AAET,OAAA,GAAA,iCAAA,eAAkB,gBAAgB,EAAE;AAClC,OAAI,cAAc,MAChB;AAEF,UAAO;;EAGT,IAAI,kBAAkB;AACtB,OAAA,GAAA,iCAAA,UAAa,cAAc,EAAE;GAC3B,MAAM,EAAE,WAAW,KAAK,qBACtBC,uBAAAA,qCAAqC,cAAc,CACpD;AAGD,QAAA,GAAA,iCAAA,eAAkB,OAAO,EAAE;AACzB,SAAA,GAAA,iCAAA,eAAkB,gBAAgB,CAChC;AAEF,WAAO;;AAET,qBAAkB;;AAGpB,MAAI,cAAc,KAChB,SAAQ,QAAQ;GACd,MAAM,yBAAyBC,uBAAAA,sBAAsB,mBACnD,KACA,gBACD;GACD,MAAM,2BACJA,uBAAAA,sBAAsB,mBAAmB,KAAK,gBAAgB;AAChE,UAAO,IAAI,GAAG,GAAG,uBAAuB,GAAG,2BAA2B;;WAE/D,cAAc,MACvB,SAAQ,QACN,gBAAiB,gBAA0C,IAAI,CAAC;MAElE,OAAM,IAAI,MAAM,qBAAqB"}