sqlspec 0.62.0__py3-none-any.whl → 0.62.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Any, Final, Literal, cast
7
7
  import asyncmy
8
8
  from typing_extensions import NotRequired
9
9
 
10
+ from sqlspec.adapters.asyncmy.core import resolve_rowcount
10
11
  from sqlspec.config import ADKConfig
11
12
  from sqlspec.extensions.adk import BaseAsyncADKStore, StoredEvent, StoredSession, normalize_session_list_options
12
13
  from sqlspec.extensions.adk.memory.store import BaseAsyncADKMemoryStore
@@ -309,7 +310,7 @@ class AsyncmyADKStore(BaseAsyncADKStore["AsyncmyConfig"]):
309
310
  async with self._config.provide_connection() as conn, conn.cursor() as cursor:
310
311
  await cursor.execute(sql, tuple(params))
311
312
  await conn.commit()
312
- return cursor.rowcount if cursor.rowcount and cursor.rowcount > 0 else 0
313
+ return resolve_rowcount(cursor)
313
314
  except asyncmy.errors.ProgrammingError as exc: # pyright: ignore[reportAttributeAccessIssue]
314
315
  if _is_mysql_table_missing(exc):
315
316
  return 0
@@ -327,7 +328,7 @@ class AsyncmyADKStore(BaseAsyncADKStore["AsyncmyConfig"]):
327
328
  async with self._config.provide_connection() as conn, conn.cursor() as cursor:
328
329
  await cursor.execute(sql, tuple(params))
329
330
  await conn.commit()
330
- return cursor.rowcount if cursor.rowcount and cursor.rowcount > 0 else 0
331
+ return resolve_rowcount(cursor)
331
332
  except asyncmy.errors.ProgrammingError as exc: # pyright: ignore[reportAttributeAccessIssue]
332
333
  if _is_mysql_table_missing(exc):
333
334
  return 0
@@ -345,7 +346,7 @@ class AsyncmyADKStore(BaseAsyncADKStore["AsyncmyConfig"]):
345
346
  async with self._config.provide_connection() as conn, conn.cursor() as cursor:
346
347
  await cursor.execute(sql, tuple(params))
347
348
  await conn.commit()
348
- return cursor.rowcount if cursor.rowcount and cursor.rowcount > 0 else 0
349
+ return resolve_rowcount(cursor)
349
350
  except asyncmy.errors.ProgrammingError as exc: # pyright: ignore[reportAttributeAccessIssue]
350
351
  if _is_mysql_table_missing(exc):
351
352
  return 0
@@ -545,7 +546,7 @@ class AsyncmyADKMemoryStore(BaseAsyncADKMemoryStore["AsyncmyConfig"]):
545
546
  entry["inserted_at"],
546
547
  )
547
548
  await cursor.execute(sql, params)
548
- inserted_count += cursor.rowcount
549
+ inserted_count += resolve_rowcount(cursor)
549
550
  await conn.commit()
550
551
  return inserted_count
551
552
 
@@ -608,7 +609,7 @@ class AsyncmyADKMemoryStore(BaseAsyncADKMemoryStore["AsyncmyConfig"]):
608
609
  async with self._config.provide_connection() as conn, conn.cursor() as cursor:
609
610
  await cursor.execute(sql, (session_id,))
610
611
  await conn.commit()
611
- return cursor.rowcount if cursor.rowcount and cursor.rowcount > 0 else 0
612
+ return resolve_rowcount(cursor)
612
613
 
613
614
  async def delete_entries_older_than(
614
615
  self, days: int, app_name: "str | None" = None, scope: "str | None" = None
@@ -632,7 +633,7 @@ class AsyncmyADKMemoryStore(BaseAsyncADKMemoryStore["AsyncmyConfig"]):
632
633
  async with self._config.provide_connection() as conn, conn.cursor() as cursor:
633
634
  await cursor.execute(sql, tuple(params))
634
635
  await conn.commit()
635
- return cursor.rowcount if cursor.rowcount and cursor.rowcount > 0 else 0
636
+ return resolve_rowcount(cursor)
636
637
 
637
638
  async def _memory_table_ddl(self) -> str:
638
639
  """Get MySQL CREATE TABLE SQL for memory entries."""
@@ -325,7 +325,7 @@ class AsyncmyConfig(AsyncDatabaseConfig[AsyncmyConnection, "AsyncmyPool", Asyncm
325
325
 
326
326
  Future driver_features can be added here if needed.
327
327
  """
328
- return cast("AsyncmyPool", await asyncmy.create_pool(**_pool_config(self.connection_config)))
328
+ return await asyncmy.create_pool(**_pool_config(self.connection_config))
329
329
 
330
330
  async def _ensure_connection(self, connection: "AsyncmyConnection") -> None:
331
331
  """Ensure connection callback has been called exactly once for this connection.
@@ -3,6 +3,7 @@
3
3
  from datetime import datetime, timedelta, timezone
4
4
  from typing import TYPE_CHECKING, Any, Final, cast
5
5
 
6
+ from sqlspec.adapters.asyncmy.core import resolve_rowcount
6
7
  from sqlspec.exceptions import ImproperConfigurationError
7
8
  from sqlspec.extensions.litestar.store import BaseSQLSpecStore
8
9
  from sqlspec.utils.logging import get_logger
@@ -227,7 +228,7 @@ class AsyncmyStore(BaseSQLSpecStore["AsyncmyConfig"]):
227
228
  async with self._config.provide_connection() as conn, conn.cursor() as cursor:
228
229
  await cursor.execute(sql)
229
230
  await conn.commit()
230
- count: int = cursor.rowcount
231
+ count = resolve_rowcount(cursor)
231
232
  if count > 0:
232
233
  self._log_delete_expired(count)
233
234
  return count
@@ -599,6 +599,8 @@ class AsyncpgADKMemoryStore(BaseAsyncADKMemoryStore["AsyncpgConfig"]):
599
599
  return
600
600
 
601
601
  async with self._config.provide_session() as driver:
602
+ if self._enable_bm25:
603
+ self._config._ensure_pg_textsearch_available()
602
604
  await driver.execute_script(await self._memory_table_ddl())
603
605
 
604
606
  async def insert_memory_entries(self, entries: "list[StoredMemory]", owner_id: "object | None" = None) -> int:
@@ -616,9 +618,9 @@ class AsyncpgADKMemoryStore(BaseAsyncADKMemoryStore["AsyncpgConfig"]):
616
618
  sql = f"""
617
619
  INSERT INTO {self._memory_table}
618
620
  (id, session_id, app_name, user_id, scope, event_id, author,
619
- {self._owner_id_column_name}, timestamp, content_json,
621
+ {self._owner_id_column_name}, timestamp, embedding, content_json,
620
622
  content_text, metadata_json, inserted_at)
621
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
623
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10::float8[]::vector, $11, $12, $13, $14)
622
624
  ON CONFLICT (event_id) DO NOTHING
623
625
  """
624
626
  result = await conn.execute(
@@ -632,6 +634,7 @@ class AsyncpgADKMemoryStore(BaseAsyncADKMemoryStore["AsyncpgConfig"]):
632
634
  entry["author"],
633
635
  owner_id,
634
636
  entry["timestamp"],
637
+ entry.get("embedding"),
635
638
  entry["content_json"],
636
639
  entry["content_text"],
637
640
  entry["metadata_json"],
@@ -641,8 +644,8 @@ class AsyncpgADKMemoryStore(BaseAsyncADKMemoryStore["AsyncpgConfig"]):
641
644
  sql = f"""
642
645
  INSERT INTO {self._memory_table}
643
646
  (id, session_id, app_name, user_id, scope, event_id, author,
644
- timestamp, content_json, content_text, metadata_json, inserted_at)
645
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
647
+ timestamp, embedding, content_json, content_text, metadata_json, inserted_at)
648
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::float8[]::vector, $10, $11, $12, $13)
646
649
  ON CONFLICT (event_id) DO NOTHING
647
650
  """
648
651
  result = await conn.execute(
@@ -655,13 +658,14 @@ class AsyncpgADKMemoryStore(BaseAsyncADKMemoryStore["AsyncpgConfig"]):
655
658
  entry["event_id"],
656
659
  entry["author"],
657
660
  entry["timestamp"],
661
+ entry.get("embedding"),
658
662
  entry["content_json"],
659
663
  entry["content_text"],
660
664
  entry["metadata_json"],
661
665
  entry["inserted_at"],
662
666
  )
663
667
  try:
664
- inserted_count += int(result.split(" ")[1])
668
+ inserted_count += int(result.rsplit(" ", 1)[-1])
665
669
  except (IndexError, ValueError):
666
670
  continue
667
671
 
@@ -706,7 +710,7 @@ class AsyncpgADKMemoryStore(BaseAsyncADKMemoryStore["AsyncpgConfig"]):
706
710
  candidate_limit = max(limit_value * 2, 50)
707
711
  sql = f"""
708
712
  WITH vector_matches AS (
709
- SELECT id, RANK() OVER (ORDER BY embedding <=> {p_vec}) AS rank_vec
713
+ SELECT id, RANK() OVER (ORDER BY embedding <=> {p_vec}::float8[]::vector) AS rank_vec
710
714
  FROM {self._memory_table}
711
715
  WHERE {where_scope} AND embedding IS NOT NULL
712
716
  LIMIT {p_cand}
@@ -732,7 +736,7 @@ class AsyncpgADKMemoryStore(BaseAsyncADKMemoryStore["AsyncpgConfig"]):
732
736
  sql = f"""
733
737
  SELECT * FROM {self._memory_table}
734
738
  WHERE {where_scope} AND embedding IS NOT NULL
735
- ORDER BY embedding <=> {p_vec} ASC, timestamp DESC
739
+ ORDER BY embedding <=> {p_vec}::float8[]::vector ASC, timestamp DESC
736
740
  LIMIT {p_lim}
737
741
  """
738
742
  params = (*scope_params, list(embedding), limit_value)
@@ -759,6 +763,8 @@ class AsyncpgADKMemoryStore(BaseAsyncADKMemoryStore["AsyncpgConfig"]):
759
763
  params = (*scope_params, f"%{query}%", limit_value)
760
764
 
761
765
  async with self._config.provide_connection() as conn:
766
+ if embedding is not None and self._enable_bm25 and query:
767
+ self._config._ensure_pg_textsearch_available()
762
768
  rows = await conn.fetch(sql, *params)
763
769
  return [cast("StoredMemory", dict(row)) for row in rows]
764
770
 
@@ -821,7 +827,7 @@ class AsyncpgADKMemoryStore(BaseAsyncADKMemoryStore["AsyncpgConfig"]):
821
827
 
822
828
  if self._enable_bm25:
823
829
  indexes.append(
824
- f"CREATE INDEX IF NOT EXISTS idx_{self._memory_table}_bm25 ON {self._memory_table} USING bm25 (content_text);"
830
+ f"CREATE INDEX IF NOT EXISTS idx_{self._memory_table}_bm25 ON {self._memory_table} USING bm25 (content_text) WITH (text_config='english');"
825
831
  )
826
832
 
827
833
  if self._vector_index_type == "scann":
@@ -326,6 +326,8 @@ class AsyncpgConfig(AsyncDatabaseConfig[AsyncpgConnection, "Pool[Record]", Async
326
326
  self._alloydb_connector: Any | None = None
327
327
  self._pgvector_available: bool | None = None
328
328
  self._paradedb_available: bool | None = None
329
+ self._pg_textsearch_available: bool | None = None
330
+ self._pg_textsearch_probe_error: Exception | None = None
329
331
 
330
332
  self._validate_connector_config()
331
333
 
@@ -452,17 +454,28 @@ class AsyncpgConfig(AsyncDatabaseConfig[AsyncpgConnection, "Pool[Record]", Async
452
454
  if self._pgvector_available is None:
453
455
  detected_extensions: set[str] = set()
454
456
  extensions = build_postgres_extension_probe_names(self.driver_features)
457
+ adk_config = self.extension_config.get("adk", {})
458
+ bm25_enabled = bool(
459
+ isinstance(adk_config, dict)
460
+ and adk_config.get("enable_memory", True)
461
+ and adk_config.get("enable_bm25", False)
462
+ )
463
+ if bm25_enabled:
464
+ extensions.append("pg_textsearch")
455
465
  if extensions:
456
466
  try:
457
467
  results = await connection.fetch(
458
468
  "SELECT extname FROM pg_extension WHERE extname = ANY($1::text[])", extensions
459
469
  )
460
470
  detected_extensions = {r["extname"] for r in results}
461
- except Exception:
471
+ except Exception as exc:
462
472
  detected_extensions = set()
473
+ if bm25_enabled:
474
+ self._pg_textsearch_probe_error = exc
463
475
  self.statement_config, self._pgvector_available, self._paradedb_available = (
464
476
  resolve_postgres_extension_state(self.statement_config, self.driver_features, detected_extensions)
465
477
  )
478
+ self._pg_textsearch_available = "pg_textsearch" in detected_extensions if bm25_enabled else False
466
479
 
467
480
  if self._pgvector_available:
468
481
  await register_pgvector_support(connection)
@@ -471,6 +484,12 @@ class AsyncpgConfig(AsyncDatabaseConfig[AsyncpgConnection, "Pool[Record]", Async
471
484
  if self._user_connection_hook is not None:
472
485
  await self._user_connection_hook(connection)
473
486
 
487
+ def _ensure_pg_textsearch_available(self) -> None:
488
+ if self._pg_textsearch_available:
489
+ return
490
+ msg = "ADK memory enable_bm25 requires the pg_textsearch PostgreSQL extension"
491
+ raise ImproperConfigurationError(msg) from self._pg_textsearch_probe_error
492
+
474
493
  async def _close_pool(self) -> None:
475
494
  """Close the actual async connection pool and cleanup connectors."""
476
495
  if self.connection_instance:
@@ -1240,6 +1240,8 @@ class PsycopgAsyncADKMemoryStore(BaseAsyncADKMemoryStore["PsycopgAsyncConfig"]):
1240
1240
  return
1241
1241
 
1242
1242
  async with self._config.provide_session() as driver:
1243
+ if self._enable_bm25:
1244
+ self._config._ensure_pg_textsearch_available()
1243
1245
  await driver.execute_script(await self._memory_table_ddl())
1244
1246
 
1245
1247
  async def insert_memory_entries(self, entries: "list[StoredMemory]", owner_id: "object | None" = None) -> int:
@@ -1256,10 +1258,10 @@ class PsycopgAsyncADKMemoryStore(BaseAsyncADKMemoryStore["PsycopgAsyncConfig"]):
1256
1258
  query = pg_sql.SQL("""
1257
1259
  INSERT INTO {table} (
1258
1260
  id, session_id, app_name, user_id, scope, event_id, author,
1259
- {owner_id_col}, timestamp, content_json, content_text,
1261
+ {owner_id_col}, timestamp, embedding, content_json, content_text,
1260
1262
  metadata_json, inserted_at
1261
1263
  ) VALUES (
1262
- %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
1264
+ %s, %s, %s, %s, %s, %s, %s, %s, %s, %s::float8[]::vector, %s, %s, %s, %s
1263
1265
  )
1264
1266
  ON CONFLICT (event_id) DO NOTHING
1265
1267
  """).format(
@@ -1269,9 +1271,9 @@ class PsycopgAsyncADKMemoryStore(BaseAsyncADKMemoryStore["PsycopgAsyncConfig"]):
1269
1271
  query = pg_sql.SQL("""
1270
1272
  INSERT INTO {table} (
1271
1273
  id, session_id, app_name, user_id, scope, event_id, author,
1272
- timestamp, content_json, content_text, metadata_json, inserted_at
1274
+ timestamp, embedding, content_json, content_text, metadata_json, inserted_at
1273
1275
  ) VALUES (
1274
- %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
1276
+ %s, %s, %s, %s, %s, %s, %s, %s, %s::float8[]::vector, %s, %s, %s, %s
1275
1277
  )
1276
1278
  ON CONFLICT (event_id) DO NOTHING
1277
1279
  """).format(table=pg_sql.Identifier(self._memory_table))
@@ -1395,7 +1397,7 @@ class PsycopgAsyncADKMemoryStore(BaseAsyncADKMemoryStore["PsycopgAsyncConfig"]):
1395
1397
  sql = pg_sql.SQL(
1396
1398
  """
1397
1399
  WITH vector_matches AS (
1398
- SELECT id, RANK() OVER (ORDER BY embedding <=> %s) AS rank_vec
1400
+ SELECT id, RANK() OVER (ORDER BY embedding <=> %s::float8[]::vector) AS rank_vec
1399
1401
  FROM {table}
1400
1402
  WHERE {where_scope} AND embedding IS NOT NULL
1401
1403
  LIMIT %s
@@ -1417,6 +1419,7 @@ class PsycopgAsyncADKMemoryStore(BaseAsyncADKMemoryStore["PsycopgAsyncConfig"]):
1417
1419
  ).format(table=pg_sql.Identifier(self._memory_table), where_scope=where_scope)
1418
1420
  params = (list(embedding), *scope_params, candidate_limit, query, *scope_params, candidate_limit, limit)
1419
1421
  async with self._config.provide_connection() as conn, conn.cursor(row_factory=dict_row) as cur:
1422
+ self._config._ensure_pg_textsearch_available()
1420
1423
  await cur.execute(sql, params)
1421
1424
  rows = await cur.fetchall()
1422
1425
  return _rows_to_records(rows)
@@ -1434,7 +1437,7 @@ class PsycopgAsyncADKMemoryStore(BaseAsyncADKMemoryStore["PsycopgAsyncConfig"]):
1434
1437
  """
1435
1438
  SELECT * FROM {table}
1436
1439
  WHERE {where_scope} AND embedding IS NOT NULL
1437
- ORDER BY embedding <=> %s ASC, timestamp DESC
1440
+ ORDER BY embedding <=> %s::float8[]::vector ASC, timestamp DESC
1438
1441
  LIMIT %s
1439
1442
  """
1440
1443
  ).format(table=pg_sql.Identifier(self._memory_table), where_scope=where_scope)
@@ -1504,6 +1507,8 @@ class PsycopgSyncADKMemoryStore(BaseSyncADKMemoryStore["PsycopgSyncConfig"]):
1504
1507
  return
1505
1508
 
1506
1509
  with self._config.provide_session() as driver:
1510
+ if self._enable_bm25:
1511
+ self._config._ensure_pg_textsearch_available()
1507
1512
  driver.execute_script(self._memory_table_ddl())
1508
1513
 
1509
1514
  def insert_memory_entries(self, entries: "list[StoredMemory]", owner_id: "object | None" = None) -> int:
@@ -1520,10 +1525,10 @@ class PsycopgSyncADKMemoryStore(BaseSyncADKMemoryStore["PsycopgSyncConfig"]):
1520
1525
  query = pg_sql.SQL("""
1521
1526
  INSERT INTO {table} (
1522
1527
  id, session_id, app_name, user_id, scope, event_id, author,
1523
- {owner_id_col}, timestamp, content_json, content_text,
1528
+ {owner_id_col}, timestamp, embedding, content_json, content_text,
1524
1529
  metadata_json, inserted_at
1525
1530
  ) VALUES (
1526
- %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
1531
+ %s, %s, %s, %s, %s, %s, %s, %s, %s, %s::float8[]::vector, %s, %s, %s, %s
1527
1532
  )
1528
1533
  ON CONFLICT (event_id) DO NOTHING
1529
1534
  """).format(
@@ -1533,9 +1538,9 @@ class PsycopgSyncADKMemoryStore(BaseSyncADKMemoryStore["PsycopgSyncConfig"]):
1533
1538
  query = pg_sql.SQL("""
1534
1539
  INSERT INTO {table} (
1535
1540
  id, session_id, app_name, user_id, scope, event_id, author,
1536
- timestamp, content_json, content_text, metadata_json, inserted_at
1541
+ timestamp, embedding, content_json, content_text, metadata_json, inserted_at
1537
1542
  ) VALUES (
1538
- %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
1543
+ %s, %s, %s, %s, %s, %s, %s, %s, %s::float8[]::vector, %s, %s, %s, %s
1539
1544
  )
1540
1545
  ON CONFLICT (event_id) DO NOTHING
1541
1546
  """).format(table=pg_sql.Identifier(self._memory_table))
@@ -1656,7 +1661,7 @@ class PsycopgSyncADKMemoryStore(BaseSyncADKMemoryStore["PsycopgSyncConfig"]):
1656
1661
  sql = pg_sql.SQL(
1657
1662
  """
1658
1663
  WITH vector_matches AS (
1659
- SELECT id, RANK() OVER (ORDER BY embedding <=> %s) AS rank_vec
1664
+ SELECT id, RANK() OVER (ORDER BY embedding <=> %s::float8[]::vector) AS rank_vec
1660
1665
  FROM {table}
1661
1666
  WHERE {where_scope} AND embedding IS NOT NULL
1662
1667
  LIMIT %s
@@ -1678,6 +1683,7 @@ class PsycopgSyncADKMemoryStore(BaseSyncADKMemoryStore["PsycopgSyncConfig"]):
1678
1683
  ).format(table=pg_sql.Identifier(self._memory_table), where_scope=where_scope)
1679
1684
  params = (list(embedding), *scope_params, candidate_limit, query, *scope_params, candidate_limit, limit)
1680
1685
  with self._config.provide_connection() as conn, conn.cursor(row_factory=dict_row) as cur:
1686
+ self._config._ensure_pg_textsearch_available()
1681
1687
  cur.execute(sql, params)
1682
1688
  rows = cur.fetchall()
1683
1689
  return _rows_to_records(rows)
@@ -1695,7 +1701,7 @@ class PsycopgSyncADKMemoryStore(BaseSyncADKMemoryStore["PsycopgSyncConfig"]):
1695
1701
  """
1696
1702
  SELECT * FROM {table}
1697
1703
  WHERE {where_scope} AND embedding IS NOT NULL
1698
- ORDER BY embedding <=> %s ASC, timestamp DESC
1704
+ ORDER BY embedding <=> %s::float8[]::vector ASC, timestamp DESC
1699
1705
  LIMIT %s
1700
1706
  """
1701
1707
  ).format(table=pg_sql.Identifier(self._memory_table), where_scope=where_scope)
@@ -1760,6 +1766,7 @@ def _build_insert_params(entry: "StoredMemory") -> "tuple[object, ...]":
1760
1766
  entry["event_id"],
1761
1767
  entry["author"],
1762
1768
  entry["timestamp"],
1769
+ entry.get("embedding"),
1763
1770
  Jsonb(entry["content_json"]),
1764
1771
  entry["content_text"],
1765
1772
  Jsonb(entry["metadata_json"]) if entry["metadata_json"] is not None else None,
@@ -1778,6 +1785,7 @@ def _build_insert_params_with_owner(entry: "StoredMemory", owner_id: "object | N
1778
1785
  entry["author"],
1779
1786
  owner_id,
1780
1787
  entry["timestamp"],
1788
+ entry.get("embedding"),
1781
1789
  Jsonb(entry["content_json"]),
1782
1790
  entry["content_text"],
1783
1791
  Jsonb(entry["metadata_json"]) if entry["metadata_json"] is not None else None,
@@ -1868,7 +1876,7 @@ def _postgres_memory_indexes(
1868
1876
 
1869
1877
  if enable_bm25:
1870
1878
  indexes.append(
1871
- f"CREATE INDEX IF NOT EXISTS idx_{memory_table}_bm25 ON {memory_table} USING bm25 (content_text);"
1879
+ f"CREATE INDEX IF NOT EXISTS idx_{memory_table}_bm25 ON {memory_table} USING bm25 (content_text) WITH (text_config='english');"
1872
1880
  )
1873
1881
 
1874
1882
  if vector_index_type == "scann":
@@ -312,6 +312,8 @@ class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool
312
312
  features_dict.setdefault("alloydb_ip_type", "PRIVATE")
313
313
  self._pgvector_available: bool | None = None
314
314
  self._paradedb_available: bool | None = None
315
+ self._pg_textsearch_available: bool | None = None
316
+ self._pg_textsearch_probe_error: Exception | None = None
315
317
  self._alloydb_connector: Any | None = None
316
318
 
317
319
  super().__init__(
@@ -428,6 +430,14 @@ class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool
428
430
  if self._pgvector_available is None:
429
431
  detected_extensions: set[str] = set()
430
432
  extensions = build_postgres_extension_probe_names(self.driver_features)
433
+ adk_config = self.extension_config.get("adk", {})
434
+ bm25_enabled = bool(
435
+ isinstance(adk_config, dict)
436
+ and adk_config.get("enable_memory", True)
437
+ and adk_config.get("enable_bm25", False)
438
+ )
439
+ if bm25_enabled:
440
+ extensions.append("pg_textsearch")
431
441
  if extensions:
432
442
  try:
433
443
  cursor = conn.execute(
@@ -435,11 +445,14 @@ class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool
435
445
  )
436
446
  results = cursor.fetchall()
437
447
  detected_extensions = {r[0] for r in results} # type: ignore[index]
438
- except Exception:
448
+ except Exception as exc:
439
449
  detected_extensions = set()
450
+ if bm25_enabled:
451
+ self._pg_textsearch_probe_error = exc
440
452
  self.statement_config, self._pgvector_available, self._paradedb_available = (
441
453
  resolve_postgres_extension_state(self.statement_config, self.driver_features, detected_extensions)
442
454
  )
455
+ self._pg_textsearch_available = "pg_textsearch" in detected_extensions if bm25_enabled else False
443
456
 
444
457
  if self._pgvector_available:
445
458
  register_pgvector_sync(conn)
@@ -452,6 +465,12 @@ class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool
452
465
  if self._user_connection_hook is not None:
453
466
  self._user_connection_hook(conn)
454
467
 
468
+ def _ensure_pg_textsearch_available(self) -> None:
469
+ if self._pg_textsearch_available:
470
+ return
471
+ msg = "ADK memory enable_bm25 requires the pg_textsearch PostgreSQL extension"
472
+ raise ImproperConfigurationError(msg) from self._pg_textsearch_probe_error
473
+
455
474
  def _close_pool(self) -> None:
456
475
  """Close the actual connection pool and cleanup connectors."""
457
476
  try:
@@ -638,6 +657,8 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
638
657
  )
639
658
  self._pgvector_available: bool | None = None
640
659
  self._paradedb_available: bool | None = None
660
+ self._pg_textsearch_available: bool | None = None
661
+ self._pg_textsearch_probe_error: Exception | None = None
641
662
 
642
663
  super().__init__(
643
664
  connection_config=connection_config,
@@ -700,6 +721,14 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
700
721
  if self._pgvector_available is None:
701
722
  detected_extensions: set[str] = set()
702
723
  extensions = build_postgres_extension_probe_names(self.driver_features)
724
+ adk_config = self.extension_config.get("adk", {})
725
+ bm25_enabled = bool(
726
+ isinstance(adk_config, dict)
727
+ and adk_config.get("enable_memory", True)
728
+ and adk_config.get("enable_bm25", False)
729
+ )
730
+ if bm25_enabled:
731
+ extensions.append("pg_textsearch")
703
732
  if extensions:
704
733
  try:
705
734
  cursor = await conn.execute(
@@ -707,11 +736,14 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
707
736
  )
708
737
  results = await cursor.fetchall()
709
738
  detected_extensions = {r[0] for r in results} # type: ignore[index]
710
- except Exception:
739
+ except Exception as exc:
711
740
  detected_extensions = set()
741
+ if bm25_enabled:
742
+ self._pg_textsearch_probe_error = exc
712
743
  self.statement_config, self._pgvector_available, self._paradedb_available = (
713
744
  resolve_postgres_extension_state(self.statement_config, self.driver_features, detected_extensions)
714
745
  )
746
+ self._pg_textsearch_available = "pg_textsearch" in detected_extensions if bm25_enabled else False
715
747
 
716
748
  if self._pgvector_available:
717
749
  await register_pgvector_async(conn)
@@ -724,6 +756,12 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
724
756
  if self._user_connection_hook is not None:
725
757
  await self._user_connection_hook(conn)
726
758
 
759
+ def _ensure_pg_textsearch_available(self) -> None:
760
+ if self._pg_textsearch_available:
761
+ return
762
+ msg = "ADK memory enable_bm25 requires the pg_textsearch PostgreSQL extension"
763
+ raise ImproperConfigurationError(msg) from self._pg_textsearch_probe_error
764
+
727
765
  async def _close_pool(self) -> None:
728
766
  """Close the actual async connection pool."""
729
767
  if not self.connection_instance:
sqlspec/builder/_ddl.py CHANGED
@@ -688,7 +688,7 @@ class _SingleObjectDropBuilder(DDLBuilder, _IfExistsDDLMixin, _CascadeRestrictDD
688
688
  self._require(self._name, f"{self._object_label} name must be set for DROP {self._drop_kind}.")
689
689
  return exp.Drop(
690
690
  kind=self._drop_kind,
691
- this=self._build_drop_this(),
691
+ tables=[self._build_drop_this()],
692
692
  exists=self._if_exists,
693
693
  cascade=self._cascade,
694
694
  **self._drop_expression_args(),
@@ -1464,10 +1464,10 @@ class AlterTable(DDLBuilder, _IfExistsDDLMixin):
1464
1464
  return build_column_expression(op.column_definition)
1465
1465
 
1466
1466
  if op_type == "DROP COLUMN":
1467
- return exp.Drop(this=exp.to_identifier(op.column_name), kind="COLUMN", exists=True)
1467
+ return exp.Drop(tables=[exp.to_identifier(op.column_name)], kind="COLUMN", exists=True)
1468
1468
 
1469
1469
  if op_type == "DROP COLUMN CASCADE":
1470
- return exp.Drop(this=exp.to_identifier(op.column_name), kind="COLUMN", cascade=True, exists=True)
1470
+ return exp.Drop(tables=[exp.to_identifier(op.column_name)], kind="COLUMN", cascade=True, exists=True)
1471
1471
 
1472
1472
  if op_type == "ALTER COLUMN TYPE":
1473
1473
  if not op.new_type:
@@ -1488,10 +1488,12 @@ class AlterTable(DDLBuilder, _IfExistsDDLMixin):
1488
1488
  return exp.AddConstraint(expressions=[constraint_expr])
1489
1489
 
1490
1490
  if op_type == "DROP CONSTRAINT":
1491
- return exp.Drop(this=exp.to_identifier(op.constraint_name), kind="CONSTRAINT", exists=True)
1491
+ return exp.Drop(tables=[exp.to_identifier(op.constraint_name)], kind="CONSTRAINT", exists=True)
1492
1492
 
1493
1493
  if op_type == "DROP CONSTRAINT CASCADE":
1494
- return exp.Drop(this=exp.to_identifier(op.constraint_name), kind="CONSTRAINT", cascade=True, exists=True)
1494
+ return exp.Drop(
1495
+ tables=[exp.to_identifier(op.constraint_name)], kind="CONSTRAINT", cascade=True, exists=True
1496
+ )
1495
1497
 
1496
1498
  if op_type == "ALTER COLUMN SET NOT NULL":
1497
1499
  return exp.AlterColumn(this=exp.to_identifier(op.column_name), allow_null=False)
sqlspec/config.py CHANGED
@@ -739,7 +739,7 @@ class ADKConfig(TypedDict):
739
739
  """Dimensionality of embedding vectors (e.g. 768 for gemini-embedding-001 with MRL). Default: 768."""
740
740
 
741
741
  enable_bm25: NotRequired[bool]
742
- """Enable native pg_textsearch BM25 full-text indexing on AlloyDB / PostgreSQL 17+. Default: False."""
742
+ """Enable native BM25 full-text indexing. Requires the pg_textsearch extension. Default: False."""
743
743
 
744
744
  scann_num_leaves: NotRequired[int]
745
745
  """Number of partition leaves (clusters) for ScaNN tree quantization. Default: 100."""
@@ -1524,8 +1524,8 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
1524
1524
  self.extension_config = extension_config or {}
1525
1525
  self.migration_config = migration_config or {}
1526
1526
  self._init_observability(observability_config)
1527
- self._initialize_migration_components()
1528
1527
  self.statement_config = statement_config or build_default_statement_config(default_dialect)
1528
+ self._initialize_migration_components()
1529
1529
  self._storage_capabilities = None
1530
1530
  self.driver_features = seed_runtime_driver_features(driver_features, self.storage_capabilities())
1531
1531
  self._attach_lifecycle_hooks()
@@ -8,8 +8,8 @@ Creates the canonical ADK tables:
8
8
  - adk_internal_metadata
9
9
  - adk_memory (when memory is enabled)
10
10
 
11
- On PostgreSQL the migration installs the ``vector`` extension before the first
12
- memory statement that declares a ``VECTOR`` column.
11
+ On PostgreSQL the migration installs required extensions before the first
12
+ memory statement that uses them.
13
13
  """
14
14
 
15
15
  import inspect
@@ -38,9 +38,11 @@ __all__ = ("down", "up")
38
38
  logger = get_logger("sqlspec.migrations.adk.create")
39
39
 
40
40
  CREATE_VECTOR_EXTENSION = "CREATE EXTENSION IF NOT EXISTS vector"
41
+ CREATE_PG_TEXTSEARCH_EXTENSION = "CREATE EXTENSION IF NOT EXISTS pg_textsearch"
41
42
 
42
43
  _POSTGRES_DIALECTS = frozenset({"postgres", "postgresql", "pgvector", "paradedb"})
43
44
  _VECTOR_COLUMN_PATTERN = re.compile(r"\bVECTOR\s*\(", re.IGNORECASE)
45
+ _BM25_INDEX_PATTERN = re.compile(r"\bUSING\s+bm25\s*\(", re.IGNORECASE)
44
46
 
45
47
 
46
48
  async def up(context: "MigrationContext | None" = None) -> "list[str]":
@@ -70,7 +72,7 @@ async def up(context: "MigrationContext | None" = None) -> "list[str]":
70
72
  if inspect.isawaitable(memory_sql):
71
73
  memory_sql = await memory_sql
72
74
  memory_statements = list(memory_sql) if isinstance(memory_sql, list) else [memory_sql]
73
- statements.extend(_with_vector_extension(memory_statements, context))
75
+ statements.extend(_with_postgres_extensions(memory_statements, context))
74
76
  log_with_context(
75
77
  logger, logging.DEBUG, "adk.migration.create.memory.create", table_name=memory_store.memory_table
76
78
  )
@@ -98,15 +100,24 @@ async def down(context: "MigrationContext | None" = None) -> "list[str]":
98
100
  return statements
99
101
 
100
102
 
101
- def _with_vector_extension(statements: "list[str]", context: "MigrationContext") -> "list[str]":
102
- """Prepend the PostgreSQL vector extension before the first vector statement."""
103
+ def _with_postgres_extensions(statements: "list[str]", context: "MigrationContext") -> "list[str]":
104
+ """Prepend required PostgreSQL extensions before their first use."""
103
105
  dialect = (context.dialect or "").lower()
104
106
  if dialect not in _POSTGRES_DIALECTS:
105
107
  return statements
106
- for index, statement in enumerate(statements):
107
- if _VECTOR_COLUMN_PATTERN.search(statement):
108
- return [*statements[:index], CREATE_VECTOR_EXTENSION, *statements[index:]]
109
- return statements
108
+
109
+ result: list[str] = []
110
+ vector_enabled = False
111
+ pg_textsearch_enabled = False
112
+ for statement in statements:
113
+ if not vector_enabled and _VECTOR_COLUMN_PATTERN.search(statement):
114
+ result.append(CREATE_VECTOR_EXTENSION)
115
+ vector_enabled = True
116
+ if not pg_textsearch_enabled and _BM25_INDEX_PATTERN.search(statement):
117
+ result.append(CREATE_PG_TEXTSEARCH_EXTENSION)
118
+ pg_textsearch_enabled = True
119
+ result.append(statement)
120
+ return result
110
121
 
111
122
 
112
123
  def _raise_missing_config() -> NoReturn:
@@ -833,12 +833,21 @@ class SQLSpecPlugin(InitPluginProtocol, CLIPlugin):
833
833
  Args:
834
834
  name: A ``session_key``, ``connection_key``, or ``pool_key``.
835
835
 
836
+ Raises:
837
+ KeyError: If ``name`` is not a known dependency key.
838
+
836
839
  Returns:
837
840
  The matching plugin state.
838
841
  """
839
- if any(state.annotation is None for state in self._plugin_configs):
840
- self._raise_plugin_not_registered()
841
- return self._get_plugin_state(name)
842
+ if isinstance(name, str) and any(
843
+ name in {state.connection_key, state.pool_key, state.session_key} for state in self._plugin_configs
844
+ ):
845
+ if any(state.annotation is None for state in self._plugin_configs):
846
+ self._raise_plugin_not_registered()
847
+ return self._get_plugin_state(name)
848
+ self._raise_config_not_found(name)
849
+ msg = "unreachable"
850
+ raise AssertionError(msg)
842
851
 
843
852
  def _get_plugin_state(
844
853
  self, key: "str | DatabaseConfigProtocol[Any, Any, Any] | type[DatabaseConfigProtocol[Any, Any, Any]]"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sqlspec
3
- Version: 0.62.0
3
+ Version: 0.62.2
4
4
  Summary: SQL Experiments in Python
5
5
  Project-URL: Discord, https://discord.gg/litestar
6
6
  Project-URL: Issue, https://github.com/litestar-org/sqlspec/issues/
@@ -4,7 +4,7 @@ sqlspec/__metadata__.py,sha256=IUw6MCTy1oeUJ1jAVYbuJLkOWbiAWorZ5W-E-SAD9N4,395
4
4
  sqlspec/_typing.py,sha256=OLBKW7FSh22fPAr4BiLmFBovxi0MSVvA-KJzWE7RDDE,21809
5
5
  sqlspec/base.py,sha256=-yJlxdfDpZ-SHMTav87zqs39pu6zsKsLXBJYp8MsmPY,30257
6
6
  sqlspec/cli.py,sha256=2cD6ZYoXGA5RyGD_KtIulfbSp3YtK3RNNW3pqEDZ0I8,42427
7
- sqlspec/config.py,sha256=uPGzMq3RAYpHC674TsbWdlcYytU-c3IfsJ6DogwfPbc,81605
7
+ sqlspec/config.py,sha256=m5MWkorlbju3AiQ1ruIvXcDv_dkqJgsBwzQ2IJEyURs,81601
8
8
  sqlspec/exceptions.py,sha256=kbk9JjaWlBIQ6xeZIJHlhKMDd1RSOPSzqgAZ4dTk9xs,15128
9
9
  sqlspec/loader.py,sha256=SMTEa6MFg6EqnKuENNQDOPizKGXD2YuaE4COjE_3MFk,36208
10
10
  sqlspec/protocols.py,sha256=zfFH3w343I3qn11Fvo20jmghmTCd3GQWW-kpx8RQN9c,33942
@@ -66,24 +66,24 @@ sqlspec/adapters/arrow_odbc/litestar/__init__.py,sha256=8X-ptnPzniv1GvGOYSUHLKil
66
66
  sqlspec/adapters/arrow_odbc/litestar/store.py,sha256=XJ_g9w3-pRdVK-eh8MBCkDbFe2gGZzdwt5mKzsBV01U,11508
67
67
  sqlspec/adapters/asyncmy/__init__.py,sha256=EgFaxoi1bDhcJIo2ApXG2rsJ1q5ELvMv4PeV3A27OPA,671
68
68
  sqlspec/adapters/asyncmy/_typing.py,sha256=B-sge2R-b8LwFUNfgtfHT68qMGOwcA2n6B7gppHY55Q,5215
69
- sqlspec/adapters/asyncmy/config.py,sha256=0cF9xapSn8O602WJuiPomRbujSExN3zGp4YzH4V4DA4,16512
69
+ sqlspec/adapters/asyncmy/config.py,sha256=F2rY_QWIgKFJgTDHm2AhfAsfZpjGFJVbWoAdwgaJboc,16491
70
70
  sqlspec/adapters/asyncmy/core.py,sha256=DD9cIVq79qaqnrdXyrsYZ5EEwIkj6TkqeUUmfkSawoA,23019
71
71
  sqlspec/adapters/asyncmy/data_dictionary.py,sha256=8Xc9YhdS9JL2JpSscDiSha6q82sbKi7SwDGI2tyPx5k,14278
72
72
  sqlspec/adapters/asyncmy/driver.py,sha256=nK6hL5DA7SFvD4NYagpmMCmXNHDfUs2kW599GwfVEho,18344
73
73
  sqlspec/adapters/asyncmy/adk/__init__.py,sha256=jD7XeHf01jPsMigmHVHg2rh3Zs_41hzNf4ejzIOP6Fk,239
74
- sqlspec/adapters/asyncmy/adk/store.py,sha256=dXBsqfvxay-xc8tbsZDJ8lQpRm_oM03ksqJXdJyqBEI,38487
74
+ sqlspec/adapters/asyncmy/adk/store.py,sha256=0tS7lGJLB1cG7IsVZ1aXnbWvH6Op6w8lGjNWlMlILj0,38350
75
75
  sqlspec/adapters/asyncmy/events/__init__.py,sha256=lbYNTyDvrtMm9Cg_IP4x-_4CymFl2SU-nkBjc7sz45k,159
76
76
  sqlspec/adapters/asyncmy/events/store.py,sha256=zQMzTYuZkX1Tuw_jXnwLM19IPMgOeH90JQdAjX0VeUo,2687
77
77
  sqlspec/adapters/asyncmy/litestar/__init__.py,sha256=VNBusWFPvw4BBLHi7gSSY3S94JxjZ7oJoAavTVvcZ28,143
78
- sqlspec/adapters/asyncmy/litestar/store.py,sha256=uMApWsPTa0ljunTJr0TpsrHwMs6Irrw7S2jSjJPd8I0,10563
78
+ sqlspec/adapters/asyncmy/litestar/store.py,sha256=1xFCxR-8KXCRmzbNflxnTuuOkbwq-RZpq8vXg1kZ17g,10626
79
79
  sqlspec/adapters/asyncpg/__init__.py,sha256=mgfrmVs5E1jnKUM76AosWJ2Lceuq0dRw-49xcgAxpxo,751
80
80
  sqlspec/adapters/asyncpg/_typing.py,sha256=67ElS_NC8PAI8wMb7tY_-DXo_tdE_HSkexqsDVBJ73A,3727
81
- sqlspec/adapters/asyncpg/config.py,sha256=v3i12_rOq2ixf7vNYL9hYDHDscTj2h-nWiYbxByEjdY,24893
81
+ sqlspec/adapters/asyncpg/config.py,sha256=80IzVYLKkwcFWH9rhUp5lzzCSM44oLef8NKfGVxkyEQ,25868
82
82
  sqlspec/adapters/asyncpg/core.py,sha256=r1oj6HFR3950GeHmA0PrsnvkgQ2iYNtc9BhTKX4imnI,19522
83
83
  sqlspec/adapters/asyncpg/data_dictionary.py,sha256=Wdg-moMyVJHUUaIpuUhwCaFMN8pJmKiW5sTsQ6PDpck,17926
84
84
  sqlspec/adapters/asyncpg/driver.py,sha256=xmXl2LH2MS44yUj9Thp1opjbNhDZR0Dj_aNYRiG-ICk,30903
85
85
  sqlspec/adapters/asyncpg/adk/__init__.py,sha256=p1ZELfzC21x4zE9vl4How2_-UIdxkWt0HVhrISWl0iQ,213
86
- sqlspec/adapters/asyncpg/adk/store.py,sha256=BmHqk8l3hUgXqFGmr9WbIBXUIswGPMxjriinA8Lf_04,36483
86
+ sqlspec/adapters/asyncpg/adk/store.py,sha256=-3-PuWfRPAA-SnSeyg7XTQCWQT5B5zzyr2e0IMsMiQ4,36947
87
87
  sqlspec/adapters/asyncpg/events/__init__.py,sha256=YOlB9kRztWLqMeW87AGQKBTLIYNM2puuKy_EwWKvJX8,301
88
88
  sqlspec/adapters/asyncpg/events/_hub.py,sha256=flKFiiSvpVT9sR11wA99X00mvmAE7dr5me3tCrQgt-M,9834
89
89
  sqlspec/adapters/asyncpg/events/backend.py,sha256=fLC8XAJd6LLqjLOMch5PTiGUOrlSUVs8-jqrTZgtPRU,15493
@@ -204,13 +204,13 @@ sqlspec/adapters/psqlpy/litestar/__init__.py,sha256=ODTxzJFNmexprYuBZcCxQWsJXPuS
204
204
  sqlspec/adapters/psqlpy/litestar/store.py,sha256=gjDTnxUCS4_79Q2dqtwxn9fXiJlCiA89REr2RkgUXrU,8779
205
205
  sqlspec/adapters/psycopg/__init__.py,sha256=mYXt-Jl2BD35wnOIodPGFfYRKUQ6AT_X1qoUUhb5S4A,969
206
206
  sqlspec/adapters/psycopg/_typing.py,sha256=eGbCUsktUgx7wC92poF8k2j-Fw5AYlJc5szmKvrJOLo,8103
207
- sqlspec/adapters/psycopg/config.py,sha256=GqFJRSk8P4qw37DbWtK5lKto_mZb_wYOXoNRe-NwadY,35195
207
+ sqlspec/adapters/psycopg/config.py,sha256=tlR1m3oxht4IaMycw5sFBaAW-w01oZ-YvuzbU3W1xnE,37145
208
208
  sqlspec/adapters/psycopg/core.py,sha256=J5P-mE1Bv5t0411HJNLrWI9LWVVVUnxM1hrusN3wz9E,24902
209
209
  sqlspec/adapters/psycopg/data_dictionary.py,sha256=xtEhbOk49iZgkncskH8tE0sX1-YfZxHgg08dB_ovheA,30658
210
210
  sqlspec/adapters/psycopg/driver.py,sha256=FoZc_Z8aOmddmEPNtnINa45tNCoCVpA0v0sQ9LsB_WA,58156
211
211
  sqlspec/adapters/psycopg/type_converter.py,sha256=C-ynmx47HvpBOd4UalspSEnFMeRE9kZBIkOdhtsz_X4,2980
212
212
  sqlspec/adapters/psycopg/adk/__init__.py,sha256=WYeffXiBnWiCXLGKkP03zsWEz_BtfU8S79P2nd5ePXA,381
213
- sqlspec/adapters/psycopg/adk/store.py,sha256=IZmATs6GdHee3p-4_PzNvmuprJ9wIxBW9yakkdIr3mI,80420
213
+ sqlspec/adapters/psycopg/adk/store.py,sha256=VJWWc1yRiigdysto2IbB0zHPJuBSw2y-M7Bh6JDNq5c,81025
214
214
  sqlspec/adapters/psycopg/events/__init__.py,sha256=bJTqdKRaUZeDqn13rIS4zPKVm79fbkoch-8dceYgVYc,623
215
215
  sqlspec/adapters/psycopg/events/_hub.py,sha256=YssMbQ1_UCe4P_OhVF4wkYyXyeftBFegJ77sGWyL-yM,21051
216
216
  sqlspec/adapters/psycopg/events/backend.py,sha256=c6RJGGPVl0QVxz5kZndjgzyu4kctrHxzlrJo1Gv6e6o,28692
@@ -274,7 +274,7 @@ sqlspec/adapters/sqlite/litestar/store.py,sha256=d8Uk2YdbbkpIWKhLmVWue16fXVRfALx
274
274
  sqlspec/builder/__init__.py,sha256=S-yrPxGah-kKg0OtDE05qkB8nIRsVlNmtsP5dEchKW8,4380
275
275
  sqlspec/builder/_base.py,sha256=JPhbA_NyHsvB1cCvkyX4qYmfYKIR5-Hb3Xt3h4y3ACA,39774
276
276
  sqlspec/builder/_column.py,sha256=_Do3Xt7wkk2uEmdNKIIx3uMgEjdeXhGMmQbMbIefQ1Y,16312
277
- sqlspec/builder/_ddl.py,sha256=ll33voSWitHYFKt7pgrlZc3_p2hpIpUimkdEEryemCA,58056
277
+ sqlspec/builder/_ddl.py,sha256=bNpLdHYo9z_N5U518dR2ua2Se8sFgD2pR8a8OAFQk_M,58106
278
278
  sqlspec/builder/_delete.py,sha256=--KFsRs1XUA3TE1PZNd5YQgmyCJGaA4GvEGgiUho80U,2614
279
279
  sqlspec/builder/_dml.py,sha256=1uQJ9jcXXHTQcfe00voNmEIxLvoaRAjZgScLZF_jO4w,15373
280
280
  sqlspec/builder/_explain.py,sha256=S7wDHWeraZDft_hJZm6ajgJiwIzRo6E5-yIXThhTsH4,18813
@@ -556,7 +556,7 @@ sqlspec/extensions/adk/memory/_types.py,sha256=2WRAEmug7D0upyakhx5QpbgOEH2dMAoSX
556
556
  sqlspec/extensions/adk/memory/converters.py,sha256=zxH4rY6dEsP0Hw05DjyA6Y3iUGBHl0N9vFLktOKeEo8,7930
557
557
  sqlspec/extensions/adk/memory/service.py,sha256=QvbRIJlKFnd8MqS6Clq1zvLswFlg39sjQ75TyladkJM,11429
558
558
  sqlspec/extensions/adk/memory/store.py,sha256=m86r-gZf8A7Y6XRjr5llGh0Fcwh8_22UDGH6fsCdbrE,16135
559
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py,sha256=dE-NmbcN8GIN5-T49Ezopi1Sh-824b1W1KyClYWzwI8,6338
559
+ sqlspec/extensions/adk/migrations/0001_create_adk_tables.py,sha256=EBC8fxJJlC320r6fiOrVQ9o2x-zrZFlcjgZz3PKiEPk,6760
560
560
  sqlspec/extensions/adk/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
561
561
  sqlspec/extensions/events/__init__.py,sha256=ZD77SUD7t_g4zpI3RmeL2SGT9cwtx6sDkhmdcIbUoWM,1808
562
562
  sqlspec/extensions/events/_buffer.py,sha256=H7Lj4g_AafICFptFVSGquapH5uWrENk27f6wCB559Y0,1404
@@ -583,7 +583,7 @@ sqlspec/extensions/litestar/channels.py,sha256=W-EKVEmXOPrdrcsNh1a-FzIWGcdEE6V24
583
583
  sqlspec/extensions/litestar/cli.py,sha256=6ZHIWNT0RPzgr3LOKVAIEk9hUcyJTMUKgnpjkBrdliA,3476
584
584
  sqlspec/extensions/litestar/config.py,sha256=EvHRJjAdGuJkbRj0Ke7QsU6eXef_okLLPm0-atD4uXM,3597
585
585
  sqlspec/extensions/litestar/handlers.py,sha256=VTtBoCfl8zxtEe9N1_aZrFA4ILrEbP_2FjFuFg-9FF4,11162
586
- sqlspec/extensions/litestar/plugin.py,sha256=4-dQc_x85_Eoi_buSZ7oqFVeIlkfRy9ND8K0uz1YbPg,46142
586
+ sqlspec/extensions/litestar/plugin.py,sha256=t_e1MHDOx-8Hzn9s7Ua7elcWh68Ove8GVED0xaN6a_8,46506
587
587
  sqlspec/extensions/litestar/providers.py,sha256=ofpZf9EJbXVmVyqKkAM2ef1HM_4bEzpAT7EvK1Ejf7k,41361
588
588
  sqlspec/extensions/litestar/store.py,sha256=4b9QC4s7R7Xh_6WDbrGKyES__XZuIhtpWw_6uUTDHBg,9996
589
589
  sqlspec/extensions/litestar/migrations/0001_create_session_table.py,sha256=60HehSre1tXoHaOBx_75Hha-7smWP61RYrRVBYnIo8w,4206
@@ -665,8 +665,8 @@ sqlspec/utils/serializers/__init__.py,sha256=X99t8YMHVGmKwrqPxumnSXu4JMJL8SpKoU7
665
665
  sqlspec/utils/serializers/_json.py,sha256=5PBan5kHoDAGqbOqT33SdEK17VZzNjzZKneWI_BnDzY,18136
666
666
  sqlspec/utils/serializers/_numpy.py,sha256=_LllCtVn_gyLrRG2naHM7Unjtpot86BPTvGPlZuAGRw,1742
667
667
  sqlspec/utils/serializers/_schema.py,sha256=kN8lW8GJa08yMi_qN_x8A7XpO7V6aAaoYqKq72rxaCk,11416
668
- sqlspec-0.62.0.dist-info/METADATA,sha256=MPSGT5xHiXgsoJ-CnU7o0C7bS6LEiP49OqoqZQTYgr8,9066
669
- sqlspec-0.62.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
670
- sqlspec-0.62.0.dist-info/entry_points.txt,sha256=T_1g2gTpkUsl6YC-KSCoNS5r7CPG2kn6wyp1WyMvpqU,404
671
- sqlspec-0.62.0.dist-info/licenses/LICENSE,sha256=MdujfZ6l5HuLz4mElxlu049itenOR3gnhN1_Nd3nVcM,1078
672
- sqlspec-0.62.0.dist-info/RECORD,,
668
+ sqlspec-0.62.2.dist-info/METADATA,sha256=pdDXwLK4BTqODd8EBgo8AAaRs7cRPDUh4sRvnZYACyY,9066
669
+ sqlspec-0.62.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
670
+ sqlspec-0.62.2.dist-info/entry_points.txt,sha256=T_1g2gTpkUsl6YC-KSCoNS5r7CPG2kn6wyp1WyMvpqU,404
671
+ sqlspec-0.62.2.dist-info/licenses/LICENSE,sha256=MdujfZ6l5HuLz4mElxlu049itenOR3gnhN1_Nd3nVcM,1078
672
+ sqlspec-0.62.2.dist-info/RECORD,,