mage-ai 0.9.32__py3-none-any.whl → 0.9.34__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.
Potentially problematic release.
This version of mage-ai might be problematic. Click here for more details.
- mage_ai/api/constants.py +37 -2
- mage_ai/api/errors.py +9 -5
- mage_ai/api/middleware.py +2 -2
- mage_ai/api/mixins/__init__.py +0 -0
- mage_ai/api/mixins/result_set.py +65 -0
- mage_ai/api/operations/base.py +41 -11
- mage_ai/api/operations/constants.py +7 -6
- mage_ai/api/parsers/BaseParser.py +6 -4
- mage_ai/api/parsers/PipelineScheduleParser.py +36 -2
- mage_ai/api/policies/BackfillPolicy.py +1 -0
- mage_ai/api/policies/BasePolicy.py +229 -40
- mage_ai/api/policies/PermissionPolicy.py +17 -0
- mage_ai/api/policies/PipelineSchedulePolicy.py +18 -2
- mage_ai/api/policies/RolePermissionPolicy.py +2 -1
- mage_ai/api/policies/RolePolicy.py +3 -0
- mage_ai/api/policies/SessionPolicy.py +36 -1
- mage_ai/api/policies/StatusPolicy.py +46 -3
- mage_ai/api/policies/UserPolicy.py +25 -2
- mage_ai/api/policies/mixins/__init__.py +0 -0
- mage_ai/api/policies/mixins/user_permissions.py +241 -0
- mage_ai/api/presenters/PermissionPresenter.py +35 -8
- mage_ai/api/presenters/RolePresenter.py +29 -12
- mage_ai/api/presenters/StatusPresenter.py +11 -0
- mage_ai/api/presenters/UserPresenter.py +21 -24
- mage_ai/api/resources/BaseResource.py +24 -9
- mage_ai/api/resources/BlockResource.py +3 -2
- mage_ai/api/resources/DatabaseResource.py +2 -2
- mage_ai/api/resources/PermissionResource.py +65 -3
- mage_ai/api/resources/Resource.py +8 -1
- mage_ai/api/resources/RolePermissionResource.py +23 -0
- mage_ai/api/resources/RoleResource.py +75 -4
- mage_ai/api/resources/StatusResource.py +34 -0
- mage_ai/api/resources/UserResource.py +35 -4
- mage_ai/api/result_set.py +8 -1
- mage_ai/authentication/permissions/constants.py +78 -0
- mage_ai/data_integrations/destinations/constants.py +1 -0
- mage_ai/data_integrations/utils/config.py +9 -0
- mage_ai/data_integrations/utils/scheduler.py +16 -7
- mage_ai/data_preparation/models/block/__init__.py +56 -16
- mage_ai/data_preparation/models/block/data_integration/mixins.py +92 -1
- mage_ai/data_preparation/models/block/data_integration/utils.py +5 -5
- mage_ai/data_preparation/models/block/integration/__init__.py +12 -7
- mage_ai/data_preparation/models/block/sql/__init__.py +5 -2
- mage_ai/data_preparation/models/block/sql/utils/shared.py +15 -1
- mage_ai/data_preparation/models/pipelines/interactions.py +15 -0
- mage_ai/data_preparation/shared/secrets.py +7 -17
- mage_ai/data_preparation/templates/data_exporters/streaming/google_cloud_pubsub.yaml +5 -0
- mage_ai/data_preparation/templates/repo/metadata.yaml +5 -0
- mage_ai/io/druid.py +9 -5
- mage_ai/io/mssql.py +52 -30
- mage_ai/io/postgres.py +1 -0
- mage_ai/io/sql.py +15 -1
- mage_ai/orchestration/db/models/oauth.py +181 -17
- mage_ai/orchestration/db/models/schedules.py +11 -0
- mage_ai/presenters/interactions/constants.py +1 -0
- mage_ai/presenters/pages/loaders/pipeline_schedules.py +9 -3
- mage_ai/server/api/base.py +16 -6
- mage_ai/server/api/v1.py +2 -1
- mage_ai/server/constants.py +1 -1
- mage_ai/server/frontend_dist/404.html +2 -2
- mage_ai/server/frontend_dist/_next/static/PBVuphyo_muEAj347ZP_b/_buildManifest.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/1124-d8fc76201b83b376.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{1749-9ec0f4709f5a9284.js → 1749-a6bdce4ee8a09bce.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/1769-613e23e361eb5bce.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/1821-953efd0da290d25f.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/2327-1a797c758f8b064a.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/2677-a85c5a72bb695304.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/3419-6c8ec8db8c398c12.js → frontend_dist/_next/static/chunks/3419-0df6c5ef72f2e672.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3684-e1a713b7c16f0151.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/3859-3501cdba0a33f9f2.js → frontend_dist/_next/static/chunks/3859-ba594d21a1260cd2.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/4636-84f545d1d238df13.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/4839-963da65cea58054f.js → frontend_dist/_next/static/chunks/4839-e5fe343a369734bc.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5457-97433bc45b42a88a.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/5499-63667ad5a785dba5.js → frontend_dist/_next/static/chunks/5499-b74459f6be5f9229.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/6043-6ea109833b88eb1d.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/6333-ca4cd6a73a597a40.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/7022-80d082a1d7fd1234.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/7361-25f211ef377e5958.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/8013-1d6b1f7c13264cb4.js → frontend_dist/_next/static/chunks/8013-e67c71ddea072a20.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/8146-941c5155c3bfcc35.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/9161-837b653aa849a76f.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/9264-5730e4e059db40a8.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-752d991f239a128f.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{block-layout-a624972d126a3dbd.js → block-layout-a27a28d2a615e364.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/files-98e27a4d7bd0da47.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/{[...slug]-a95787fe1695f493.js → [...slug]-9eb5dad57da13efd.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{global-data-products-0d55711df91a78d0.js → global-data-products-26909dec66f00231.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/settings-b9eea6abc676ca81.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-11c601c6ef07fe86.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/new-ae6083077c9c1c41.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-bfce0ee677d57206.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-476c921d62f565fc.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/overview-9bc34ef66d84330a.js → frontend_dist/_next/static/chunks/pages/overview-2ec6b17e45a52be8.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipeline-runs-605918f3a5c1aac4.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-84ec3ab0770bcd68.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ee65a62ed166bd85.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-2402004a19a6ad53.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-9a5b4768a640cd68.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-8781db69f19759a1.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-d7fd4857579e2b00.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-bd4bd009146bab36.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-234007c99efdccf6.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-8405a83adeaa8ff5.js → block-runs-da7510d4b277e47b.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runtime-98aa0840a00cc661.js → block-runtime-eae853ff34b09481.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{monitors-0fb48e1cc51f78b2.js → monitors-a057b17847b82468.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/{[run]-845c1f010d5ec380.js → [run]-99d11c86f8b15369.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-9255f85760e1f57a.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-3f0980d8810a540b.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{settings-187ac359020704e1.js → settings-9edf75d03460aaeb.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-c52d0c49439ec620.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-e7692e54979f037d.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-7b3b57523b226a0e.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-cb6a3bcaf4fa1a81.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-5eff96c149584e87.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{pipelines-efc080913a247e99.js → pipelines-270b912e1ac189b5.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/profile-2058d022972cdea4.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/[...slug]-1a95628ea8d0d846.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions-cb1cdf5f8e5bf9c5.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-58978256db4efbda.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles/[...slug]-9ddd7eb842d5a911.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles-1694c5eb1acbcf30.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-6850e854fbedbb61.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/[...slug]-5061c073e1c0de07.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-f551c5665bfd3494.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-6fe3657070f98aca.js → frontend_dist/_next/static/chunks/pages/sign-in-e779dbab123e626e.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/templates/[...slug]-935113d252ada806.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/templates-25b6d24cfa81c306.js → frontend_dist/_next/static/chunks/pages/templates-7079d637e396f2a8.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/terminal-67fdb4a3be93aa14.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-9c0374c7c783b34a.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-ea3a0d48e5822b42.js +1 -0
- mage_ai/server/frontend_dist/block-layout.html +2 -2
- mage_ai/server/frontend_dist/files.html +2 -2
- mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-data-products.html +2 -2
- mage_ai/server/frontend_dist/index.html +2 -2
- mage_ai/server/frontend_dist/manage/settings.html +2 -2
- mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist/manage/users.html +2 -2
- mage_ai/server/frontend_dist/manage.html +2 -2
- mage_ai/server/frontend_dist/overview.html +2 -2
- mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist/pipelines.html +2 -2
- mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +24 -0
- mage_ai/server/frontend_dist/settings/workspace/permissions.html +24 -0
- mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +24 -0
- mage_ai/server/frontend_dist/settings/workspace/roles.html +24 -0
- mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +24 -0
- mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist/settings.html +2 -2
- mage_ai/server/frontend_dist/sign-in.html +5 -5
- mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist/templates.html +2 -2
- mage_ai/server/frontend_dist/terminal.html +2 -2
- mage_ai/server/frontend_dist/test.html +2 -2
- mage_ai/server/frontend_dist/triggers.html +2 -2
- mage_ai/server/frontend_dist/version-control.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/_next/static/L-IKw5_bRZUs-wyjnpN_j/_buildManifest.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1124-d8fc76201b83b376.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1749-9ec0f4709f5a9284.js → 1749-a6bdce4ee8a09bce.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1769-613e23e361eb5bce.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1821-953efd0da290d25f.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2327-1a797c758f8b064a.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2677-a85c5a72bb695304.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/3419-6c8ec8db8c398c12.js → frontend_dist_base_path_template/_next/static/chunks/3419-0df6c5ef72f2e672.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3684-e1a713b7c16f0151.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/3859-3501cdba0a33f9f2.js → frontend_dist_base_path_template/_next/static/chunks/3859-ba594d21a1260cd2.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4636-84f545d1d238df13.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/4839-963da65cea58054f.js → frontend_dist_base_path_template/_next/static/chunks/4839-e5fe343a369734bc.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5457-97433bc45b42a88a.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/5499-63667ad5a785dba5.js → frontend_dist_base_path_template/_next/static/chunks/5499-b74459f6be5f9229.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6043-6ea109833b88eb1d.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6333-ca4cd6a73a597a40.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7022-80d082a1d7fd1234.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-25f211ef377e5958.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/8013-1d6b1f7c13264cb4.js → frontend_dist_base_path_template/_next/static/chunks/8013-e67c71ddea072a20.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8146-941c5155c3bfcc35.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9161-837b653aa849a76f.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-5730e4e059db40a8.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-752d991f239a128f.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{block-layout-a624972d126a3dbd.js → block-layout-a27a28d2a615e364.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-98e27a4d7bd0da47.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/{[...slug]-a95787fe1695f493.js → [...slug]-9eb5dad57da13efd.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{global-data-products-0d55711df91a78d0.js → global-data-products-26909dec66f00231.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/settings-b9eea6abc676ca81.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-11c601c6ef07fe86.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/new-ae6083077c9c1c41.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-bfce0ee677d57206.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-476c921d62f565fc.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/overview-9bc34ef66d84330a.js → frontend_dist_base_path_template/_next/static/chunks/pages/overview-2ec6b17e45a52be8.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-605918f3a5c1aac4.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-84ec3ab0770bcd68.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ee65a62ed166bd85.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-2402004a19a6ad53.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-9a5b4768a640cd68.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-8781db69f19759a1.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-d7fd4857579e2b00.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-bd4bd009146bab36.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-234007c99efdccf6.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-8405a83adeaa8ff5.js → block-runs-da7510d4b277e47b.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runtime-98aa0840a00cc661.js → block-runtime-eae853ff34b09481.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{monitors-0fb48e1cc51f78b2.js → monitors-a057b17847b82468.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/{[run]-845c1f010d5ec380.js → [run]-99d11c86f8b15369.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-9255f85760e1f57a.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-3f0980d8810a540b.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{settings-187ac359020704e1.js → settings-9edf75d03460aaeb.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-c52d0c49439ec620.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-e7692e54979f037d.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-7b3b57523b226a0e.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-cb6a3bcaf4fa1a81.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-5eff96c149584e87.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{pipelines-efc080913a247e99.js → pipelines-270b912e1ac189b5.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-2058d022972cdea4.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/[...slug]-1a95628ea8d0d846.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions-cb1cdf5f8e5bf9c5.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-58978256db4efbda.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles/[...slug]-9ddd7eb842d5a911.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles-1694c5eb1acbcf30.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-6850e854fbedbb61.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/[...slug]-5061c073e1c0de07.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-f551c5665bfd3494.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/sign-in-6fe3657070f98aca.js → frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-e779dbab123e626e.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/templates/[...slug]-935113d252ada806.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/templates-25b6d24cfa81c306.js → frontend_dist_base_path_template/_next/static/chunks/pages/templates-7079d637e396f2a8.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/terminal-67fdb4a3be93aa14.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-9c0374c7c783b34a.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-ea3a0d48e5822b42.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
- 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/index.html +2 -2
- 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/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 +24 -0
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +24 -0
- 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 +24 -0
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +24 -0
- 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 +24 -0
- 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 +13 -13
- 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 +4 -4
- 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 +37 -2
- mage_ai/services/aws/__init__.py +19 -8
- mage_ai/services/spark/config.py +5 -1
- mage_ai/services/spark/spark.py +5 -4
- mage_ai/settings/__init__.py +2 -0
- mage_ai/streaming/constants.py +1 -0
- mage_ai/streaming/sinks/google_cloud_pubsub.py +66 -0
- mage_ai/streaming/sinks/sink_factory.py +6 -0
- mage_ai/tests/api/operations/test_operations.py +8 -2
- mage_ai/tests/api/operations/test_pipeline_schedules.py +3 -0
- mage_ai/tests/data_preparation/models/block/sql/utils/test_shared.py +130 -5
- mage_ai/tests/factory.py +2 -0
- mage_ai/tests/orchestration/test_pipeline_scheduler.py +20 -3
- mage_ai/tests/streaming/sinks/test_google_cloud_pubsub.py +28 -0
- mage_ai/usage_statistics/logger.py +4 -1
- {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/METADATA +1 -1
- {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/RECORD +302 -268
- mage_ai/api/policies/utils.py +0 -14
- mage_ai/server/frontend_dist/_next/static/cbN7L4Ms6UUPoANozEh9w/_buildManifest.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/1769-e2efd4df8d09481f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2327-2d8a1555605cf4af.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2369-cb9cd97052e18d27.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2677-aea54e655c4a727f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5457-994e1044953f1425.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5597-c034402ee26af3b4.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/6333-d1f8db4e7d9656a5.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/6648-9bd31397f1d1b551.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9161-0101571a3635a938.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9264-7c4fcfed1200046a.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9696-3e8ab7786f0e3a0e.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-976b488b8aea327f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/files-1a6c6654bfc953ac.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/settings-49004d918b04c866.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-97177740fbb6eb9f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/new-5b6411c9eb8c4ba4.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-0a7a746cc0998608.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-606012a580245001.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipeline-runs-0801de3c9a2976ea.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-0a5865d4cf012127.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-87b1a0601c4236cd.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-77ffaa2d721a0a4e.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/profile-4e72d40881ac0605.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-8da8f8e2fdb1c99f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-be029347e99fcea2.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-d4b07df78b3d6037.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/templates/[...slug]-87c492e9edc6064e.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/terminal-2ab9f3d0c50cce81.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-0ba40243a030ddf4.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-28a3a43d65074394.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1769-e2efd4df8d09481f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2327-2d8a1555605cf4af.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2369-cb9cd97052e18d27.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2677-aea54e655c4a727f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5457-994e1044953f1425.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5597-c034402ee26af3b4.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6333-d1f8db4e7d9656a5.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6648-9bd31397f1d1b551.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9161-0101571a3635a938.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-7c4fcfed1200046a.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9696-3e8ab7786f0e3a0e.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-976b488b8aea327f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-1a6c6654bfc953ac.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/settings-49004d918b04c866.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-97177740fbb6eb9f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/new-5b6411c9eb8c4ba4.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-0a7a746cc0998608.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-606012a580245001.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-0801de3c9a2976ea.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-0a5865d4cf012127.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-87b1a0601c4236cd.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-77ffaa2d721a0a4e.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-4e72d40881ac0605.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-8da8f8e2fdb1c99f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-be029347e99fcea2.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-d4b07df78b3d6037.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/templates/[...slug]-87c492e9edc6064e.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/terminal-2ab9f3d0c50cce81.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-0ba40243a030ddf4.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-28a3a43d65074394.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/o_Yc57jh8Te2SI-VoipGQ/_buildManifest.js +0 -1
- /mage_ai/server/frontend_dist/_next/static/{cbN7L4Ms6UUPoANozEh9w → PBVuphyo_muEAj347ZP_b}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{o_Yc57jh8Te2SI-VoipGQ → L-IKw5_bRZUs-wyjnpN_j}/_ssgManifest.js +0 -0
- {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/LICENSE +0 -0
- {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/WHEEL +0 -0
- {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/top_level.txt +0 -0
|
@@ -551,6 +551,7 @@ class Block(DataIntegrationMixin):
|
|
|
551
551
|
from mage_ai.data_preparation.models.block.sql.utils.shared import (
|
|
552
552
|
extract_create_statement_table_name,
|
|
553
553
|
extract_insert_statement_table_names,
|
|
554
|
+
extract_update_statement_table_names,
|
|
554
555
|
)
|
|
555
556
|
|
|
556
557
|
if not self.content:
|
|
@@ -561,6 +562,9 @@ class Block(DataIntegrationMixin):
|
|
|
561
562
|
return table_name
|
|
562
563
|
|
|
563
564
|
matches = extract_insert_statement_table_names(self.content)
|
|
565
|
+
if len(matches) == 0:
|
|
566
|
+
matches = extract_update_statement_table_names(self.content)
|
|
567
|
+
|
|
564
568
|
if len(matches) == 0:
|
|
565
569
|
return None
|
|
566
570
|
|
|
@@ -1036,7 +1040,7 @@ class Block(DataIntegrationMixin):
|
|
|
1036
1040
|
variable_mapping,
|
|
1037
1041
|
execution_partition=execution_partition,
|
|
1038
1042
|
override_outputs=True,
|
|
1039
|
-
spark=(global_vars
|
|
1043
|
+
spark=self.__get_spark_session_from_global_vars(global_vars=global_vars),
|
|
1040
1044
|
dynamic_block_uuid=dynamic_block_uuid,
|
|
1041
1045
|
)
|
|
1042
1046
|
except ValueError as e:
|
|
@@ -1612,6 +1616,34 @@ class Block(DataIntegrationMixin):
|
|
|
1612
1616
|
variable_uuid=variable_uuid,
|
|
1613
1617
|
)
|
|
1614
1618
|
|
|
1619
|
+
def get_raw_outputs(
|
|
1620
|
+
self,
|
|
1621
|
+
block_uuid: str,
|
|
1622
|
+
execution_partition: str = None,
|
|
1623
|
+
from_notebook: bool = False,
|
|
1624
|
+
global_vars: Dict = None,
|
|
1625
|
+
) -> List[Any]:
|
|
1626
|
+
all_variables = self.get_variables_by_block(
|
|
1627
|
+
block_uuid=block_uuid,
|
|
1628
|
+
partition=execution_partition,
|
|
1629
|
+
)
|
|
1630
|
+
|
|
1631
|
+
outputs = []
|
|
1632
|
+
|
|
1633
|
+
for variable_uuid in all_variables:
|
|
1634
|
+
variable = self.pipeline.get_block_variable(
|
|
1635
|
+
block_uuid,
|
|
1636
|
+
variable_uuid,
|
|
1637
|
+
from_notebook=from_notebook,
|
|
1638
|
+
global_vars=global_vars,
|
|
1639
|
+
partition=execution_partition,
|
|
1640
|
+
raise_exception=True,
|
|
1641
|
+
spark=self.__get_spark_session_from_global_vars(global_vars),
|
|
1642
|
+
)
|
|
1643
|
+
outputs.append(variable)
|
|
1644
|
+
|
|
1645
|
+
return outputs
|
|
1646
|
+
|
|
1615
1647
|
def get_outputs(
|
|
1616
1648
|
self,
|
|
1617
1649
|
execution_partition: str = None,
|
|
@@ -2237,21 +2269,12 @@ df = get_variable('{self.pipeline.uuid}', '{block_uuid}', 'df')
|
|
|
2237
2269
|
if not test_functions or len(test_functions) == 0:
|
|
2238
2270
|
return
|
|
2239
2271
|
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
partition=execution_partition,
|
|
2247
|
-
spark=(global_vars or dict()).get('spark'),
|
|
2248
|
-
)
|
|
2249
|
-
for variable in self.output_variables(
|
|
2250
|
-
execution_partition=execution_partition,
|
|
2251
|
-
from_notebook=from_notebook,
|
|
2252
|
-
global_vars=global_vars,
|
|
2253
|
-
)
|
|
2254
|
-
]
|
|
2272
|
+
outputs = self.get_raw_outputs(
|
|
2273
|
+
dynamic_block_uuid or self.uuid,
|
|
2274
|
+
execution_partition=execution_partition,
|
|
2275
|
+
from_notebook=from_notebook,
|
|
2276
|
+
global_vars=global_vars,
|
|
2277
|
+
)
|
|
2255
2278
|
|
|
2256
2279
|
if logger and 'logger' not in global_vars:
|
|
2257
2280
|
global_vars['logger'] = logger
|
|
@@ -2468,6 +2491,23 @@ df = get_variable('{self.pipeline.uuid}', '{block_uuid}', 'df')
|
|
|
2468
2491
|
self.spark_init = True
|
|
2469
2492
|
return self.spark
|
|
2470
2493
|
|
|
2494
|
+
def __get_spark_session_from_global_vars(self, global_vars: Dict = None):
|
|
2495
|
+
if global_vars is None:
|
|
2496
|
+
global_vars = dict()
|
|
2497
|
+
spark = global_vars.get('spark')
|
|
2498
|
+
if self.pipeline and self.pipeline.spark_config:
|
|
2499
|
+
spark_config = self.pipeline.spark_config
|
|
2500
|
+
else:
|
|
2501
|
+
repo_config = RepoConfig(repo_path=self.repo_path)
|
|
2502
|
+
spark_config = repo_config.spark_config
|
|
2503
|
+
if not spark_config:
|
|
2504
|
+
return spark
|
|
2505
|
+
spark_config = SparkConfig.load(config=spark_config)
|
|
2506
|
+
if spark_config.use_custom_session:
|
|
2507
|
+
return global_vars.get('context', dict()).get(
|
|
2508
|
+
spark_config.custom_session_var_name, spark)
|
|
2509
|
+
return spark
|
|
2510
|
+
|
|
2471
2511
|
def __store_variables_prepare(
|
|
2472
2512
|
self,
|
|
2473
2513
|
variable_mapping: Dict,
|
|
@@ -53,6 +53,12 @@ class DataIntegrationMixin:
|
|
|
53
53
|
|
|
54
54
|
@property
|
|
55
55
|
def inputs_only_uuids(self) -> List[str]:
|
|
56
|
+
"""
|
|
57
|
+
Get a list of UUIDs of input streams that are marked as 'input_only'.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
List[str]: List of UUIDs.
|
|
61
|
+
"""
|
|
56
62
|
arr = []
|
|
57
63
|
|
|
58
64
|
for stream_id, settings in self.data_integration_inputs.items():
|
|
@@ -63,6 +69,12 @@ class DataIntegrationMixin:
|
|
|
63
69
|
|
|
64
70
|
@property
|
|
65
71
|
def data_integration_inputs(self) -> Dict:
|
|
72
|
+
"""
|
|
73
|
+
Get the data integration inputs configuration for this block.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Dict: Data integration inputs configuration.
|
|
77
|
+
"""
|
|
66
78
|
mapping = {}
|
|
67
79
|
|
|
68
80
|
if self.configuration_data_integration:
|
|
@@ -77,6 +89,12 @@ class DataIntegrationMixin:
|
|
|
77
89
|
|
|
78
90
|
@property
|
|
79
91
|
def uuids_for_inputs(self) -> List[str]:
|
|
92
|
+
"""
|
|
93
|
+
Get a list of UUIDs associated with data integration inputs.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
List[str]: List of UUIDs.
|
|
97
|
+
"""
|
|
80
98
|
arr = []
|
|
81
99
|
|
|
82
100
|
for stream_id, settings in self.data_integration_inputs.items():
|
|
@@ -87,12 +105,27 @@ class DataIntegrationMixin:
|
|
|
87
105
|
|
|
88
106
|
@property
|
|
89
107
|
def upstream_block_uuids_for_inputs(self) -> List[str]:
|
|
108
|
+
"""
|
|
109
|
+
Get a list of upstream block UUIDs associated with data integration inputs.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
List[str]: List of upstream block UUIDs.
|
|
113
|
+
"""
|
|
90
114
|
if self.configuration_data_integration:
|
|
91
115
|
inputs_combined = self.uuids_for_inputs + self.inputs_only_uuids
|
|
92
116
|
|
|
93
117
|
return [up_uuid for up_uuid in self.upstream_block_uuids if up_uuid in inputs_combined]
|
|
94
118
|
|
|
95
119
|
def get_block_data_integration_settings_directory_path(self, block_uuid: str = None) -> str:
|
|
120
|
+
"""
|
|
121
|
+
Get the directory path for storing data integration settings associated with a block.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
block_uuid (str, optional): UUID of the block. Defaults to None.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
str: Directory path for data integration settings.
|
|
128
|
+
"""
|
|
96
129
|
if not self.pipeline:
|
|
97
130
|
return
|
|
98
131
|
|
|
@@ -104,12 +137,27 @@ class DataIntegrationMixin:
|
|
|
104
137
|
)
|
|
105
138
|
|
|
106
139
|
def get_catalog_file_path(self, block_uuid: str = None) -> str:
|
|
140
|
+
"""
|
|
141
|
+
Get the file path for the data integration catalog file associated with a block.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
block_uuid (str, optional): UUID of the block. Defaults to None.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
str: File path for the catalog file.
|
|
148
|
+
"""
|
|
107
149
|
return os.path.join(
|
|
108
150
|
self.get_block_data_integration_settings_directory_path(block_uuid),
|
|
109
151
|
BLOCK_CATALOG_FILENAME,
|
|
110
152
|
)
|
|
111
153
|
|
|
112
154
|
def get_catalog_from_file(self) -> Dict:
|
|
155
|
+
"""
|
|
156
|
+
Read and return the data integration catalog from a file.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Dict: Data integration catalog.
|
|
160
|
+
"""
|
|
113
161
|
catalog_full_path = self.get_catalog_file_path()
|
|
114
162
|
|
|
115
163
|
if os.path.exists(catalog_full_path):
|
|
@@ -122,6 +170,12 @@ class DataIntegrationMixin:
|
|
|
122
170
|
return
|
|
123
171
|
|
|
124
172
|
async def get_catalog_from_file_async(self) -> Dict:
|
|
173
|
+
"""
|
|
174
|
+
Asynchronously read and return the data integration catalog from a file.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Dict: Data integration catalog.
|
|
178
|
+
"""
|
|
125
179
|
catalog_full_path = self.get_catalog_file_path()
|
|
126
180
|
|
|
127
181
|
if os.path.exists(catalog_full_path):
|
|
@@ -133,7 +187,13 @@ class DataIntegrationMixin:
|
|
|
133
187
|
except json.decoder.JSONDecodeError:
|
|
134
188
|
return
|
|
135
189
|
|
|
136
|
-
def update_catalog_file(self, catalog: Dict = None) ->
|
|
190
|
+
def update_catalog_file(self, catalog: Dict = None) -> None:
|
|
191
|
+
"""
|
|
192
|
+
Update the data integration catalog file with the provided catalog.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
catalog (Dict, optional): Data integration catalog to be saved. Defaults to None.
|
|
196
|
+
"""
|
|
137
197
|
catalog_full_path = self.get_catalog_file_path()
|
|
138
198
|
|
|
139
199
|
os.makedirs(os.path.dirname(catalog_full_path), exist_ok=True)
|
|
@@ -143,6 +203,13 @@ class DataIntegrationMixin:
|
|
|
143
203
|
f.write(json.dumps(catalog))
|
|
144
204
|
|
|
145
205
|
def is_data_integration(self) -> bool:
|
|
206
|
+
"""
|
|
207
|
+
Check if the block is a data integration block.
|
|
208
|
+
If the data_integration_in_batch_pipeline feature is not enabled, return False.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
bool: True if it's a data integration block, False otherwise.
|
|
212
|
+
"""
|
|
146
213
|
if not self.pipeline or not \
|
|
147
214
|
Project(self.pipeline.repo_config).is_feature_enabled(
|
|
148
215
|
FeatureUUID.DATA_INTEGRATION_IN_BATCH_PIPELINE,
|
|
@@ -185,6 +252,30 @@ class DataIntegrationMixin:
|
|
|
185
252
|
partition: str = None,
|
|
186
253
|
**kwargs,
|
|
187
254
|
) -> Dict:
|
|
255
|
+
"""
|
|
256
|
+
Retrieve data integration settings for the current block.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
data_integration_uuid_only (bool, optional): If True, retrieve only the data integration
|
|
260
|
+
UUID. Defaults to False.
|
|
261
|
+
dynamic_block_index (Union[int, None], optional): The index of the dynamic block, if
|
|
262
|
+
applicable. Defaults to None.
|
|
263
|
+
dynamic_upstream_block_uuids (Union[List[str], None], optional): List of upstream block
|
|
264
|
+
UUIDs, if applicable. Defaults to None.
|
|
265
|
+
from_notebook (bool, optional): Whether the request is made from a notebook context.
|
|
266
|
+
Defaults to False.
|
|
267
|
+
global_vars (Dict, optional): Global variables to be used in template rendering.
|
|
268
|
+
Defaults to None.
|
|
269
|
+
input_vars (List[Any], optional): Input variables for the block. Defaults to None.
|
|
270
|
+
partition (str, optional): Partition identifier, if applicable.
|
|
271
|
+
Defaults to None.
|
|
272
|
+
**kwargs: Additional keyword arguments.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
Dict: A dictionary containing the data integration settings, including catalog, config,
|
|
276
|
+
data_integration_uuid, selected_streams, and the appropriate key
|
|
277
|
+
(source or destination).
|
|
278
|
+
"""
|
|
188
279
|
if not self.is_data_integration():
|
|
189
280
|
return
|
|
190
281
|
|
|
@@ -13,6 +13,7 @@ from mage_ai.data_integrations.logger.utils import (
|
|
|
13
13
|
print_log_from_line,
|
|
14
14
|
print_logs_from_output,
|
|
15
15
|
)
|
|
16
|
+
from mage_ai.data_integrations.utils.config import get_batch_fetch_limit
|
|
16
17
|
from mage_ai.data_integrations.utils.parsers import parse_logs_and_json
|
|
17
18
|
from mage_ai.data_preparation.models.block.data_integration.constants import (
|
|
18
19
|
EXECUTION_PARTITION_FROM_NOTEBOOK,
|
|
@@ -383,21 +384,20 @@ def execute_data_integration(
|
|
|
383
384
|
# Handle incremental sync
|
|
384
385
|
state_file_path = None
|
|
385
386
|
if index is not None:
|
|
387
|
+
batch_fetch_limit = get_batch_fetch_limit(config)
|
|
386
388
|
state_file_path = get_state_file_path(block, data_integration_uuid, stream)
|
|
387
|
-
|
|
388
389
|
stream_catalogs = get_streams_from_catalog(catalog, [stream]) or []
|
|
390
|
+
|
|
389
391
|
if len(stream_catalogs) == 1 and \
|
|
390
392
|
REPLICATION_METHOD_INCREMENTAL == stream_catalogs[0].get('replication_method'):
|
|
391
393
|
# Use the state to adjust the query
|
|
392
394
|
# How do we write to the state when the source syncs can run in parallel?
|
|
393
395
|
pass
|
|
394
396
|
else:
|
|
395
|
-
|
|
396
|
-
query_data['_offset'] = BATCH_FETCH_LIMIT * index
|
|
397
|
+
query_data['_offset'] = batch_fetch_limit * index
|
|
397
398
|
|
|
398
399
|
if not is_last_block_run:
|
|
399
|
-
|
|
400
|
-
query_data['_limit'] = BATCH_FETCH_LIMIT
|
|
400
|
+
query_data['_limit'] = batch_fetch_limit
|
|
401
401
|
|
|
402
402
|
tags = dict(block_tags=dict(
|
|
403
403
|
index=index,
|
|
@@ -10,7 +10,11 @@ import pandas as pd
|
|
|
10
10
|
|
|
11
11
|
from mage_ai.data_cleaner.transformer_actions.utils import clean_column_name
|
|
12
12
|
from mage_ai.data_integrations.logger.utils import print_log_from_line
|
|
13
|
-
from mage_ai.data_integrations.utils.config import
|
|
13
|
+
from mage_ai.data_integrations.utils.config import (
|
|
14
|
+
build_config,
|
|
15
|
+
get_batch_fetch_limit,
|
|
16
|
+
get_catalog_by_stream,
|
|
17
|
+
)
|
|
14
18
|
from mage_ai.data_preparation.models.block import Block
|
|
15
19
|
from mage_ai.data_preparation.models.constants import PYTHON_COMMAND, BlockType
|
|
16
20
|
from mage_ai.data_preparation.shared.stream import StreamToLogger
|
|
@@ -50,8 +54,6 @@ class IntegrationBlock(Block):
|
|
|
50
54
|
runtime_arguments: Dict = None,
|
|
51
55
|
**kwargs,
|
|
52
56
|
) -> List:
|
|
53
|
-
from mage_integrations.sources.constants import BATCH_FETCH_LIMIT
|
|
54
|
-
|
|
55
57
|
if logging_tags is None:
|
|
56
58
|
logging_tags = dict()
|
|
57
59
|
|
|
@@ -106,10 +108,6 @@ class IntegrationBlock(Block):
|
|
|
106
108
|
source_state_file_path,
|
|
107
109
|
destination_state_file_path,
|
|
108
110
|
)
|
|
109
|
-
else:
|
|
110
|
-
query_data['_offset'] = BATCH_FETCH_LIMIT * index
|
|
111
|
-
if not is_last_block_run:
|
|
112
|
-
query_data['_limit'] = BATCH_FETCH_LIMIT
|
|
113
111
|
|
|
114
112
|
outputs = []
|
|
115
113
|
if BlockType.DATA_LOADER == self.type:
|
|
@@ -120,6 +118,13 @@ class IntegrationBlock(Block):
|
|
|
120
118
|
self.pipeline.data_loader.file_path,
|
|
121
119
|
variables_dictionary_for_config,
|
|
122
120
|
)
|
|
121
|
+
batch_fetch_limit = get_batch_fetch_limit(config)
|
|
122
|
+
|
|
123
|
+
if stream_catalog.get('replication_method') != 'INCREMENTAL':
|
|
124
|
+
query_data['_offset'] = batch_fetch_limit * index
|
|
125
|
+
if not is_last_block_run:
|
|
126
|
+
query_data['_limit'] = batch_fetch_limit
|
|
127
|
+
|
|
123
128
|
args = [
|
|
124
129
|
PYTHON_COMMAND,
|
|
125
130
|
self.pipeline.source_file_path,
|
|
@@ -19,6 +19,7 @@ from mage_ai.data_preparation.models.block.sql import (
|
|
|
19
19
|
from mage_ai.data_preparation.models.block.sql.utils.shared import (
|
|
20
20
|
has_create_or_insert_statement,
|
|
21
21
|
has_drop_statement,
|
|
22
|
+
has_update_statement,
|
|
22
23
|
interpolate_vars,
|
|
23
24
|
split_query_string,
|
|
24
25
|
table_name_parts_from_query,
|
|
@@ -29,6 +30,7 @@ from mage_ai.io.config import ConfigFileLoader
|
|
|
29
30
|
from mage_ai.settings.repo import get_repo_path
|
|
30
31
|
|
|
31
32
|
PREVIEWABLE_BLOCK_TYPES = [
|
|
33
|
+
BlockType.CUSTOM,
|
|
32
34
|
BlockType.DATA_EXPORTER,
|
|
33
35
|
BlockType.DATA_LOADER,
|
|
34
36
|
BlockType.DBT,
|
|
@@ -646,16 +648,17 @@ def execute_raw_sql(
|
|
|
646
648
|
|
|
647
649
|
has_create_or_insert = has_create_or_insert_statement(query_string)
|
|
648
650
|
has_drop = has_drop_statement(query_string)
|
|
651
|
+
has_update = has_update_statement(query_string)
|
|
649
652
|
|
|
650
653
|
for query in split_query_string(query_string):
|
|
651
|
-
if has_create_or_insert or has_drop:
|
|
654
|
+
if has_create_or_insert or has_drop or has_update:
|
|
652
655
|
queries.append(query)
|
|
653
656
|
fetch_query_at_indexes.append(False)
|
|
654
657
|
else:
|
|
655
658
|
queries.append(query)
|
|
656
659
|
fetch_query_at_indexes.append(True)
|
|
657
660
|
|
|
658
|
-
if should_query and has_create_or_insert:
|
|
661
|
+
if should_query and (has_create_or_insert or has_update) and block.full_table_name:
|
|
659
662
|
queries.append(f'SELECT * FROM {block.full_table_name} LIMIT 1000')
|
|
660
663
|
fetch_query_at_indexes.append(block.full_table_name)
|
|
661
664
|
|
|
@@ -494,7 +494,16 @@ def extract_insert_statement_table_names(text: str) -> List[str]:
|
|
|
494
494
|
|
|
495
495
|
def extract_drop_statement_table_names(text: str) -> List[str]:
|
|
496
496
|
matches = re.findall(
|
|
497
|
-
r'
|
|
497
|
+
r'\bdrop\s+table(?:\s+if\s+exists)?\s+([\w.]+)',
|
|
498
|
+
remove_comments(text),
|
|
499
|
+
re.IGNORECASE,
|
|
500
|
+
)
|
|
501
|
+
return matches
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
def extract_update_statement_table_names(text: str) -> List[str]:
|
|
505
|
+
matches = re.findall(
|
|
506
|
+
r'\bupdate\b\s+([\w.]+)\s+set\s+[\s\S]*?\bwhere\b',
|
|
498
507
|
remove_comments(text),
|
|
499
508
|
re.IGNORECASE,
|
|
500
509
|
)
|
|
@@ -515,6 +524,11 @@ def has_drop_statement(text: str) -> bool:
|
|
|
515
524
|
return len(matches) >= 1
|
|
516
525
|
|
|
517
526
|
|
|
527
|
+
def has_update_statement(text: str) -> bool:
|
|
528
|
+
matches = extract_update_statement_table_names(text)
|
|
529
|
+
return len(matches) >= 1
|
|
530
|
+
|
|
531
|
+
|
|
518
532
|
def split_query_string(query_string: str) -> List[str]:
|
|
519
533
|
text_parts = []
|
|
520
534
|
|
|
@@ -326,6 +326,21 @@ class PipelineInteractions:
|
|
|
326
326
|
|
|
327
327
|
await self.save()
|
|
328
328
|
|
|
329
|
+
async def variables(self) -> Dict:
|
|
330
|
+
variables = {}
|
|
331
|
+
|
|
332
|
+
interaction = await self.interaction()
|
|
333
|
+
if not interaction:
|
|
334
|
+
return variables
|
|
335
|
+
|
|
336
|
+
for block_interactions in (interaction.blocks or {}).values():
|
|
337
|
+
for block_interaction in block_interactions:
|
|
338
|
+
interaction_base = InteractionBase(block_interaction.uuid)
|
|
339
|
+
interaction_variables = await interaction_base.variables()
|
|
340
|
+
variables.update(interaction_variables)
|
|
341
|
+
|
|
342
|
+
return variables
|
|
343
|
+
|
|
329
344
|
async def to_dict(self) -> Dict:
|
|
330
345
|
interaction = await self.interaction()
|
|
331
346
|
|
|
@@ -155,6 +155,7 @@ def get_secret_value(
|
|
|
155
155
|
pipeline_uuid: str = None,
|
|
156
156
|
project_uuid: str = None,
|
|
157
157
|
repo_name: str = None,
|
|
158
|
+
**kwargs,
|
|
158
159
|
) -> Optional[str]:
|
|
159
160
|
from mage_ai.orchestration.db.models.secrets import Secret
|
|
160
161
|
key, key_uuid = _get_encryption_key(
|
|
@@ -189,29 +190,17 @@ def get_secret_value(
|
|
|
189
190
|
return fernet.decrypt(secret_legacy.value.encode('utf-8')).decode('utf-8')
|
|
190
191
|
except InvalidToken:
|
|
191
192
|
pass
|
|
193
|
+
if not kwargs.get('suppress_warning', False):
|
|
194
|
+
print(f'WARNING: Could not find secret value for secret {name}.')
|
|
192
195
|
|
|
193
|
-
print(f'WARNING: Could not find secret value for secret {name}.')
|
|
194
196
|
|
|
195
|
-
|
|
196
|
-
def get_secret_value_db_safe(
|
|
197
|
-
name: str,
|
|
198
|
-
entity: Entity = Entity.GLOBAL,
|
|
199
|
-
pipeline_uuid: str = None,
|
|
200
|
-
project_uuid: str = None,
|
|
201
|
-
repo_name: str = None,
|
|
202
|
-
) -> Optional[str]:
|
|
197
|
+
def get_secret_value_db_safe(name: str, **kwargs) -> Optional[str]:
|
|
203
198
|
"""
|
|
204
199
|
Calls get_secret_value only if the db has already been initialized.
|
|
205
200
|
"""
|
|
206
201
|
from mage_ai.orchestration.db import db_connection
|
|
207
202
|
if db_connection.session and db_connection.session.is_active:
|
|
208
|
-
return get_secret_value(
|
|
209
|
-
name,
|
|
210
|
-
entity=entity,
|
|
211
|
-
pipeline_uuid=pipeline_uuid,
|
|
212
|
-
project_uuid=project_uuid,
|
|
213
|
-
repo_name=repo_name,
|
|
214
|
-
)
|
|
203
|
+
return get_secret_value(name, **kwargs)
|
|
215
204
|
else:
|
|
216
205
|
return None
|
|
217
206
|
|
|
@@ -222,6 +211,7 @@ def delete_secret(
|
|
|
222
211
|
entity: Entity = Entity.GLOBAL,
|
|
223
212
|
pipeline_uuid: str = None,
|
|
224
213
|
project_uuid: str = None,
|
|
214
|
+
**kwargs,
|
|
225
215
|
) -> None:
|
|
226
216
|
from mage_ai.orchestration.db.models.secrets import Secret
|
|
227
217
|
secret = None
|
|
@@ -242,7 +232,7 @@ def delete_secret(
|
|
|
242
232
|
|
|
243
233
|
if secret:
|
|
244
234
|
secret.delete()
|
|
245
|
-
|
|
235
|
+
elif not kwargs.get('suppress_warning', False):
|
|
246
236
|
print(f'WARNING: Could not find secret {name}')
|
|
247
237
|
|
|
248
238
|
|
|
@@ -37,6 +37,11 @@ spark_config:
|
|
|
37
37
|
# List of key-value pairs to be set in SparkConf
|
|
38
38
|
# e.g., others: {'spark.executor.memory': '4g', 'spark.executor.cores': '2'}
|
|
39
39
|
others: {}
|
|
40
|
+
# Wehther to create custom SparkSession via code and set in kwargs['context']
|
|
41
|
+
use_custom_session: false
|
|
42
|
+
# The variable name to set in kwargs['context'],
|
|
43
|
+
# e.g. kwargs['context']['spark'] = spark_session
|
|
44
|
+
custom_session_var_name: 'spark'
|
|
40
45
|
|
|
41
46
|
notification_config:
|
|
42
47
|
alert_on:
|
mage_ai/io/druid.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import IO, Any, Dict, List, Union
|
|
2
|
+
|
|
3
|
+
from pandas import DataFrame, Series
|
|
4
|
+
from pydruid.db.api import Connection
|
|
5
|
+
from pydruid.db.api import Cursor as CursorParent
|
|
6
|
+
|
|
7
|
+
from mage_ai.io.base import QUERY_ROW_LIMIT, ExportWritePolicy
|
|
2
8
|
from mage_ai.io.config import BaseConfigLoader, ConfigKey
|
|
3
9
|
from mage_ai.io.sql import BaseSQL
|
|
4
|
-
from pandas import DataFrame, Series
|
|
5
|
-
from pydruid.db.api import Connection, Cursor as CursorParent
|
|
6
|
-
from typing import Dict, List, Union, Any, IO
|
|
7
10
|
|
|
8
11
|
WRITE_NOT_SUPPORTED_EXCEPTION = Exception('write operations are not supported.')
|
|
9
12
|
|
|
@@ -138,7 +141,8 @@ class Druid(BaseSQL):
|
|
|
138
141
|
db_dtypes: List[str],
|
|
139
142
|
dtypes: List[str],
|
|
140
143
|
full_table_name: str,
|
|
141
|
-
buffer: Union[IO, None] = None
|
|
144
|
+
buffer: Union[IO, None] = None,
|
|
145
|
+
**kwargs) -> None:
|
|
142
146
|
raise WRITE_NOT_SUPPORTED_EXCEPTION
|
|
143
147
|
|
|
144
148
|
def export(self,
|
mage_ai/io/mssql.py
CHANGED
|
@@ -4,8 +4,9 @@ import numpy as np
|
|
|
4
4
|
import pyodbc
|
|
5
5
|
import simplejson
|
|
6
6
|
from pandas import DataFrame, Series
|
|
7
|
+
from sqlalchemy import create_engine
|
|
7
8
|
|
|
8
|
-
from mage_ai.io.base import QUERY_ROW_LIMIT
|
|
9
|
+
from mage_ai.io.base import QUERY_ROW_LIMIT, ExportWritePolicy
|
|
9
10
|
from mage_ai.io.config import BaseConfigLoader, ConfigKey
|
|
10
11
|
from mage_ai.io.export_utils import PandasTypes
|
|
11
12
|
from mage_ai.io.sql import BaseSQL
|
|
@@ -21,6 +22,7 @@ class MSSQL(BaseSQL):
|
|
|
21
22
|
user: str,
|
|
22
23
|
schema: str = None,
|
|
23
24
|
port: int = 1433,
|
|
25
|
+
verbose: bool = True,
|
|
24
26
|
**kwargs,
|
|
25
27
|
) -> None:
|
|
26
28
|
super().__init__(
|
|
@@ -30,24 +32,25 @@ class MSSQL(BaseSQL):
|
|
|
30
32
|
password=password,
|
|
31
33
|
schema=schema,
|
|
32
34
|
port=port,
|
|
35
|
+
verbose=verbose,
|
|
33
36
|
**kwargs
|
|
34
37
|
)
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
password
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
@property
|
|
40
|
+
def connection_string(self):
|
|
41
|
+
driver = self.settings['driver']
|
|
42
|
+
server = self.settings['server']
|
|
43
|
+
database = self.settings['database']
|
|
44
|
+
username = self.settings['user']
|
|
45
|
+
password = self.settings['password']
|
|
46
|
+
return (
|
|
47
|
+
f'DRIVER={{{driver}}};'
|
|
48
|
+
f'SERVER={server};'
|
|
49
|
+
f'DATABASE={database};'
|
|
50
|
+
f'UID={username};'
|
|
51
|
+
f'PWD={password};'
|
|
52
|
+
'ENCRYPT=yes;'
|
|
53
|
+
'TrustServerCertificate=yes;'
|
|
51
54
|
)
|
|
52
55
|
|
|
53
56
|
def default_schema(self) -> str:
|
|
@@ -55,21 +58,9 @@ class MSSQL(BaseSQL):
|
|
|
55
58
|
|
|
56
59
|
def open(self) -> None:
|
|
57
60
|
with self.printer.print_msg('Opening connection to MSSQL database'):
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
database = self.settings['database']
|
|
61
|
-
username = self.settings['user']
|
|
62
|
-
password = self.settings['password']
|
|
63
|
-
connection_string = (
|
|
64
|
-
f'DRIVER={{{driver}}};'
|
|
65
|
-
f'SERVER={server};'
|
|
66
|
-
f'DATABASE={database};'
|
|
67
|
-
f'UID={username};'
|
|
68
|
-
f'PWD={password};'
|
|
69
|
-
'ENCRYPT=yes;'
|
|
70
|
-
'TrustServerCertificate=yes;'
|
|
61
|
+
self._ctx = pyodbc.connect(
|
|
62
|
+
self.connection_string,
|
|
71
63
|
)
|
|
72
|
-
self._ctx = pyodbc.connect(connection_string)
|
|
73
64
|
|
|
74
65
|
def build_create_schema_command(
|
|
75
66
|
self,
|
|
@@ -149,6 +140,20 @@ class MSSQL(BaseSQL):
|
|
|
149
140
|
sql = f'INSERT INTO {full_table_name} VALUES ({values_placeholder})'
|
|
150
141
|
cursor.executemany(sql, values)
|
|
151
142
|
|
|
143
|
+
def upload_dataframe_fast(
|
|
144
|
+
self,
|
|
145
|
+
df: DataFrame,
|
|
146
|
+
schema_name: str,
|
|
147
|
+
table_name: str,
|
|
148
|
+
if_exists: ExportWritePolicy = ExportWritePolicy.REPLACE,
|
|
149
|
+
|
|
150
|
+
):
|
|
151
|
+
engine = create_engine(
|
|
152
|
+
f'mssql+pyodbc://?odbc_connect={self.connection_string}',
|
|
153
|
+
fast_executemany=True,
|
|
154
|
+
)
|
|
155
|
+
df.to_sql(table_name, engine, schema=schema_name, if_exists=if_exists, index=False)
|
|
156
|
+
|
|
152
157
|
def get_type(self, column: Series, dtype: str) -> str:
|
|
153
158
|
if dtype in (
|
|
154
159
|
PandasTypes.MIXED,
|
|
@@ -199,3 +204,20 @@ class MSSQL(BaseSQL):
|
|
|
199
204
|
print(f'Invalid datatype provided: {dtype}')
|
|
200
205
|
|
|
201
206
|
return 'char(255)'
|
|
207
|
+
|
|
208
|
+
@classmethod
|
|
209
|
+
def with_config(cls, config: BaseConfigLoader) -> 'MSSQL':
|
|
210
|
+
return cls(
|
|
211
|
+
database=config[ConfigKey.MSSQL_DATABASE],
|
|
212
|
+
schema=config[ConfigKey.MSSQL_SCHEMA],
|
|
213
|
+
driver=config[ConfigKey.MSSQL_DRIVER],
|
|
214
|
+
host=config[ConfigKey.MSSQL_HOST],
|
|
215
|
+
password=config[ConfigKey.MSSQL_PASSWORD],
|
|
216
|
+
port=config[ConfigKey.MSSQL_PORT],
|
|
217
|
+
user=config[ConfigKey.MSSQL_USER],
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
def _enforce_limit(self, query: str, limit: int = QUERY_ROW_LIMIT) -> str:
|
|
221
|
+
# MSSQL doesn't support WITH statements in subqueries, so if the user uses a WITH
|
|
222
|
+
# statement in their query, it would break if we tried to enforce a limit.
|
|
223
|
+
return query
|