Skip to content

Commit af54639

Browse files
committed
refactor!: Refactor AlloyDBVectorStore to depend on PGVectorstore
1 parent 3b6fc68 commit af54639

12 files changed

+86
-3750
lines changed

src/langchain_google_alloydb_pg/async_vectorstore.py

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

src/langchain_google_alloydb_pg/vectorstore.py

Lines changed: 26 additions & 716 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
@@ -28,9 +28,6 @@
2828
from langchain_google_alloydb_pg import AlloyDBEngine, Column
2929
from langchain_google_alloydb_pg.async_vectorstore import AsyncAlloyDBVectorStore
3030

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

@@ -109,43 +106,9 @@ async def engine(self, db_project, db_region, db_cluster, db_instance, db_name):
109106
)
110107

111108
yield engine
112-
await aexecute(engine, f'DROP TABLE IF EXISTS "{DEFAULT_TABLE}"')
113-
await aexecute(engine, f'DROP TABLE IF EXISTS "{CUSTOM_TABLE}"')
109+
await aexecute(engine, f'DROP TABLE IF EXISTS "{IMAGE_TABLE}"')
114110
await engine.close()
115111

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

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

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

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

0 commit comments

Comments
 (0)