iris-vector-graph 1.78.0__tar.gz → 1.80.0__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 (247) hide show
  1. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/PKG-INFO +1 -1
  2. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/cypher/ast.py +3 -0
  3. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/cypher/parser.py +58 -13
  4. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/cypher/translator.py +99 -23
  5. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/pyproject.toml +1 -1
  6. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/.gitignore +0 -0
  7. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/LICENSE +0 -0
  8. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/README.md +0 -0
  9. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/demo_biomedical.py +0 -0
  10. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/demo_fraud_detection.py +0 -0
  11. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/demo_fraud_detection_sql.py +0 -0
  12. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/demo_utils.py +0 -0
  13. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/demo_working_system.py +0 -0
  14. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/__init__.py +0 -0
  15. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/biomedical/__init__.py +0 -0
  16. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/biomedical/loaders.py +0 -0
  17. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/biomedical/resolver.py +0 -0
  18. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/biomedical/types.py +0 -0
  19. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/biomedical_legacy/__init__.py +0 -0
  20. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/biomedical_legacy/biomedical_engine.py +0 -0
  21. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/biomedical_legacy/biomedical_schema.py +0 -0
  22. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/biomedical_legacy/legacy_wrapper.py +0 -0
  23. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/fraud/__init__.py +0 -0
  24. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/fraud/loaders.py +0 -0
  25. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/fraud/resolver.py +0 -0
  26. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/domains/fraud/types.py +0 -0
  27. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/graphQL.http +0 -0
  28. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/hybrid_vector_graph_query.cypher +0 -0
  29. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/examples/rest.http +0 -0
  30. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/Algorithms.cls +0 -0
  31. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/ArnoAccel.cls +0 -0
  32. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/BM25Index.cls +0 -0
  33. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/BenchFormat.cls +0 -0
  34. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/BenchSeeder.cls +0 -0
  35. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/Benchmark.cls +0 -0
  36. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/Edge.cls +0 -0
  37. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/EdgeScan.cls +0 -0
  38. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/GraphIndex.cls +0 -0
  39. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/IVFIndex.cls +0 -0
  40. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/Loader.cls +0 -0
  41. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/MCPService.cls +0 -0
  42. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/MCPToolSet.cls +0 -0
  43. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/MCPTools.cls +0 -0
  44. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/Meta.cls +0 -0
  45. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/NKGAccel.cls +0 -0
  46. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/PLAIDSearch.cls +0 -0
  47. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/PageRank.cls +0 -0
  48. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/PyOps.cls +0 -0
  49. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/Service.cls +0 -0
  50. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/Snapshot.cls +0 -0
  51. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/Subgraph.cls +0 -0
  52. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/TemporalIndex.cls +0 -0
  53. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/TestEdge.cls +0 -0
  54. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/Traversal.cls +0 -0
  55. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/Graph/KG/VecIndex.cls +0 -0
  56. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/IVG/Percentile.cls +0 -0
  57. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/PageRankEmbedded.cls +0 -0
  58. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/User.Exec.cls +0 -0
  59. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_src/src/iris/vector/graph/GraphOperators.cls +0 -0
  60. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/__init__.py +0 -0
  61. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/bolt_server.py +0 -0
  62. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/bulk_loader.py +0 -0
  63. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/capabilities.py +0 -0
  64. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/cypher/__init__.py +0 -0
  65. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/cypher/algorithms/__init__.py +0 -0
  66. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/cypher/algorithms/paths.py +0 -0
  67. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/cypher/lexer.py +0 -0
  68. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/cypher_api.py +0 -0
  69. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/embedded.py +0 -0
  70. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/engine.py +0 -0
  71. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/fusion.py +0 -0
  72. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/gql/__init__.py +0 -0
  73. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/gql/constants.py +0 -0
  74. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/gql/engine.py +0 -0
  75. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/gql/pooling.py +0 -0
  76. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/gql/resolvers.py +0 -0
  77. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/gql/schema.py +0 -0
  78. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/models.py +0 -0
  79. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/operators.py +0 -0
  80. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/py.typed +0 -0
  81. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/schema.py +0 -0
  82. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/security.py +0 -0
  83. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/status.py +0 -0
  84. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/text_search.py +0 -0
  85. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/utils.py +0 -0
  86. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/iris_vector_graph/vector_utils.py +0 -0
  87. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/fhir_bridges.sql +0 -0
  88. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/fraud_sample_data.sql +0 -0
  89. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/globals_schema.sql +0 -0
  90. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/graph_path_globals.sql +0 -0
  91. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/graph_walk_tvf.sql +0 -0
  92. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/migrations/000_base_schema_iris.sql +0 -0
  93. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/migrations/001_add_nodepk_table.sql +0 -0
  94. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/migrations/001_rollback_nodepk.sql +0 -0
  95. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/migrations/002_add_fk_constraints.sql +0 -0
  96. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/operators.sql +0 -0
  97. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/operators_fixed.sql +0 -0
  98. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/procedures/kg_PageRank.sql +0 -0
  99. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/rdf_reifications.sql +0 -0
  100. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/sql/schema.sql +0 -0
  101. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/TESTING.md +0 -0
  102. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/benchmark_parser.py +0 -0
  103. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/benchmarks/benchmark_neo4j.py +0 -0
  104. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/benchmarks/bfs_benchmark.py +0 -0
  105. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/benchmarks/establish_baseline.py +0 -0
  106. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/benchmarks/graph_gen.py +0 -0
  107. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/benchmarks/iris_baseline_run.py +0 -0
  108. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/benchmarks/iris_os_run.py +0 -0
  109. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/benchmarks/load_neo4j.py +0 -0
  110. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/benchmarks/synthetic_baseline.csv +0 -0
  111. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/conftest.py +0 -0
  112. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/contract/__init__.py +0 -0
  113. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/contract/test_cypher_api.py +0 -0
  114. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/contract/test_cypher_api_errors.py +0 -0
  115. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/contract/test_graphql_queries.py +0 -0
  116. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/contract/test_graphql_schema.py +0 -0
  117. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/contract/test_ppr_api.py +0 -0
  118. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/curl_suite.sh +0 -0
  119. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/__init__.py +0 -0
  120. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/conftest.py +0 -0
  121. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_biomedical_demo.py +0 -0
  122. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_biomedical_ui.py +0 -0
  123. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_cypher_coerce_e2e.py +0 -0
  124. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_cypher_sprints_e2e.py +0 -0
  125. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_cypher_vector_search.py +0 -0
  126. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_fhir_bridges_e2e.py +0 -0
  127. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_fraud_demo.py +0 -0
  128. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_fraud_ui.py +0 -0
  129. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_gql_autogen_startup.py +0 -0
  130. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_gql_cypher_passthrough.py +0 -0
  131. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_gql_node_queries.py +0 -0
  132. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_gql_semantic_search.py +0 -0
  133. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_gql_traversal.py +0 -0
  134. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_graph_kernels_e2e.py +0 -0
  135. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_hla_kg_e2e.py +0 -0
  136. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_multi_query_engine_platform.py +0 -0
  137. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_named_paths_e2e.py +0 -0
  138. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_nkg_index_e2e.py +0 -0
  139. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_operator_wiring_e2e.py +0 -0
  140. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_plaid_search_e2e.py +0 -0
  141. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_ppr_cls_fast_path.py +0 -0
  142. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_ppr_guided_e2e.py +0 -0
  143. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_procedure_installation.py +0 -0
  144. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_reification_e2e.py +0 -0
  145. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_schema_procedures_e2e.py +0 -0
  146. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_subgraph_e2e.py +0 -0
  147. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_subquery_call_e2e.py +0 -0
  148. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/e2e/test_vecindex_e2e.py +0 -0
  149. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/__init__.py +0 -0
  150. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/conftest.py +0 -0
  151. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/gql/__init__.py +0 -0
  152. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/gql/test_graphql_mutations.py +0 -0
  153. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/gql/test_graphql_nested_queries.py +0 -0
  154. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/gql/test_graphql_queries.py +0 -0
  155. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/gql/test_graphql_vector_search.py +0 -0
  156. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_bidirectional_ppr.py +0 -0
  157. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_cls_layer.py +0 -0
  158. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_cypher_advanced.py +0 -0
  159. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_cypher_enhancements.py +0 -0
  160. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_cypher_multi_type.py +0 -0
  161. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_cypher_rd.py +0 -0
  162. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_cypher_rel_vars.py +0 -0
  163. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_cypher_single_type.py +0 -0
  164. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_cypher_untyped.py +0 -0
  165. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_cypher_vector_search.py +0 -0
  166. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_embeddings_api.py +0 -0
  167. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_fastapi_graphql.py +0 -0
  168. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_fhir_bridges_integration.py +0 -0
  169. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_named_paths_integration.py +0 -0
  170. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_nodepk_advanced_benchmarks.py +0 -0
  171. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_nodepk_constraints.py +0 -0
  172. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_nodepk_graph_analytics.py +0 -0
  173. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_nodepk_migration.py +0 -0
  174. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_nodepk_performance.py +0 -0
  175. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_nodepk_production_scale.py +0 -0
  176. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_objectscript_classes.py +0 -0
  177. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_pagerank_sql_optimization.py +0 -0
  178. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_reification_integration.py +0 -0
  179. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_schema_migration.py +0 -0
  180. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_stored_procedure_install.py +0 -0
  181. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/integration/test_subquery_call_integration.py +0 -0
  182. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/performance/conftest.py +0 -0
  183. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/performance/scale_benchmark.py +0 -0
  184. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/performance/test_ppr_stress.py +0 -0
  185. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/performance/test_stress_v1_5.py +0 -0
  186. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/python/run_all_tests.py +0 -0
  187. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/python/test_iris_rest_api.py +0 -0
  188. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/python/test_networkx_loader.py +0 -0
  189. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/python/test_performance_benchmarks.py +0 -0
  190. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/python/test_pyops_vector_conversion.py +0 -0
  191. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/python/test_python_operators.py +0 -0
  192. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/python/test_python_sdk.py +0 -0
  193. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/python/test_schema_validation.py +0 -0
  194. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/python/test_sql_queries.py +0 -0
  195. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/python/test_vector_functions.py +0 -0
  196. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/cypher/__init__.py +0 -0
  197. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/cypher/test_lexer.py +0 -0
  198. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/cypher/test_lexer_advanced.py +0 -0
  199. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/cypher/test_parser.py +0 -0
  200. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/cypher/test_parser_advanced.py +0 -0
  201. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_batch_mutations.py +0 -0
  202. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_bfs_arno.py +0 -0
  203. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_bm25_index.py +0 -0
  204. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_bolt_server.py +0 -0
  205. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cls_deployment.py +0 -0
  206. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_benchmark.py +0 -0
  207. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_benchmark_scale.py +0 -0
  208. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_case_when.py +0 -0
  209. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_e2e_new_features.py +0 -0
  210. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_functions.py +0 -0
  211. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_parser.py +0 -0
  212. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_posos_bugs.py +0 -0
  213. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_procedures.py +0 -0
  214. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_translator.py +0 -0
  215. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_union_exists.py +0 -0
  216. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_var_length.py +0 -0
  217. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_cypher_vector_search.py +0 -0
  218. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_edge_embeddings.py +0 -0
  219. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_edgeprop_ndjson.py +0 -0
  220. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_embedded.py +0 -0
  221. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_engine_dimension_fix.py +0 -0
  222. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_engine_embeddings.py +0 -0
  223. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_engine_status.py +0 -0
  224. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_fhir_bridges.py +0 -0
  225. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_get_nodes.py +0 -0
  226. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_graph_kernels.py +0 -0
  227. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_graphql_dataloader.py +0 -0
  228. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_ingest_formats.py +0 -0
  229. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_ivf_index.py +0 -0
  230. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_named_graphs.py +0 -0
  231. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_named_paths.py +0 -0
  232. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_operators_wiring.py +0 -0
  233. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_plaid_search.py +0 -0
  234. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_ppr_guided_subgraph.py +0 -0
  235. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_reification.py +0 -0
  236. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_schema_init.py +0 -0
  237. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_schema_procedures.py +0 -0
  238. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_shortest_path.py +0 -0
  239. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_snapshot.py +0 -0
  240. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_sql_splitter.py +0 -0
  241. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_sql_table_bridge.py +0 -0
  242. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_subgraph.py +0 -0
  243. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_subquery_call.py +0 -0
  244. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_temporal_cypher.py +0 -0
  245. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_temporal_edges.py +0 -0
  246. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_unified_edge_store.py +0 -0
  247. {iris_vector_graph-1.78.0 → iris_vector_graph-1.80.0}/tests/unit/test_weighted_shortest_path.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iris-vector-graph
3
- Version: 1.78.0
3
+ Version: 1.80.0
4
4
  Summary: Transactional Graph + Vector retrieval system for InterSystems IRIS with hybrid search, openCypher, and GraphQL APIs
5
5
  Project-URL: Homepage, https://github.com/intersystems-community/iris-vector-graph
6
6
  Project-URL: Documentation, https://github.com/intersystems-community/iris-vector-graph/tree/main/docs
@@ -56,11 +56,13 @@ class NodePattern:
56
56
  """
57
57
  Node pattern in MATCH clause.
58
58
  Example: (p:Protein {id: 'PROTEIN:TP53'})
59
+ labels_or: when True, labels use OR semantics (:A|B), else AND (:A:B)
59
60
  """
60
61
 
61
62
  variable: Optional[str] = None
62
63
  labels: List[str] = field(default_factory=list)
63
64
  properties: Dict[str, Any] = field(default_factory=dict)
65
+ labels_or: bool = False
64
66
 
65
67
 
66
68
  @dataclass(slots=True)
@@ -451,6 +453,7 @@ class ReduceExpression:
451
453
  class ExistsExpression:
452
454
  pattern: "GraphPattern"
453
455
  negated: bool = False
456
+ where_condition: Optional[Any] = None
454
457
 
455
458
 
456
459
  @dataclass(slots=True)
@@ -116,12 +116,14 @@ class Parser:
116
116
  self.peek().kind == TokenType.IDENTIFIER
117
117
  and self.peek().value
118
118
  and self.peek().value.upper() == "USE"
119
- and self.lexer.peek_ahead(1).kind == TokenType.IDENTIFIER
120
- and self.lexer.peek_ahead(1).value
121
- and self.lexer.peek_ahead(1).value.upper() == "GRAPH"
122
119
  ):
123
120
  self.eat()
124
- self.eat()
121
+ if (
122
+ self.peek().kind == TokenType.IDENTIFIER
123
+ and self.peek().value
124
+ and self.peek().value.upper() == "GRAPH"
125
+ ):
126
+ self.eat()
125
127
  graph_name_tok = self.peek()
126
128
  if graph_name_tok.kind == TokenType.STRING_LITERAL:
127
129
  graph_context = self.eat().value
@@ -213,7 +215,7 @@ class Parser:
213
215
  while self.peek().kind in _QUERY_STARTERS or (
214
216
  self.peek().kind == TokenType.IDENTIFIER
215
217
  and self.peek().value
216
- and self.peek().value.upper() in ("OPTIONAL", "USE")
218
+ and self.peek().value.upper() == "OPTIONAL"
217
219
  ) or self.peek().kind == TokenType.WHERE or self.peek().kind == TokenType.RETURN:
218
220
  if self.peek().kind == TokenType.WHERE:
219
221
  self.eat()
@@ -300,10 +302,25 @@ class Parser:
300
302
  and tok.value
301
303
  and tok.value.upper() == "OPTIONAL"
302
304
  ):
303
- # Check for OPTIONAL MATCH
304
- self.eat() # OPTIONAL
305
- self.expect(TokenType.MATCH)
306
- clauses.append(self.parse_match_clause(optional=True))
305
+ self.eat()
306
+ if self.peek().kind == TokenType.MATCH:
307
+ self.expect(TokenType.MATCH)
308
+ clauses.append(self.parse_match_clause(optional=True))
309
+ elif (
310
+ self.peek().kind == TokenType.CALL
311
+ and self.lexer.peek_ahead(1).kind == TokenType.LBRACE
312
+ ):
313
+ subq = self.parse_subquery_call()
314
+ subq_optional = ast.SubqueryCall(
315
+ inner_query=subq.inner_query,
316
+ import_variables=subq.import_variables,
317
+ in_transactions=subq.in_transactions,
318
+ transactions_batch_size=subq.transactions_batch_size,
319
+ )
320
+ clauses.append(subq_optional)
321
+ else:
322
+ self.expect(TokenType.MATCH)
323
+ clauses.append(self.parse_match_clause(optional=True))
307
324
  elif kind == TokenType.UNWIND:
308
325
  clauses.append(self.parse_unwind_clause())
309
326
  elif kind in (
@@ -426,7 +443,13 @@ class Parser:
426
443
  if self.peek().kind == TokenType.RETURN:
427
444
  inner_return = self.parse_return_clause()
428
445
 
429
- if inner_return is None:
446
+ has_updating = any(
447
+ isinstance(c, ast.UpdatingClause)
448
+ for part in inner_parts
449
+ for c in part.clauses
450
+ )
451
+
452
+ if inner_return is None and not has_updating:
430
453
  tok = self.peek()
431
454
  raise CypherParseError(
432
455
  "Subquery must contain a RETURN clause",
@@ -705,10 +728,20 @@ class Parser:
705
728
  var = self.eat().value
706
729
 
707
730
  labels = []
731
+ labels_or = False
708
732
  while self.matches(TokenType.COLON):
709
733
  label_tok = self.expect(TokenType.IDENTIFIER)
710
734
  if label_tok.value:
711
735
  labels.append(label_tok.value)
736
+ while self.peek().kind == TokenType.PIPE or (
737
+ self.peek().kind == TokenType.IDENTIFIER
738
+ and self.peek().value == "|"
739
+ ):
740
+ self.eat()
741
+ labels_or = True
742
+ alt_tok = self.expect(TokenType.IDENTIFIER)
743
+ if alt_tok.value:
744
+ labels.append(alt_tok.value)
712
745
 
713
746
  props = {}
714
747
  if self.matches(TokenType.LBRACE):
@@ -716,7 +749,7 @@ class Parser:
716
749
  self.expect(TokenType.RBRACE)
717
750
 
718
751
  self.expect(TokenType.RPAREN)
719
- return ast.NodePattern(variable=var, labels=labels, properties=props)
752
+ return ast.NodePattern(variable=var, labels=labels, properties=props, labels_or=labels_or)
720
753
 
721
754
  def parse_relationship_pattern(self) -> ast.RelationshipPattern:
722
755
  """Parse -[r:TYPE]-> or <-[r:TYPE]- or -[r:TYPE]-"""
@@ -868,8 +901,12 @@ class Parser:
868
901
  if self.peek().kind == TokenType.MATCH:
869
902
  self.eat()
870
903
  pattern = self.parse_graph_pattern()
904
+ where_cond = None
905
+ if self.peek().kind == TokenType.WHERE:
906
+ self.eat()
907
+ where_cond = self.parse_expression()
871
908
  self.expect(TokenType.RBRACE)
872
- return ast.ExistsExpression(pattern=pattern, negated=True)
909
+ return ast.ExistsExpression(pattern=pattern, negated=True, where_condition=where_cond)
873
910
  operand = self.parse_not_expression()
874
911
  return ast.BooleanExpression(ast.BooleanOperator.NOT, [operand])
875
912
  return self.parse_comparison_expression()
@@ -1027,8 +1064,16 @@ class Parser:
1027
1064
  if self.peek().kind == TokenType.MATCH:
1028
1065
  self.eat()
1029
1066
  pattern = self.parse_graph_pattern()
1067
+ where_cond = None
1068
+ if self.peek().kind == TokenType.WHERE:
1069
+ self.eat()
1070
+ where_cond = self.parse_expression()
1071
+ if self.peek().kind == TokenType.RETURN:
1072
+ self.eat()
1073
+ while self.peek().kind not in (TokenType.RBRACE, TokenType.EOF):
1074
+ self.eat()
1030
1075
  self.expect(TokenType.RBRACE)
1031
- return ast.ExistsExpression(pattern=pattern, negated=False)
1076
+ return ast.ExistsExpression(pattern=pattern, negated=False, where_condition=where_cond)
1032
1077
 
1033
1078
  if name.lower() in ("shortestpath", "allshortestpaths") and self.peek().kind == TokenType.LPAREN:
1034
1079
  self.eat()
@@ -1027,7 +1027,9 @@ def translate_to_sql(
1027
1027
  context.foreach_literals = getattr(
1028
1028
  context, "foreach_literals", {}
1029
1029
  )
1030
- context.foreach_literals[clause.variable] = item
1030
+ context.foreach_literals[clause.variable] = (
1031
+ item.value if isinstance(item, ast.Literal) else item
1032
+ )
1031
1033
  for uc in clause.update_clauses:
1032
1034
  if isinstance(uc, ast.UpdatingClause):
1033
1035
  translate_updating_clause(uc, context, metadata)
@@ -1391,6 +1393,9 @@ def translate_create_clause(create, context, metadata):
1391
1393
  val = v.value
1392
1394
  elif isinstance(v, ast.Variable) and v.name in context.input_params:
1393
1395
  val = context.input_params[v.name]
1396
+ elif isinstance(v, ast.Variable) and getattr(context, "foreach_literals", {}).get(v.name) is not None:
1397
+ raw = context.foreach_literals[v.name]
1398
+ val = raw.value if isinstance(raw, ast.Literal) else raw
1394
1399
  else:
1395
1400
  val = v
1396
1401
  context.add_dml(
@@ -1526,25 +1531,43 @@ def translate_delete_clause(delete, context, metadata):
1526
1531
 
1527
1532
  def translate_merge_clause(merge, context, metadata):
1528
1533
  translate_create_clause(ast.CreateClause(patterns=[merge.pattern]), context, metadata)
1534
+ var = merge.pattern.nodes[0].variable if merge.pattern.nodes else None
1529
1535
  for action, is_create in [(merge.on_create, True), (merge.on_match, False)]:
1530
1536
  if action:
1531
1537
  for item in action.items:
1532
1538
  if isinstance(item, ast.SetItem) and isinstance(
1533
1539
  item.expression, ast.PropertyReference
1534
1540
  ):
1535
- node_id = context.variable_aliases.get(item.expression.variable)
1541
+ var_name = item.expression.variable
1542
+ sql_alias = context.variable_aliases.get(var_name, "")
1543
+ actual_id = (
1544
+ context.input_params.get(f"__create_id_{var_name}")
1545
+ or context.input_params.get(var_name)
1546
+ )
1536
1547
  k, v = item.expression.property_name, item.value
1537
1548
  val = v.value if isinstance(v, ast.Literal) else v
1538
1549
  if is_create:
1539
- context.add_dml(
1540
- f'INSERT INTO {_table("rdf_props")} (s, "key", val) SELECT node_id, ?, ? FROM {_table("nodes")} WHERE node_id = ? AND NOT EXISTS (SELECT 1 FROM {_table("rdf_props")} WHERE s = ? AND "key" = ?)',
1541
- [k, val, node_id, node_id, k],
1542
- )
1550
+ if actual_id:
1551
+ context.add_dml(
1552
+ f'INSERT INTO {_table("rdf_props")} (s, "key", val) SELECT ?, ?, ? WHERE NOT EXISTS (SELECT 1 FROM {_table("rdf_props")} WHERE s = ? AND "key" = ?)',
1553
+ [actual_id, k, val, actual_id, k],
1554
+ )
1555
+ else:
1556
+ context.add_dml(
1557
+ f'INSERT INTO {_table("rdf_props")} (s, "key", val) SELECT node_id, ?, ? FROM {_table("nodes")} WHERE node_id = ? AND NOT EXISTS (SELECT 1 FROM {_table("rdf_props")} WHERE s = ? AND "key" = ?)',
1558
+ [k, val, sql_alias, sql_alias, k],
1559
+ )
1543
1560
  else:
1544
- context.add_dml(
1545
- f'UPDATE {_table("rdf_props")} SET val = ? WHERE s = ? AND "key" = ?',
1546
- [val, node_id, k],
1547
- )
1561
+ if actual_id:
1562
+ context.add_dml(
1563
+ f'UPDATE {_table("rdf_props")} SET val = ? WHERE s = ? AND "key" = ?',
1564
+ [val, actual_id, k],
1565
+ )
1566
+ else:
1567
+ context.add_dml(
1568
+ f'UPDATE {_table("rdf_props")} SET val = ? WHERE s IN (SELECT node_id FROM {_table("nodes")} WHERE node_id = ?) AND "key" = ?',
1569
+ [val, sql_alias, k],
1570
+ )
1548
1571
 
1549
1572
 
1550
1573
  def translate_set_clause(set_cl, context, metadata):
@@ -1914,13 +1937,23 @@ def translate_node_pattern(node, context, metadata, optional=False):
1914
1937
  alias in j for j in context.join_clauses
1915
1938
  ):
1916
1939
  context.join_clauses.append(f"CROSS JOIN {nodes_tbl} {alias}")
1917
- for label in node.labels:
1918
- l_alias = context.next_alias("l")
1919
- context.join_clauses.append(
1920
- f"{jt} {_table('rdf_labels')} {l_alias} ON {l_alias}.s = {alias}.node_id AND {l_alias}.label = {context.add_join_param(label)}"
1921
- )
1922
- if not optional:
1923
- context.where_conditions.append(f"{l_alias}.s IS NOT NULL")
1940
+ if node.labels:
1941
+ if getattr(node, 'labels_or', False) and len(node.labels) > 1:
1942
+ l_alias = context.next_alias("l")
1943
+ labels_inlined = ", ".join(f"'{lab}'" for lab in node.labels)
1944
+ context.join_clauses.append(
1945
+ f"{jt} {_table('rdf_labels')} {l_alias} ON {l_alias}.s = {alias}.node_id AND {l_alias}.label IN ({labels_inlined})"
1946
+ )
1947
+ if not optional:
1948
+ context.where_conditions.append(f"{l_alias}.s IS NOT NULL")
1949
+ else:
1950
+ for label in node.labels:
1951
+ l_alias = context.next_alias("l")
1952
+ context.join_clauses.append(
1953
+ f"{jt} {_table('rdf_labels')} {l_alias} ON {l_alias}.s = {alias}.node_id AND {l_alias}.label = {context.add_join_param(label)}"
1954
+ )
1955
+ if not optional:
1956
+ context.where_conditions.append(f"{l_alias}.s IS NOT NULL")
1924
1957
  for k, v in node.properties.items():
1925
1958
  val_sql = translate_expression(v, context, segment="where")
1926
1959
  if k in ("node_id", "id"):
@@ -2359,6 +2392,13 @@ def translate_boolean_expression(expr, context) -> str:
2359
2392
  and tgt_node.variable in context.variable_aliases
2360
2393
  )
2361
2394
  edge_alias = f"_ex{len(context.variable_aliases) + 1}"
2395
+ child_ctx = TranslationContext()
2396
+ child_ctx.input_params = context.input_params
2397
+ child_ctx._alias_counter = context._alias_counter
2398
+ child_ctx.variable_aliases = dict(context.variable_aliases)
2399
+ if tgt_node and tgt_node.variable and not tgt_bound:
2400
+ tgt_alias = child_ctx.next_alias("n")
2401
+ child_ctx.variable_aliases[tgt_node.variable] = tgt_alias
2362
2402
  if tgt_bound:
2363
2403
  tgt_ref = context.variable_aliases[tgt_node.variable]
2364
2404
  cond = f"{edge_alias}.o_id = {tgt_ref}.node_id"
@@ -2369,7 +2409,23 @@ def translate_boolean_expression(expr, context) -> str:
2369
2409
  cond = "1=1"
2370
2410
  if rel.types:
2371
2411
  cond += f" AND {edge_alias}.p = '{rel.types[0]}'"
2372
- sub = f"SELECT 1 FROM {_table('rdf_edges')} {edge_alias} WHERE {cond}"
2412
+ sub_froms = [f"{_table('rdf_edges')} {edge_alias}"]
2413
+ sub_wheres = [cond]
2414
+ if tgt_node and tgt_node.variable and not tgt_bound:
2415
+ tgt_alias = child_ctx.variable_aliases.get(tgt_node.variable, "_tn")
2416
+ sub_froms.append(f"{_table('nodes')} {tgt_alias}")
2417
+ sub_wheres.append(f"{tgt_alias}.node_id = {edge_alias}.o_id")
2418
+ if tgt_node.labels:
2419
+ for lbl in tgt_node.labels:
2420
+ lbl_alias = child_ctx.next_alias("l")
2421
+ sub_froms.append(f"{_table('rdf_labels')} {lbl_alias}")
2422
+ sub_wheres.append(f"{lbl_alias}.s = {tgt_alias}.node_id AND {lbl_alias}.label = '{lbl}'")
2423
+ if expr.where_condition:
2424
+ where_sql = translate_boolean_expression(expr.where_condition, child_ctx)
2425
+ for p in child_ctx.where_params:
2426
+ context.where_params.append(p)
2427
+ sub_wheres.append(where_sql)
2428
+ sub = f"SELECT 1 FROM {', '.join(sub_froms)} WHERE {' AND '.join(sub_wheres)}"
2373
2429
  prefix = "NOT " if expr.negated else ""
2374
2430
  return f"{prefix}EXISTS ({sub})"
2375
2431
  return "1=1"
@@ -2798,14 +2854,25 @@ def translate_expression(expr, context, segment="select") -> str:
2798
2854
  inner = " || ',' || ".join(parts)
2799
2855
  return f"('{{'||{inner}||'}}')"
2800
2856
  if isinstance(expr, ast.SubscriptExpression):
2801
- base_sql = translate_expression(expr.expression, context, segment=segment)
2802
- if isinstance(expr.index, ast.Literal) and isinstance(expr.index.value, int):
2803
- idx = expr.index.value
2857
+ base = expr.expression
2858
+ idx = expr.index
2859
+ if isinstance(base, ast.Variable) and isinstance(idx, ast.Variable):
2860
+ node_alias = context.variable_aliases.get(base.name, "")
2861
+ key_val = context.input_params.get(idx.name, idx.name)
2862
+ p_alias = context.next_alias("dp")
2863
+ node_ref = f"{node_alias}.node_id" if node_alias else "NULL"
2864
+ context.join_clauses.append(
2865
+ f"LEFT JOIN {_table('rdf_props')} {p_alias} ON {p_alias}.s = {node_ref} AND {p_alias}.\"key\" = {context.add_join_param(key_val)}"
2866
+ )
2867
+ return f"{p_alias}.val"
2868
+ base_sql = translate_expression(base, context, segment=segment)
2869
+ if isinstance(idx, ast.Literal) and isinstance(idx.value, int):
2870
+ i = idx.value
2804
2871
  return (
2805
2872
  f"(SELECT elem FROM JSON_TABLE({base_sql}, "
2806
- f"'$[{idx}]' COLUMNS (elem VARCHAR(1000) PATH '$')) __jt)"
2873
+ f"'$[{i}]' COLUMNS (elem VARCHAR(1000) PATH '$')) __jt)"
2807
2874
  )
2808
- idx_sql = translate_expression(expr.index, context, segment=segment)
2875
+ idx_sql = translate_expression(idx, context, segment=segment)
2809
2876
  return (
2810
2877
  f"JSON_TABLE({base_sql}, '$[*]' COLUMNS "
2811
2878
  f"(idx FOR ORDINALITY, elem VARCHAR(1000) PATH '$'))[{idx_sql}].elem"
@@ -2825,6 +2892,15 @@ def translate_expression(expr, context, segment="select") -> str:
2825
2892
  return f"SQLUser.JSON_VALUE({base_sql}, '$.{prop}')"
2826
2893
  if isinstance(expr, ast.Variable):
2827
2894
  alias = context.variable_aliases.get(expr.name)
2895
+ if alias == "__foreach_literal__":
2896
+ val = getattr(context, "foreach_literals", {}).get(expr.name)
2897
+ if val is not None:
2898
+ if isinstance(val, str):
2899
+ safe = val.replace("'", "''")
2900
+ return f"'{safe}'"
2901
+ if isinstance(val, bool):
2902
+ return "1" if val else "0"
2903
+ return str(val)
2828
2904
  if not alias:
2829
2905
  if expr.name in context.input_params:
2830
2906
  v = context.input_params[expr.name]
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "iris-vector-graph"
7
- version = "1.78.0"
7
+ version = "1.80.0"
8
8
  description = "Transactional Graph + Vector retrieval system for InterSystems IRIS with hybrid search, openCypher, and GraphQL APIs"
9
9
  readme = "README.md"
10
10
  license = "MIT"