mage-ai 0.9.46__py3-none-any.whl → 0.9.47__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mage_ai/api/operations/base.py +27 -5
- mage_ai/api/policies/GlobalHookPolicy.py +1 -1
- mage_ai/api/policies/IntegrationSourcePolicy.py +62 -0
- mage_ai/api/policies/OauthPolicy.py +6 -6
- mage_ai/api/presenters/GlobalHookPresenter.py +1 -1
- mage_ai/api/presenters/IntegrationSourcePresenter.py +9 -2
- mage_ai/api/presenters/PipelinePresenter.py +2 -0
- mage_ai/api/presenters/PipelineRunPresenter.py +8 -3
- mage_ai/api/presenters/PipelineSchedulePresenter.py +22 -1
- mage_ai/api/resources/BlockResource.py +5 -0
- mage_ai/api/resources/DataProviderResource.py +2 -0
- mage_ai/api/resources/IntegrationSourceResource.py +149 -2
- mage_ai/data_integrations/sources/constants.py +5 -0
- mage_ai/data_integrations/utils/scheduler.py +57 -2
- mage_ai/data_preparation/executors/block_executor.py +9 -1
- mage_ai/data_preparation/models/block/__init__.py +25 -12
- mage_ai/data_preparation/models/block/data_integration/constants.py +3 -0
- mage_ai/data_preparation/models/block/data_integration/utils.py +196 -37
- mage_ai/data_preparation/models/block/sql/utils/shared.py +18 -1
- mage_ai/data_preparation/models/block/utils.py +28 -13
- mage_ai/data_preparation/models/global_hooks/constants.py +50 -1
- mage_ai/data_preparation/models/global_hooks/models.py +148 -84
- mage_ai/data_preparation/models/global_hooks/predicates.py +316 -0
- mage_ai/data_preparation/models/pipeline.py +2 -0
- mage_ai/data_preparation/models/pipelines/integration_pipeline.py +0 -1
- mage_ai/data_preparation/preferences.py +29 -18
- mage_ai/data_preparation/repo_manager.py +12 -2
- mage_ai/data_preparation/sync/__init__.py +2 -0
- mage_ai/data_preparation/templates/constants.py +14 -0
- mage_ai/data_preparation/templates/data_exporters/chroma.py +24 -0
- mage_ai/data_preparation/templates/data_exporters/streaming/rabbitmq.yaml +7 -0
- mage_ai/data_preparation/templates/data_loaders/chroma.py +27 -0
- mage_ai/data_preparation/templates/repo/io_config.yaml +3 -0
- mage_ai/io/base.py +1 -0
- mage_ai/io/chroma.py +153 -0
- mage_ai/io/config.py +8 -0
- mage_ai/orchestration/db/models/schedules.py +98 -34
- mage_ai/orchestration/pipeline_scheduler.py +58 -19
- mage_ai/server/constants.py +1 -1
- mage_ai/server/frontend_dist/404.html +2 -2
- mage_ai/server/frontend_dist/_next/static/N3FS4bHv0jpYeeg672uYK/_buildManifest.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{1749-9a6276b2918fdae1.js → 1749-bf512b4dabbab7fa.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/{1952-ac7722e8b1ab88fe.js → 1952-57858e7445d24413.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/2714-1e79e9f2e998b544.js → frontend_dist/_next/static/chunks/2714-68fef54789d7eaeb.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2717-92cdffd87b6f6e05.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/3419-f8d518d024e7b5c8.js → frontend_dist/_next/static/chunks/3419-715ca383fa15a5ef.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3437-b4d6a037cf5781f8.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/3943-c9fb980f03df6450.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/4267-cb102e060a43d9bd.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/4366-93e09e5a4a7e182c.js → frontend_dist/_next/static/chunks/4366-3e52497942acbafe.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/{4783-1a21d9be47574bba.js → 4783-422429203610c318.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5810-e26a0768db1cfdba.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{5896-14e5a23b1c6a0769.js → 5896-7b8e36634d7d94eb.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/{6285-e9b45335bfb9ccaf.js → 6285-648f9a732e100b2f.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/6798-b904395b0c18647b.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/7022-070ec0144a4d029c.js → frontend_dist/_next/static/chunks/7022-e76cae3ba5ee5312.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/722-900f786d24f91b2e.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{7361-694e1e4fb9c97d68.js → 7361-6c5c9063b9f91700.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/8146-92e7ccfed169ee9c.js → frontend_dist/_next/static/chunks/8146-27f0e31f309897a5.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/845-9a73c65fe3fdc328.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/8487-8e1c09546dff4dbf.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/9264-cc44b07f248707b0.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/9618-4eb49cdbd1ba11d7.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{976-18c98af60b76f1a7.js → 976-0a8c2c4d7acd957b.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-78c4a077a2f279c2.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/files-b37d221eb5ddc248.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/global-hooks/[...slug]-7adc543fc490367a.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/global-hooks-51d366993f6dd449.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{files-449a022f2f0f2d94.js → files-fe6e73463a20d67c.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{manage-f83deb790548693b.js → manage-d8a38b5d1f50e798.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-9adc2974aada27ba.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-51b1311dff2a974e.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-2333e524d34b474a.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-e051057d9fe94f23.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-6d1afeb4a84f50f7.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1ff9bb8e22ca1e75.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-11363aa58d51f4e1.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-779c3ef0676a12ac.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-bbea9a088657404a.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-3737f2b0afc2ede3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/profile-3c8f062913c66f3e.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-c1f4ed17d501ccca.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-8bdd858240d5dbf6.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-dd4fb405695f74bf.js +1 -0
- mage_ai/server/frontend_dist/block-layout.html +2 -2
- mage_ai/server/frontend_dist/compute.html +5 -5
- mage_ai/server/frontend_dist/files.html +5 -5
- mage_ai/server/frontend_dist/global-data-products/[...slug].html +5 -5
- mage_ai/server/frontend_dist/global-data-products.html +5 -5
- mage_ai/server/frontend_dist/global-hooks/[...slug].html +5 -5
- mage_ai/server/frontend_dist/global-hooks.html +5 -5
- mage_ai/server/frontend_dist/index.html +2 -2
- mage_ai/server/frontend_dist/manage/files.html +5 -5
- mage_ai/server/frontend_dist/manage/settings.html +5 -5
- mage_ai/server/frontend_dist/manage/users/[user].html +5 -5
- mage_ai/server/frontend_dist/manage/users/new.html +5 -5
- mage_ai/server/frontend_dist/manage/users.html +5 -5
- mage_ai/server/frontend_dist/manage.html +5 -5
- mage_ai/server/frontend_dist/oauth.html +4 -4
- mage_ai/server/frontend_dist/overview.html +5 -5
- mage_ai/server/frontend_dist/pipeline-runs.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist/pipelines.html +5 -5
- mage_ai/server/frontend_dist/settings/account/profile.html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/permissions.html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/preferences.html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/roles.html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/sync-data.html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/users.html +5 -5
- mage_ai/server/frontend_dist/settings.html +2 -2
- mage_ai/server/frontend_dist/sign-in.html +20 -20
- mage_ai/server/frontend_dist/templates/[...slug].html +5 -5
- mage_ai/server/frontend_dist/templates.html +5 -5
- mage_ai/server/frontend_dist/terminal.html +5 -5
- mage_ai/server/frontend_dist/test.html +5 -5
- mage_ai/server/frontend_dist/triggers.html +5 -5
- mage_ai/server/frontend_dist/version-control.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/_next/static/aoO6jYZLVlUGCCdY-wmy8/_buildManifest.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1749-9a6276b2918fdae1.js → 1749-bf512b4dabbab7fa.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1952-ac7722e8b1ab88fe.js → 1952-57858e7445d24413.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/2714-1e79e9f2e998b544.js → frontend_dist_base_path_template/_next/static/chunks/2714-68fef54789d7eaeb.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-92cdffd87b6f6e05.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/3419-f8d518d024e7b5c8.js → frontend_dist_base_path_template/_next/static/chunks/3419-715ca383fa15a5ef.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3437-b4d6a037cf5781f8.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3943-c9fb980f03df6450.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4267-cb102e060a43d9bd.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/4366-93e09e5a4a7e182c.js → frontend_dist_base_path_template/_next/static/chunks/4366-3e52497942acbafe.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{4783-1a21d9be47574bba.js → 4783-422429203610c318.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5810-e26a0768db1cfdba.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{5896-14e5a23b1c6a0769.js → 5896-7b8e36634d7d94eb.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{6285-e9b45335bfb9ccaf.js → 6285-648f9a732e100b2f.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6798-b904395b0c18647b.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/7022-070ec0144a4d029c.js → frontend_dist_base_path_template/_next/static/chunks/7022-e76cae3ba5ee5312.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/722-900f786d24f91b2e.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{7361-694e1e4fb9c97d68.js → 7361-6c5c9063b9f91700.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/8146-92e7ccfed169ee9c.js → frontend_dist_base_path_template/_next/static/chunks/8146-27f0e31f309897a5.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/845-9a73c65fe3fdc328.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8487-8e1c09546dff4dbf.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-cc44b07f248707b0.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9618-4eb49cdbd1ba11d7.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{976-18c98af60b76f1a7.js → 976-0a8c2c4d7acd957b.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-78c4a077a2f279c2.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-b37d221eb5ddc248.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks/[...slug]-7adc543fc490367a.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks-51d366993f6dd449.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{files-449a022f2f0f2d94.js → files-fe6e73463a20d67c.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{manage-f83deb790548693b.js → manage-d8a38b5d1f50e798.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-9adc2974aada27ba.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-51b1311dff2a974e.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-2333e524d34b474a.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-e051057d9fe94f23.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-6d1afeb4a84f50f7.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1ff9bb8e22ca1e75.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-11363aa58d51f4e1.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-779c3ef0676a12ac.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-bbea9a088657404a.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-3737f2b0afc2ede3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-3c8f062913c66f3e.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-c1f4ed17d501ccca.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-8bdd858240d5dbf6.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-dd4fb405695f74bf.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/compute.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/files.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/global-data-products.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/global-hooks.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/files.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/manage/settings.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/manage/users.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/manage.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/oauth.html +4 -4
- mage_ai/server/frontend_dist_base_path_template/overview.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/sign-in.html +23 -23
- mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/templates.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/terminal.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/test.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/triggers.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/version-control.html +5 -5
- mage_ai/server/server.py +9 -3
- mage_ai/services/k8s/job_manager.py +1 -0
- mage_ai/settings/repo.py +3 -0
- mage_ai/shared/files.py +47 -0
- mage_ai/shared/models.py +1 -0
- mage_ai/streaming/constants.py +1 -0
- mage_ai/streaming/sinks/postgres.py +2 -0
- mage_ai/streaming/sinks/rabbitmq.py +76 -0
- mage_ai/streaming/sinks/sink_factory.py +4 -0
- mage_ai/tests/api/operations/test_operations_with_hooks.py +136 -91
- mage_ai/tests/api/policies/test_oauth_policy.py +38 -0
- mage_ai/tests/data_preparation/models/global_hooks/test_global_hooks.py +33 -8
- mage_ai/tests/data_preparation/models/global_hooks/test_hook.py +82 -38
- mage_ai/tests/data_preparation/models/global_hooks/test_predicates.py +803 -0
- mage_ai/tests/data_preparation/models/global_hooks/test_utils.py +6 -1
- mage_ai/tests/data_preparation/models/test_block.py +26 -0
- mage_ai/tests/data_preparation/models/test_pipeline.py +10 -0
- mage_ai/tests/factory.py +40 -2
- mage_ai/tests/orchestration/test_pipeline_scheduler.py +82 -1
- mage_ai/tests/services/k8s/test_job_manager.py +16 -0
- mage_ai/tests/shared/mixins.py +60 -23
- mage_ai/tests/streaming/sinks/test_rabbitmq.py +36 -0
- {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/METADATA +7 -4
- {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/RECORD +257 -243
- {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/WHEEL +1 -1
- mage_ai/server/frontend_dist/_next/static/9jB4XPuz6BzxBcG9VNao5/_buildManifest.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3943-9e1105393a3be0de.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/4267-fd4d8049e83178de.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5810-12eadc488265d55b.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/595-0d174b1f9fbfce4f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/6333-bc1b433b428a9095.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/722-a1584445357a276c.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/8487-032ef9b17d20aad9.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9264-1d4f0327d42fed91.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9618-2c5045255ac5a6e7.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-ebef928183f9a3bb.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/files-0f2d4be6fdca86ca.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/global-hooks/[...slug]-77edfa32d000e88b.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/global-hooks-e561ae38cf5592e8.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-10e9a2d19541caa2.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c8d3a5289ab93f88.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-ff7e9108502f5716.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-0691711636fa95c7.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-2914e326a5f1ffe0.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-3a7500e6e53084d3.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-c0e551d265a8d467.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-e47db5c3eaf683af.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/profile-55ac955dfa9a5a8d.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-29c92a9bc54ae5cd.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-572d82d6eb7a5d43.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-2d26d80370a2e481.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3943-9e1105393a3be0de.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4267-fd4d8049e83178de.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5810-12eadc488265d55b.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/595-0d174b1f9fbfce4f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6333-bc1b433b428a9095.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/722-a1584445357a276c.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8487-032ef9b17d20aad9.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-1d4f0327d42fed91.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9618-2c5045255ac5a6e7.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-ebef928183f9a3bb.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-0f2d4be6fdca86ca.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks/[...slug]-77edfa32d000e88b.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks-e561ae38cf5592e8.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-10e9a2d19541caa2.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c8d3a5289ab93f88.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-ff7e9108502f5716.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-0691711636fa95c7.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-2914e326a5f1ffe0.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-3a7500e6e53084d3.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-c0e551d265a8d467.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-e47db5c3eaf683af.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-55ac955dfa9a5a8d.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-29c92a9bc54ae5cd.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-572d82d6eb7a5d43.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-2d26d80370a2e481.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/uPDjJYpJMst1q6psbRyte/_buildManifest.js +0 -1
- /mage_ai/server/frontend_dist/_next/static/{9jB4XPuz6BzxBcG9VNao5 → N3FS4bHv0jpYeeg672uYK}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{uPDjJYpJMst1q6psbRyte → aoO6jYZLVlUGCCdY-wmy8}/_ssgManifest.js +0 -0
- {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/LICENSE +0 -0
- {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/top_level.txt +0 -0
|
@@ -8,7 +8,9 @@ from mage_ai.data_integrations.sources.constants import SQL_SOURCES
|
|
|
8
8
|
from mage_ai.data_integrations.utils.config import build_config, get_batch_fetch_limit
|
|
9
9
|
from mage_ai.data_preparation.logging.logger import DictLogger
|
|
10
10
|
from mage_ai.data_preparation.models.block.data_integration.constants import (
|
|
11
|
+
KEY_REPLICATION_METHOD,
|
|
11
12
|
MAX_QUERY_STRING_SIZE,
|
|
13
|
+
REPLICATION_METHOD_INCREMENTAL,
|
|
12
14
|
)
|
|
13
15
|
from mage_ai.data_preparation.models.block.data_integration.utils import (
|
|
14
16
|
convert_block_output_data_for_destination,
|
|
@@ -19,6 +21,7 @@ from mage_ai.data_preparation.models.block.data_integration.utils import (
|
|
|
19
21
|
from mage_ai.data_preparation.models.pipelines.integration_pipeline import (
|
|
20
22
|
IntegrationPipeline,
|
|
21
23
|
)
|
|
24
|
+
from mage_ai.data_preparation.models.triggers import ScheduleInterval
|
|
22
25
|
from mage_ai.orchestration.db import db_connection
|
|
23
26
|
from mage_ai.orchestration.db.models.schedules import BlockRun, PipelineRun
|
|
24
27
|
from mage_ai.orchestration.metrics.pipeline_run import calculate_metrics
|
|
@@ -253,6 +256,7 @@ def build_block_run_metadata(
|
|
|
253
256
|
logging_tags: Dict = None,
|
|
254
257
|
parent_stream: str = None,
|
|
255
258
|
partition: str = None,
|
|
259
|
+
pipeline_run: PipelineRun = None,
|
|
256
260
|
selected_streams: List[str] = None,
|
|
257
261
|
) -> List[Dict]:
|
|
258
262
|
block_run_metadata = []
|
|
@@ -270,9 +274,11 @@ def build_block_run_metadata(
|
|
|
270
274
|
|
|
271
275
|
if block.is_source():
|
|
272
276
|
return __build_block_run_metadata_for_source(
|
|
277
|
+
block,
|
|
273
278
|
data_integration_settings,
|
|
274
279
|
logger,
|
|
275
280
|
logging_tags=logging_tags,
|
|
281
|
+
pipeline_run=pipeline_run,
|
|
276
282
|
selected_streams=selected_streams,
|
|
277
283
|
)
|
|
278
284
|
|
|
@@ -377,9 +383,11 @@ def __build_block_run_metadata_for_destination(
|
|
|
377
383
|
|
|
378
384
|
|
|
379
385
|
def __build_block_run_metadata_for_source(
|
|
386
|
+
block,
|
|
380
387
|
data_integration_settings: Dict,
|
|
381
388
|
logger: DictLogger,
|
|
382
389
|
logging_tags: Dict = None,
|
|
390
|
+
pipeline_run: PipelineRun = None,
|
|
383
391
|
selected_streams: List[str] = None,
|
|
384
392
|
) -> List[Dict]:
|
|
385
393
|
block_run_metadata = []
|
|
@@ -388,20 +396,66 @@ def __build_block_run_metadata_for_source(
|
|
|
388
396
|
config = data_integration_settings.get('config')
|
|
389
397
|
batch_fetch_limit = get_batch_fetch_limit(config)
|
|
390
398
|
|
|
391
|
-
|
|
392
|
-
|
|
399
|
+
stream_dicts_by_stream_id = index_by(
|
|
400
|
+
lambda x: x.get('tap_stream_id') or x.get('stream'),
|
|
401
|
+
get_selected_streams(catalog),
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
streams = []
|
|
405
|
+
|
|
406
|
+
if selected_streams:
|
|
407
|
+
streams = selected_streams
|
|
408
|
+
else:
|
|
409
|
+
streams = list(stream_dicts_by_stream_id.keys())
|
|
410
|
+
|
|
411
|
+
at_least_one_incremental = False
|
|
412
|
+
|
|
413
|
+
for stream_id in streams:
|
|
414
|
+
if at_least_one_incremental:
|
|
415
|
+
break
|
|
416
|
+
|
|
417
|
+
stream_dict = stream_dicts_by_stream_id.get(stream_id)
|
|
418
|
+
if not stream_dict:
|
|
419
|
+
continue
|
|
420
|
+
|
|
421
|
+
if REPLICATION_METHOD_INCREMENTAL == stream_dict.get(KEY_REPLICATION_METHOD):
|
|
422
|
+
at_least_one_incremental = True
|
|
423
|
+
break
|
|
424
|
+
|
|
425
|
+
execution_partition_previous = None
|
|
426
|
+
|
|
427
|
+
if at_least_one_incremental and pipeline_run:
|
|
428
|
+
pipeline_runs_completed = \
|
|
429
|
+
PipelineRun.recently_completed_pipeline_runs(
|
|
430
|
+
pipeline_run.pipeline_uuid,
|
|
431
|
+
pipeline_run_id=pipeline_run.id,
|
|
432
|
+
pipeline_schedule_id=(
|
|
433
|
+
None if
|
|
434
|
+
ScheduleInterval.ONCE == pipeline_run.pipeline_schedule.schedule_interval else
|
|
435
|
+
pipeline_run.pipeline_schedule_id
|
|
436
|
+
),
|
|
437
|
+
sample_size=1,
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
if pipeline_runs_completed:
|
|
441
|
+
execution_partition_previous = pipeline_runs_completed[0].execution_partition
|
|
442
|
+
|
|
393
443
|
data_integration_uuid = data_integration_settings.get('data_integration_uuid')
|
|
394
444
|
|
|
395
445
|
is_sql_source = data_integration_uuid in SQL_SOURCES_UUID
|
|
396
446
|
record_counts_by_stream = {}
|
|
397
447
|
if is_sql_source:
|
|
448
|
+
|
|
398
449
|
record_counts_by_stream = index_by(
|
|
399
450
|
lambda x: x['id'],
|
|
400
451
|
count_records(
|
|
401
452
|
config,
|
|
402
453
|
data_integration_uuid,
|
|
403
454
|
streams,
|
|
455
|
+
block=block,
|
|
404
456
|
catalog=catalog,
|
|
457
|
+
partition=execution_partition_previous,
|
|
458
|
+
variables=pipeline_run.variables if pipeline_run else None,
|
|
405
459
|
),
|
|
406
460
|
)
|
|
407
461
|
|
|
@@ -432,6 +486,7 @@ def __build_block_run_metadata_for_source(
|
|
|
432
486
|
|
|
433
487
|
for idx in range(number_of_batches):
|
|
434
488
|
block_run_metadata.append(dict(
|
|
489
|
+
execution_partition_previous=execution_partition_previous,
|
|
435
490
|
index=idx,
|
|
436
491
|
number_of_batches=number_of_batches,
|
|
437
492
|
stream=tap_stream_id,
|
|
@@ -735,6 +735,14 @@ class BlockExecutor:
|
|
|
735
735
|
except Exception as err:
|
|
736
736
|
print(f'[WARNING] BlockExecutor._execute: {err}')
|
|
737
737
|
|
|
738
|
+
is_source = self.block.is_source()
|
|
739
|
+
if is_source and data_integration_metadata:
|
|
740
|
+
execution_partition_previous = data_integration_metadata.get(
|
|
741
|
+
'execution_partition_previous',
|
|
742
|
+
)
|
|
743
|
+
if execution_partition_previous:
|
|
744
|
+
extra_options['execution_partition_previous'] = execution_partition_previous
|
|
745
|
+
|
|
738
746
|
if di_settings and \
|
|
739
747
|
data_integration_metadata and \
|
|
740
748
|
data_integration_metadata.get('controller') and \
|
|
@@ -746,7 +754,6 @@ class BlockExecutor:
|
|
|
746
754
|
if is_data_integration:
|
|
747
755
|
arr = []
|
|
748
756
|
|
|
749
|
-
is_source = self.block.is_source()
|
|
750
757
|
data_integration_uuid = di_settings.get('data_integration_uuid')
|
|
751
758
|
catalog = di_settings.get('catalog', [])
|
|
752
759
|
|
|
@@ -770,6 +777,7 @@ class BlockExecutor:
|
|
|
770
777
|
logging_tags=logging_tags,
|
|
771
778
|
parent_stream=data_integration_metadata.get('parent_stream'),
|
|
772
779
|
partition=self.execution_partition,
|
|
780
|
+
pipeline_run=pipeline_run,
|
|
773
781
|
selected_streams=[stream],
|
|
774
782
|
)
|
|
775
783
|
for br_metadata in block_run_metadata:
|
|
@@ -23,6 +23,7 @@ from jinja2 import Template
|
|
|
23
23
|
import mage_ai.data_preparation.decorators
|
|
24
24
|
from mage_ai.cache.block import BlockCache
|
|
25
25
|
from mage_ai.data_cleaner.shared.utils import is_geo_dataframe, is_spark_dataframe
|
|
26
|
+
from mage_ai.data_integrations.sources.constants import SQL_SOURCES_MAPPING
|
|
26
27
|
from mage_ai.data_preparation.logging.logger import DictLogger
|
|
27
28
|
from mage_ai.data_preparation.logging.logger_manager_factory import LoggerManagerFactory
|
|
28
29
|
from mage_ai.data_preparation.models.block.data_integration.mixins import (
|
|
@@ -466,11 +467,14 @@ class Block(DataIntegrationMixin, SparkBlock):
|
|
|
466
467
|
uuid = settings.get('source') or settings.get('destination')
|
|
467
468
|
mapping = grouped_templates.get(uuid) or {}
|
|
468
469
|
|
|
470
|
+
di_metadata = merge_dict(
|
|
471
|
+
extract(mapping or {}, ['name']),
|
|
472
|
+
settings,
|
|
473
|
+
)
|
|
474
|
+
di_metadata['sql'] = uuid in SQL_SOURCES_MAPPING
|
|
475
|
+
|
|
469
476
|
return dict(
|
|
470
|
-
data_integration=
|
|
471
|
-
extract(mapping or {}, ['name']),
|
|
472
|
-
settings,
|
|
473
|
-
),
|
|
477
|
+
data_integration=di_metadata,
|
|
474
478
|
)
|
|
475
479
|
elif BlockLanguage.PYTHON == self.language:
|
|
476
480
|
try:
|
|
@@ -482,15 +486,18 @@ class Block(DataIntegrationMixin, SparkBlock):
|
|
|
482
486
|
uuid = di_settings.get('data_integration_uuid')
|
|
483
487
|
mapping = grouped_templates.get(uuid) or {}
|
|
484
488
|
|
|
489
|
+
di_metadata = merge_dict(
|
|
490
|
+
extract(mapping or {}, ['name']),
|
|
491
|
+
ignore_keys(di_settings or {}, [
|
|
492
|
+
'catalog',
|
|
493
|
+
'config',
|
|
494
|
+
'data_integration_uuid',
|
|
495
|
+
]),
|
|
496
|
+
)
|
|
497
|
+
di_metadata['sql'] = uuid in SQL_SOURCES_MAPPING
|
|
498
|
+
|
|
485
499
|
return dict(
|
|
486
|
-
data_integration=
|
|
487
|
-
extract(mapping or {}, ['name']),
|
|
488
|
-
ignore_keys(di_settings or {}, [
|
|
489
|
-
'catalog',
|
|
490
|
-
'config',
|
|
491
|
-
'data_integration_uuid',
|
|
492
|
-
]),
|
|
493
|
-
),
|
|
500
|
+
data_integration=di_metadata,
|
|
494
501
|
)
|
|
495
502
|
except Exception as err:
|
|
496
503
|
if is_debug():
|
|
@@ -991,6 +998,7 @@ class Block(DataIntegrationMixin, SparkBlock):
|
|
|
991
998
|
output_messages_to_logs: bool = False,
|
|
992
999
|
disable_json_serialization: bool = False,
|
|
993
1000
|
data_integration_runtime_settings: Dict = None,
|
|
1001
|
+
execution_partition_previous: str = None,
|
|
994
1002
|
**kwargs,
|
|
995
1003
|
) -> Dict:
|
|
996
1004
|
if logging_tags is None:
|
|
@@ -1044,6 +1052,7 @@ class Block(DataIntegrationMixin, SparkBlock):
|
|
|
1044
1052
|
dynamic_upstream_block_uuids=dynamic_upstream_block_uuids,
|
|
1045
1053
|
run_settings=run_settings,
|
|
1046
1054
|
data_integration_runtime_settings=data_integration_runtime_settings,
|
|
1055
|
+
execution_partition_previous=execution_partition_previous,
|
|
1047
1056
|
**kwargs,
|
|
1048
1057
|
)
|
|
1049
1058
|
|
|
@@ -1223,6 +1232,7 @@ class Block(DataIntegrationMixin, SparkBlock):
|
|
|
1223
1232
|
dynamic_upstream_block_uuids: List[str] = None,
|
|
1224
1233
|
run_settings: Dict = None,
|
|
1225
1234
|
data_integration_runtime_settings: str = None,
|
|
1235
|
+
execution_partition_previous: str = None,
|
|
1226
1236
|
**kwargs,
|
|
1227
1237
|
) -> Dict:
|
|
1228
1238
|
if logging_tags is None:
|
|
@@ -1301,6 +1311,7 @@ class Block(DataIntegrationMixin, SparkBlock):
|
|
|
1301
1311
|
upstream_block_uuids=upstream_block_uuids,
|
|
1302
1312
|
run_settings=run_settings,
|
|
1303
1313
|
data_integration_runtime_settings=data_integration_runtime_settings,
|
|
1314
|
+
execution_partition_previous=execution_partition_previous,
|
|
1304
1315
|
**kwargs,
|
|
1305
1316
|
)
|
|
1306
1317
|
|
|
@@ -1356,6 +1367,7 @@ class Block(DataIntegrationMixin, SparkBlock):
|
|
|
1356
1367
|
upstream_block_uuids: List[str] = None,
|
|
1357
1368
|
run_settings: Dict = None,
|
|
1358
1369
|
data_integration_runtime_settings: str = None,
|
|
1370
|
+
execution_partition_previous: str = None,
|
|
1359
1371
|
**kwargs,
|
|
1360
1372
|
) -> List:
|
|
1361
1373
|
if logging_tags is None:
|
|
@@ -1379,6 +1391,7 @@ class Block(DataIntegrationMixin, SparkBlock):
|
|
|
1379
1391
|
dynamic_block_index=dynamic_block_index,
|
|
1380
1392
|
dynamic_upstream_block_uuids=dynamic_upstream_block_uuids,
|
|
1381
1393
|
execution_partition=execution_partition,
|
|
1394
|
+
execution_partition_previous=execution_partition_previous,
|
|
1382
1395
|
from_notebook=from_notebook,
|
|
1383
1396
|
global_vars=global_vars,
|
|
1384
1397
|
input_vars=input_vars,
|
|
@@ -50,6 +50,7 @@ EXECUTION_PARTITION_FROM_NOTEBOOK = '_from_notebook'
|
|
|
50
50
|
|
|
51
51
|
OUTPUT_TYPE_RECORD = 'RECORD'
|
|
52
52
|
OUTPUT_TYPE_SCHEMA = 'SCHEMA'
|
|
53
|
+
OUTPUT_TYPE_STATE = 'STATE'
|
|
53
54
|
TYPE_OBJECT = 'object'
|
|
54
55
|
|
|
55
56
|
KEY_BOOKMARK_PROPERTIES = 'bookmark_properties'
|
|
@@ -77,6 +78,8 @@ REPLICATION_METHOD_LOG_BASED = 'LOG_BASED'
|
|
|
77
78
|
MB_1 = 1024 * 1000
|
|
78
79
|
MAX_QUERY_STRING_SIZE = 10 * MB_1
|
|
79
80
|
|
|
81
|
+
VARIABLE_BOOKMARK_VALUES_KEY = '__bookmark_values__'
|
|
82
|
+
|
|
80
83
|
|
|
81
84
|
class IngestMode(str, Enum):
|
|
82
85
|
DISK = 'disk'
|
|
@@ -24,6 +24,7 @@ from mage_ai.data_preparation.models.block.data_integration.constants import (
|
|
|
24
24
|
KEY_METADATA,
|
|
25
25
|
KEY_PARTITION_KEYS,
|
|
26
26
|
KEY_PROPERTIES,
|
|
27
|
+
KEY_RECORD,
|
|
27
28
|
KEY_REPLICATION_METHOD,
|
|
28
29
|
KEY_SCHEMA,
|
|
29
30
|
KEY_STREAM,
|
|
@@ -31,10 +32,14 @@ from mage_ai.data_preparation.models.block.data_integration.constants import (
|
|
|
31
32
|
KEY_TYPE,
|
|
32
33
|
KEY_UNIQUE_CONFLICT_METHOD,
|
|
33
34
|
KEY_UNIQUE_CONSTRAINTS,
|
|
35
|
+
KEY_VALUE,
|
|
34
36
|
MAX_QUERY_STRING_SIZE,
|
|
37
|
+
OUTPUT_TYPE_RECORD,
|
|
35
38
|
OUTPUT_TYPE_SCHEMA,
|
|
39
|
+
OUTPUT_TYPE_STATE,
|
|
36
40
|
REPLICATION_METHOD_INCREMENTAL,
|
|
37
41
|
STATE_FILENAME,
|
|
42
|
+
VARIABLE_BOOKMARK_VALUES_KEY,
|
|
38
43
|
IngestMode,
|
|
39
44
|
)
|
|
40
45
|
from mage_ai.data_preparation.models.block.data_integration.data import (
|
|
@@ -48,6 +53,7 @@ from mage_ai.data_preparation.models.constants import (
|
|
|
48
53
|
)
|
|
49
54
|
from mage_ai.data_preparation.models.pipelines.utils import number_string
|
|
50
55
|
from mage_ai.shared.array import find
|
|
56
|
+
from mage_ai.shared.files import reverse_readline
|
|
51
57
|
from mage_ai.shared.hash import dig, extract, merge_dict
|
|
52
58
|
from mage_ai.shared.parsers import encode_complex, extract_json_objects
|
|
53
59
|
from mage_ai.shared.security import filter_out_config_values
|
|
@@ -278,23 +284,82 @@ def get_streams_from_output_directory(
|
|
|
278
284
|
# or
|
|
279
285
|
# ../[block_uuid]/[data_integration_uuid]
|
|
280
286
|
dir_full_path1 = os.path.join(output_directory_path, dir_name1)
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
287
|
+
if os.path.isdir(dir_full_path1):
|
|
288
|
+
for dir_name2 in os.listdir(dir_full_path1):
|
|
289
|
+
if not data_integration_uuid:
|
|
290
|
+
mapping[dir_name2] = []
|
|
291
|
+
# ../[block_uuid]/[data_integration_uuid]/[stream]/00000000000000000000
|
|
292
|
+
# or
|
|
293
|
+
# ../[block_uuid]/[data_integration_uuid]/[stream]
|
|
294
|
+
dir_full_path2 = os.path.join(dir_full_path1, dir_name2)
|
|
295
|
+
if data_integration_uuid:
|
|
296
|
+
mapping[dir_name1].append(dir_full_path2)
|
|
297
|
+
elif os.path.isdir(dir_full_path2):
|
|
298
|
+
for dir_name3 in os.listdir(dir_full_path2):
|
|
299
|
+
dir_full_path3 = os.path.join(dir_full_path2, dir_name3)
|
|
300
|
+
mapping[dir_name2].append(dir_full_path3)
|
|
294
301
|
|
|
295
302
|
return mapping
|
|
296
303
|
|
|
297
304
|
|
|
305
|
+
def get_state_data(
|
|
306
|
+
block,
|
|
307
|
+
catalog: Dict,
|
|
308
|
+
from_notebook: bool = False,
|
|
309
|
+
index: int = None,
|
|
310
|
+
partition: str = None,
|
|
311
|
+
data_integration_uuid: str = None,
|
|
312
|
+
include_record: bool = False,
|
|
313
|
+
stream_id: str = None,
|
|
314
|
+
) -> Union[Dict, Tuple[Dict, Dict]]:
|
|
315
|
+
output_file_paths = get_output_file_paths(
|
|
316
|
+
block,
|
|
317
|
+
catalog,
|
|
318
|
+
from_notebook=from_notebook,
|
|
319
|
+
index=index,
|
|
320
|
+
partition=partition,
|
|
321
|
+
data_integration_uuid=data_integration_uuid,
|
|
322
|
+
stream_id=stream_id,
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
output_file_paths.sort()
|
|
326
|
+
|
|
327
|
+
record = None
|
|
328
|
+
state_data = None
|
|
329
|
+
|
|
330
|
+
if output_file_paths:
|
|
331
|
+
output_file_path = output_file_paths[-1]
|
|
332
|
+
|
|
333
|
+
for line in reverse_readline(output_file_path):
|
|
334
|
+
if line:
|
|
335
|
+
try:
|
|
336
|
+
row = json.loads(line)
|
|
337
|
+
row_type = row.get(KEY_TYPE)
|
|
338
|
+
|
|
339
|
+
if include_record and \
|
|
340
|
+
OUTPUT_TYPE_RECORD == row_type and \
|
|
341
|
+
KEY_RECORD in row and \
|
|
342
|
+
(not stream_id or stream_id == row.get(KEY_STREAM)):
|
|
343
|
+
|
|
344
|
+
record = row[KEY_RECORD]
|
|
345
|
+
elif OUTPUT_TYPE_STATE == row_type and KEY_VALUE in row:
|
|
346
|
+
# If it finds a state again even before it find a record, break.
|
|
347
|
+
if state_data is not None:
|
|
348
|
+
break
|
|
349
|
+
|
|
350
|
+
state_data = row[KEY_VALUE]
|
|
351
|
+
|
|
352
|
+
if not include_record or record:
|
|
353
|
+
break
|
|
354
|
+
except json.JSONDecodeError:
|
|
355
|
+
pass
|
|
356
|
+
|
|
357
|
+
if include_record:
|
|
358
|
+
return state_data, record
|
|
359
|
+
|
|
360
|
+
return state_data
|
|
361
|
+
|
|
362
|
+
|
|
298
363
|
def execute_data_integration(
|
|
299
364
|
block,
|
|
300
365
|
outputs_from_input_vars,
|
|
@@ -303,6 +368,7 @@ def execute_data_integration(
|
|
|
303
368
|
dynamic_block_index: int = None,
|
|
304
369
|
dynamic_upstream_block_uuids: List[str] = None,
|
|
305
370
|
execution_partition: str = None,
|
|
371
|
+
execution_partition_previous: str = None,
|
|
306
372
|
from_notebook: bool = False,
|
|
307
373
|
global_vars: Dict = None,
|
|
308
374
|
input_from_output: Dict = None,
|
|
@@ -382,17 +448,34 @@ def execute_data_integration(
|
|
|
382
448
|
return []
|
|
383
449
|
|
|
384
450
|
# Handle incremental sync
|
|
385
|
-
|
|
451
|
+
state_data = None
|
|
386
452
|
if index is not None:
|
|
387
453
|
batch_fetch_limit = get_batch_fetch_limit(config)
|
|
388
|
-
state_file_path = get_state_file_path(block, data_integration_uuid, stream)
|
|
389
454
|
stream_catalogs = get_streams_from_catalog(catalog, [stream]) or []
|
|
390
455
|
|
|
391
456
|
if len(stream_catalogs) == 1 and \
|
|
392
457
|
REPLICATION_METHOD_INCREMENTAL == stream_catalogs[0].get('replication_method'):
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
458
|
+
|
|
459
|
+
if global_vars_more and VARIABLE_BOOKMARK_VALUES_KEY in global_vars_more:
|
|
460
|
+
bookmark_values_by_block_uuid = global_vars_more.get(
|
|
461
|
+
VARIABLE_BOOKMARK_VALUES_KEY,
|
|
462
|
+
) or {}
|
|
463
|
+
|
|
464
|
+
if bookmark_values_by_block_uuid.get(block.uuid):
|
|
465
|
+
state_data = dict(
|
|
466
|
+
bookmarks=bookmark_values_by_block_uuid.get(block.uuid),
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
if not state_data and execution_partition_previous:
|
|
470
|
+
state_data = get_state_data(
|
|
471
|
+
block,
|
|
472
|
+
catalog,
|
|
473
|
+
data_integration_uuid=data_integration_uuid,
|
|
474
|
+
from_notebook=from_notebook,
|
|
475
|
+
index=index,
|
|
476
|
+
partition=execution_partition_previous,
|
|
477
|
+
stream_id=stream,
|
|
478
|
+
)
|
|
396
479
|
else:
|
|
397
480
|
query_data['_offset'] = batch_fetch_limit * index
|
|
398
481
|
|
|
@@ -436,10 +519,14 @@ def execute_data_integration(
|
|
|
436
519
|
block.get_catalog_file_path(),
|
|
437
520
|
]
|
|
438
521
|
|
|
439
|
-
if
|
|
522
|
+
if state_data:
|
|
440
523
|
args += [
|
|
441
|
-
'--
|
|
442
|
-
|
|
524
|
+
'--state_json',
|
|
525
|
+
simplejson.dumps(
|
|
526
|
+
state_data,
|
|
527
|
+
default=encode_complex,
|
|
528
|
+
ignore_nan=True,
|
|
529
|
+
),
|
|
443
530
|
]
|
|
444
531
|
|
|
445
532
|
if len(selected_streams) >= 1:
|
|
@@ -953,7 +1040,7 @@ def __execute_destination(
|
|
|
953
1040
|
return proc
|
|
954
1041
|
|
|
955
1042
|
|
|
956
|
-
def
|
|
1043
|
+
def get_output_file_paths(
|
|
957
1044
|
block,
|
|
958
1045
|
catalog: Dict,
|
|
959
1046
|
from_notebook: bool = False,
|
|
@@ -961,8 +1048,7 @@ def convert_outputs_to_data(
|
|
|
961
1048
|
partition: str = None,
|
|
962
1049
|
data_integration_uuid: str = None,
|
|
963
1050
|
stream_id: str = None,
|
|
964
|
-
|
|
965
|
-
) -> Dict:
|
|
1051
|
+
) -> List[str]:
|
|
966
1052
|
variable = build_variable(
|
|
967
1053
|
block,
|
|
968
1054
|
data_integration_uuid=data_integration_uuid,
|
|
@@ -987,6 +1073,29 @@ def convert_outputs_to_data(
|
|
|
987
1073
|
output_file_paths.append(output_file_path)
|
|
988
1074
|
output_file_paths.sort()
|
|
989
1075
|
|
|
1076
|
+
return output_file_paths
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
def convert_outputs_to_data(
|
|
1080
|
+
block,
|
|
1081
|
+
catalog: Dict,
|
|
1082
|
+
from_notebook: bool = False,
|
|
1083
|
+
index: int = None,
|
|
1084
|
+
partition: str = None,
|
|
1085
|
+
data_integration_uuid: str = None,
|
|
1086
|
+
stream_id: str = None,
|
|
1087
|
+
sample_count: int = None,
|
|
1088
|
+
) -> Dict:
|
|
1089
|
+
output_file_paths = get_output_file_paths(
|
|
1090
|
+
block,
|
|
1091
|
+
catalog,
|
|
1092
|
+
from_notebook=from_notebook,
|
|
1093
|
+
index=index,
|
|
1094
|
+
partition=partition,
|
|
1095
|
+
data_integration_uuid=data_integration_uuid,
|
|
1096
|
+
stream_id=stream_id,
|
|
1097
|
+
)
|
|
1098
|
+
|
|
990
1099
|
columns_to_select = []
|
|
991
1100
|
rows = []
|
|
992
1101
|
stream_settings = {}
|
|
@@ -1011,19 +1120,20 @@ def convert_outputs_to_data(
|
|
|
1011
1120
|
columns_to_select = [d.get('column') for d in columns]
|
|
1012
1121
|
|
|
1013
1122
|
for output_file_path in output_file_paths:
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1123
|
+
if os.path.exists(output_file_path):
|
|
1124
|
+
with open(output_file_path) as f:
|
|
1125
|
+
for line in f:
|
|
1126
|
+
try:
|
|
1127
|
+
if sample_count is not None and row_count >= sample_count:
|
|
1128
|
+
break
|
|
1129
|
+
|
|
1130
|
+
row = json.loads(line)
|
|
1131
|
+
record = row.get('record')
|
|
1132
|
+
if record and stream_id == row.get('stream'):
|
|
1133
|
+
rows.append([record.get(col) for col in columns_to_select])
|
|
1134
|
+
row_count += 1
|
|
1135
|
+
except json.JSONDecodeError:
|
|
1136
|
+
pass
|
|
1027
1137
|
|
|
1028
1138
|
if sample_count is not None:
|
|
1029
1139
|
rows = rows[:sample_count]
|
|
@@ -1113,8 +1223,12 @@ def count_records(
|
|
|
1113
1223
|
config: Dict,
|
|
1114
1224
|
source_uuid: str,
|
|
1115
1225
|
streams: List[str],
|
|
1226
|
+
block=None,
|
|
1116
1227
|
catalog: Dict = None,
|
|
1117
1228
|
catalog_file_path: str = None,
|
|
1229
|
+
from_notebook: bool = False,
|
|
1230
|
+
partition: str = None,
|
|
1231
|
+
variables: Dict = None,
|
|
1118
1232
|
) -> List[Dict]:
|
|
1119
1233
|
arr = []
|
|
1120
1234
|
|
|
@@ -1152,6 +1266,51 @@ def count_records(
|
|
|
1152
1266
|
catalog_file_path,
|
|
1153
1267
|
]
|
|
1154
1268
|
|
|
1269
|
+
state_data = None
|
|
1270
|
+
# Make sure replication method is INCREMENTAL
|
|
1271
|
+
if block:
|
|
1272
|
+
stream_dicts = catalog.get('streams')
|
|
1273
|
+
if stream_dicts:
|
|
1274
|
+
stream_dict = find(lambda x, stream=stream: x['stream'] == stream, stream_dicts)
|
|
1275
|
+
if not stream_dict:
|
|
1276
|
+
raise Exception(
|
|
1277
|
+
f'No stream settings found for stream {stream} in source {source_uuid}, '
|
|
1278
|
+
'this is unexpected.',
|
|
1279
|
+
)
|
|
1280
|
+
|
|
1281
|
+
if stream_dict and \
|
|
1282
|
+
REPLICATION_METHOD_INCREMENTAL == stream_dict.get(KEY_REPLICATION_METHOD):
|
|
1283
|
+
|
|
1284
|
+
if variables and VARIABLE_BOOKMARK_VALUES_KEY in variables:
|
|
1285
|
+
bookmark_values_by_block_uuid = variables.get(
|
|
1286
|
+
VARIABLE_BOOKMARK_VALUES_KEY,
|
|
1287
|
+
) or {}
|
|
1288
|
+
|
|
1289
|
+
if bookmark_values_by_block_uuid.get(block.uuid):
|
|
1290
|
+
state_data = dict(
|
|
1291
|
+
bookmarks=bookmark_values_by_block_uuid.get(block.uuid),
|
|
1292
|
+
)
|
|
1293
|
+
|
|
1294
|
+
if not state_data:
|
|
1295
|
+
state_data = get_state_data(
|
|
1296
|
+
block,
|
|
1297
|
+
catalog,
|
|
1298
|
+
data_integration_uuid=source_uuid,
|
|
1299
|
+
from_notebook=from_notebook,
|
|
1300
|
+
partition=partition,
|
|
1301
|
+
stream_id=stream,
|
|
1302
|
+
)
|
|
1303
|
+
|
|
1304
|
+
if state_data:
|
|
1305
|
+
args += [
|
|
1306
|
+
'--state_json',
|
|
1307
|
+
simplejson.dumps(
|
|
1308
|
+
state_data,
|
|
1309
|
+
default=encode_complex,
|
|
1310
|
+
ignore_nan=True,
|
|
1311
|
+
),
|
|
1312
|
+
]
|
|
1313
|
+
|
|
1155
1314
|
arr += json.loads(__run_in_subprocess(args, config=config))
|
|
1156
1315
|
|
|
1157
1316
|
return arr
|
|
@@ -10,9 +10,12 @@ from mage_ai.data_preparation.models.block.sql.constants import (
|
|
|
10
10
|
CONFIG_KEY_UPSTREAM_BLOCK_CONFIGURATION_TABLE_NAME,
|
|
11
11
|
)
|
|
12
12
|
from mage_ai.data_preparation.models.constants import BlockLanguage, BlockType
|
|
13
|
+
from mage_ai.data_preparation.shared.utils import get_template_vars
|
|
14
|
+
from mage_ai.data_preparation.templates.utils import get_variable_for_template
|
|
13
15
|
from mage_ai.data_preparation.variable_manager import get_variable
|
|
14
16
|
from mage_ai.io.config import ConfigFileLoader
|
|
15
17
|
from mage_ai.settings.repo import get_repo_path
|
|
18
|
+
from mage_ai.shared.hash import merge_dict
|
|
16
19
|
|
|
17
20
|
MAGE_SEMI_COLON = '__MAGE_SEMI_COLON__'
|
|
18
21
|
|
|
@@ -228,7 +231,21 @@ def interpolate_input(
|
|
|
228
231
|
def interpolate_vars(query, global_vars=None):
|
|
229
232
|
if global_vars is None:
|
|
230
233
|
global_vars = dict()
|
|
231
|
-
|
|
234
|
+
|
|
235
|
+
return Template(
|
|
236
|
+
query,
|
|
237
|
+
undefined=StrictUndefined,
|
|
238
|
+
).render(
|
|
239
|
+
variables=lambda x, p=None, v=global_vars: get_variable_for_template(
|
|
240
|
+
x,
|
|
241
|
+
parse=p,
|
|
242
|
+
variables=v,
|
|
243
|
+
),
|
|
244
|
+
**merge_dict(
|
|
245
|
+
global_vars,
|
|
246
|
+
get_template_vars(),
|
|
247
|
+
),
|
|
248
|
+
)
|
|
232
249
|
|
|
233
250
|
|
|
234
251
|
def table_name_parts(
|