pyobvector 0.2.7__tar.gz → 0.2.9__tar.gz

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.
Files changed (35) hide show
  1. {pyobvector-0.2.7 → pyobvector-0.2.9}/PKG-INFO +3 -3
  2. {pyobvector-0.2.7 → pyobvector-0.2.9}/README.md +1 -1
  3. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/ob_vec_json_table_client.py +59 -34
  4. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyproject.toml +2 -2
  5. {pyobvector-0.2.7 → pyobvector-0.2.9}/LICENSE +0 -0
  6. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/__init__.py +0 -0
  7. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/__init__.py +0 -0
  8. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/collection_schema.py +0 -0
  9. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/enum.py +0 -0
  10. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/exceptions.py +0 -0
  11. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/fts_index_param.py +0 -0
  12. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/index_param.py +0 -0
  13. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/milvus_like_client.py +0 -0
  14. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/ob_vec_client.py +0 -0
  15. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/partitions.py +0 -0
  16. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/client/schema_type.py +0 -0
  17. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/json_table/__init__.py +0 -0
  18. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/json_table/json_value_returning_func.py +0 -0
  19. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/json_table/oceanbase_dialect.py +0 -0
  20. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/json_table/virtual_data_type.py +0 -0
  21. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/__init__.py +0 -0
  22. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/dialect.py +0 -0
  23. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/full_text_index.py +0 -0
  24. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/geo_srid_point.py +0 -0
  25. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/gis_func.py +0 -0
  26. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/match_against_func.py +0 -0
  27. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/ob_table.py +0 -0
  28. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/reflection.py +0 -0
  29. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/replace_stmt.py +0 -0
  30. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/vec_dist_func.py +0 -0
  31. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/vector.py +0 -0
  32. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/schema/vector_index.py +0 -0
  33. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/util/__init__.py +0 -0
  34. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/util/ob_version.py +0 -0
  35. {pyobvector-0.2.7 → pyobvector-0.2.9}/pyobvector/util/vector.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyobvector
3
- Version: 0.2.7
3
+ Version: 0.2.9
4
4
  Summary: A python SDK for OceanBase Vector Store, based on SQLAlchemy, compatible with Milvus API.
5
5
  Author: shanhaikang.shk
6
6
  Author-email: shanhaikang.shk@oceanbase.com
@@ -15,7 +15,7 @@ Requires-Dist: aiomysql (>=0.2.0,<0.3.0)
15
15
  Requires-Dist: numpy (>=1.17.0,<2.0.0)
16
16
  Requires-Dist: pydantic (>=2.7.0,<3)
17
17
  Requires-Dist: pymysql (>=1.1.1,<2.0.0)
18
- Requires-Dist: sqlalchemy (>=1.4,<2.0.36)
18
+ Requires-Dist: sqlalchemy (>=1.4,<=3)
19
19
  Requires-Dist: sqlglot (>=26.0.1,<27.0.0)
20
20
  Description-Content-Type: text/markdown
21
21
 
@@ -36,7 +36,7 @@ poetry install
36
36
  - install with pip:
37
37
 
38
38
  ```shell
39
- pip install pyobvector==0.2.7
39
+ pip install pyobvector==0.2.9
40
40
  ```
41
41
 
42
42
  ## Build Doc
@@ -15,7 +15,7 @@ poetry install
15
15
  - install with pip:
16
16
 
17
17
  ```shell
18
- pip install pyobvector==0.2.7
18
+ pip install pyobvector==0.2.9
19
19
  ```
20
20
 
21
21
  ## Build Doc
@@ -1,7 +1,7 @@
1
1
  import json
2
2
  import logging
3
3
  import re
4
- from typing import Dict, List, Optional, Any
4
+ from typing import Dict, List, Optional, Any, Union
5
5
 
6
6
  from sqlalchemy import Column, Integer, String, JSON, Engine, select, text, func, CursorResult
7
7
  from sqlalchemy.dialects.mysql import TINYINT
@@ -144,15 +144,16 @@ class ObVecJsonTableClient(ObVecClient):
144
144
  if self.user_id is None:
145
145
  return True
146
146
 
147
- session = self.session()
148
- distinct_admin_ids = (
149
- session.query(ObVecJsonTableClient.JsonTableDataTBL.admin_id)
150
- .filter_by(user_id = self.user_id)
151
- .distinct()
152
- .all()
153
- )
154
- admin_ids = [admin_id[0] for admin_id in distinct_admin_ids]
155
- return (len(admin_ids) == 0) or (len(admin_ids) == 1 and admin_ids[0] == self.admin_id)
147
+ with self.session() as session:
148
+ with session.begin():
149
+ distinct_admin_ids = (
150
+ session.query(ObVecJsonTableClient.JsonTableDataTBL.admin_id)
151
+ .filter_by(user_id = self.user_id)
152
+ .distinct()
153
+ .all()
154
+ )
155
+ admin_ids = [admin_id[0] for admin_id in distinct_admin_ids]
156
+ return (len(admin_ids) == 0) or (len(admin_ids) == 1 and admin_ids[0] == self.admin_id)
156
157
 
157
158
  def _reset(self):
158
159
  # Only for test
@@ -163,7 +164,12 @@ class ObVecJsonTableClient(ObVecClient):
163
164
  def refresh_metadata(self) -> None:
164
165
  self.jmetadata.reflect(self.engine)
165
166
 
166
- def perform_json_table_sql(self, sql: str, select_with_data_id: bool = False) -> Optional[CursorResult]:
167
+ def perform_json_table_sql(
168
+ self,
169
+ sql: str,
170
+ select_with_data_id: bool = False,
171
+ opt_user_id: Optional[str] = None,
172
+ ) -> Union[Optional[CursorResult], int]:
167
173
  """Perform common SQL that operates on JSON Table."""
168
174
  ast = parse_one(sql, dialect="oceanbase")
169
175
  if isinstance(ast, exp.Create):
@@ -176,16 +182,16 @@ class ObVecJsonTableClient(ObVecClient):
176
182
  self._handle_alter_json_table(ast)
177
183
  return None
178
184
  elif isinstance(ast, exp.Insert):
179
- self._handle_jtable_dml_insert(ast)
180
- return None
185
+ row_count = self._handle_jtable_dml_insert(ast, opt_user_id)
186
+ return row_count
181
187
  elif isinstance(ast, exp.Update):
182
- self._handle_jtable_dml_update(ast)
183
- return None
188
+ row_count = self._handle_jtable_dml_update(ast, opt_user_id)
189
+ return row_count
184
190
  elif isinstance(ast, exp.Delete):
185
- self._handle_jtable_dml_delete(ast)
186
- return None
191
+ row_count = self._handle_jtable_dml_delete(ast, opt_user_id)
192
+ return row_count
187
193
  elif isinstance(ast, exp.Select):
188
- return self._handle_jtable_dml_select(ast, select_with_data_id)
194
+ return self._handle_jtable_dml_select(ast, select_with_data_id, opt_user_id)
189
195
  else:
190
196
  raise ValueError(f"{type(ast)} not supported")
191
197
 
@@ -642,8 +648,10 @@ class ObVecJsonTableClient(ObVecClient):
642
648
  finally:
643
649
  session.close()
644
650
 
645
- def _handle_jtable_dml_insert(self, ast: Expression):
646
- if self.user_id is None:
651
+ def _handle_jtable_dml_insert(self, ast: Expression, opt_user_id: Optional[str] = None):
652
+ real_user_id = opt_user_id or self.user_id
653
+
654
+ if real_user_id is None:
647
655
  raise ValueError(f"inserting is disabled when user_id is None")
648
656
 
649
657
  if isinstance(ast.this, exp.Schema):
@@ -673,6 +681,7 @@ class ObVecJsonTableClient(ObVecClient):
673
681
  raise ValueError(f"Invalid ast type {ast.this}")
674
682
 
675
683
  session = self.session()
684
+ n_new_records = 0
676
685
  for tuple in ast.expression.expressions:
677
686
  expr_list = tuple.expressions
678
687
  if len(expr_list) != len(insert_col_names):
@@ -691,21 +700,26 @@ class ObVecJsonTableClient(ObVecClient):
691
700
  logger.debug(f"================= [INSERT] =============== {kv}")
692
701
 
693
702
  session.add(ObVecJsonTableClient.JsonTableDataTBL(
694
- user_id = self.user_id,
703
+ user_id = real_user_id,
695
704
  admin_id = self.admin_id,
696
705
  jtable_name = table_name,
697
706
  jdata = kv,
698
707
  ))
708
+ n_new_records += 1
699
709
 
700
710
  try:
701
711
  session.commit()
702
712
  except Exception as e:
703
713
  session.rollback()
704
714
  logger.error(f"Error occurred: {e}")
715
+ n_new_records = 0
705
716
  finally:
706
717
  session.close()
718
+ return n_new_records
719
+
720
+ def _handle_jtable_dml_update(self, ast: Expression, opt_user_id: Optional[str] = None):
721
+ real_user_id = opt_user_id or self.user_id
707
722
 
708
- def _handle_jtable_dml_update(self, ast: Expression):
709
723
  table_name = ast.this.this.this
710
724
  if not self._check_table_exists(table_name):
711
725
  raise ValueError(f"Table {table_name} does not exists")
@@ -733,7 +747,7 @@ class ObVecJsonTableClient(ObVecClient):
733
747
  path_settings.append(f"'$.{col_name}', {str(col_expr)}")
734
748
 
735
749
  where_clause = None
736
- if 'where' in ast.args.keys():
750
+ if 'where' in ast.args.keys() and ast.args['where']:
737
751
  for column in ast.args['where'].find_all(exp.Column):
738
752
  where_col_name = column.this.this
739
753
  if not self._check_col_exists(table_name, where_col_name):
@@ -741,8 +755,8 @@ class ObVecJsonTableClient(ObVecClient):
741
755
  column.parent.args['this'] = parse_one(
742
756
  f"JSON_VALUE({JSON_TABLE_DATA_TABLE_NAME}.jdata, '$.{where_col_name}')"
743
757
  )
744
- if self.user_id:
745
- where_clause = f"{JSON_TABLE_DATA_TABLE_NAME}.user_id = '{self.user_id}' AND {JSON_TABLE_DATA_TABLE_NAME}.jtable_name = '{table_name}' AND ({str(ast.args['where'].this)})"
758
+ if real_user_id:
759
+ where_clause = f"{JSON_TABLE_DATA_TABLE_NAME}.user_id = '{real_user_id}' AND {JSON_TABLE_DATA_TABLE_NAME}.jtable_name = '{table_name}' AND ({str(ast.args['where'].this)})"
746
760
  else:
747
761
  where_clause = f"{JSON_TABLE_DATA_TABLE_NAME}.jtable_name = '{table_name}' AND ({str(ast.args['where'].this)})"
748
762
 
@@ -752,15 +766,18 @@ class ObVecJsonTableClient(ObVecClient):
752
766
  update_sql = f"UPDATE {JSON_TABLE_DATA_TABLE_NAME} SET jdata = JSON_REPLACE({JSON_TABLE_DATA_TABLE_NAME}.jdata, {', '.join(path_settings)})"
753
767
 
754
768
  logger.debug(f"===================== do update: {update_sql}")
755
- self.perform_raw_text_sql(update_sql)
769
+ res = self.perform_raw_text_sql(update_sql)
770
+ return res.rowcount
771
+
772
+ def _handle_jtable_dml_delete(self, ast: Expression, opt_user_id: Optional[str] = None):
773
+ real_user_id = opt_user_id or self.user_id
756
774
 
757
- def _handle_jtable_dml_delete(self, ast: Expression):
758
775
  table_name = ast.this.this.this
759
776
  if not self._check_table_exists(table_name):
760
777
  raise ValueError(f"Table {table_name} does not exists")
761
778
 
762
779
  where_clause = None
763
- if 'where' in ast.args.keys():
780
+ if 'where' in ast.args.keys() and ast.args['where']:
764
781
  for column in ast.args['where'].find_all(exp.Column):
765
782
  where_col_name = column.this.this
766
783
  if not self._check_col_exists(table_name, where_col_name):
@@ -768,8 +785,8 @@ class ObVecJsonTableClient(ObVecClient):
768
785
  column.parent.args['this'] = parse_one(
769
786
  f"JSON_VALUE({JSON_TABLE_DATA_TABLE_NAME}.jdata, '$.{where_col_name}')"
770
787
  )
771
- if self.user_id:
772
- where_clause = f"{JSON_TABLE_DATA_TABLE_NAME}.user_id = '{self.user_id}' AND {JSON_TABLE_DATA_TABLE_NAME}.jtable_name = '{table_name}' AND ({str(ast.args['where'].this)})"
788
+ if real_user_id:
789
+ where_clause = f"{JSON_TABLE_DATA_TABLE_NAME}.user_id = '{real_user_id}' AND {JSON_TABLE_DATA_TABLE_NAME}.jtable_name = '{table_name}' AND ({str(ast.args['where'].this)})"
773
790
  else:
774
791
  where_clause = f"{JSON_TABLE_DATA_TABLE_NAME}.jtable_name = '{table_name}' AND ({str(ast.args['where'].this)})"
775
792
 
@@ -779,7 +796,8 @@ class ObVecJsonTableClient(ObVecClient):
779
796
  delete_sql = f"DELETE FROM {JSON_TABLE_DATA_TABLE_NAME}"
780
797
 
781
798
  logger.debug(f"===================== do delete: {delete_sql}")
782
- self.perform_raw_text_sql(delete_sql)
799
+ res = self.perform_raw_text_sql(delete_sql)
800
+ return res.rowcount
783
801
 
784
802
  def _get_full_datatype(self, jdata_type: str):
785
803
  if jdata_type.upper() == "VARCHAR":
@@ -788,7 +806,14 @@ class ObVecJsonTableClient(ObVecClient):
788
806
  return "DECIMAL(10, 0)"
789
807
  return jdata_type
790
808
 
791
- def _handle_jtable_dml_select(self, ast: Expression, select_with_data_id: bool = False):
809
+ def _handle_jtable_dml_select(
810
+ self,
811
+ ast: Expression,
812
+ select_with_data_id: bool = False,
813
+ opt_user_id: Optional[str] = None
814
+ ):
815
+ real_user_id = opt_user_id or self.user_id
816
+
792
817
  table_name = ast.args['from'].this.this.this
793
818
  if not self._check_table_exists(table_name):
794
819
  raise ValueError(f"Table {table_name} does not exists")
@@ -856,8 +881,8 @@ class ObVecJsonTableClient(ObVecClient):
856
881
  else:
857
882
  ast.args['joins'] = [join_node]
858
883
 
859
- if self.user_id:
860
- extra_filter_str = f"{JSON_TABLE_DATA_TABLE_NAME}.user_id = '{self.user_id}' AND {JSON_TABLE_DATA_TABLE_NAME}.jtable_name = '{table_name}'"
884
+ if real_user_id:
885
+ extra_filter_str = f"{JSON_TABLE_DATA_TABLE_NAME}.user_id = '{real_user_id}' AND {JSON_TABLE_DATA_TABLE_NAME}.jtable_name = '{table_name}'"
861
886
  else:
862
887
  extra_filter_str = f"{JSON_TABLE_DATA_TABLE_NAME}.jtable_name = '{table_name}'"
863
888
  if 'where' in ast.args.keys():
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pyobvector"
3
- version = "0.2.7"
3
+ version = "0.2.9"
4
4
  description = "A python SDK for OceanBase Vector Store, based on SQLAlchemy, compatible with Milvus API."
5
5
  authors = ["shanhaikang.shk <shanhaikang.shk@oceanbase.com>"]
6
6
  readme = "README.md"
@@ -8,7 +8,7 @@ readme = "README.md"
8
8
  [tool.poetry.dependencies]
9
9
  python = ">=3.9,<4.0"
10
10
  numpy = ">=1.17.0,<2.0.0"
11
- sqlalchemy = ">=1.4,<2.0.36"
11
+ sqlalchemy = ">=1.4,<=3"
12
12
  pymysql = "^1.1.1"
13
13
  aiomysql = "^0.2.0"
14
14
  sqlglot = "^26.0.1"
File without changes