cocoindex 0.1.27__tar.gz → 0.1.29__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 (190) hide show
  1. {cocoindex-0.1.27 → cocoindex-0.1.29}/Cargo.lock +1 -1
  2. {cocoindex-0.1.27 → cocoindex-0.1.29}/Cargo.toml +1 -1
  3. {cocoindex-0.1.27 → cocoindex-0.1.29}/PKG-INFO +2 -1
  4. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/ops/storages.md +98 -64
  5. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/docs_to_knowledge_graph/main.py +16 -17
  6. {cocoindex-0.1.27 → cocoindex-0.1.29}/pyproject.toml +1 -1
  7. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/cli.py +7 -3
  8. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/flow.py +54 -1
  9. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/storages.py +15 -8
  10. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/base/schema.rs +2 -0
  11. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/storages/neo4j.rs +34 -33
  12. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/storages/spec.rs +9 -14
  13. {cocoindex-0.1.27 → cocoindex-0.1.29}/.cargo/config.toml +0 -0
  14. {cocoindex-0.1.27 → cocoindex-0.1.29}/.env.lib_debug +0 -0
  15. {cocoindex-0.1.27 → cocoindex-0.1.29}/.github/ISSUE_TEMPLATE//360/237/220/233-bug-report.md" +0 -0
  16. {cocoindex-0.1.27 → cocoindex-0.1.29}/.github/ISSUE_TEMPLATE//360/237/222/241-feature-request.md" +0 -0
  17. {cocoindex-0.1.27 → cocoindex-0.1.29}/.github/scripts/update_version.sh +0 -0
  18. {cocoindex-0.1.27 → cocoindex-0.1.29}/.github/workflows/CI.yml +0 -0
  19. {cocoindex-0.1.27 → cocoindex-0.1.29}/.github/workflows/_test.yml +0 -0
  20. {cocoindex-0.1.27 → cocoindex-0.1.29}/.github/workflows/docs.yml +0 -0
  21. {cocoindex-0.1.27 → cocoindex-0.1.29}/.github/workflows/release.yml +0 -0
  22. {cocoindex-0.1.27 → cocoindex-0.1.29}/.gitignore +0 -0
  23. {cocoindex-0.1.27 → cocoindex-0.1.29}/.vscode/settings.json +0 -0
  24. {cocoindex-0.1.27 → cocoindex-0.1.29}/CODE_OF_CONDUCT.md +0 -0
  25. {cocoindex-0.1.27 → cocoindex-0.1.29}/CONTRIBUTING.md +0 -0
  26. {cocoindex-0.1.27 → cocoindex-0.1.29}/LICENSE +0 -0
  27. {cocoindex-0.1.27 → cocoindex-0.1.29}/README.md +0 -0
  28. {cocoindex-0.1.27 → cocoindex-0.1.29}/dev/neo4j.yaml +0 -0
  29. {cocoindex-0.1.27 → cocoindex-0.1.29}/dev/postgres.yaml +0 -0
  30. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/.gitignore +0 -0
  31. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/README.md +0 -0
  32. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/about/community.md +0 -0
  33. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/about/contributing.md +0 -0
  34. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/ai/llm.mdx +0 -0
  35. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/core/basics.md +0 -0
  36. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/core/cli.mdx +0 -0
  37. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/core/custom_function.mdx +0 -0
  38. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/core/data_example.svg +0 -0
  39. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/core/data_types.mdx +0 -0
  40. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/core/flow_def.mdx +0 -0
  41. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/core/flow_example.svg +0 -0
  42. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/core/flow_methods.mdx +0 -0
  43. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/core/initialization.mdx +0 -0
  44. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/getting_started/installation.md +0 -0
  45. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/getting_started/markdown_files.zip +0 -0
  46. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/getting_started/overview.md +0 -0
  47. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/getting_started/quickstart.md +0 -0
  48. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/ops/functions.md +0 -0
  49. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docs/ops/sources.md +0 -0
  50. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/docusaurus.config.ts +0 -0
  51. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/package.json +0 -0
  52. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/sidebars.ts +0 -0
  53. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/src/components/HomepageFeatures/index.tsx +0 -0
  54. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/src/components/HomepageFeatures/styles.module.css +0 -0
  55. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/src/css/custom.css +0 -0
  56. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/src/theme/Root.js +0 -0
  57. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/static/.nojekyll +0 -0
  58. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/static/img/docusaurus.png +0 -0
  59. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/static/img/favicon.ico +0 -0
  60. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/static/img/icon.svg +0 -0
  61. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/static/robots.txt +0 -0
  62. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/tsconfig.json +0 -0
  63. {cocoindex-0.1.27 → cocoindex-0.1.29}/docs/yarn.lock +0 -0
  64. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/code_embedding/.env +0 -0
  65. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/code_embedding/README.md +0 -0
  66. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/code_embedding/main.py +0 -0
  67. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/code_embedding/pyproject.toml +0 -0
  68. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/docs_to_knowledge_graph/.env +0 -0
  69. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/docs_to_knowledge_graph/README.md +0 -0
  70. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/docs_to_knowledge_graph/markdown_files/1706.03762v7.md +0 -0
  71. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/docs_to_knowledge_graph/markdown_files/1810.04805v2.md +0 -0
  72. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/docs_to_knowledge_graph/markdown_files/rfc8259.md +0 -0
  73. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/docs_to_knowledge_graph/pyproject.toml +0 -0
  74. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/gdrive_text_embedding/.env.example +0 -0
  75. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/gdrive_text_embedding/.gitignore +0 -0
  76. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/gdrive_text_embedding/README.md +0 -0
  77. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/gdrive_text_embedding/data/1706.03762v7.docx +0 -0
  78. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/gdrive_text_embedding/data/1810.04805v2.docx +0 -0
  79. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/gdrive_text_embedding/main.py +0 -0
  80. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/gdrive_text_embedding/pyproject.toml +0 -0
  81. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/manuals_llm_extraction/.env +0 -0
  82. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/manuals_llm_extraction/README.md +0 -0
  83. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/manuals_llm_extraction/main.py +0 -0
  84. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/manuals_llm_extraction/manuals/array.pdf +0 -0
  85. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/manuals_llm_extraction/manuals/base64.pdf +0 -0
  86. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/manuals_llm_extraction/manuals/copy.pdf +0 -0
  87. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/manuals_llm_extraction/manuals/glob.pdf +0 -0
  88. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/manuals_llm_extraction/pyproject.toml +0 -0
  89. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/pdf_embedding/.env +0 -0
  90. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/pdf_embedding/README.md +0 -0
  91. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/pdf_embedding/main.py +0 -0
  92. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/pdf_embedding/pdf_files/1706.03762v7.pdf +0 -0
  93. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/pdf_embedding/pdf_files/1810.04805v2.pdf +0 -0
  94. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/pdf_embedding/pdf_files/rfc8259.pdf +0 -0
  95. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/pdf_embedding/pyproject.toml +0 -0
  96. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding/.env +0 -0
  97. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding/README.md +0 -0
  98. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding/Text_Embedding.ipynb +0 -0
  99. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding/main.py +0 -0
  100. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding/markdown_files/1706.03762v7.md +0 -0
  101. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding/markdown_files/1810.04805v2.md +0 -0
  102. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding/markdown_files/rfc8259.md +0 -0
  103. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding/pyproject.toml +0 -0
  104. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding_qdrant/.env +0 -0
  105. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding_qdrant/README.md +0 -0
  106. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding_qdrant/main.py +0 -0
  107. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding_qdrant/markdown_files/rfc8259.md +0 -0
  108. {cocoindex-0.1.27 → cocoindex-0.1.29}/examples/text_embedding_qdrant/pyproject.toml +0 -0
  109. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/__init__.py +0 -0
  110. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/auth_registry.py +0 -0
  111. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/convert.py +0 -0
  112. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/functions.py +0 -0
  113. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/index.py +0 -0
  114. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/lib.py +0 -0
  115. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/llm.py +0 -0
  116. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/op.py +0 -0
  117. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/py.typed +0 -0
  118. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/query.py +0 -0
  119. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/runtime.py +0 -0
  120. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/setup.py +0 -0
  121. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/sources.py +0 -0
  122. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/tests/__init__.py +0 -0
  123. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/tests/test_convert.py +0 -0
  124. {cocoindex-0.1.27 → cocoindex-0.1.29}/python/cocoindex/typing.py +0 -0
  125. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/base/field_attrs.rs +0 -0
  126. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/base/json_schema.rs +0 -0
  127. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/base/mod.rs +0 -0
  128. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/base/spec.rs +0 -0
  129. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/base/value.rs +0 -0
  130. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/builder/analyzed_flow.rs +0 -0
  131. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/builder/analyzer.rs +0 -0
  132. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/builder/flow_builder.rs +0 -0
  133. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/builder/mod.rs +0 -0
  134. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/builder/plan.rs +0 -0
  135. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/db_tracking.rs +0 -0
  136. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/db_tracking_setup.rs +0 -0
  137. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/dumper.rs +0 -0
  138. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/evaluator.rs +0 -0
  139. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/live_updater.rs +0 -0
  140. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/memoization.rs +0 -0
  141. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/mod.rs +0 -0
  142. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/query.rs +0 -0
  143. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/row_indexer.rs +0 -0
  144. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/source_indexer.rs +0 -0
  145. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/execution/stats.rs +0 -0
  146. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/lib.rs +0 -0
  147. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/lib_context.rs +0 -0
  148. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/llm/anthropic.rs +0 -0
  149. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/llm/gemini.rs +0 -0
  150. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/llm/mod.rs +0 -0
  151. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/llm/ollama.rs +0 -0
  152. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/llm/openai.rs +0 -0
  153. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/factory_bases.rs +0 -0
  154. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/functions/extract_by_llm.rs +0 -0
  155. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/functions/mod.rs +0 -0
  156. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/functions/parse_json.rs +0 -0
  157. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/functions/split_recursively.rs +0 -0
  158. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/interface.rs +0 -0
  159. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/mod.rs +0 -0
  160. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/py_factory.rs +0 -0
  161. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/registration.rs +0 -0
  162. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/registry.rs +0 -0
  163. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/sdk.rs +0 -0
  164. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/sources/google_drive.rs +0 -0
  165. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/sources/local_file.rs +0 -0
  166. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/sources/mod.rs +0 -0
  167. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/storages/mod.rs +0 -0
  168. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/storages/postgres.rs +0 -0
  169. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/ops/storages/qdrant.rs +0 -0
  170. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/prelude.rs +0 -0
  171. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/py/convert.rs +0 -0
  172. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/py/mod.rs +0 -0
  173. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/server.rs +0 -0
  174. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/service/error.rs +0 -0
  175. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/service/flows.rs +0 -0
  176. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/service/mod.rs +0 -0
  177. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/service/search.rs +0 -0
  178. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/settings.rs +0 -0
  179. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/setup/auth_registry.rs +0 -0
  180. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/setup/components.rs +0 -0
  181. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/setup/db_metadata.rs +0 -0
  182. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/setup/driver.rs +0 -0
  183. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/setup/mod.rs +0 -0
  184. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/setup/states.rs +0 -0
  185. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/utils/db.rs +0 -0
  186. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/utils/fingerprint.rs +0 -0
  187. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/utils/immutable.rs +0 -0
  188. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/utils/mod.rs +0 -0
  189. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/utils/retriable.rs +0 -0
  190. {cocoindex-0.1.27 → cocoindex-0.1.29}/src/utils/yaml_ser.rs +0 -0
@@ -533,7 +533,7 @@ dependencies = [
533
533
 
534
534
  [[package]]
535
535
  name = "cocoindex"
536
- version = "0.1.27"
536
+ version = "0.1.29"
537
537
  dependencies = [
538
538
  "anyhow",
539
539
  "async-openai",
@@ -2,7 +2,7 @@
2
2
  name = "cocoindex"
3
3
  # Version used for local development is always higher than others to take precedence.
4
4
  # Will be overridden for specific release versions.
5
- version = "0.1.27"
5
+ version = "0.1.29"
6
6
  edition = "2021"
7
7
 
8
8
  # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -1,8 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex
3
- Version: 0.1.27
3
+ Version: 0.1.29
4
4
  Requires-Dist: sentence-transformers>=3.3.1
5
5
  Requires-Dist: click>=8.1.8
6
+ Requires-Dist: rich>=14.0.0
6
7
  Requires-Dist: pytest ; extra == 'test'
7
8
  Provides-Extra: test
8
9
  License-File: LICENSE
@@ -87,24 +87,34 @@ You can find an end-to-end example [here](https://github.com/cocoindex-io/cocoin
87
87
 
88
88
  ## Property Graph Targets
89
89
 
90
- Property graph is a graph data model where both nodes and relationships can have properties.
90
+ Property graph is a widely-adopted model for knowledge graphs, where both nodes and relationships can have properties.
91
+ [Graph database concepts](https://neo4j.com/docs/getting-started/appendix/graphdb-concepts/) has a good introduction to basic concepts of property graphs.
92
+
93
+ The following concepts will be used in the following sections:
94
+ * [Node](https://neo4j.com/docs/getting-started/appendix/graphdb-concepts/#graphdb-node)
95
+ * [Node label](https://neo4j.com/docs/getting-started/appendix/graphdb-concepts/#graphdb-labels), which represents a type of nodes.
96
+ * [Relationship](https://neo4j.com/docs/getting-started/appendix/graphdb-concepts/#graphdb-relationship), which describes a connection between two nodes.
97
+ * [Relationship type](https://neo4j.com/docs/getting-started/appendix/graphdb-concepts/#graphdb-relationship-type)
98
+ * [Properties](https://neo4j.com/docs/getting-started/appendix/graphdb-concepts/#graphdb-properties), which are key-value pairs associated with nodes and relationships.
91
99
 
92
100
  ### Data Mapping
93
101
 
94
- In CocoIndex, you can export data to property graph databases.
95
- This usually involves more than one collectors, and you export them to different types of graph elements (nodes and relationships).
96
- In particular,
102
+ Data from collectors are mapped to graph elements in various types:
103
+
104
+ 1. Rows from collectors → Nodes in the graph
105
+ 2. Rows from collectors → Relationships in the graph (including source and target nodes of the relationship)
97
106
 
98
- 1. You can export rows from some collectors to nodes in the graph.
99
- 2. You can export rows from some other collectors to relationships in the graph.
100
- 3. Some nodes referenced by relationships exported in 2 may not exist as nodes exported in 1.
101
- CocoIndex will automatically create and keep these nodes, as long as they're still referenced by at least one relationship.
102
- This guarantees that all relationships exported in 2 are valid.
107
+ This is what you need to provide to define these mappings:
103
108
 
104
- We provide common types `NodeMapping`, `RelationshipMapping`, and `ReferencedNode`, to configure for each situation.
105
- They're agnostic to specific graph databases.
109
+ * Specify [nodes to export](#nodes-to-export).
110
+ * [Declare extra node labels](#declare-extra-node-labels), for labels to appear as source/target nodes of relationships but not exported as nodes.
111
+ * Specify [relationships to export](#relationships-to-export).
106
112
 
107
- #### Nodes
113
+ In addition, the same node may appear multiple times, from exported nodes and various relationships.
114
+ They should appear as the same node in the target graph database.
115
+ CocoIndex automatically [matches and deduplicates nodes](#nodes-matching-and-deduplicating) based on their primary key values.
116
+
117
+ #### Nodes to Export
108
118
 
109
119
  Here's how CocoIndex data elements map to nodes in the graph:
110
120
 
@@ -114,9 +124,9 @@ Here's how CocoIndex data elements map to nodes in the graph:
114
124
  | a collected row | a node |
115
125
  | a field | a property of node |
116
126
 
117
- Note that the label used in different `NodeMapping`s should be unique.
127
+ Note that the label used in different `Nodes`s should be unique.
118
128
 
119
- `cocoindex.storages.NodeMapping` is to describe mapping to nodes. It has the following fields:
129
+ `cocoindex.storages.Nodes` is to describe mapping to nodes. It has the following fields:
120
130
 
121
131
  * `label` (type: `str`): The label of the node.
122
132
 
@@ -138,7 +148,7 @@ document_collector.export(
138
148
  ...
139
149
  cocoindex.storages.Neo4j(
140
150
  ...
141
- mapping=cocoindex.storages.NodeMapping(label="Document"),
151
+ mapping=cocoindex.storages.Nodes(label="Document"),
142
152
  ),
143
153
  primary_key_fields=["filename"],
144
154
  )
@@ -167,7 +177,32 @@ graph TD
167
177
  classDef node font-size:8pt,text-align:left,stroke-width:2;
168
178
  ```
169
179
 
170
- #### Relationships
180
+ #### Declare Extra Node Labels
181
+
182
+ If a node label needs to appear as source or target of a relationship, but not exported as a node, you need to [declare](../core/flow_def#target-declarations) the label with necessary configuration.
183
+
184
+ The dataclass to describe the declaration is specific to each target storage (e.g. `cocoindex.storages.Neo4jDeclarations`),
185
+ while they share the following common fields:
186
+
187
+ * `nodes_label` (required): The label of the node.
188
+ * Options for [storage indexes](../core/flow_def#storage-indexes).
189
+ * `primary_key_fields` (required)
190
+ * `vector_indexes` (optional)
191
+
192
+ Continuing the same example above.
193
+ Considering we want to extract relationships from `Document` to `Place` later (i.e. a document mentions a place), but the `Place` label isn't exported as a node, we need to declare it:
194
+
195
+ ```python
196
+ flow_builder.declare(
197
+ cocoindex.storages.Neo4jDeclarations(
198
+ connection = ...,
199
+ nodes_label="Place",
200
+ primary_key_fields=["name"],
201
+ ),
202
+ )
203
+ ```
204
+
205
+ #### Relationships to Export
171
206
 
172
207
  Here's how CocoIndex data elements map to relationships in the graph:
173
208
 
@@ -177,12 +212,12 @@ Here's how CocoIndex data elements map to relationships in the graph:
177
212
  | a collected row | a relationship |
178
213
  | a field | a property of relationship, or a property of source/target node, based on configuration |
179
214
 
180
- Note that the type used in different `RelationshipMapping`s should be unique.
215
+ Note that the type used in different `Relationships`s should be unique.
181
216
 
182
- `cocoindex.storages.RelationshipMapping` is to describe mapping to relationships. It has the following fields:
217
+ `cocoindex.storages.Relationships` is to describe mapping to relationships. It has the following fields:
183
218
 
184
219
  * `rel_type` (type: `str`): The type of the relationship.
185
- * `source`/`target` (type: `cocoindex.storages.NodeReferenceMapping`): Specify how to extract source/target node information from the collected row. It has the following fields:
220
+ * `source`/`target` (type: `cocoindex.storages.NodeFromFields`): Specify how to extract source/target node information from specific fields in the collected row. It has the following fields:
186
221
  * `label` (type: `str`): The label of the node.
187
222
  * `fields` (type: `Sequence[cocoindex.storages.TargetFieldMapping]`): Specify field mappings from the collected rows to node properties, with the following fields:
188
223
  * `source` (type: `str`): The name of the field in the collected row.
@@ -218,13 +253,13 @@ doc_place_collector.export(
218
253
  ...
219
254
  cocoindex.storages.Neo4j(
220
255
  ...
221
- mapping=cocoindex.storages.RelationshipMapping(
256
+ mapping=cocoindex.storages.Relationships(
222
257
  rel_type="MENTION",
223
- source=cocoindex.storages.NodeReferenceMapping(
258
+ source=cocoindex.storages.NodeFromFields(
224
259
  label="Document",
225
260
  fields=[cocoindex.storages.TargetFieldMapping(source="doc_filename", target="filename")],
226
261
  ),
227
- target=cocoindex.storages.NodeReferenceMapping(
262
+ target=cocoindex.storages.NodeFromFields(
228
263
  label="Place",
229
264
  fields=[
230
265
  cocoindex.storages.TargetFieldMapping(source="place_name", target="name"),
@@ -250,19 +285,26 @@ graph TD
250
285
  classDef: nodeRef
251
286
  }
252
287
 
253
- Doc_Chapter2@{
288
+ Doc_Chapter2_a@{
254
289
  shape: rounded
255
290
  label: "**[Document]**
256
291
  **filename\\*: chapter2.md**"
257
292
  classDef: nodeRef
258
293
  }
259
294
 
260
- Place_CrystalPalace@{
295
+ Doc_Chapter2_b@{
296
+ shape: rounded
297
+ label: "**[Document]**
298
+ **filename\\*: chapter2.md**"
299
+ classDef: nodeRef
300
+ }
301
+
302
+ Place_CrystalPalace_a@{
261
303
  shape: rounded
262
304
  label: "**[Place]**
263
305
  **name\\*: Crystal Palace**
264
306
  embedding: [0.1, 0.5, ...]"
265
- classDef: nodeRef
307
+ classDef: node
266
308
  }
267
309
 
268
310
  Place_MagicForest@{
@@ -270,38 +312,43 @@ graph TD
270
312
  label: "**[Place]**
271
313
  **name\\*: Magic Forest**
272
314
  embedding: [0.4, 0.2, ...]"
273
- classDef: nodeRef
315
+ classDef: node
316
+ }
317
+
318
+ Place_CrystalPalace_b@{
319
+ shape: rounded
320
+ label: "**[Place]**
321
+ **name\\*: Crystal Palace**
322
+ embedding: [0.1, 0.5, ...]"
323
+ classDef: node
274
324
  }
275
325
 
276
- Doc_Chapter1:::nodeRef -- **[MENTION]**{location:12} --> Place_CrystalPalace:::nodeRef
277
- Doc_Chapter2:::nodeRef -- **[MENTION]**{location:23} --> Place_MagicForest:::nodeRef
278
- Doc_Chapter2:::nodeRef -- **[MENTION]**{location:56} --> Place_CrystalPalace:::nodeRef
326
+
327
+ Doc_Chapter1:::nodeRef -- **:MENTION** (location:12) --> Place_CrystalPalace_a:::node
328
+ Doc_Chapter2_a:::nodeRef -- **:MENTION** (location:23) --> Place_MagicForest:::node
329
+ Doc_Chapter2_b:::nodeRef -- **:MENTION** (location:56) --> Place_CrystalPalace_b:::node
279
330
 
280
331
  classDef nodeRef font-size:8pt,text-align:left,fill:transparent,stroke-width:1,stroke-dasharray:5 5;
332
+ classDef node font-size:8pt,text-align:left,stroke-width:2;
281
333
 
282
334
  ```
283
335
 
336
+ #### Nodes Matching and Deduplicating
284
337
 
285
- #### Nodes only referenced by relationships
338
+ The nodes and relationships we got above are discrete elements.
339
+ To fit them into a connected property graph, CocoIndex will match and deduplicate nodes automatically:
286
340
 
287
- If a node appears as source or target of a relationship, but not exported using `NodeMapping`, CocoIndex will automatically create and keep these nodes until they're no longer referenced by any relationships.
341
+ * Match nodes based on their primary key values. Nodes with the same primary key values are considered as the same node.
342
+ * For non-primary key fields (a.k.a. value fields), CocoIndex will pick the values from an arbitrary one.
343
+ If multiple nodes (before deduplication) with the same primary key provide value fields, an arbitrary one will be picked.
288
344
 
289
- :::note Merge of node values
345
+ :::note
290
346
 
291
- If the same node (as identified by primary key values) appears multiple times (e.g. they're referenced by different relationships),
292
- CocoIndex uses value fields provided by an arbitrary one of them.
293
347
  The best practice is to make the value fields consistent across different appearances of the same node, to avoid non-determinism in the exported graph.
294
348
 
295
349
  :::
296
350
 
297
- If a node's label specified in `NodeReferenceMapping` doesn't exist in any `NodeMapping`, you need to [declare](../core/flow_def#target-declarations) a `ReferencedNode` to configure [storage indexes](../core/flow_def#storage-indexes) for nodes with this label.
298
- The following options are supported:
299
-
300
- * `primary_key_fields` (required)
301
- * `vector_indexes` (optional)
302
-
303
- Using the same example above.
304
- After combining exported nodes and relationships, we get the knowledge graph with all information:
351
+ After matching and deduplication, we get the final graph:
305
352
 
306
353
  ```mermaid
307
354
  graph TD
@@ -326,7 +373,7 @@ graph TD
326
373
  label: "**[Place]**
327
374
  **name\\*: Crystal Palace**
328
375
  embedding: [0.1, 0.5, ...]"
329
- classDef: nodeRef
376
+ classDef: node
330
377
  }
331
378
 
332
379
  Place_MagicForest@{
@@ -334,30 +381,14 @@ graph TD
334
381
  label: "**[Place]**
335
382
  **name\\*: Magic Forest**
336
383
  embedding: [0.4, 0.2, ...]"
337
- classDef: nodeRef
384
+ classDef: node
338
385
  }
339
386
 
340
- Doc_Chapter1:::node -- **[MENTION]**{location:12} --> Place_CrystalPalace:::nodeRef
341
- Doc_Chapter2:::node -- **[MENTION]**{location:23} --> Place_MagicForest:::nodeRef
342
- Doc_Chapter2:::node -- **[MENTION]**{location:56} --> Place_CrystalPalace:::nodeRef
387
+ Doc_Chapter1:::node -- **:MENTION** (location:12) --> Place_CrystalPalace:::node
388
+ Doc_Chapter2:::node -- **:MENTION** (location:23) --> Place_MagicForest:::node
389
+ Doc_Chapter2:::node -- **:MENTION** (location:56) --> Place_CrystalPalace:::node
343
390
 
344
391
  classDef node font-size:8pt,text-align:left,stroke-width:2;
345
- classDef nodeRef font-size:8pt,text-align:left,fill:transparent,stroke-width:1,stroke-dasharray:5 5;
346
-
347
- ```
348
-
349
- Nodes with `Place` label in the example aren't exported explicitly using `NodeMapping`, so CocoIndex will automatically create them as long as they're still referenced by any relationship.
350
- You need to declare a `ReferencedNode`:
351
-
352
- ```python
353
- flow_builder.declare(
354
- cocoindex.storages.Neo4jDeclarations(
355
- ...
356
- referenced_nodes=[
357
- cocoindex.storages.ReferencedNode(label="Place", primary_key_fields=["name"]),
358
- ],
359
- ),
360
- )
361
392
  ```
362
393
 
363
394
  ### Neo4j
@@ -388,6 +419,9 @@ The `Neo4j` storage exports each row as a relationship to Neo4j Knowledge Graph.
388
419
  Neo4j also provides a declaration spec `Neo4jDeclaration`, to configure indexing options for nodes only referenced by relationships. It has the following fields:
389
420
 
390
421
  * `connection` (type: auth reference to `Neo4jConnectionSpec`)
391
- * `relationships` (type: `Sequence[ReferencedNode]`)
422
+ * Fields for [nodes to declare](#nodes-to-declare), including
423
+ * `nodes_label` (required)
424
+ * `primary_key_fields` (required)
425
+ * `vector_indexes` (optional)
392
426
 
393
427
  You can find an end-to-end example [here](https://github.com/cocoindex-io/cocoindex/tree/main/examples/docs_to_knowledge_graph).
@@ -13,7 +13,10 @@ class DocumentSummary:
13
13
 
14
14
  @dataclasses.dataclass
15
15
  class Relationship:
16
- """Describe a relationship between two entities."""
16
+ """
17
+ Describe a relationship between two entities.
18
+ Subject and object should be Core CocoIndex concepts only, should be nouns. For example, `CocoIndex`, `Incremental Processing`, `ETL`, `Data` etc.
19
+ """
17
20
  subject: str
18
21
  predicate: str
19
22
  object: str
@@ -62,8 +65,8 @@ def docs_to_kg_flow(flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.D
62
65
  output_type=list[Relationship],
63
66
  instruction=(
64
67
  "Please extract relationships from CocoIndex documents. "
65
- "Focus on concepts and ingnore specific examples. "
66
- "Each relationship should be a tuple of (subject, predicate, object).")))
68
+ "Focus on concepts and ignore examples and code. "
69
+ )))
67
70
 
68
71
  with doc["relationships"].row() as relationship:
69
72
  # relationship between two entities
@@ -90,35 +93,31 @@ def docs_to_kg_flow(flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.D
90
93
  "document_node",
91
94
  cocoindex.storages.Neo4j(
92
95
  connection=conn_spec,
93
- mapping=cocoindex.storages.NodeMapping(label="Document")),
96
+ mapping=cocoindex.storages.Nodes(label="Document")),
94
97
  primary_key_fields=["filename"],
95
98
  )
96
99
  # Declare reference Node to reference entity node in a relationship
97
100
  flow_builder.declare(
98
- cocoindex.storages.Neo4jDeclarations(
101
+ cocoindex.storages.Neo4jDeclaration(
99
102
  connection=conn_spec,
100
- referenced_nodes=[
101
- cocoindex.storages.ReferencedNode(
102
- label="Entity",
103
- primary_key_fields=["value"],
104
- )
105
- ]
103
+ nodes_label="Entity",
104
+ primary_key_fields=["value"],
106
105
  )
107
106
  )
108
107
  entity_relationship.export(
109
108
  "entity_relationship",
110
109
  cocoindex.storages.Neo4j(
111
110
  connection=conn_spec,
112
- mapping=cocoindex.storages.RelationshipMapping(
111
+ mapping=cocoindex.storages.Relationships(
113
112
  rel_type="RELATIONSHIP",
114
- source=cocoindex.storages.NodeReferenceMapping(
113
+ source=cocoindex.storages.NodeFromFields(
115
114
  label="Entity",
116
115
  fields=[
117
116
  cocoindex.storages.TargetFieldMapping(
118
117
  source="subject", target="value"),
119
118
  ]
120
119
  ),
121
- target=cocoindex.storages.NodeReferenceMapping(
120
+ target=cocoindex.storages.NodeFromFields(
122
121
  label="Entity",
123
122
  fields=[
124
123
  cocoindex.storages.TargetFieldMapping(
@@ -133,13 +132,13 @@ def docs_to_kg_flow(flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.D
133
132
  "entity_mention",
134
133
  cocoindex.storages.Neo4j(
135
134
  connection=conn_spec,
136
- mapping=cocoindex.storages.RelationshipMapping(
135
+ mapping=cocoindex.storages.Relationships(
137
136
  rel_type="MENTION",
138
- source=cocoindex.storages.NodeReferenceMapping(
137
+ source=cocoindex.storages.NodeFromFields(
139
138
  label="Document",
140
139
  fields=[cocoindex.storages.TargetFieldMapping("filename")],
141
140
  ),
142
- target=cocoindex.storages.NodeReferenceMapping(
141
+ target=cocoindex.storages.NodeFromFields(
143
142
  label="Entity",
144
143
  fields=[cocoindex.storages.TargetFieldMapping(
145
144
  source="entity", target="value")],
@@ -9,7 +9,7 @@ description = "With CocoIndex, users declare the transformation, CocoIndex creat
9
9
  authors = [{ name = "CocoIndex", email = "cocoindex.io@gmail.com" }]
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.11"
12
- dependencies = ["sentence-transformers>=3.3.1", "click>=8.1.8"]
12
+ dependencies = ["sentence-transformers>=3.3.1", "click>=8.1.8", "rich>=14.0.0"]
13
13
  license = "Apache-2.0"
14
14
  urls = { Homepage = "https://cocoindex.io/" }
15
15
 
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import click
3
3
  import datetime
4
+ from rich.console import Console
4
5
 
5
6
  from . import flow, lib
6
7
  from .setup import sync_setup, drop_setup, flow_names_with_setup, apply_setup_changes
@@ -52,11 +53,14 @@ def ls(show_all: bool):
52
53
 
53
54
  @cli.command()
54
55
  @click.argument("flow_name", type=str, required=False)
55
- def show(flow_name: str | None):
56
+ @click.option("--color/--no-color", default=True)
57
+ def show(flow_name: str | None, color: bool):
56
58
  """
57
- Show the flow spec.
59
+ Show the flow spec in a readable format with colored output.
58
60
  """
59
- click.echo(str(_flow_by_name(flow_name)))
61
+ flow = _flow_by_name(flow_name)
62
+ console = Console(no_color=not color)
63
+ console.print(flow._render_text())
60
64
 
61
65
  @cli.command()
62
66
  def setup():
@@ -8,11 +8,14 @@ import asyncio
8
8
  import re
9
9
  import inspect
10
10
  import datetime
11
+ import json
11
12
 
12
13
  from typing import Any, Callable, Sequence, TypeVar
13
14
  from threading import Lock
14
15
  from enum import Enum
15
16
  from dataclasses import dataclass
17
+ from rich.text import Text
18
+ from rich.console import Console
16
19
 
17
20
  from . import _engine
18
21
  from . import index
@@ -451,8 +454,58 @@ class Flow:
451
454
  return engine_flow
452
455
  self._lazy_engine_flow = _lazy_engine_flow
453
456
 
457
+ def _format_flow(self, flow_dict: dict) -> Text:
458
+ output = Text()
459
+
460
+ def add_line(content, indent=0, style=None, end="\n"):
461
+ output.append(" " * indent)
462
+ output.append(content, style=style)
463
+ output.append(end)
464
+
465
+ def format_key_value(key, value, indent):
466
+ if isinstance(value, (dict, list)):
467
+ add_line(f"- {key}:", indent, style="green")
468
+ format_data(value, indent + 2)
469
+ else:
470
+ add_line(f"- {key}:", indent, style="green", end="")
471
+ add_line(f" {value}", style="yellow")
472
+
473
+ def format_data(data, indent=0):
474
+ if isinstance(data, dict):
475
+ for key, value in data.items():
476
+ format_key_value(key, value, indent)
477
+ elif isinstance(data, list):
478
+ for i, item in enumerate(data):
479
+ format_key_value(f"[{i}]", item, indent)
480
+ else:
481
+ add_line(str(data), indent, style="yellow")
482
+
483
+ # Header
484
+ flow_name = flow_dict.get("name", "Unnamed")
485
+ add_line(f"Flow: {flow_name}", style="bold cyan")
486
+
487
+ # Section
488
+ for section_title, section_key in [
489
+ ("Sources:", "import_ops"),
490
+ ("Processing:", "reactive_ops"),
491
+ ("Targets:", "export_ops"),
492
+ ]:
493
+ add_line("")
494
+ add_line(section_title, style="bold cyan")
495
+ format_data(flow_dict.get(section_key, []), indent=0)
496
+
497
+ return output
498
+
499
+ def _render_text(self) -> Text:
500
+ flow_spec_str = str(self._lazy_engine_flow())
501
+ try:
502
+ flow_dict = json.loads(flow_spec_str)
503
+ return self._format_flow(flow_dict)
504
+ except json.JSONDecodeError:
505
+ return Text(flow_spec_str)
506
+
454
507
  def __str__(self):
455
- return str(self._lazy_engine_flow())
508
+ return str(self._render_text())
456
509
 
457
510
  def __repr__(self):
458
511
  return repr(self._lazy_engine_flow())
@@ -37,7 +37,7 @@ class TargetFieldMapping:
37
37
  target: str | None = None
38
38
 
39
39
  @dataclass
40
- class NodeReferenceMapping:
40
+ class NodeFromFields:
41
41
  """Spec for a referenced graph node, usually as part of a relationship."""
42
42
  label: str
43
43
  fields: list[TargetFieldMapping]
@@ -50,30 +50,37 @@ class ReferencedNode:
50
50
  vector_indexes: Sequence[index.VectorIndexDef] = ()
51
51
 
52
52
  @dataclass
53
- class NodeMapping:
53
+ class Nodes:
54
54
  """Spec to map a row to a graph node."""
55
55
  kind = "Node"
56
56
 
57
57
  label: str
58
58
 
59
59
  @dataclass
60
- class RelationshipMapping:
60
+ class Relationships:
61
61
  """Spec to map a row to a graph relationship."""
62
62
  kind = "Relationship"
63
63
 
64
64
  rel_type: str
65
- source: NodeReferenceMapping
66
- target: NodeReferenceMapping
65
+ source: NodeFromFields
66
+ target: NodeFromFields
67
+
68
+ # For backwards compatibility only
69
+ NodeMapping = Nodes
70
+ RelationshipMapping = Relationships
71
+ NodeReferenceMapping = NodeFromFields
67
72
 
68
73
  class Neo4j(op.StorageSpec):
69
74
  """Graph storage powered by Neo4j."""
70
75
 
71
76
  connection: AuthEntryReference
72
- mapping: NodeMapping | RelationshipMapping
77
+ mapping: Nodes | Relationships
73
78
 
74
- class Neo4jDeclarations(op.DeclarationSpec):
79
+ class Neo4jDeclaration(op.DeclarationSpec):
75
80
  """Declarations for Neo4j."""
76
81
 
77
82
  kind = "Neo4j"
78
83
  connection: AuthEntryReference
79
- referenced_nodes: Sequence[ReferencedNode] = ()
84
+ nodes_label: str
85
+ primary_key_fields: Sequence[str]
86
+ vector_indexes: Sequence[index.VectorIndexDef] = ()
@@ -120,8 +120,10 @@ pub enum TableKind {
120
120
  /// An table with unordered rows, without key.
121
121
  UTable,
122
122
  /// A table's first field is the key.
123
+ #[serde(alias = "Table")]
123
124
  KTable,
124
125
  /// A table whose rows orders are preserved.
126
+ #[serde(alias = "List")]
125
127
  LTable,
126
128
  }
127
129