{"version":3,"file":"libsql.cjs","names":["VectorStore","embeddings: EmbeddingsInterface","options: LibSQLVectorStoreArgs","documents: Document<Metadata>[]","vectors: number[][]","ids: string[]","insertQueries: InStatement[]","query: number[]","k: number","filter?: this[\"FilterType\"]","SqliteWhereBuilder","row: any","Document","params: {\n    ids?: string[] | number[];\n    deleteAll?: boolean;\n  }","texts: string[]","metadatas: Metadata[] | Metadata","docs: Document<Metadata>[]"],"sources":["../../src/vectorstores/libsql.ts"],"sourcesContent":["import { Document } from \"@langchain/core/documents\";\nimport type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport { VectorStore } from \"@langchain/core/vectorstores\";\nimport type { Client, InStatement } from \"@libsql/client\";\nimport {\n  SqliteWhereBuilder,\n  WhereCondition,\n} from \"../utils/sqlite_where_builder.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype MetadataDefault = Record<string, any>;\n\n/**\n * Interface for LibSQLVectorStore configuration options.\n */\nexport interface LibSQLVectorStoreArgs {\n  db: Client;\n  /** Name of the table to store vectors. Defaults to \"vectors\". */\n  table?: string;\n  /** Name of the column to store embeddings. Defaults to \"embedding\". */\n  column?: string;\n  // TODO: Support adding additional columns to the table for metadata.\n}\n\n/**\n * A vector store using LibSQL/Turso for storage and retrieval.\n */\nexport class LibSQLVectorStore<\n  Metadata extends MetadataDefault = MetadataDefault,\n> extends VectorStore {\n  declare FilterType: string | InStatement | WhereCondition<Metadata>;\n\n  private db;\n\n  private readonly table: string;\n\n  private readonly column: string;\n\n  /**\n   * Returns the type of vector store.\n   * @returns {string} The string \"libsql\".\n   */\n  _vectorstoreType(): string {\n    return \"libsql\";\n  }\n\n  /**\n   * Initializes a new instance of the LibSQLVectorStore.\n   * @param {EmbeddingsInterface} embeddings - The embeddings interface to use.\n   * @param {Client} db - The LibSQL client instance.\n   * @param {LibSQLVectorStoreArgs} options - Configuration options for the vector store.\n   */\n  constructor(embeddings: EmbeddingsInterface, options: LibSQLVectorStoreArgs) {\n    super(embeddings, options);\n\n    this.db = options.db;\n    this.table = options.table || \"vectors\";\n    this.column = options.column || \"embedding\";\n  }\n\n  /**\n   * Adds documents to the vector store.\n   * @param {Document<Metadata>[]} documents - The documents to add.\n   * @returns {Promise<string[]>} The IDs of the added documents.\n   */\n  async addDocuments(documents: Document<Metadata>[]): Promise<string[]> {\n    const texts = documents.map(({ pageContent }) => pageContent);\n    const embeddings = await this.embeddings.embedDocuments(texts);\n\n    return this.addVectors(embeddings, documents);\n  }\n\n  /**\n   * Adds vectors to the vector store.\n   * @param {number[][]} vectors - The vectors to add.\n   * @param {Document<Metadata>[]} documents - The documents associated with the vectors.\n   * @returns {Promise<string[]>} The IDs of the added vectors.\n   */\n  async addVectors(\n    vectors: number[][],\n    documents: Document<Metadata>[]\n  ): Promise<string[]> {\n    const rows = vectors.map((embedding, idx) => ({\n      content: documents[idx].pageContent,\n      embedding: `[${embedding.join(\",\")}]`,\n      metadata: JSON.stringify(documents[idx].metadata),\n    }));\n\n    const batchSize = 100;\n    const ids: string[] = [];\n\n    for (let i = 0; i < rows.length; i += batchSize) {\n      const chunk = rows.slice(i, i + batchSize);\n\n      const insertQueries: InStatement[] = chunk.map((row) => ({\n        sql: `INSERT INTO ${this.table} (content, metadata, ${this.column}) VALUES (:content, :metadata, vector(:embedding)) RETURNING ${this.table}.rowid AS id`,\n        args: row,\n      }));\n\n      const results = await this.db.batch(insertQueries);\n\n      ids.push(\n        ...results.flatMap((result) => result.rows.map((row) => String(row.id)))\n      );\n    }\n\n    return ids;\n  }\n\n  /**\n   * Performs a similarity search using a vector query and returns documents with their scores.\n   * @param {number[]} query - The query vector.\n   * @param {number} k - The number of results to return.\n   * @returns {Promise<[Document<Metadata>, number][]>} An array of tuples containing the similar documents and their scores.\n   */\n  async similaritySearchVectorWithScore(\n    query: number[],\n    k: number,\n    filter?: this[\"FilterType\"]\n  ): Promise<[Document<Metadata>, number][]> {\n    // Potential SQL injection risk if query vector is not properly sanitized.\n    if (!query.every((num) => typeof num === \"number\" && !Number.isNaN(num))) {\n      throw new Error(\"Invalid query vector: all elements must be numbers\");\n    }\n\n    const queryVector = `[${query.join(\",\")}]`;\n\n    const sql = {\n      sql: `SELECT ${this.table}.rowid as id, ${this.table}.content, ${this.table}.metadata, vector_distance_cos(${this.table}.${this.column}, vector(:queryVector)) AS distance\n      FROM vector_top_k('idx_${this.table}_${this.column}', vector(:queryVector), CAST(:k AS INTEGER)) as top_k\n      JOIN ${this.table} ON top_k.rowid = ${this.table}.rowid`,\n      args: { queryVector, k },\n    } satisfies InStatement;\n\n    // Filter is a raw sql where clause, so append it to the join\n    if (typeof filter === \"string\") {\n      sql.sql += ` AND ${filter}`;\n    } else if (typeof filter === \"object\") {\n      // Filter is an in statement.\n      if (\"sql\" in filter) {\n        sql.sql += ` AND ${filter.sql}`;\n        sql.args = {\n          ...filter.args,\n          ...sql.args,\n        };\n      } else {\n        const builder = new SqliteWhereBuilder(filter);\n        const where = builder.buildWhereClause();\n\n        sql.sql += ` AND ${where.sql}`;\n        sql.args = {\n          ...where.args,\n          ...sql.args,\n        };\n      }\n    }\n\n    const results = await this.db.execute(sql);\n\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    return results.rows.map((row: any) => {\n      const metadata = JSON.parse(row.metadata);\n\n      const doc = new Document<Metadata>({\n        id: String(row.id),\n        metadata,\n        pageContent: row.content,\n      });\n\n      return [doc, row.distance];\n    });\n  }\n\n  /**\n   * Deletes vectors from the store.\n   * @param {Object} params - Delete parameters.\n   * @param {string[] | number[]} [params.ids] - The ids of the vectors to delete.\n   * @returns {Promise<void>}\n   */\n  async delete(params: {\n    ids?: string[] | number[];\n    deleteAll?: boolean;\n  }): Promise<void> {\n    if (params.deleteAll) {\n      await this.db.execute(`DELETE FROM ${this.table}`);\n    } else if (params.ids !== undefined) {\n      await this.db.batch(\n        params.ids.map((id) => ({\n          sql: `DELETE FROM ${this.table} WHERE rowid = :id`,\n          args: { id },\n        }))\n      );\n    } else {\n      throw new Error(\n        `You must provide an \"ids\" parameter or a \"deleteAll\" parameter.`\n      );\n    }\n  }\n\n  /**\n   * Creates a new LibSQLVectorStore instance from texts.\n   * @param {string[]} texts - The texts to add to the store.\n   * @param {object[] | object} metadatas - The metadata for the texts.\n   * @param {EmbeddingsInterface} embeddings - The embeddings interface to use.\n   * @param {Client} dbClient - The LibSQL client instance.\n   * @param {LibSQLVectorStoreArgs} [options] - Configuration options for the vector store.\n   * @returns {Promise<LibSQLVectorStore>} A new LibSQLVectorStore instance.\n   */\n  static async fromTexts<Metadata extends MetadataDefault = MetadataDefault>(\n    texts: string[],\n    metadatas: Metadata[] | Metadata,\n    embeddings: EmbeddingsInterface,\n    options: LibSQLVectorStoreArgs\n  ): Promise<LibSQLVectorStore<Metadata>> {\n    const docs = texts.map((text, i) => {\n      const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas;\n\n      return new Document({ pageContent: text, metadata });\n    });\n\n    return LibSQLVectorStore.fromDocuments(docs, embeddings, options);\n  }\n\n  /**\n   * Creates a new LibSQLVectorStore instance from documents.\n   * @param {Document[]} docs - The documents to add to the store.\n   * @param {EmbeddingsInterface} embeddings - The embeddings interface to use.\n   * @param {Client} dbClient - The LibSQL client instance.\n   * @param {LibSQLVectorStoreArgs} [options] - Configuration options for the vector store.\n   * @returns {Promise<LibSQLVectorStore>} A new LibSQLVectorStore instance.\n   */\n  static async fromDocuments<\n    Metadata extends MetadataDefault = MetadataDefault,\n  >(\n    docs: Document<Metadata>[],\n    embeddings: EmbeddingsInterface,\n    options: LibSQLVectorStoreArgs\n  ): Promise<LibSQLVectorStore<Metadata>> {\n    const instance = new this<Metadata>(embeddings, options);\n\n    await instance.addDocuments(docs);\n\n    return instance;\n  }\n}\n"],"mappings":"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"}