data-syncmaster 0.2.3__tar.gz → 0.2.5__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 (223) hide show
  1. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/PKG-INFO +14 -10
  2. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/README.rst +3 -2
  3. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/pyproject.toml +19 -15
  4. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/__init__.py +1 -1
  5. data_syncmaster-0.2.5/syncmaster/db/migrations/versions/2025-08-10_0012_update_ts.py +243 -0
  6. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/models/connection.py +19 -5
  7. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/models/group.py +16 -3
  8. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/models/queue.py +16 -2
  9. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/models/transfer.py +38 -12
  10. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/base.py +11 -3
  11. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/connection.py +3 -3
  12. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/group.py +7 -3
  13. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/queue.py +3 -1
  14. data_syncmaster-0.2.5/syncmaster/db/repositories/search.py +96 -0
  15. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/transfer.py +3 -3
  16. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/auth.py +16 -0
  17. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/v1/auth.py +21 -11
  18. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/v1/runs.py +0 -2
  19. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/handler.py +5 -3
  20. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/middlewares/monitoring/metrics.py +1 -1
  21. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/middlewares/session.py +4 -4
  22. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/providers/auth/base_provider.py +8 -3
  23. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/providers/auth/dummy_provider.py +14 -12
  24. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/providers/auth/keycloak_provider.py +32 -30
  25. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/auth/jwt.py +5 -1
  26. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/server/session.py +20 -3
  27. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/base.py +3 -4
  28. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/spark.py +29 -37
  29. data_syncmaster-0.2.3/syncmaster/server/utils/state.py +0 -15
  30. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/LICENSE.txt +0 -0
  31. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/__init__.py +0 -0
  32. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/factory.py +0 -0
  33. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/README +0 -0
  34. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/__main__.py +0 -0
  35. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/alembic.ini +0 -0
  36. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/env.py +0 -0
  37. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/script.py.mako +0 -0
  38. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2023-11-23_0001_create_user_table.py +0 -0
  39. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2023-11-23_0002_create_group_table.py +0 -0
  40. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2023-11-23_0003_create_queue_table.py +0 -0
  41. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2023-11-23_0004_create_connection_table.py +0 -0
  42. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2023-11-23_0005_create_user_group_table.py +0 -0
  43. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2023-11-23_0006_create_auth_data_table.py +0 -0
  44. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2023-11-23_0007_create_transfer_table.py +0 -0
  45. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2023-11-23_0008_create_run_table.py +0 -0
  46. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2023-11-23_0009_create_celery_tables.py +0 -0
  47. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2024-10-07_0010_add_pg_trgm_extension.py +0 -0
  48. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/2024-11-01_0011_create_apscheduler_table.py +0 -0
  49. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/migrations/versions/__init__.py +0 -0
  50. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/mixins/__init__.py +0 -0
  51. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/mixins/resource.py +0 -0
  52. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/mixins/timestamp.py +0 -0
  53. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/models/__init__.py +0 -0
  54. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/models/apscheduler_job.py +0 -0
  55. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/models/auth_data.py +0 -0
  56. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/models/base.py +0 -0
  57. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/models/run.py +0 -0
  58. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/models/user.py +0 -0
  59. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/__init__.py +0 -0
  60. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/credentials_repository.py +0 -0
  61. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/repository_with_owner.py +0 -0
  62. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/run.py +0 -0
  63. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/user.py +0 -0
  64. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/repositories/utils.py +0 -0
  65. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/db/utils.py +0 -0
  66. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/dto/__init__.py +0 -0
  67. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/dto/connections.py +0 -0
  68. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/dto/runs.py +0 -0
  69. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/dto/transfers.py +0 -0
  70. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/dto/transfers_resources.py +0 -0
  71. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/dto/transfers_strategy.py +0 -0
  72. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/errors/__init__.py +0 -0
  73. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/errors/base.py +0 -0
  74. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/errors/registration.py +0 -0
  75. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/errors/schemas/__init__.py +0 -0
  76. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/errors/schemas/bad_request.py +0 -0
  77. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/errors/schemas/invalid_request.py +0 -0
  78. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/errors/schemas/not_authorized.py +0 -0
  79. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/__init__.py +0 -0
  80. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/base.py +0 -0
  81. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/connection.py +0 -0
  82. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/credentials.py +0 -0
  83. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/group.py +0 -0
  84. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/queue.py +0 -0
  85. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/redirect.py +0 -0
  86. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/run.py +0 -0
  87. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/transfer.py +0 -0
  88. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/exceptions/user.py +0 -0
  89. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/scheduler/__init__.py +0 -0
  90. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/scheduler/__main__.py +0 -0
  91. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/scheduler/celery.py +0 -0
  92. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/scheduler/settings/__init__.py +0 -0
  93. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/scheduler/transfer_fetcher.py +0 -0
  94. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/scheduler/transfer_job_manager.py +0 -0
  95. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/scheduler/utils.py +0 -0
  96. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/__init__.py +0 -0
  97. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/ping.py +0 -0
  98. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/__init__.py +0 -0
  99. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/auth/__init__.py +0 -0
  100. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/auth/basic.py +0 -0
  101. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/auth/s3.py +0 -0
  102. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/auth/samba.py +0 -0
  103. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/auth/token.py +0 -0
  104. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connection_types.py +0 -0
  105. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/__init__.py +0 -0
  106. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/clickhouse.py +0 -0
  107. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/connection.py +0 -0
  108. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/connection_base.py +0 -0
  109. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/ftp.py +0 -0
  110. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/ftps.py +0 -0
  111. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/hdfs.py +0 -0
  112. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/hive.py +0 -0
  113. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/mssql.py +0 -0
  114. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/mysql.py +0 -0
  115. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/oracle.py +0 -0
  116. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/postgres.py +0 -0
  117. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/s3.py +0 -0
  118. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/samba.py +0 -0
  119. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/sftp.py +0 -0
  120. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/connections/webdav.py +0 -0
  121. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/file_formats.py +0 -0
  122. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/groups.py +0 -0
  123. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/page.py +0 -0
  124. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/queue.py +0 -0
  125. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfer_types.py +0 -0
  126. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/__init__.py +0 -0
  127. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/db.py +0 -0
  128. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/file/__init__.py +0 -0
  129. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/file/base.py +0 -0
  130. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/file/ftp.py +0 -0
  131. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/file/ftps.py +0 -0
  132. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/file/hdfs.py +0 -0
  133. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/file/s3.py +0 -0
  134. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/file/samba.py +0 -0
  135. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/file/sftp.py +0 -0
  136. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/file/webdav.py +0 -0
  137. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/file_format.py +0 -0
  138. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/resources.py +0 -0
  139. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/run.py +0 -0
  140. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/strategy.py +0 -0
  141. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/transformations/__init__.py +0 -0
  142. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/transformations/dataframe_columns_filter.py +0 -0
  143. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/transformations/dataframe_rows_filter.py +0 -0
  144. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transfers/transformations/file_metadata_filter.py +0 -0
  145. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/transformation_types.py +0 -0
  146. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/types.py +0 -0
  147. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/schemas/v1/users.py +0 -0
  148. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/__init__.py +0 -0
  149. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/__main__.py +0 -0
  150. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/__init__.py +0 -0
  151. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/monitoring.py +0 -0
  152. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/router.py +0 -0
  153. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/v1/__init__.py +0 -0
  154. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/v1/connections.py +0 -0
  155. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/v1/groups.py +0 -0
  156. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/v1/queue.py +0 -0
  157. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/v1/router.py +0 -0
  158. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/v1/transfers.py +0 -0
  159. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/api/v1/users.py +0 -0
  160. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/dependencies/__init__.py +0 -0
  161. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/dependencies/get_access_token.py +0 -0
  162. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/dependencies/stub.py +0 -0
  163. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/middlewares/__init__.py +0 -0
  164. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/middlewares/cors.py +0 -0
  165. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/middlewares/monitoring/__init__.py +0 -0
  166. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/middlewares/openapi.py +0 -0
  167. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/middlewares/request_id.py +0 -0
  168. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/middlewares/static_files.py +0 -0
  169. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/providers/__init__.py +0 -0
  170. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/providers/auth/__init__.py +0 -0
  171. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/scripts/export_openapi_schema.py +0 -0
  172. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/scripts/manage_superusers.py +0 -0
  173. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/services/__init__.py +0 -0
  174. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/services/get_user.py +0 -0
  175. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/services/unit_of_work.py +0 -0
  176. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/__init__.py +0 -0
  177. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/auth/__init__.py +0 -0
  178. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/auth/dummy.py +0 -0
  179. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/auth/keycloak.py +0 -0
  180. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/server/__init__.py +0 -0
  181. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/server/cors.py +0 -0
  182. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/server/monitoring.py +0 -0
  183. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/server/openapi.py +0 -0
  184. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/server/request_id.py +0 -0
  185. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/settings/server/static_files.py +0 -0
  186. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/utils/__init__.py +0 -0
  187. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/utils/jwt.py +0 -0
  188. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/server/utils/slug.py +0 -0
  189. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/settings/__init__.py +0 -0
  190. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/settings/broker.py +0 -0
  191. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/settings/credentials.py +0 -0
  192. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/settings/database.py +0 -0
  193. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/settings/log/__init__.py +0 -0
  194. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/settings/log/colored.yml +0 -0
  195. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/settings/log/json.yml +0 -0
  196. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/settings/log/plain.yml +0 -0
  197. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/__init__.py +0 -0
  198. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/base.py +0 -0
  199. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/celery.py +0 -0
  200. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/controller.py +0 -0
  201. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/__init__.py +0 -0
  202. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/base.py +0 -0
  203. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/db/__init__.py +0 -0
  204. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/db/base.py +0 -0
  205. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/db/clickhouse.py +0 -0
  206. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/db/hive.py +0 -0
  207. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/db/mssql.py +0 -0
  208. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/db/mysql.py +0 -0
  209. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/db/oracle.py +0 -0
  210. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/db/postgres.py +0 -0
  211. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/__init__.py +0 -0
  212. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/ftp.py +0 -0
  213. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/ftps.py +0 -0
  214. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/hdfs.py +0 -0
  215. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/local_df.py +0 -0
  216. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/remote_df.py +0 -0
  217. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/s3.py +0 -0
  218. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/samba.py +0 -0
  219. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/sftp.py +0 -0
  220. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/handlers/file/webdav.py +0 -0
  221. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/settings/__init__.py +0 -0
  222. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/settings/hwm_store.py +0 -0
  223. {data_syncmaster-0.2.3 → data_syncmaster-0.2.5}/syncmaster/worker/transfer.py +0 -0
@@ -1,8 +1,9 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: data-syncmaster
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Syncmaster REST API + Worker
5
5
  License: Apache-2.0
6
+ License-File: LICENSE.txt
6
7
  Keywords: Syncmaster,REST,API,Worker,Spark,Transfer,ETL
7
8
  Author: DataOps.ETL
8
9
  Author-email: onetools@mts.ru
@@ -18,6 +19,7 @@ Classifier: Programming Language :: Python :: 3
18
19
  Classifier: Programming Language :: Python :: 3.11
19
20
  Classifier: Programming Language :: Python :: 3.12
20
21
  Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
21
23
  Classifier: Programming Language :: Python :: 3 :: Only
22
24
  Classifier: Topic :: Software Development :: Libraries
23
25
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -31,24 +33,25 @@ Requires-Dist: asgi-correlation-id (>=4.3.4,<5.0.0) ; extra == "server" or extra
31
33
  Requires-Dist: asyncpg (>=0.30.0,<0.31.0) ; extra == "server" or extra == "scheduler"
32
34
  Requires-Dist: celery (>=5.5.0,<6.0.0) ; extra == "server" or extra == "worker" or extra == "scheduler"
33
35
  Requires-Dist: coloredlogs ; extra == "server" or extra == "worker" or extra == "scheduler"
34
- Requires-Dist: fastapi (>=0.115.12,<0.116.0) ; extra == "server"
36
+ Requires-Dist: fastapi (>=0.115.12,<0.119.0) ; extra == "server"
35
37
  Requires-Dist: horizon-hwm-store (>=1.1.2,<2.0.0) ; extra == "worker"
36
38
  Requires-Dist: itsdangerous (>=2.2.0,<3.0.0) ; extra == "server"
37
39
  Requires-Dist: jinja2 (>=3.1.6,<4.0.0) ; extra == "server" or extra == "worker"
38
- Requires-Dist: onetl[all] (>=0.13.4,<0.14.0) ; extra == "worker"
40
+ Requires-Dist: onetl[all] (>=0.13.5,<0.15.0) ; extra == "worker"
39
41
  Requires-Dist: psycopg2-binary (>=2.9.10,<3.0.0) ; extra == "server" or extra == "worker"
40
- Requires-Dist: pydantic (>=2.11.1,<3.0.0)
42
+ Requires-Dist: pydantic (>=2.11.7,<3.0.0)
41
43
  Requires-Dist: pydantic-settings (>=2.8.1,<3.0.0) ; extra == "server" or extra == "worker" or extra == "scheduler"
42
44
  Requires-Dist: pyjwt (>=2.10.1,<3.0.0) ; extra == "server"
45
+ Requires-Dist: pyspark (<4.0.0) ; extra == "worker"
43
46
  Requires-Dist: python-json-logger ; extra == "server" or extra == "worker" or extra == "scheduler"
44
47
  Requires-Dist: python-keycloak (>=5.3.1,<6.0.0) ; extra == "server"
45
48
  Requires-Dist: python-multipart (>=0.0.20,<0.0.21) ; extra == "server"
46
49
  Requires-Dist: pyyaml ; extra == "server" or extra == "worker" or extra == "scheduler"
47
50
  Requires-Dist: sqlalchemy (>=2.0.40,<3.0.0) ; extra == "server" or extra == "worker" or extra == "scheduler"
48
- Requires-Dist: sqlalchemy-utils (>=0.41.2,<0.42.0) ; extra == "server" or extra == "worker" or extra == "scheduler"
51
+ Requires-Dist: sqlalchemy-utils (>=0.41.2,<0.43.0) ; extra == "server" or extra == "worker" or extra == "scheduler"
49
52
  Requires-Dist: starlette-exporter (>=0.23.0,<0.24.0) ; extra == "server"
50
- Requires-Dist: uuid6 (>=2024.7.10,<2025.0.0) ; extra == "server" or extra == "worker"
51
- Requires-Dist: uvicorn (>=0.34.0,<0.35.0) ; extra == "server"
53
+ Requires-Dist: uuid6 (>=2025.0.0,<2026.0.0) ; extra == "server" or extra == "worker"
54
+ Requires-Dist: uvicorn (>=0.34,<0.38) ; extra == "server"
52
55
  Project-URL: CI/CD, https://github.com/MobileTeleSystems/syncmaster/actions
53
56
  Project-URL: Documentation, https://syncmaster.readthedocs.io
54
57
  Project-URL: Homepage, https://github.com/MobileTeleSystems/syncmaster
@@ -78,8 +81,9 @@ Data.SyncMaster
78
81
  :target: https://syncmaster.readthedocs.io
79
82
  .. |Build Status| image:: https://github.com/MobileTeleSystems/syncmaster/workflows/Run%20All%20Tests/badge.svg
80
83
  :target: https://github.com/MobileTeleSystems/syncmaster/actions
81
- .. |Coverage| image:: https://codecov.io/gh/MobileTeleSystems/syncmaster/graph/badge.svg?token=ky7UyUxolB
82
- :target: https://codecov.io/gh/MobileTeleSystems/syncmaster
84
+ .. |Coverage| image:: https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/
85
+ MTSOnGithub/03e73a82ecc4709934540ce8201cc3b4/raw/syncmaster_badge.json
86
+ :target: https://github.com/MobileTeleSystems/syncmaster/actions
83
87
  .. |pre-commit.ci| image:: https://results.pre-commit.ci/badge/github/MobileTeleSystems/syncmaster/develop.svg
84
88
  :target: https://results.pre-commit.ci/latest/github/MobileTeleSystems/syncmaster/develop
85
89
 
@@ -20,8 +20,9 @@ Data.SyncMaster
20
20
  :target: https://syncmaster.readthedocs.io
21
21
  .. |Build Status| image:: https://github.com/MobileTeleSystems/syncmaster/workflows/Run%20All%20Tests/badge.svg
22
22
  :target: https://github.com/MobileTeleSystems/syncmaster/actions
23
- .. |Coverage| image:: https://codecov.io/gh/MobileTeleSystems/syncmaster/graph/badge.svg?token=ky7UyUxolB
24
- :target: https://codecov.io/gh/MobileTeleSystems/syncmaster
23
+ .. |Coverage| image:: https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/
24
+ MTSOnGithub/03e73a82ecc4709934540ce8201cc3b4/raw/syncmaster_badge.json
25
+ :target: https://github.com/MobileTeleSystems/syncmaster/actions
25
26
  .. |pre-commit.ci| image:: https://results.pre-commit.ci/badge/github/MobileTeleSystems/syncmaster/develop.svg
26
27
  :target: https://results.pre-commit.ci/latest/github/MobileTeleSystems/syncmaster/develop
27
28
 
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "data-syncmaster"
7
- version = "0.2.3"
7
+ version = "0.2.5"
8
8
  license = "Apache-2.0"
9
9
  description = "Syncmaster REST API + Worker"
10
10
  authors = ["DataOps.ETL <onetools@mts.ru>"]
@@ -44,22 +44,23 @@ exclude = [
44
44
 
45
45
  [tool.poetry.dependencies]
46
46
  python = "^3.11"
47
- pydantic = "^2.11.1"
47
+ pydantic = "^2.11.7"
48
48
  pydantic-settings = { version = "^2.8.1", optional = true }
49
49
  sqlalchemy = { version = "^2.0.40", optional = true }
50
- sqlalchemy-utils = { version = "^0.41.2", optional = true }
51
- fastapi = { version = "^0.115.12", optional = true}
50
+ sqlalchemy-utils = { version = ">=0.41.2,<0.43.0", optional = true }
51
+ fastapi = { version = ">=0.115.12,<0.119.0", optional = true}
52
52
  asgi-correlation-id = {version = "^4.3.4", optional = true}
53
- uvicorn = { version = "^0.34.0", optional = true }
53
+ uvicorn = { version = ">=0.34,<0.38", optional = true }
54
54
  alembic = { version = "^1.15.2", optional = true }
55
55
  pyjwt = { version = "^2.10.1", optional = true }
56
56
  jinja2 = { version = "^3.1.6", optional = true }
57
57
  python-multipart = { version = "^0.0.20", optional = true }
58
58
  celery = { version = "^5.5.0", optional = true }
59
- onetl = { version = "^0.13.4", extras = ["all"], optional = true }
59
+ onetl = { version = ">=0.13.5,<0.15.0", extras = ["all"], optional = true }
60
+ pyspark = { version = "<4.0.0", optional = true }
60
61
  pyyaml = { version = "*", optional = true }
61
62
  psycopg2-binary = { version = "^2.9.10", optional = true }
62
- uuid6 = {version = "^2024.7.10", optional = true}
63
+ uuid6 = {version = "^2025.0.0", optional = true}
63
64
  coloredlogs = {version = "*", optional = true}
64
65
  python-json-logger = {version = "*", optional = true}
65
66
  asyncpg = { version = "^0.30.0", optional = true }
@@ -99,6 +100,7 @@ worker = [
99
100
  "sqlalchemy-utils",
100
101
  "celery",
101
102
  "onetl",
103
+ "pyspark",
102
104
  "asgi-correlation-id",
103
105
  "jinja2",
104
106
  "psycopg2-binary",
@@ -124,16 +126,17 @@ scheduler = [
124
126
  [tool.poetry.group.test.dependencies]
125
127
  pytest = "^8.3.5"
126
128
  httpx = "^0.28.1"
127
- pytest-asyncio = "^0.26.0"
128
- pytest-randomly = "^3.15.0"
129
- pytest-rerunfailures = "^15.0"
129
+ pytest-asyncio = ">=0.26.0,<1.0"
130
+ pytest-randomly = ">=3.15,<5.0"
131
+ pytest-rerunfailures = ">=15,<17"
130
132
  pytest-deadfixtures = "^2.2.1"
131
133
  pytest-mock = "^3.14.0"
132
134
  pytest-lazy-fixtures = "^1.1.1"
133
- faker = "^37.1.0"
134
- coverage = "^7.8.0"
135
- gevent = "^24.11.1"
136
- responses = "^0.25.7"
135
+ faker = "^37.4.0"
136
+ coverage = "^7.9.1"
137
+ gevent = ">=24.11.1,<26.0.0"
138
+ respx = "^0.22.0"
139
+ dirty-equals = "^0.9.0"
137
140
 
138
141
  [tool.poetry.group.dev.dependencies]
139
142
  mypy = "^1.15.0"
@@ -142,12 +145,13 @@ black = "^25.1.0"
142
145
  flake8 = "^7.2.0"
143
146
  flake8-pyproject = "^1.2.3"
144
147
  sqlalchemy = {extras = ["mypy"], version = "^2.0.40"}
148
+ types-jwcrypto = "^1.5.0"
145
149
 
146
150
  [tool.poetry.group.docs.dependencies]
147
151
  autodoc-pydantic = "^2.2.0"
148
152
  numpydoc = "^1.8.0"
149
153
  sphinx = "^8.2.3"
150
- furo = "^2024.8.6"
154
+ furo = ">=2024.8.6,<2026.0.0"
151
155
  sphinx-copybutton = "^0.5.2"
152
156
  sphinxcontrib-towncrier = "^0.5.0a0"
153
157
  towncrier = "^24.8.0"
@@ -1,6 +1,6 @@
1
1
  # SPDX-FileCopyrightText: 2023-2024 MTS PJSC
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
 
4
- _raw_version = "0.2.3"
4
+ _raw_version = "0.2.5"
5
5
  # version always contain only release number like 0.0.1
6
6
  __version__ = ".".join(_raw_version.split(".")[:3]) # noqa: WPS410
@@ -0,0 +1,243 @@
1
+ # SPDX-FileCopyrightText: 2023-2024 MTS PJSC
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ """Update text search
4
+
5
+ Revision ID: 0012
6
+ Revises: 0011
7
+ Create Date: 2025-08-10 20:03:02.105470
8
+
9
+ """
10
+
11
+ import sqlalchemy as sa
12
+ from alembic import op
13
+ from sqlalchemy.dialects import postgresql
14
+
15
+ # revision identifiers, used by Alembic.
16
+ revision = "0012"
17
+ down_revision = "0011"
18
+ branch_labels = None
19
+ depends_on = None
20
+
21
+
22
+ def upgrade() -> None:
23
+ op.drop_index(op.f("idx_connection_search_vector"), table_name="connection", postgresql_using="gin")
24
+ op.drop_column("connection", "search_vector")
25
+ op.drop_column("group", "search_vector")
26
+ op.drop_index(op.f("idx_transfer_search_vector"), table_name="transfer", postgresql_using="gin")
27
+ op.drop_column("transfer", "search_vector")
28
+ op.drop_column("queue", "search_vector")
29
+
30
+ op.add_column(
31
+ "connection",
32
+ sa.Column(
33
+ "search_vector",
34
+ postgresql.TSVECTOR(),
35
+ sa.Computed(
36
+ """
37
+ -- === NAME FIELD ===
38
+ -- Russian stemming for better morphological matching of regular words
39
+ to_tsvector('russian', coalesce(name, ''))
40
+ -- Simple dictionary (no stemming) for exact token match
41
+ || to_tsvector('simple', coalesce(name, ''))
42
+ -- Simple dictionary with translate(): split by . / - _ : \
43
+ -- (used when 'name' contains technical fields)
44
+ || to_tsvector(
45
+ 'simple',
46
+ translate(coalesce(name, ''), './-_:\\', ' ')
47
+ )
48
+
49
+ -- === HOST FIELD (from JSON) ===
50
+ -- Simple dictionary (no stemming) for exact match
51
+ || to_tsvector('simple', coalesce(data->>'host', ''))
52
+ -- Simple dictionary with translate(): split by . / - _ : \\ for partial token matching
53
+ || to_tsvector(
54
+ 'simple',
55
+ translate(coalesce(data->>'host', ''), './-_:\\', ' ')
56
+ )
57
+ """,
58
+ persisted=True,
59
+ ),
60
+ nullable=False,
61
+ ),
62
+ )
63
+ op.create_index(
64
+ "idx_connection_search_vector",
65
+ "connection",
66
+ ["search_vector"],
67
+ unique=False,
68
+ postgresql_using="gin",
69
+ )
70
+
71
+ op.add_column(
72
+ "group",
73
+ sa.Column(
74
+ "search_vector",
75
+ postgresql.TSVECTOR(),
76
+ sa.Computed(
77
+ """
78
+ -- === NAME FIELD ===
79
+ -- Russian stemming for better morphological matching of regular words
80
+ to_tsvector('russian', coalesce(name, ''))
81
+ -- Simple dictionary (no stemming) for exact token match
82
+ || to_tsvector('simple', coalesce(name, ''))
83
+ -- Simple dictionary with translate(): split by . / - _ : \
84
+ -- (used when 'name' contains technical fields)
85
+ || to_tsvector(
86
+ 'simple',
87
+ translate(coalesce(name, ''), './-_:\\', ' ')
88
+ )
89
+ """,
90
+ persisted=True,
91
+ ),
92
+ nullable=False,
93
+ ),
94
+ )
95
+
96
+ op.add_column(
97
+ "queue",
98
+ sa.Column(
99
+ "search_vector",
100
+ postgresql.TSVECTOR(),
101
+ sa.Computed(
102
+ """
103
+ -- === NAME FIELD ===
104
+ -- Russian stemming for better morphological matching of regular words
105
+ to_tsvector('russian', coalesce(name, ''))
106
+ -- Simple dictionary (no stemming) for exact token match
107
+ || to_tsvector('simple', coalesce(name, ''))
108
+ -- Simple dictionary with translate(): split by . / - _ : \
109
+ -- (used when 'name' contains technical fields)
110
+ || to_tsvector(
111
+ 'simple',
112
+ translate(coalesce(name, ''), './-_:\\', ' ')
113
+ )
114
+ """,
115
+ persisted=True,
116
+ ),
117
+ nullable=False,
118
+ ),
119
+ )
120
+
121
+ op.add_column(
122
+ "transfer",
123
+ sa.Column(
124
+ "search_vector",
125
+ postgresql.TSVECTOR(),
126
+ sa.Computed(
127
+ """
128
+ -- === NAME FIELD ===
129
+ -- Russian stemming for better morphological matching of regular words
130
+ to_tsvector('russian', coalesce(name, ''))
131
+ -- Simple dictionary (no stemming) for exact token match
132
+ || to_tsvector('simple', coalesce(name, ''))
133
+ -- Simple dictionary with translate(): split by . / - _ : \
134
+ -- (used when 'name' contains technical fields)
135
+ || to_tsvector(
136
+ 'simple',
137
+ translate(coalesce(name, ''), './-_:\\', ' ')
138
+ )
139
+
140
+ -- === TABLE NAME FIELDS ===
141
+ -- Simple dictionary (no stemming) for exact match
142
+ || to_tsvector('simple', coalesce(source_params->>'table_name', ''))
143
+ || to_tsvector('simple', coalesce(target_params->>'table_name', ''))
144
+ -- Simple dictionary with translate(): split by . / - _ : \\ for partial token matching
145
+ || to_tsvector(
146
+ 'simple',
147
+ translate(coalesce(source_params->>'table_name', ''), './-_:\\', ' ')
148
+ )
149
+ || to_tsvector(
150
+ 'simple',
151
+ translate(coalesce(target_params->>'table_name', ''), './-_:\\', ' ')
152
+ )
153
+
154
+ -- === DIRECTORY PATH FIELDS ===
155
+ -- Simple dictionary (no stemming) for exact match
156
+ || to_tsvector('simple', coalesce(source_params->>'directory_path', ''))
157
+ || to_tsvector('simple', coalesce(target_params->>'directory_path', ''))
158
+ -- Simple dictionary with translate(): split by . / - _ : \\ for partial token matching
159
+ || to_tsvector(
160
+ 'simple',
161
+ translate(coalesce(source_params->>'directory_path', ''), './-_:\\', ' ')
162
+ )
163
+ || to_tsvector(
164
+ 'simple',
165
+ translate(coalesce(target_params->>'directory_path', ''), './-_:\\', ' ')
166
+ )
167
+ """,
168
+ persisted=True,
169
+ ),
170
+ nullable=False,
171
+ ),
172
+ )
173
+ op.create_index("idx_transfer_search_vector", "transfer", ["search_vector"], unique=False, postgresql_using="gin")
174
+
175
+
176
+ def downgrade() -> None:
177
+ op.drop_index("idx_transfer_search_vector", table_name="transfer", postgresql_using="gin")
178
+ op.drop_column("transfer", "search_vector")
179
+ op.drop_column("group", "search_vector")
180
+ op.drop_index("idx_connection_search_vector", table_name="connection", postgresql_using="gin")
181
+ op.drop_column("connection", "search_vector")
182
+ op.drop_column("queue", "search_vector")
183
+
184
+ op.add_column(
185
+ "transfer",
186
+ sa.Column(
187
+ "search_vector",
188
+ postgresql.TSVECTOR(),
189
+ sa.Computed(
190
+ "to_tsvector('english'::regconfig, (((((((((((((((((((name)::text || ' '::text) || COALESCE(json_extract_path_text(source_params, VARIADIC ARRAY['table_name'::text]), ''::text)) || ' '::text) || COALESCE(json_extract_path_text(target_params, VARIADIC ARRAY['table_name'::text]), ''::text)) || ' '::text) || COALESCE(json_extract_path_text(source_params, VARIADIC ARRAY['directory_path'::text]), ''::text)) || ' '::text) || COALESCE(json_extract_path_text(target_params, VARIADIC ARRAY['directory_path'::text]), ''::text)) || ' '::text) || translate((name)::text, './'::text, ' '::text)) || ' '::text) || COALESCE(translate(json_extract_path_text(source_params, VARIADIC ARRAY['table_name'::text]), './'::text, ' '::text), ''::text)) || ' '::text) || COALESCE(translate(json_extract_path_text(target_params, VARIADIC ARRAY['table_name'::text]), './'::text, ' '::text), ''::text)) || ' '::text) || COALESCE(translate(json_extract_path_text(source_params, VARIADIC ARRAY['directory_path'::text]), './'::text, ' '::text), ''::text)) || ' '::text) || COALESCE(translate(json_extract_path_text(target_params, VARIADIC ARRAY['directory_path'::text]), './'::text, ' '::text), ''::text)))",
191
+ persisted=True,
192
+ ),
193
+ autoincrement=False,
194
+ nullable=False,
195
+ ),
196
+ )
197
+ op.create_index(
198
+ op.f("idx_transfer_search_vector"),
199
+ "transfer",
200
+ ["search_vector"],
201
+ unique=False,
202
+ postgresql_using="gin",
203
+ )
204
+ op.add_column(
205
+ "group",
206
+ sa.Column(
207
+ "search_vector",
208
+ postgresql.TSVECTOR(),
209
+ sa.Computed("to_tsvector('english'::regconfig, (name)::text)", persisted=True),
210
+ autoincrement=False,
211
+ nullable=False,
212
+ ),
213
+ )
214
+ op.add_column(
215
+ "connection",
216
+ sa.Column(
217
+ "search_vector",
218
+ postgresql.TSVECTOR(),
219
+ sa.Computed(
220
+ "to_tsvector('english'::regconfig, (((((name)::text || ' '::text) || COALESCE(json_extract_path_text(data, VARIADIC ARRAY['host'::text]), ''::text)) || ' '::text) || COALESCE(translate(json_extract_path_text(data, VARIADIC ARRAY['host'::text]), '.'::text, ' '::text), ''::text)))",
221
+ persisted=True,
222
+ ),
223
+ autoincrement=False,
224
+ nullable=False,
225
+ ),
226
+ )
227
+ op.create_index(
228
+ op.f("idx_connection_search_vector"),
229
+ "connection",
230
+ ["search_vector"],
231
+ unique=False,
232
+ postgresql_using="gin",
233
+ )
234
+ op.add_column(
235
+ "queue",
236
+ sa.Column(
237
+ "search_vector",
238
+ postgresql.TSVECTOR(),
239
+ sa.Computed("to_tsvector('english'::regconfig, (name)::text)", persisted=True),
240
+ autoincrement=False,
241
+ nullable=False,
242
+ ),
243
+ )
@@ -41,11 +41,25 @@ class Connection(Base, ResourceMixin, TimestampMixin):
41
41
  TSVECTOR,
42
42
  Computed(
43
43
  """
44
- to_tsvector(
45
- 'english'::regconfig,
46
- name || ' ' ||
47
- COALESCE(json_extract_path_text(data, 'host'), '') || ' ' ||
48
- COALESCE(translate(json_extract_path_text(data, 'host'), '.', ' '), '')
44
+ -- === NAME FIELD ===
45
+ -- Russian stemming for better morphological matching of regular words
46
+ to_tsvector('russian', coalesce(name, ''))
47
+ -- Simple dictionary (no stemming) for exact token match
48
+ || to_tsvector('simple', coalesce(name, ''))
49
+ -- Simple dictionary with translate(): split by . / - _ : \
50
+ -- (used when 'name' contains technical fields)
51
+ || to_tsvector(
52
+ 'simple',
53
+ translate(coalesce(name, ''), './-_:\\', ' ')
54
+ )
55
+
56
+ -- === HOST FIELD (from JSON) ===
57
+ -- Simple dictionary (no stemming) for exact match
58
+ || to_tsvector('simple', coalesce(data->>'host', ''))
59
+ -- Simple dictionary with translate(): split by . / - _ : \\ for partial token matching
60
+ || to_tsvector(
61
+ 'simple',
62
+ translate(coalesce(data->>'host', ''), './-_:\\', ' ')
49
63
  )
50
64
  """,
51
65
  persisted=True,
@@ -77,13 +77,26 @@ class Group(Base, TimestampMixin):
77
77
 
78
78
  owner: Mapped[User] = relationship(User)
79
79
  queue: Mapped[Queue] = relationship(back_populates="group", cascade="all, delete-orphan")
80
-
81
80
  search_vector: Mapped[str] = mapped_column(
82
81
  TSVECTOR,
83
- Computed("to_tsvector('english'::regconfig, name)", persisted=True),
82
+ Computed(
83
+ """
84
+ -- === NAME FIELD ===
85
+ -- Russian stemming for better morphological matching of regular words
86
+ to_tsvector('russian', coalesce(name, ''))
87
+ -- Simple dictionary (no stemming) for exact token match
88
+ || to_tsvector('simple', coalesce(name, ''))
89
+ -- Simple dictionary with translate(): split by . / - _ : \
90
+ -- (used when 'name' contains technical fields)
91
+ || to_tsvector(
92
+ 'simple',
93
+ translate(coalesce(name, ''), './-_:\\', ' ')
94
+ )
95
+ """,
96
+ persisted=True,
97
+ ),
84
98
  nullable=False,
85
99
  deferred=True,
86
- doc="Full-text search vector",
87
100
  )
88
101
 
89
102
  def __repr__(self) -> str:
@@ -25,10 +25,24 @@ class Queue(Base, ResourceMixin, TimestampMixin):
25
25
 
26
26
  search_vector: Mapped[str] = mapped_column(
27
27
  TSVECTOR,
28
- Computed("to_tsvector('english'::regconfig, name)", persisted=True),
28
+ Computed(
29
+ """
30
+ -- === NAME FIELD ===
31
+ -- Russian stemming for better morphological matching of regular words
32
+ to_tsvector('russian', coalesce(name, ''))
33
+ -- Simple dictionary (no stemming) for exact token match
34
+ || to_tsvector('simple', coalesce(name, ''))
35
+ -- Simple dictionary with translate(): split by . / - _ : \
36
+ -- (used when 'name' contains technical fields)
37
+ || to_tsvector(
38
+ 'simple',
39
+ translate(coalesce(name, ''), './-_:\\', ' ')
40
+ )
41
+ """,
42
+ persisted=True,
43
+ ),
29
44
  nullable=False,
30
45
  deferred=True,
31
- doc="Full-text search vector",
32
46
  )
33
47
 
34
48
  def __repr__(self):
@@ -65,18 +65,44 @@ class Transfer(
65
65
  TSVECTOR,
66
66
  Computed(
67
67
  """
68
- to_tsvector(
69
- 'english'::regconfig,
70
- name || ' ' ||
71
- COALESCE(json_extract_path_text(source_params, 'table_name'), '') || ' ' ||
72
- COALESCE(json_extract_path_text(target_params, 'table_name'), '') || ' ' ||
73
- COALESCE(json_extract_path_text(source_params, 'directory_path'), '') || ' ' ||
74
- COALESCE(json_extract_path_text(target_params, 'directory_path'), '') || ' ' ||
75
- translate(name, './', ' ') || ' ' ||
76
- COALESCE(translate(json_extract_path_text(source_params, 'table_name'), './', ' '), '') || ' ' ||
77
- COALESCE(translate(json_extract_path_text(target_params, 'table_name'), './', ' '), '') || ' ' ||
78
- COALESCE(translate(json_extract_path_text(source_params, 'directory_path'), './', ' '), '') || ' ' ||
79
- COALESCE(translate(json_extract_path_text(target_params, 'directory_path'), './', ' '), '')
68
+ -- === NAME FIELD ===
69
+ -- Russian stemming for better morphological matching of regular words
70
+ to_tsvector('russian', coalesce(name, ''))
71
+ -- Simple dictionary (no stemming) for exact token match
72
+ || to_tsvector('simple', coalesce(name, ''))
73
+ -- Simple dictionary with translate(): split by . / - _ : \
74
+ -- (used when 'name' contains technical fields)
75
+ || to_tsvector(
76
+ 'simple',
77
+ translate(coalesce(name, ''), './-_:\\', ' ')
78
+ )
79
+
80
+ -- === TABLE NAME FIELDS ===
81
+ -- Simple dictionary (no stemming) for exact match
82
+ || to_tsvector('simple', coalesce(source_params->>'table_name', ''))
83
+ || to_tsvector('simple', coalesce(target_params->>'table_name', ''))
84
+ -- Simple dictionary with translate(): split by . / - _ : \\ for partial token matching
85
+ || to_tsvector(
86
+ 'simple',
87
+ translate(coalesce(source_params->>'table_name', ''), './-_:\\', ' ')
88
+ )
89
+ || to_tsvector(
90
+ 'simple',
91
+ translate(coalesce(target_params->>'table_name', ''), './-_:\\', ' ')
92
+ )
93
+
94
+ -- === DIRECTORY PATH FIELDS ===
95
+ -- Simple dictionary (no stemming) for exact match
96
+ || to_tsvector('simple', coalesce(source_params->>'directory_path', ''))
97
+ || to_tsvector('simple', coalesce(target_params->>'directory_path', ''))
98
+ -- Simple dictionary with translate(): split by . / - _ : \\ for partial token matching
99
+ || to_tsvector(
100
+ 'simple',
101
+ translate(coalesce(source_params->>'directory_path', ''), './-_:\\', ' ')
102
+ )
103
+ || to_tsvector(
104
+ 'simple',
105
+ translate(coalesce(target_params->>'directory_path', ''), './-_:\\', ' ')
80
106
  )
81
107
  """,
82
108
  persisted=True,
@@ -3,7 +3,16 @@
3
3
  from abc import ABC
4
4
  from typing import Any, Generic, TypeVar
5
5
 
6
- from sqlalchemy import ScalarResult, Select, delete, func, insert, select, update
6
+ from sqlalchemy import (
7
+ ColumnElement,
8
+ ScalarResult,
9
+ Select,
10
+ delete,
11
+ func,
12
+ insert,
13
+ select,
14
+ update,
15
+ )
7
16
  from sqlalchemy.exc import NoResultFound
8
17
  from sqlalchemy.ext.asyncio import AsyncSession
9
18
 
@@ -98,8 +107,7 @@ class Repository(Generic[Model], ABC):
98
107
  page_size=page_size,
99
108
  )
100
109
 
101
- def _construct_vector_search(self, query: Select, search_query: str) -> Select:
102
- ts_query = func.plainto_tsquery("english", search_query)
110
+ def _construct_vector_search(self, query: Select, ts_query: ColumnElement) -> Select:
103
111
  query = (
104
112
  query.where(self._model.search_vector.op("@@")(ts_query))
105
113
  .add_columns(func.ts_rank(self._model.search_vector, ts_query).label("rank"))
@@ -8,6 +8,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
8
8
 
9
9
  from syncmaster.db.models import Connection
10
10
  from syncmaster.db.repositories.repository_with_owner import RepositoryWithOwner
11
+ from syncmaster.db.repositories.search import make_tsquery
11
12
  from syncmaster.db.utils import Pagination
12
13
  from syncmaster.exceptions import EntityNotFoundError, SyncmasterError
13
14
  from syncmaster.exceptions.connection import (
@@ -35,9 +36,8 @@ class ConnectionRepository(RepositoryWithOwner[Connection]):
35
36
  Connection.group_id == group_id,
36
37
  )
37
38
  if search_query:
38
- processed_query = search_query.replace(".", " ")
39
- combined_query = f"{search_query} {processed_query}"
40
- stmt = self._construct_vector_search(stmt, combined_query)
39
+ ts_query = make_tsquery(search_query)
40
+ stmt = self._construct_vector_search(stmt, ts_query)
41
41
 
42
42
  if connection_type is not None:
43
43
  stmt = stmt.where(Connection.type.in_(connection_type))
@@ -10,6 +10,7 @@ from sqlalchemy.orm import joinedload
10
10
 
11
11
  from syncmaster.db.models import Group, GroupMemberRole, User, UserGroup
12
12
  from syncmaster.db.repositories.base import Repository
13
+ from syncmaster.db.repositories.search import make_tsquery
13
14
  from syncmaster.db.utils import Pagination, Permission
14
15
  from syncmaster.exceptions import EntityNotFoundError, SyncmasterError
15
16
  from syncmaster.exceptions.group import (
@@ -33,7 +34,8 @@ class GroupRepository(Repository[Group]):
33
34
  ) -> Pagination:
34
35
  stmt = select(Group)
35
36
  if search_query:
36
- stmt = self._construct_vector_search(stmt, search_query)
37
+ ts_query = make_tsquery(search_query)
38
+ stmt = self._construct_vector_search(stmt, ts_query)
37
39
 
38
40
  paginated_result = await self._paginate_scalar_result(
39
41
  query=stmt.order_by(Group.name),
@@ -78,7 +80,8 @@ class GroupRepository(Repository[Group]):
78
80
 
79
81
  # apply search filtering if a search query is provided
80
82
  if search_query:
81
- owned_groups_stmt = self._construct_vector_search(owned_groups_stmt, search_query)
83
+ ts_query = make_tsquery(search_query)
84
+ owned_groups_stmt = self._construct_vector_search(owned_groups_stmt, ts_query)
82
85
 
83
86
  # get total count of owned groups
84
87
  total_owned_groups = (
@@ -114,7 +117,8 @@ class GroupRepository(Repository[Group]):
114
117
 
115
118
  # apply search filtering if a search query is provided
116
119
  if search_query:
117
- user_groups_stmt = self._construct_vector_search(user_groups_stmt, search_query)
120
+ ts_query = make_tsquery(search_query)
121
+ user_groups_stmt = self._construct_vector_search(user_groups_stmt, ts_query)
118
122
 
119
123
  # get total count of user groups
120
124
  total_user_groups = (