Skip to content

Commit 4c918dc

Browse files
committed
refactor!: Refactor AlloyDBVectorStore to depend on PGVectorstore
1 parent 55b7af3 commit 4c918dc

12 files changed

+81
-3755
lines changed

src/langchain_google_alloydb_pg/async_vectorstore.py

Lines changed: 8 additions & 1213 deletions
Large diffs are not rendered by default.

src/langchain_google_alloydb_pg/vectorstore.py

Lines changed: 25 additions & 714 deletions
Large diffs are not rendered by default.

tests/test_async_vectorstore.py

Lines changed: 2 additions & 265 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@
2929
from langchain_google_alloydb_pg import AlloyDBEngine
3030
from langchain_google_alloydb_pg.async_vectorstore import AsyncAlloyDBVectorStore
3131

32-
DEFAULT_TABLE = "test_table" + str(uuid.uuid4())
33-
DEFAULT_TABLE_SYNC = "test_table_sync" + str(uuid.uuid4())
34-
CUSTOM_TABLE = "test-table-custom" + str(uuid.uuid4())
3532
IMAGE_TABLE = "test_image_table" + str(uuid.uuid4())
3633
VECTOR_SIZE = 768
3734

@@ -110,43 +107,9 @@ async def engine(self, db_project, db_region, db_cluster, db_instance, db_name):
110107
)
111108

112109
yield engine
113-
await aexecute(engine, f'DROP TABLE IF EXISTS "{DEFAULT_TABLE}"')
114-
await aexecute(engine, f'DROP TABLE IF EXISTS "{CUSTOM_TABLE}"')
110+
await aexecute(engine, f'DROP TABLE IF EXISTS "{IMAGE_TABLE}"')
115111
await engine.close()
116112

117-
@pytest_asyncio.fixture(scope="class")
118-
async def vs(self, engine):
119-
await engine._ainit_vectorstore_table(DEFAULT_TABLE, VECTOR_SIZE)
120-
vs = await AsyncAlloyDBVectorStore.create(
121-
engine,
122-
embedding_service=embeddings_service,
123-
table_name=DEFAULT_TABLE,
124-
)
125-
yield vs
126-
127-
@pytest_asyncio.fixture(scope="class")
128-
async def vs_custom(self, engine):
129-
await engine._ainit_vectorstore_table(
130-
CUSTOM_TABLE,
131-
VECTOR_SIZE,
132-
id_column="myid",
133-
content_column="mycontent",
134-
embedding_column="myembedding",
135-
metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
136-
metadata_json_column="mymeta",
137-
)
138-
vs = await AsyncAlloyDBVectorStore.create(
139-
engine,
140-
embedding_service=embeddings_service,
141-
table_name=CUSTOM_TABLE,
142-
id_column="myid",
143-
content_column="mycontent",
144-
embedding_column="myembedding",
145-
metadata_columns=["page", "source"],
146-
metadata_json_column="mymeta",
147-
)
148-
yield vs
149-
150113
@pytest_asyncio.fixture(scope="class")
151114
async def image_vs(self, engine):
152115
await engine._ainit_vectorstore_table(
@@ -187,32 +150,6 @@ async def image_uris(self):
187150
except FileNotFoundError:
188151
pass
189152

190-
async def test_init_with_constructor(self, engine):
191-
with pytest.raises(Exception):
192-
AsyncAlloyDBVectorStore(
193-
engine,
194-
embedding_service=embeddings_service,
195-
table_name=CUSTOM_TABLE,
196-
id_column="myid",
197-
content_column="noname",
198-
embedding_column="myembedding",
199-
metadata_columns=["page", "source"],
200-
metadata_json_column="mymeta",
201-
)
202-
203-
async def test_post_init(self, engine):
204-
with pytest.raises(ValueError):
205-
await AsyncAlloyDBVectorStore.create(
206-
engine,
207-
embedding_service=embeddings_service,
208-
table_name=CUSTOM_TABLE,
209-
id_column="myid",
210-
content_column="noname",
211-
embedding_column="myembedding",
212-
metadata_columns=["page", "source"],
213-
metadata_json_column="mymeta",
214-
)
215-
216153
async def test_id_metadata_column(self, engine):
217154
table_name = "id_metadata" + str(uuid.uuid4())
218155
await engine._ainit_vectorstore_table(
@@ -236,39 +173,6 @@ async def test_id_metadata_column(self, engine):
236173
assert results[2]["id"] == "2"
237174
await aexecute(engine, f'DROP TABLE IF EXISTS "{table_name}"')
238175

239-
async def test_aadd_texts(self, engine, vs):
240-
ids = [str(uuid.uuid4()) for i in range(len(texts))]
241-
await vs.aadd_texts(texts, ids=ids)
242-
results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
243-
assert len(results) == 3
244-
245-
ids = [str(uuid.uuid4()) for i in range(len(texts))]
246-
await vs.aadd_texts(texts, metadatas, ids)
247-
results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
248-
assert len(results) == 6
249-
await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
250-
251-
async def test_aadd_texts_edge_cases(self, engine, vs):
252-
texts = ["Taylor's", '"Swift"', "best-friend"]
253-
ids = [str(uuid.uuid4()) for i in range(len(texts))]
254-
await vs.aadd_texts(texts, ids=ids)
255-
results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
256-
assert len(results) == 3
257-
await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
258-
259-
async def test_aadd_docs(self, engine, vs):
260-
ids = [str(uuid.uuid4()) for i in range(len(texts))]
261-
await vs.aadd_documents(docs, ids=ids)
262-
results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
263-
assert len(results) == 3
264-
await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
265-
266-
async def test_aadd_docs_no_ids(self, engine, vs):
267-
await vs.aadd_documents(docs)
268-
results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
269-
assert len(results) == 3
270-
await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
271-
272176
async def test_aadd_images(self, engine, image_vs, image_uris):
273177
ids = [str(uuid.uuid4()) for i in range(len(image_uris))]
274178
metadatas = [
@@ -305,171 +209,4 @@ async def test_aadd_images_store_uri_only(self, engine, image_vs, image_uris):
305209
result_row[image_vs.metadata_json_column]["image_uri"] == image_uris[i]
306210
)
307211

308-
await aexecute(engine, (f'TRUNCATE TABLE "{IMAGE_TABLE}"'))
309-
310-
async def test_adelete(self, engine, vs):
311-
ids = [str(uuid.uuid4()) for i in range(len(texts))]
312-
await vs.aadd_texts(texts, ids=ids)
313-
results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
314-
assert len(results) == 3
315-
# delete an ID
316-
await vs.adelete([ids[0]])
317-
results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
318-
assert len(results) == 2
319-
# delete with no ids
320-
result = await vs.adelete()
321-
assert result == False
322-
await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
323-
324-
##### Custom Vector Store #####
325-
async def test_aadd_embeddings(self, engine, vs_custom):
326-
await vs_custom.aadd_embeddings(
327-
texts=texts, embeddings=embeddings, metadatas=metadatas
328-
)
329-
results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
330-
assert len(results) == 3
331-
assert results[0]["mycontent"] == "foo"
332-
assert results[0]["myembedding"]
333-
assert results[0]["page"] == "0"
334-
assert results[0]["source"] == "google.com"
335-
await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
336-
337-
async def test_aadd_texts_custom(self, engine, vs_custom):
338-
ids = [str(uuid.uuid4()) for i in range(len(texts))]
339-
await vs_custom.aadd_texts(texts, ids=ids)
340-
results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
341-
assert len(results) == 3
342-
assert results[0]["mycontent"] == "foo"
343-
assert results[0]["myembedding"]
344-
assert results[0]["page"] is None
345-
assert results[0]["source"] is None
346-
347-
ids = [str(uuid.uuid4()) for i in range(len(texts))]
348-
await vs_custom.aadd_texts(texts, metadatas, ids)
349-
results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
350-
assert len(results) == 6
351-
await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
352-
353-
async def test_aadd_docs_custom(self, engine, vs_custom):
354-
ids = [str(uuid.uuid4()) for i in range(len(texts))]
355-
docs = [
356-
Document(
357-
page_content=texts[i],
358-
metadata={"page": str(i), "source": "google.com"},
359-
)
360-
for i in range(len(texts))
361-
]
362-
await vs_custom.aadd_documents(docs, ids=ids)
363-
364-
results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
365-
assert len(results) == 3
366-
assert results[0]["mycontent"] == "foo"
367-
assert results[0]["myembedding"]
368-
assert results[0]["page"] == "0"
369-
assert results[0]["source"] == "google.com"
370-
await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
371-
372-
async def test_adelete_custom(self, engine, vs_custom):
373-
ids = [str(uuid.uuid4()) for i in range(len(texts))]
374-
await vs_custom.aadd_texts(texts, ids=ids)
375-
results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
376-
content = [result["mycontent"] for result in results]
377-
assert len(results) == 3
378-
assert "foo" in content
379-
# delete an ID
380-
await vs_custom.adelete([ids[0]])
381-
results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
382-
content = [result["mycontent"] for result in results]
383-
assert len(results) == 2
384-
assert "foo" not in content
385-
await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
386-
387-
async def test_ignore_metadata_columns(self, engine):
388-
column_to_ignore = "source"
389-
vs = await AsyncAlloyDBVectorStore.create(
390-
engine,
391-
embedding_service=embeddings_service,
392-
table_name=CUSTOM_TABLE,
393-
ignore_metadata_columns=[column_to_ignore],
394-
id_column="myid",
395-
content_column="mycontent",
396-
embedding_column="myembedding",
397-
metadata_json_column="mymeta",
398-
)
399-
assert column_to_ignore not in vs.metadata_columns
400-
401-
async def test_create_vectorstore_with_invalid_parameters_1(self, engine):
402-
with pytest.raises(ValueError):
403-
await AsyncAlloyDBVectorStore.create(
404-
engine,
405-
embedding_service=embeddings_service,
406-
table_name=CUSTOM_TABLE,
407-
id_column="myid",
408-
content_column="mycontent",
409-
embedding_column="myembedding",
410-
metadata_columns=["random_column"], # invalid metadata column
411-
)
412-
413-
async def test_create_vectorstore_with_invalid_parameters_2(self, engine):
414-
with pytest.raises(ValueError):
415-
await AsyncAlloyDBVectorStore.create(
416-
engine,
417-
embedding_service=embeddings_service,
418-
table_name=CUSTOM_TABLE,
419-
id_column="myid",
420-
content_column="langchain_id", # invalid content column type
421-
embedding_column="myembedding",
422-
metadata_columns=["random_column"],
423-
)
424-
425-
async def test_create_vectorstore_with_invalid_parameters_3(self, engine):
426-
with pytest.raises(ValueError):
427-
await AsyncAlloyDBVectorStore.create(
428-
engine,
429-
embedding_service=embeddings_service,
430-
table_name=CUSTOM_TABLE,
431-
id_column="myid",
432-
content_column="mycontent",
433-
embedding_column="random_column", # invalid embedding column
434-
metadata_columns=["random_column"],
435-
)
436-
437-
async def test_create_vectorstore_with_invalid_parameters_4(self, engine):
438-
with pytest.raises(ValueError):
439-
await AsyncAlloyDBVectorStore.create(
440-
engine,
441-
embedding_service=embeddings_service,
442-
table_name=CUSTOM_TABLE,
443-
id_column="myid",
444-
content_column="mycontent",
445-
embedding_column="langchain_id", # invalid embedding column data type
446-
metadata_columns=["random_column"],
447-
)
448-
449-
async def test_create_vectorstore_with_invalid_parameters_5(self, engine):
450-
with pytest.raises(ValueError):
451-
await AsyncAlloyDBVectorStore.create(
452-
engine,
453-
embedding_service=embeddings_service,
454-
table_name=CUSTOM_TABLE,
455-
id_column="myid",
456-
content_column="mycontent",
457-
embedding_column="langchain_id",
458-
metadata_columns=["random_column"],
459-
ignore_metadata_columns=[
460-
"one",
461-
"two",
462-
], # invalid use of metadata_columns and ignore columns
463-
)
464-
465-
async def test_create_vectorstore_with_init(self, engine):
466-
with pytest.raises(Exception):
467-
await AsyncAlloyDBVectorStore(
468-
engine._pool,
469-
embedding_service=embeddings_service,
470-
table_name=CUSTOM_TABLE,
471-
id_column="myid",
472-
content_column="mycontent",
473-
embedding_column="myembedding",
474-
metadata_columns=["random_column"], # invalid metadata column
475-
)
212+
await aexecute(engine, (f'TRUNCATE TABLE "{IMAGE_TABLE}"'))

0 commit comments

Comments
 (0)