├── example_snowpark ├── app │ ├── __init__.py │ ├── common.py │ ├── functions.py │ └── procedures.py ├── requirements.txt ├── .gitignore ├── template.yml └── snowflake.yml ├── .gitignore ├── app_streamlit_java ├── src │ ├── module-add │ │ ├── .gitignore │ │ ├── src │ │ │ ├── main │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── snowflake │ │ │ │ │ └── add │ │ │ │ │ └── Add.java │ │ │ └── test │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── snowflake │ │ │ │ └── add │ │ │ │ └── AddTest.java │ │ └── pom.xml │ └── module-ui │ │ └── src │ │ ├── environment.yml │ │ └── ui.py ├── .gitignore ├── app │ ├── README.md │ ├── manifest.yml │ └── setup_script.sql ├── scripts │ ├── any-provider-setup.sql │ └── shared-content.sql ├── template.yml ├── snowflake.yml └── README.md ├── snowpark_with_external_access ├── app │ ├── __init__.py │ ├── functions.py │ ├── procedures.py │ └── common.py ├── requirements.txt ├── .gitignore ├── setup.sql ├── template.yml ├── snowflake.yml └── README.md ├── streamlit_vnext_multi_page ├── .streamlit │ ├── config.toml │ └── secrets.toml ├── app_pages │ ├── example_page.py │ └── home_page.py ├── common │ ├── ui.py │ └── snowflake_connection.py ├── pyproject.toml ├── streamlit_app.py ├── snowflake.yml ├── README.md └── template.yml ├── streamlit_vnext_single_page ├── .streamlit │ ├── config.toml │ └── secrets.toml ├── common │ ├── ui.py │ └── snowflake_connection.py ├── pyproject.toml ├── snowflake.yml ├── README.md ├── template.yml └── streamlit_app.py ├── app_basic ├── .gitignore ├── template.yml ├── app │ ├── manifest.yml │ ├── setup_script.sql │ └── README.md ├── snowflake.yml └── README.md ├── app_spcs_basic ├── .gitignore ├── app │ ├── setup.sql │ ├── README.md │ ├── service_spec.yml │ ├── manifest.yml │ └── services.sql ├── template.yml ├── service │ ├── Dockerfile │ ├── index.html │ └── main.py ├── build-and-push.sh ├── snowflake.yml └── README.md ├── example_plugin ├── src │ └── snowflake_cli_example_plugin │ │ ├── __init__.py │ │ ├── plugin_spec.py │ │ ├── manager.py │ │ └── commands.py ├── template.yml ├── pyproject.toml └── README.md ├── .github ├── CODEOWNERS ├── repo_meta.yml └── workflows │ ├── lint.yaml │ └── tests.yaml ├── app_streamlit_js ├── .gitignore ├── app │ ├── README.md │ ├── manifest.yml │ └── setup_script.sql ├── scripts │ ├── any-provider-setup.sql │ └── shared-content.sql ├── template.yml ├── src │ └── module-ui │ │ └── src │ │ ├── environment.yml │ │ └── ui.py ├── snowflake.yml └── README.md ├── example_streamlit ├── common │ └── hello.py ├── .gitignore ├── pages │ └── my_page.py ├── environment.yml ├── streamlit_app.py ├── template.yml └── snowflake.yml ├── streamlit_with_external_access ├── requirements.txt ├── .gitignore ├── streamlit_app.py ├── setup.sql ├── template.yml ├── snowflake.yml └── README.md ├── app_streamlit_python ├── pytest.ini ├── .gitignore ├── app │ ├── README.md │ ├── manifest.yml │ └── setup_script.sql ├── scripts │ ├── any-provider-setup.sql │ └── shared-content.sql ├── template.yml ├── src │ ├── module-ui │ │ ├── src │ │ │ ├── environment.yml │ │ │ └── ui.py │ │ └── test │ │ │ └── test_ui.py │ └── module-add │ │ └── src │ │ ├── main │ │ └── python │ │ │ └── add.py │ │ └── test │ │ └── python │ │ └── test_add.py ├── local_test_env.yml ├── snowflake.yml └── README.md ├── dcm_project ├── template.yml ├── manifest.yml ├── definitions │ ├── access.sql │ ├── raw.sql │ ├── serve.sql │ ├── ingest.sql │ └── analytics.sql └── README.md ├── .pre-commit-config.yaml ├── README.md ├── .tests ├── test_V2_definition_has_cli_version_limit.py ├── test_examples.py └── test_render_templates.py └── LICENSE /example_snowpark/app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .idea 3 | *.pyc 4 | -------------------------------------------------------------------------------- /app_streamlit_java/src/module-add/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snowpark_with_external_access/app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/.streamlit/config.toml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /streamlit_vnext_single_page/.streamlit/config.toml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app_basic/.gitignore: -------------------------------------------------------------------------------- 1 | snowflake.local.yml 2 | output/** 3 | -------------------------------------------------------------------------------- /app_spcs_basic/.gitignore: -------------------------------------------------------------------------------- 1 | snowflake.local.yml 2 | output/** 3 | -------------------------------------------------------------------------------- /example_plugin/src/snowflake_cli_example_plugin/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example_snowpark/requirements.txt: -------------------------------------------------------------------------------- 1 | snowflake-snowpark-python 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @snowflakedb/snowcli 2 | 3 | app_* @snowflakedb/nade 4 | -------------------------------------------------------------------------------- /app_streamlit_java/.gitignore: -------------------------------------------------------------------------------- 1 | snowflake.local.yml 2 | output/** 3 | target 4 | -------------------------------------------------------------------------------- /app_streamlit_js/.gitignore: -------------------------------------------------------------------------------- 1 | snowflake.local.yml 2 | output/** 3 | target 4 | -------------------------------------------------------------------------------- /example_streamlit/common/hello.py: -------------------------------------------------------------------------------- 1 | def say_hello(): 2 | return "Hello!" 3 | -------------------------------------------------------------------------------- /snowpark_with_external_access/requirements.txt: -------------------------------------------------------------------------------- 1 | snowflake-snowpark-python 2 | -------------------------------------------------------------------------------- /streamlit_with_external_access/requirements.txt: -------------------------------------------------------------------------------- 1 | snowflake-snowpark-python 2 | -------------------------------------------------------------------------------- /example_snowpark/.gitignore: -------------------------------------------------------------------------------- 1 | .packages/ 2 | .venv/ 3 | app.zip 4 | __pycache__ 5 | -------------------------------------------------------------------------------- /example_streamlit/.gitignore: -------------------------------------------------------------------------------- 1 | .packages/ 2 | .venv/ 3 | app.zip 4 | __pycache__ 5 | -------------------------------------------------------------------------------- /example_snowpark/app/common.py: -------------------------------------------------------------------------------- 1 | def print_hello(name: str): 2 | return f"Hello {name}!" 3 | -------------------------------------------------------------------------------- /example_streamlit/pages/my_page.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | 3 | st.title("Example page") 4 | -------------------------------------------------------------------------------- /snowpark_with_external_access/.gitignore: -------------------------------------------------------------------------------- 1 | .packages/ 2 | .venv/ 3 | app.zip 4 | __pycache__ 5 | -------------------------------------------------------------------------------- /streamlit_with_external_access/.gitignore: -------------------------------------------------------------------------------- 1 | .packages/ 2 | .venv/ 3 | app.zip 4 | __pycache__ 5 | -------------------------------------------------------------------------------- /app_streamlit_python/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | pythonpath=src/module-add/src/main/python src/module-ui/src 3 | -------------------------------------------------------------------------------- /app_streamlit_python/.gitignore: -------------------------------------------------------------------------------- 1 | snowflake.local.yml 2 | output/ 3 | **/__pycache__/ 4 | **/.pytest_cache/ 5 | -------------------------------------------------------------------------------- /app_spcs_basic/app/setup.sql: -------------------------------------------------------------------------------- 1 | create application role if not exists app_public; 2 | execute immediate from './services.sql'; 3 | -------------------------------------------------------------------------------- /app_spcs_basic/app/README.md: -------------------------------------------------------------------------------- 1 | # Snowflake Native App - SPCS 2 | 3 | This is a sample Snowflake Native App deployed using Snowpark Container Services. 4 | -------------------------------------------------------------------------------- /example_streamlit/environment.yml: -------------------------------------------------------------------------------- 1 | name: sf_env 2 | channels: 3 | - snowflake 4 | dependencies: 5 | - streamlit 6 | - snowflake-snowpark-python 7 | -------------------------------------------------------------------------------- /app_streamlit_java/app/README.md: -------------------------------------------------------------------------------- 1 | # Snowflake Native App - Add 2 | 3 | This is a sample Snowflake Native App that adds two numbers using Streamlit and Java. 4 | -------------------------------------------------------------------------------- /example_streamlit/streamlit_app.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from common.hello import say_hello 3 | 4 | st.title(f"Example streamlit app. {say_hello()}") 5 | -------------------------------------------------------------------------------- /app_streamlit_js/app/README.md: -------------------------------------------------------------------------------- 1 | # Snowflake Native App - Add 2 | 3 | This is a sample Snowflake Native App that adds two numbers using Streamlit and JavaScript. 4 | -------------------------------------------------------------------------------- /app_streamlit_python/app/README.md: -------------------------------------------------------------------------------- 1 | # Snowflake Native App - Add 2 | 3 | This is a sample Snowflake Native App that adds two numbers using Streamlit and Python. 4 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/app_pages/example_page.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | 3 | st.title("Example Page") 4 | st.markdown("Let's do something interesting!") 5 | -------------------------------------------------------------------------------- /dcm_project/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "3.12.0" 2 | files_to_render: 3 | - definitions/access.sql 4 | variables: 5 | - name: username 6 | prompt: "User with read role" 7 | type: string 8 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/.streamlit/secrets.toml: -------------------------------------------------------------------------------- 1 | [connections.snowflake] 2 | account = ... 3 | user = ... 4 | authenticator = "externalbrowser" 5 | database = ... 6 | schema = ... 7 | warehouse = ... 8 | -------------------------------------------------------------------------------- /streamlit_vnext_single_page/.streamlit/secrets.toml: -------------------------------------------------------------------------------- 1 | [connections.snowflake] 2 | account = ... 3 | user = ... 4 | authenticator = "externalbrowser" 5 | database = ... 6 | schema = ... 7 | warehouse = ... 8 | -------------------------------------------------------------------------------- /app_spcs_basic/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "2.8.0" 2 | files_to_render: 3 | - snowflake.yml 4 | variables: 5 | - name: project_name 6 | prompt: "Project identifier" 7 | default: my_app_spcs_basic 8 | type: string 9 | -------------------------------------------------------------------------------- /app_streamlit_js/scripts/any-provider-setup.sql: -------------------------------------------------------------------------------- 1 | -- Any script that should be run by the provider, such as creating and populating database objects that need to be shared with the application package. 2 | -- This script must be idempotent. 3 | -------------------------------------------------------------------------------- /app_spcs_basic/service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3-alpine 2 | 3 | RUN mkdir /web 4 | COPY index.html /web 5 | COPY main.py /web 6 | 7 | # default port is 8080 8 | EXPOSE 8080 9 | 10 | WORKDIR /web 11 | 12 | CMD ["python", "main.py"] 13 | -------------------------------------------------------------------------------- /app_streamlit_java/scripts/any-provider-setup.sql: -------------------------------------------------------------------------------- 1 | -- Any script that should be run by the provider, such as creating and populating database objects that need to be shared with the application package. 2 | -- This script must be idempotent. 3 | -------------------------------------------------------------------------------- /app_streamlit_python/scripts/any-provider-setup.sql: -------------------------------------------------------------------------------- 1 | -- Any script that should be run as the provider, such as creating and populating database objects that need to be shared with the application package. 2 | -- This script must be idempotent. 3 | -------------------------------------------------------------------------------- /.github/repo_meta.yml: -------------------------------------------------------------------------------- 1 | point_of_contact: "@snowflakedb/snowcli" 2 | production: true 3 | distributed: true 4 | modified: false 5 | code_owners_file_present: true 6 | release_branches: 7 | - main 8 | jira_area: Developer Platform 9 | audit_in_scope: true 10 | -------------------------------------------------------------------------------- /app_basic/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "2.8.0" 2 | files_to_render: 3 | - snowflake.yml 4 | - README.md 5 | variables: 6 | - name: project_name 7 | prompt: "Project identifier" 8 | default: my_native_app_project 9 | type: string 10 | -------------------------------------------------------------------------------- /app_spcs_basic/service/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Welcome to SPCS + NA 5 | 6 | 7 |

Hello World!

8 |

We can show a container-based UI!

9 | 10 | 11 | -------------------------------------------------------------------------------- /app_streamlit_js/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "2.8.0" 2 | files_to_render: 3 | - snowflake.yml 4 | - README.md 5 | variables: 6 | - name: project_name 7 | prompt: "Project identifier" 8 | default: my_app_streamlit_js 9 | type: string 10 | -------------------------------------------------------------------------------- /app_streamlit_java/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "2.8.0" 2 | files_to_render: 3 | - snowflake.yml 4 | - README.md 5 | variables: 6 | - name: project_name 7 | prompt: "Project identifier" 8 | default: my_app_streamlit_java 9 | type: string 10 | -------------------------------------------------------------------------------- /snowpark_with_external_access/app/functions.py: -------------------------------------------------------------------------------- 1 | from common import get_secret_value, send_request 2 | 3 | 4 | def request_function() -> str: 5 | # Retrieve secret value 6 | _ = get_secret_value() 7 | 8 | # Send request 9 | return send_request() 10 | -------------------------------------------------------------------------------- /app_streamlit_python/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "2.8.0" 2 | files_to_render: 3 | - snowflake.yml 4 | - local_test_env.yml 5 | - README.md 6 | variables: 7 | - name: project_name 8 | prompt: "Project identifier" 9 | default: my_app_streamlit_python 10 | type: string 11 | -------------------------------------------------------------------------------- /app_streamlit_js/src/module-ui/src/environment.yml: -------------------------------------------------------------------------------- 1 | # This file is used to install packages used by the Streamlit App. 2 | # For more details, refer to https://docs.snowflake.com/en/developer-guide/streamlit/create-streamlit-sql#label-streamlit-install-packages-manual 3 | channels: 4 | - snowflake 5 | dependencies: 6 | - streamlit=1.26.0 7 | -------------------------------------------------------------------------------- /app_streamlit_java/src/module-ui/src/environment.yml: -------------------------------------------------------------------------------- 1 | # This file is used to install packages used by the Streamlit App. 2 | # For more details, refer to https://docs.snowflake.com/en/developer-guide/streamlit/create-streamlit-sql#label-streamlit-install-packages-manual 3 | channels: 4 | - snowflake 5 | dependencies: 6 | - streamlit=1.26.0 7 | -------------------------------------------------------------------------------- /app_streamlit_python/src/module-ui/src/environment.yml: -------------------------------------------------------------------------------- 1 | # This file is used to install packages used by the Streamlit App. 2 | # For more details, refer to https://docs.snowflake.com/en/developer-guide/streamlit/create-streamlit-sql#label-streamlit-install-packages-manual 3 | 4 | channels: 5 | - snowflake 6 | dependencies: 7 | - streamlit=1.26.0 8 | -------------------------------------------------------------------------------- /app_spcs_basic/app/service_spec.yml: -------------------------------------------------------------------------------- 1 | spec: 2 | container: 3 | - name: my-service 4 | image: /spcs_na_db/public/images/spcs_na_service:latest 5 | env: 6 | PORT: 8080 7 | readinessProbe: 8 | port: 8080 9 | path: /healthcheck 10 | endpoint: 11 | - name: my-endpoint 12 | port: 8080 13 | public: true 14 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/common/ui.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | 3 | 4 | def read_app_name() -> str: 5 | """Read the app name from the snowflake.yml file.""" 6 | with open("snowflake.yml", "r") as f: 7 | config = yaml.safe_load(f) 8 | return list(config["entities"].keys())[0] 9 | 10 | 11 | APP_NAME = read_app_name().title() 12 | -------------------------------------------------------------------------------- /streamlit_vnext_single_page/common/ui.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | 3 | 4 | def read_app_name() -> str: 5 | """Read the app name from the snowflake.yml file.""" 6 | with open("snowflake.yml", "r") as f: 7 | config = yaml.safe_load(f) 8 | return list(config["entities"].keys())[0] 9 | 10 | 11 | APP_NAME = read_app_name().title() 12 | -------------------------------------------------------------------------------- /dcm_project/manifest.yml: -------------------------------------------------------------------------------- 1 | manifest_version: 1.0 2 | 3 | type: dcm_project 4 | 5 | include_definitions: 6 | - definitions/.* 7 | 8 | configurations: 9 | DEV: 10 | db: "DEV" 11 | wh_size: "X-SMALL" 12 | role: "DEV" 13 | scope: "TEST" 14 | 15 | PROD: 16 | db: "PROD" 17 | wh_size: "LARGE" 18 | role: "PROD" 19 | scope: "ALL" 20 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "APP_NAME" 3 | version = "0.1.0" 4 | description = "APP_DESCRIPTION" 5 | requires-python = ">=3.11" 6 | dependencies = [ 7 | "streamlit[snowflake]>=1.50.0", 8 | ] 9 | 10 | [tool.uv] 11 | # earlier versions of numba require a python version < 3.11 12 | constraint-dependencies = ["numba>=0.56.0"] 13 | -------------------------------------------------------------------------------- /streamlit_vnext_single_page/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "APP_NAME" 3 | version = "0.1.0" 4 | description = "APP_DESCRIPTION" 5 | requires-python = ">=3.11" 6 | dependencies = [ 7 | "streamlit[snowflake]>=1.50.0", 8 | ] 9 | 10 | [tool.uv] 11 | # earlier versions of numba require a python version < 3.11 12 | constraint-dependencies = ["numba>=0.56.0"] 13 | -------------------------------------------------------------------------------- /snowpark_with_external_access/app/procedures.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from snowflake.snowpark import Session 4 | from common import get_secret_value, send_request 5 | 6 | 7 | def request_procedure(session: Session) -> str: 8 | # Retrieve secret value 9 | _ = get_secret_value() 10 | 11 | # Send request 12 | return send_request() 13 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v5.0.0 4 | hooks: 5 | - id: trailing-whitespace 6 | - id: end-of-file-fixer 7 | - repo: https://github.com/codespell-project/codespell 8 | rev: v2.2.4 9 | hooks: 10 | - id: codespell 11 | additional_dependencies: 12 | - tomli 13 | -------------------------------------------------------------------------------- /app_streamlit_java/src/module-add/src/main/java/com/snowflake/add/Add.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This file should contain the classes, and their methods, that you plan to use 3 | * for UDFs and Stored Procedures. 4 | * You may also use scala code in .scala files. 5 | */ 6 | package com.snowflake.add; 7 | 8 | public class Add { 9 | public static int two(int num1, int num2) { 10 | return num1 + num2; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example_snowpark/app/functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import sys 4 | 5 | from common import print_hello 6 | 7 | 8 | def hello_function(name: str) -> str: 9 | return print_hello(name) 10 | 11 | 12 | # For local debugging 13 | # Be aware you may need to type-convert arguments if you add input parameters 14 | if __name__ == "__main__": 15 | print(hello_function(*sys.argv[1:])) # type: ignore 16 | -------------------------------------------------------------------------------- /snowpark_with_external_access/app/common.py: -------------------------------------------------------------------------------- 1 | import _snowflake 2 | from http.client import HTTPSConnection 3 | 4 | 5 | def get_secret_value(): 6 | return _snowflake.get_generic_secret_string("generic_secret") 7 | 8 | 9 | def send_request(): 10 | host = "docs.snowflake.com" 11 | conn = HTTPSConnection(host) 12 | conn.request("GET", "/") 13 | response = conn.getresponse() 14 | return response.status 15 | -------------------------------------------------------------------------------- /example_snowpark/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "2.8.0" 2 | files_to_render: 3 | - snowflake.yml 4 | variables: 5 | - name: project_name 6 | prompt: "Project identifier (used to determine artifacts stage path)" 7 | default: my_snowpark_project 8 | type: string 9 | - name: stage 10 | prompt: "What stage should the procedures and functions be deployed to?" 11 | default: dev_deployment 12 | type: string 13 | -------------------------------------------------------------------------------- /app_streamlit_java/src/module-add/src/test/java/com/snowflake/add/AddTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a sample file that should contain any unit tests for your Java code. 3 | */ 4 | package com.snowflake.add; 5 | 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import org.junit.Test; 9 | 10 | public class AddTest { 11 | @Test 12 | public void shouldAnswerWithTrue() { 13 | assertTrue(Add.two(1, 2) == 3); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app_streamlit_java/app/manifest.yml: -------------------------------------------------------------------------------- 1 | # For more information on creating manifest, go to https://docs.snowflake.com/en/developer-guide/native-apps/creating-manifest 2 | manifest_version: 1 3 | 4 | version: 5 | name: Dev 6 | label: "Dev Version" 7 | comment: "Default version used for development. Override for actual deployment." 8 | 9 | artifacts: 10 | setup_script: setup_script.sql 11 | readme: README.md 12 | default_streamlit: core.ui 13 | extension_code: true 14 | -------------------------------------------------------------------------------- /app_streamlit_js/app/manifest.yml: -------------------------------------------------------------------------------- 1 | # For more information on creating manifest, go to https://docs.snowflake.com/en/developer-guide/native-apps/creating-manifest 2 | manifest_version: 1 3 | 4 | version: 5 | name: Dev 6 | label: "Dev Version" 7 | comment: "Default version used for development. Override for actual deployment." 8 | 9 | artifacts: 10 | setup_script: setup_script.sql 11 | readme: README.md 12 | default_streamlit: core.ui 13 | extension_code: true 14 | -------------------------------------------------------------------------------- /app_streamlit_python/app/manifest.yml: -------------------------------------------------------------------------------- 1 | # For more information on creating manifest, go to https://docs.snowflake.com/en/developer-guide/native-apps/creating-manifest 2 | manifest_version: 1 3 | 4 | version: 5 | name: Dev 6 | label: "Dev Version" 7 | comment: "Default version used for development. Override for actual deployment." 8 | 9 | artifacts: 10 | setup_script: setup_script.sql 11 | readme: README.md 12 | default_streamlit: core.ui 13 | extension_code: true 14 | -------------------------------------------------------------------------------- /example_streamlit/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "2.8.0" 2 | files_to_render: 3 | - snowflake.yml 4 | variables: 5 | - name: name 6 | default: streamlit_app 7 | prompt: "Name of the streamlit app" 8 | - name: stage 9 | default: my_streamlit_stage 10 | prompt: "What stage should the app be deployed to?" 11 | - name: query_warehouse 12 | default: my_streamlit_warehouse 13 | prompt: "On which warehouse SQL queries issued by the application are run" 14 | -------------------------------------------------------------------------------- /app_basic/app/manifest.yml: -------------------------------------------------------------------------------- 1 | # This is a manifest.yml file, a required component of creating a Snowflake Native App. 2 | # This file defines properties required by the application package, including the location of the setup script and version definitions. 3 | # Refer to https://docs.snowflake.com/en/developer-guide/native-apps/creating-manifest for a detailed understanding of this file. 4 | 5 | manifest_version: 1 6 | 7 | artifacts: 8 | setup_script: setup_script.sql 9 | readme: README.md 10 | -------------------------------------------------------------------------------- /example_plugin/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "3.5.0" 2 | files_to_render: 3 | - README.md 4 | - pyproject.toml 5 | - src/snowflake_cli_example_plugin/manager.py 6 | variables: 7 | - name: plugin_name 8 | prompt: "Plugin name (used to identify plugin inside CLI)" 9 | default: example-plugin 10 | type: string 11 | - name: plugin_package_name 12 | prompt: "Package name (used to identify package by installers)" 13 | default: snowflakecli-example-plugin 14 | type: string 15 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/streamlit_app.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | 3 | navigation = [ 4 | st.Page( 5 | "app_pages/home_page.py", 6 | title="Home", 7 | icon=":material/home:", 8 | ), 9 | st.Page( 10 | "app_pages/example_page.py", 11 | title="Example page", 12 | icon=":material/comedy_mask:", 13 | ), 14 | # Add more pages here! 15 | ] 16 | 17 | current_page = st.navigation( 18 | navigation, 19 | position="top", # You can try position="sidebar" too! 20 | ) 21 | 22 | current_page.run() 23 | -------------------------------------------------------------------------------- /streamlit_with_external_access/streamlit_app.py: -------------------------------------------------------------------------------- 1 | import _snowflake 2 | import streamlit as st 3 | from http.client import HTTPSConnection 4 | 5 | 6 | def get_secret_value(): 7 | return _snowflake.get_generic_secret_string("generic_secret") 8 | 9 | 10 | def send_request(): 11 | host = "docs.snowflake.com" 12 | conn = HTTPSConnection(host) 13 | conn.request("GET", "/") 14 | response = conn.getresponse() 15 | st.success(f"Response status: {response.status}") 16 | 17 | 18 | st.title(f"Example streamlit app.") 19 | st.button("Send request", on_click=send_request) 20 | -------------------------------------------------------------------------------- /app_basic/app/setup_script.sql: -------------------------------------------------------------------------------- 1 | -- This is the setup script that runs while installing a Snowflake Native App in a consumer account. 2 | -- To write this script, you can familiarize yourself with some of the following concepts: 3 | -- Application Roles 4 | -- Versioned Schemas 5 | -- UDFs/Procs 6 | -- Extension Code 7 | -- Refer to https://docs.snowflake.com/en/developer-guide/native-apps/creating-setup-script for a detailed understanding of this file. 8 | 9 | CREATE OR ALTER VERSIONED SCHEMA core; 10 | 11 | -- The rest of this script is left blank for purposes of your learning and exploration. 12 | -------------------------------------------------------------------------------- /example_plugin/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Example pyproject.toml for a Snowflake CLI plugin 2 | 3 | [build-system] 4 | requires = ["setuptools"] 5 | build-backend = "setuptools.build_meta" 6 | 7 | [project] 8 | name = "" 9 | requires-python = ">=3.8" 10 | dependencies = [ 11 | "snowflake-cli>=3.5.0" 12 | ] 13 | version = "1.0.0" 14 | 15 | # Each entrypoint defined in this section will appear as separate plugin in Snowflake CLI. 16 | # You can enable/disable them separately 17 | [project.entry-points."snowflake.cli.plugin.command"] 18 | = "snowflake_cli_example_plugin.plugin_spec" 19 | -------------------------------------------------------------------------------- /app_streamlit_python/src/module-add/src/main/python/add.py: -------------------------------------------------------------------------------- 1 | # This is where you can create python functions, which can further 2 | # be used to create Snowpark UDFs and Stored Procedures in your setup_script.sql file. 3 | 4 | from snowflake.snowpark import Session 5 | from snowflake.snowpark.functions import lit 6 | 7 | # UDF example: 8 | def add_fn(x: int, y: int) -> int: 9 | return x + y 10 | 11 | 12 | # Stored Procedure example: 13 | def increment_by_one_fn(session: Session, x: int) -> int: 14 | df = session.create_dataframe([[]]).select((lit(1) + lit(x)).as_('RESULT')) 15 | return df.collect()[0]['RESULT'] 16 | -------------------------------------------------------------------------------- /app_streamlit_python/local_test_env.yml: -------------------------------------------------------------------------------- 1 | # This file is used to install packages for local testing 2 | name: streamlit-python-testing 3 | channels: 4 | - snowflake 5 | dependencies: 6 | - python=3.83.10 7 | - pip 8 | - pip: 9 | - pytest 10 | - snowflake-cli-labs>=2.0.0,<3.0.0>=3.0.0 11 | - snowflake-snowpark-python>=1.15.0 12 | - streamlit>=1.28.0 # this version could be different than the streamlit version in Snowflake, and therefore, 100% compatibility is not guaranteed. 13 | -------------------------------------------------------------------------------- /example_snowpark/app/procedures.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import sys 4 | 5 | from common import print_hello 6 | from snowflake.snowpark import Session 7 | 8 | 9 | def hello_procedure(session: Session, name: str) -> str: 10 | return print_hello(name) 11 | 12 | 13 | def test_procedure(session: Session) -> str: 14 | return "Test procedure" 15 | 16 | 17 | # For local debugging 18 | # Beware you may need to type-convert arguments if you add input parameters 19 | if __name__ == "__main__": 20 | # Create a local Snowpark session 21 | with Session.builder.config("local_testing", True).getOrCreate() as session: 22 | print(hello_procedure(session, *sys.argv[1:])) # type: ignore 23 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: Code quality checks 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "*" 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | lint: 14 | name: Check code quality 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | persist-credentials: false 20 | - name: Set up Python 21 | uses: actions/setup-python@v5 22 | with: 23 | python-version: '3.x' 24 | - name: Install pre-commit 25 | run: python -m pip install pre-commit tomlkit 26 | - name: Run pre-commit 27 | run: pre-commit run --all-files 28 | -------------------------------------------------------------------------------- /example_plugin/src/snowflake_cli_example_plugin/plugin_spec.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of plugin_hook, where the new commands should be registered. 3 | """ 4 | 5 | from snowflake.cli.api.plugins.command import ( 6 | CommandPath, 7 | CommandSpec, 8 | CommandType, 9 | plugin_hook_impl, 10 | ) 11 | 12 | from snowflake_cli_example_plugin import commands 13 | 14 | 15 | @plugin_hook_impl 16 | def command_spec(): 17 | return CommandSpec( 18 | # new command will be visible as "snow object COMMAND" 19 | parent_command_path=CommandPath(["object"]), 20 | # choose CommandType.SINGLE_COMMAND for a single command 21 | command_type=CommandType.COMMAND_GROUP, 22 | # link to the commands implementation 23 | typer_instance=commands.app.create_instance(), 24 | ) 25 | -------------------------------------------------------------------------------- /app_streamlit_python/src/module-add/src/test/python/test_add.py: -------------------------------------------------------------------------------- 1 | # This is a sample file that can contain any unit tests for your python code. 2 | # You can use your own testing frameworks as part of the tests too. 3 | import pytest 4 | from add import add_fn, increment_by_one_fn 5 | from unittest.mock import MagicMock 6 | from snowflake.snowpark import Session 7 | from snowflake.snowpark.functions import lit 8 | from functools import partial 9 | 10 | @pytest.fixture() 11 | def session(): 12 | session = Session.builder.config('local_testing', True).create() 13 | yield session 14 | session.close() 15 | 16 | # Unit tests for UDF 17 | def test_add_fn(): 18 | assert add_fn(1, 4) == 5 19 | 20 | # Unit tests for Stored Procedure 21 | def test_increment_by_one_fn(session): 22 | assert increment_by_one_fn(session, 3) == 4 23 | -------------------------------------------------------------------------------- /streamlit_vnext_single_page/snowflake.yml: -------------------------------------------------------------------------------- 1 | definition_version: 2 2 | entities: 3 | : 4 | type: streamlit 5 | identifier: 6 | name: 7 | database: 8 | schema: 9 | title: 10 | main_file: streamlit_app.py 11 | query_warehouse: 12 | runtime_name: SYSTEM$ST_CONTAINER_RUNTIME_PY3_11 13 | compute_pool: 14 | external_access_integrations: 15 | - 16 | artifacts: 17 | - pyproject.toml 18 | - streamlit_app.py 19 | - common/*.py 20 | - README.md 21 | - snowflake.yml 22 | -------------------------------------------------------------------------------- /app_streamlit_js/src/module-ui/src/ui.py: -------------------------------------------------------------------------------- 1 | # Import python packages 2 | import streamlit as st 3 | from snowflake.snowpark import Session 4 | 5 | # Write directly to the app 6 | st.title("Hello Snowflake!") 7 | st.write(""" 8 | The sum of the two numbers is calculated by the JavaScript 9 | core.add() UDF defined in your setup_script.sql. 10 | """) 11 | 12 | num1 = st.number_input('First number', value=1) 13 | num2 = st.number_input('Second number', value=1) 14 | # Get the current credentials 15 | session = Session.builder.getOrCreate() 16 | 17 | # Create an example data frame 18 | data_frame = session.sql("SELECT core.add(%s, %s);" % (num1, num2)) 19 | 20 | # Execute the query and convert it into a Pandas data frame 21 | queried_data = data_frame.to_pandas() 22 | 23 | # Display the Pandas data frame as a Streamlit data frame. 24 | st.dataframe(queried_data, use_container_width=True) 25 | -------------------------------------------------------------------------------- /snowpark_with_external_access/setup.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS ; 2 | CREATE SCHEMA IF NOT EXISTS .; 3 | USE SCHEMA .; 4 | 5 | CREATE SECRET IF NOT EXISTS TYPE = GENERIC_STRING SECRET_STRING = 'very_secret_string'; 6 | 7 | CREATE OR REPLACE NETWORK RULE snowpark_example_network_rule 8 | MODE = EGRESS 9 | TYPE = HOST_PORT 10 | VALUE_LIST = ('docs.snowflake.com'); 11 | 12 | CREATE EXTERNAL ACCESS INTEGRATION IF NOT EXISTS 13 | ALLOWED_NETWORK_RULES = (snowpark_example_network_rule) 14 | ALLOWED_AUTHENTICATION_SECRETS = () 15 | ENABLED = true; 16 | -------------------------------------------------------------------------------- /streamlit_with_external_access/setup.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS ; 2 | CREATE SCHEMA IF NOT EXISTS .; 3 | USE SCHEMA .; 4 | 5 | CREATE SECRET IF NOT EXISTS TYPE = GENERIC_STRING SECRET_STRING = 'very_secret_string'; 6 | 7 | CREATE OR REPLACE NETWORK RULE streamlit_example_network_rule 8 | MODE = EGRESS 9 | TYPE = HOST_PORT 10 | VALUE_LIST = ('docs.snowflake.com'); 11 | 12 | CREATE EXTERNAL ACCESS INTEGRATION IF NOT EXISTS 13 | ALLOWED_NETWORK_RULES = (streamlit_example_network_rule) 14 | ALLOWED_AUTHENTICATION_SECRETS = () 15 | ENABLED = true; 16 | -------------------------------------------------------------------------------- /app_spcs_basic/build-and-push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DB_NAME="spcs_na_db" 3 | SCHEMA_NAME="public" 4 | IMAGE_REPO_NAME="images" 5 | SERVICE_NAME="spcs_na_service" # service_spec.yml and manifest.yml needs to agree with this name as it is the service and image name. 6 | DIR_NAME="./service" 7 | 8 | # make sure the target repository exists 9 | snow sql -q "create database if not exists $DB_NAME" 10 | snow sql -q "create schema if not exists $DB_NAME.$SCHEMA_NAME" 11 | snow sql -q "create image repository if not exists $DB_NAME.$SCHEMA_NAME.$IMAGE_REPO_NAME" 12 | 13 | IMAGE_REPO_URL=$(snow spcs image-repository url $IMAGE_REPO_NAME --database $DB_NAME --schema $SCHEMA_NAME) 14 | IMAGE_FQN="$IMAGE_REPO_URL/$SERVICE_NAME" 15 | 16 | # build and push the image (uses :latest implicitly) 17 | docker buildx build --platform=linux/amd64 -t $IMAGE_FQN $DIR_NAME 18 | snow spcs image-registry login 19 | docker image push $IMAGE_FQN 20 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/snowflake.yml: -------------------------------------------------------------------------------- 1 | definition_version: 2 2 | entities: 3 | : 4 | type: streamlit 5 | identifier: 6 | name: 7 | database: 8 | schema: 9 | title: 10 | main_file: streamlit_app.py 11 | query_warehouse: 12 | runtime_name: SYSTEM$ST_CONTAINER_RUNTIME_PY3_11 13 | compute_pool: 14 | external_access_integrations: 15 | - 16 | pages_dir: app_pages 17 | artifacts: 18 | - pyproject.toml 19 | - streamlit_app.py 20 | - app_pages/*.py 21 | - common/*.py 22 | - README.md 23 | - snowflake.yml 24 | -------------------------------------------------------------------------------- /app_streamlit_java/src/module-ui/src/ui.py: -------------------------------------------------------------------------------- 1 | # Import python packages 2 | import streamlit as st 3 | from snowflake.snowpark.context import get_active_session 4 | 5 | # Write directly to the app 6 | st.title("Hello Snowflake!") 7 | st.write(""" 8 | The sum of the two numbers is calculated by the Java Add.two() function 9 | which is called from core.add() UDF defined in your setup_script.sql. 10 | """) 11 | 12 | num1 = st.number_input('First number', value=1) 13 | num2 = st.number_input('Second number', value=1) 14 | # Get the current credentials 15 | session = get_active_session() 16 | 17 | # Create an example data frame 18 | data_frame = session.sql("SELECT core.add(%s, %s);" % (num1, num2)) 19 | 20 | # Execute the query and convert it into a Pandas data frame 21 | queried_data = data_frame.to_pandas() 22 | 23 | # Display the Pandas data frame as a Streamlit data frame. 24 | st.dataframe(queried_data, use_container_width=True) 25 | -------------------------------------------------------------------------------- /example_streamlit/snowflake.yml: -------------------------------------------------------------------------------- 1 | definition_version: "1.1" 2 | streamlit: 3 | name: 4 | stage: 5 | query_warehouse: 6 | main_file: streamlit_app.py 7 | env_file: environment.yml 8 | pages_dir: pages/ 9 | additional_source_files: 10 | - common/hello.py 11 | definition_version: '2' 12 | entities: 13 | : 14 | type: streamlit 15 | identifier: 16 | name: 17 | main_file: streamlit_app.py 18 | pages_dir: pages 19 | query_warehouse: 20 | stage: 21 | artifacts: 22 | - streamlit_app.py 23 | - environment.yml 24 | - pages 25 | - common/hello.py 26 | 27 | -------------------------------------------------------------------------------- /snowpark_with_external_access/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "3.0.0" 2 | files_to_render: 3 | - snowflake.yml 4 | - README.md 5 | - setup.sql 6 | variables: 7 | - name: database_name 8 | prompt: "Database where the functions and procedures will be created" 9 | type: string 10 | - name: schema_name 11 | prompt: "Schema where the functions and procedures will be created" 12 | type: string 13 | default: public 14 | - name: stage_name 15 | prompt: "What stage should the functions and procedures be deployed to" 16 | default: dev_deployment 17 | type: string 18 | - name: secret_name 19 | prompt: "Secret name to be used in the functions and procedures" 20 | type: string 21 | default: snowpark_secret 22 | - name: external_access_integration_name 23 | prompt: "External access integration name to be used in the functions and procedures" 24 | type: string 25 | default: snowpark_external_access_integration 26 | -------------------------------------------------------------------------------- /app_basic/app/README.md: -------------------------------------------------------------------------------- 1 | ## Welcome to your First Snowflake Native App! 2 | 3 | In this Snowflake Native App, you will be able to explore some basic concepts such as application role, versioned schemas and creating procedures and functions within a setup script. 4 | 5 | For more information about a Snowflake Native App, please read the [official Snowflake documentation](https://docs.snowflake.com/en/developer-guide/native-apps/native-apps-about) which goes in depth about many additional functionalities of this framework. 6 | 7 | ## Using the application after installation 8 | To interact with the application after it has successfully installed in your account, switch to the application owner role first. 9 | 10 | ### Calling a stored procedure 11 | 12 | ``` 13 | CALL ..; 14 | ``` 15 | 16 | ### Calling a function 17 | 18 | ``` 19 | SELECT ..; 20 | ``` 21 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/README.md: -------------------------------------------------------------------------------- 1 | # Multi-page Streamlit App Template 2 | 3 | This template provides a foundation for building multi-page Streamlit applications that connect to Snowflake. It includes: 4 | 5 | - A clean project structure with separate pages in `app_pages/` 6 | - Common utilities for Snowflake connectivity and UI components in `common/` 7 | - Sample pages demonstrating: 8 | - Data fetching from Snowflake 9 | - Data visualization 10 | - Material Design icons 11 | - Top navigation bar (configurable to sidebar) 12 | - App logo (use your own logo, or drop this) 13 | 14 | ## Getting Started 15 | 16 | 1. Update the app name and description in `pyproject.toml` 17 | 2. Configure your Snowflake connection details in `snowflake.yml` 18 | 3. Start building your pages in the `app_pages/` directory 19 | 4. Add new pages to the navigation list in `streamlit_app.py` 20 | 5. Create a `uv` environment using `uv sync` 21 | 6. Run the app using `uv run streamlit run streamlit_app.py` 22 | -------------------------------------------------------------------------------- /streamlit_vnext_single_page/README.md: -------------------------------------------------------------------------------- 1 | # Multi-page Streamlit App Template 2 | 3 | This template provides a foundation for building multi-page Streamlit applications that connect to Snowflake. It includes: 4 | 5 | - A clean project structure with separate pages in `app_pages/` 6 | - Common utilities for Snowflake connectivity and UI components in `common/` 7 | - Sample pages demonstrating: 8 | - Data fetching from Snowflake 9 | - Data visualization 10 | - Material Design icons 11 | - Top navigation bar (configurable to sidebar) 12 | - App logo (use your own logo, or drop this) 13 | 14 | ## Getting Started 15 | 16 | 1. Update the app name and description in `pyproject.toml` 17 | 2. Configure your Snowflake connection details in `snowflake.yml` 18 | 3. Start building your pages in the `app_pages/` directory 19 | 4. Add new pages to the navigation list in `streamlit_app.py` 20 | 5. Create a `uv` environment using `uv sync` 21 | 6. Run the app using `uv run streamlit run streamlit_app.py` 22 | -------------------------------------------------------------------------------- /.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "*" 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | tests: 14 | name: Run tests 15 | runs-on: ${{ matrix.os }} 16 | strategy: 17 | matrix: 18 | os: [ ubuntu-latest, windows-latest ] 19 | cli_version: ['-labs==2.7.0', '-labs==2.8.0', ''] # check 2.X and latest release 20 | steps: 21 | - uses: actions/checkout@v4 22 | with: 23 | persist-credentials: false 24 | - name: Set up Python 25 | uses: actions/setup-python@v5 26 | with: 27 | python-version: '3.11' 28 | - name: Install Snowflake CLI 29 | run: python -m pip install pytest snowflake-snowpark-python click==8.2.1 snowflake-cli${{ matrix.cli_version }} 30 | - name: Run tests 31 | run: python -m pytest .tests/ -vv 32 | -------------------------------------------------------------------------------- /app_spcs_basic/app/manifest.yml: -------------------------------------------------------------------------------- 1 | # For more information on creating manifest, go to https://docs.snowflake.com/en/developer-guide/native-apps/creating-manifest 2 | manifest_version: 1 3 | 4 | version: 5 | name: Dev 6 | label: "Dev Version" 7 | comment: "Default version used for development. Override for actual deployment." 8 | 9 | configuration: 10 | log_level: INFO 11 | trace_level: ALWAYS 12 | grant_callback: setup.create_service 13 | 14 | artifacts: 15 | readme: README.md 16 | 17 | default_web_endpoint: 18 | service: services.spcs_na_service 19 | endpoint: my-endpoint 20 | 21 | setup_script: setup.sql 22 | 23 | container_services: 24 | images: 25 | - /spcs_na_db/public/images/spcs_na_service:latest 26 | 27 | privileges: 28 | - CREATE COMPUTE POOL: 29 | required_at_setup: true 30 | description: "Permission to create compute pools" 31 | - BIND SERVICE ENDPOINT: 32 | required_at_setup: true 33 | description: "Required to create endpoints in services we can assign to functions" 34 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "3.13.0" 2 | files_to_render: 3 | - snowflake.yml 4 | variables: 5 | - name: title 6 | default: My Streamlit App 7 | prompt: "Title of the streamlit app e.g. 'My Streamlit App'" 8 | - name: name 9 | default: my_streamlit_app 10 | prompt: "What is the name of the streamlit app object in Snowflake? e.g. 'my_streamlit_app'" 11 | - name: database 12 | default: my_database 13 | prompt: "What database should the app be deployed to?" 14 | - name: schema 15 | default: my_schema 16 | prompt: "What schema should the app be deployed to?" 17 | - name: query_warehouse 18 | default: my_streamlit_warehouse 19 | prompt: "On which warehouse SQL queries issued by the application are run" 20 | - name: compute_pool 21 | default: my_compute_pool 22 | prompt: "What compute pool should the app use?" 23 | - name: pypi_access_integration 24 | default: pypi_access_integration 25 | prompt: "What is the name of your external access integration for PyPI?" 26 | -------------------------------------------------------------------------------- /streamlit_vnext_single_page/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "3.13.0" 2 | files_to_render: 3 | - snowflake.yml 4 | variables: 5 | - name: title 6 | default: My Streamlit App 7 | prompt: "Title of the streamlit app e.g. 'My Streamlit App'" 8 | - name: name 9 | default: my_streamlit_app 10 | prompt: "What is the name of the streamlit app object in Snowflake? e.g. 'my_streamlit_app'" 11 | - name: database 12 | default: my_database 13 | prompt: "What database should the app be deployed to?" 14 | - name: schema 15 | default: my_schema 16 | prompt: "What schema should the app be deployed to?" 17 | - name: query_warehouse 18 | default: my_streamlit_warehouse 19 | prompt: "On which warehouse SQL queries issued by the application are run" 20 | - name: compute_pool 21 | default: my_compute_pool 22 | prompt: "What compute pool should the app use?" 23 | - name: pypi_access_integration 24 | default: pypi_access_integration 25 | prompt: "What is the name of your external access integration for PyPI?" 26 | -------------------------------------------------------------------------------- /streamlit_with_external_access/template.yml: -------------------------------------------------------------------------------- 1 | minimum_cli_version: "3.0.0" 2 | files_to_render: 3 | - snowflake.yml 4 | - README.md 5 | - setup.sql 6 | variables: 7 | - name: database_name 8 | prompt: "Database where the application will be created" 9 | type: string 10 | - name: schema_name 11 | prompt: "Schema where the application will be created" 12 | type: string 13 | default: public 14 | - name: warehouse_name 15 | prompt: "Warehouse to be used by the application" 16 | type: string 17 | - name: stage_name 18 | prompt: "What stage should the procedures and functions be deployed to" 19 | default: dev_deployment 20 | type: string 21 | - name: secret_name 22 | prompt: "Secret name to be used in the procedures and functions" 23 | type: string 24 | default: streamlit_secret 25 | - name: external_access_integration_name 26 | prompt: "External access integration name to be used in the procedures and functions" 27 | type: string 28 | default: streamlit_external_access_integration 29 | -------------------------------------------------------------------------------- /app_streamlit_python/src/module-ui/test/test_ui.py: -------------------------------------------------------------------------------- 1 | from pytest import fixture 2 | from snowflake.snowpark import Session 3 | from snowflake.snowpark.functions import lit 4 | from streamlit.testing.v1 import AppTest 5 | import add as add 6 | import ui as ui 7 | 8 | @fixture 9 | def session(): 10 | session = Session.builder.config('local_testing', True).create() 11 | yield session 12 | session.close() 13 | 14 | @fixture(autouse=True) 15 | def set_up(session: Session): 16 | session.sproc.register(add.increment_by_one_fn, name='core.increment_by_one') 17 | session.udf.register(add.add_fn, name='core.add') 18 | 19 | def test_streamlit(): 20 | at = AppTest.from_function(ui.run_streamlit) 21 | at.run() 22 | 23 | at.number_input('numToAdd1').set_value(6).run() 24 | at.number_input('numToAdd2').set_value(3).run() 25 | assert (at.dataframe[0].value[:].values == [[9]]).all() 26 | 27 | at.number_input('numToIncrement').set_value(4).run() 28 | assert (at.dataframe[1].value[:].values == [[5]]).all() 29 | assert not at.exception 30 | -------------------------------------------------------------------------------- /app_basic/snowflake.yml: -------------------------------------------------------------------------------- 1 | # This is a project definition file, a required component if you intend to use Snowflake CLI in a project directory such as this template. 2 | 3 | definition_version: 1 4 | native_app: 5 | name: 6 | source_stage: app_src.stage 7 | artifacts: 8 | - src: app/* 9 | dest: ./ 10 | 11 | definition_version: 2 12 | entities: 13 | pkg: 14 | type: application package 15 | identifier: <% fn.concat_ids('_pkg', ctx.env.suffix) %> 16 | artifacts: 17 | - src: app/* 18 | dest: ./ 19 | 20 | manifest: app/manifest.yml 21 | 22 | app: 23 | type: application 24 | from: 25 | target: pkg 26 | identifier: <% fn.concat_ids('', ctx.env.suffix) %> 27 | 28 | env: 29 | suffix: <% fn.concat_ids('_', fn.sanitize_id(fn.get_username('unknown_user')) | lower) %> 30 | 31 | -------------------------------------------------------------------------------- /app_spcs_basic/snowflake.yml: -------------------------------------------------------------------------------- 1 | # This is a project definition file, a required component if you intend to use Snowflake CLI in a project directory such as this template. 2 | 3 | definition_version: 1 4 | native_app: 5 | name: 6 | source_stage: app_src.stage 7 | artifacts: 8 | - src: app/* 9 | dest: ./ 10 | 11 | definition_version: 2 12 | entities: 13 | pkg: 14 | type: application package 15 | identifier: <% fn.concat_ids('_pkg', ctx.env.suffix) %> 16 | artifacts: 17 | - src: app/* 18 | dest: ./ 19 | 20 | manifest: app/manifest.yml 21 | 22 | 23 | app: 24 | type: application 25 | from: 26 | target: pkg 27 | identifier: <% fn.concat_ids('', ctx.env.suffix) %> 28 | 29 | env: 30 | suffix: <% fn.concat_ids('_', fn.sanitize_id(fn.get_username('unknown_user')) | lower) %> 31 | 32 | -------------------------------------------------------------------------------- /app_streamlit_java/scripts/shared-content.sql: -------------------------------------------------------------------------------- 1 | -- An example script to share your data with consumer -- 2 | 3 | -- Scenario: You want to create an application package which is able to access some data that resides in a different database in your account. 4 | -- Let this database be called past_add_transactions, with a schema called core, and a table in the schema called transactions. 5 | 6 | -- To share past_add_transactions.core.transactions with your application package, we recommend carrying out the following steps: 7 | -- 1. Create a view over the table past_add_transactions.core.transactions that can be shared with the application package, such as past_add_transactions.core.transactions_v; 8 | -- 2. Grant reference_usage on database past_add_transactions to share in application package; 9 | -- 3. Grant usage on schema past_add_transactions.core to share in the application package; 10 | -- 4. Grant select/any required privilege on the view past_add_transactions.core.transactions_v to share in application package; 11 | 12 | -- For more information, refer to https://docs.snowflake.com/en/developer-guide/native-apps/preparing-data-content 13 | -------------------------------------------------------------------------------- /app_streamlit_js/scripts/shared-content.sql: -------------------------------------------------------------------------------- 1 | -- An example script to share your data with consumer -- 2 | 3 | -- Scenario: You want to create an application package which is able to access some data that resides in a different database in your account. 4 | -- Let this database be called past_add_transactions, with a schema called core, and a table in the schema called transactions. 5 | 6 | -- To share past_add_transactions.core.transactions with your application package, we recommend carrying out the following steps: 7 | -- 1. Create a view over the table past_add_transactions.core.transactions that can be shared with the application package, such as past_add_transactions.core.transactions_v; 8 | -- 2. Grant reference_usage on database past_add_transactions to share in application package; 9 | -- 3. Grant usage on schema past_add_transactions.core to share in the application package; 10 | -- 4. Grant select/any required privilege on the view past_add_transactions.core.transactions_v to share in application package; 11 | 12 | -- For more information, refer to https://docs.snowflake.com/en/developer-guide/native-apps/preparing-data-content 13 | -------------------------------------------------------------------------------- /app_streamlit_python/scripts/shared-content.sql: -------------------------------------------------------------------------------- 1 | -- An example script to share your data with consumer -- 2 | 3 | -- Scenario: You want to create an application package which is able to access some data that resides in a different database in your account. 4 | -- Let this database be called past_add_transactions, with a schema called core, and a table in the schema called transactions. 5 | 6 | -- To share past_add_transactions.core.transactions with your application package, we recommend carrying out the following steps: 7 | -- 1. Create a view over the table past_add_transactions.core.transactions that can be shared with the application package, such as past_add_transactions.core.transactions_v; 8 | -- 2. Grant reference_usage on database past_add_transactions to share in application package; 9 | -- 3. Grant usage on schema past_add_transactions.core to share in the application package; 10 | -- 4. Grant select/any required privilege on the view past_add_transactions.core.transactions_v to share in application package; 11 | 12 | -- For more information, refer to https://docs.snowflake.com/en/developer-guide/native-apps/preparing-data-content 13 | -------------------------------------------------------------------------------- /dcm_project/definitions/access.sql: -------------------------------------------------------------------------------- 1 | define warehouse DCM_PROJECT_WH_{{db}} 2 | with 3 | warehouse_size = '{{wh_size}}' 4 | auto_suspend = 5 5 | comment = 'For Quickstart Demo of DCM Projects PrPr' 6 | ; 7 | 8 | define role DCM_PROJECT_{{role}}_READ; 9 | grant role DCM_PROJECT_{{role}}_READ to user ; 10 | 11 | 12 | grant USAGE on database DCM_PROJECT_{{db}} to role DCM_PROJECT_{{role}}_READ; 13 | 14 | grant usage on schema DCM_PROJECT_{{db}}.RAW to role DCM_PROJECT_{{role}}_READ; 15 | grant usage on schema DCM_PROJECT_{{db}}.ANALYTICS to role DCM_PROJECT_{{role}}_READ; 16 | grant usage on schema DCM_PROJECT_{{db}}.SERVE to role DCM_PROJECT_{{role}}_READ; 17 | grant usage on warehouse DCM_PROJECT_WH_{{db}} to role DCM_PROJECT_{{role}}_READ; 18 | 19 | 20 | grant select on all tables in database DCM_PROJECT_{{db}} to role DCM_PROJECT_{{role}}_READ; 21 | 22 | --grant SELECT on ALL dynamic tables in database DCM_PROJECT_{{db}} to role DCM_PROJECT_{{role}}_READ; 23 | -- //awaiting bug fix to roll out 24 | 25 | grant select on all views in database DCM_PROJECT_{{db}} to role DCM_PROJECT_{{role}}_READ; 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Snowflake CLI project templates 2 | 3 | This repository collects templates to be used with `snow init` command of 4 | [Snowflake CLI](https://github.com/snowflakedb/snowflake-cli). 5 | For more details, check the 6 | [documentation](https://docs.snowflake.com/en/developer-guide/snowflake-cli-v2/bootstrap-project/bootstrap). 7 | 8 | ## Contributing 9 | 10 | ### Issues or feature requests 11 | If you want to report as issue or request a new feature, please do so in 12 | [Snowflake CLI project repository](https://github.com/snowflakedb/snowflake-cli/issues). 13 | 14 | ### Custom templates 15 | Check the 16 | [documentation](https://docs.snowflake.com/en/developer-guide/snowflake-cli-v2/bootstrap-project/bootstrap#label-cli-project-templating-custom-templates) 17 | on how to create a custom project template. You can use `snow init` command of 18 | [Snowflake CLI](https://github.com/snowflakedb/snowflake-cli) for testing. 19 | 20 | If you want to request your template to be added to this repository, please 21 | create an issue in [Snowflake CLI project repository](https://github.com/snowflakedb/snowflake-cli/issues) with a link to 22 | the [pull request](https://github.com/snowflakedb/snowflake-cli-templates/pulls) 23 | for us to review. 24 | -------------------------------------------------------------------------------- /streamlit_vnext_single_page/streamlit_app.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | 3 | from common.snowflake_connection import SAMPLE_DATAFRAME_SQL, run_query 4 | from common.ui import APP_NAME 5 | 6 | f""" 7 | # {APP_NAME} 8 | 9 | Welcome to the home page of my app! 10 | 11 | Let's collect data from Snowflake and display it in a dataframe. 12 | """ 13 | 14 | df = run_query(SAMPLE_DATAFRAME_SQL) 15 | 16 | 17 | st.dataframe( 18 | df, 19 | column_config={ 20 | "TIMESTAMP": st.column_config.DatetimeColumn( 21 | "Timestamp", format="DD/MM/YY HH:mm" 22 | ), 23 | "CHART_DATA": st.column_config.AreaChartColumn("Chart Data"), 24 | "PROGRESS": st.column_config.ProgressColumn( 25 | "Progress", min_value=0, max_value=1 26 | ), 27 | "STATUS": st.column_config.SelectboxColumn( 28 | "Status", options=["Low", "Medium", "High"] 29 | ), 30 | }, 31 | hide_index=True, 32 | ) 33 | 34 | 35 | """ 36 | Cool, right? You can discover the SQL query by expanding the code block below. 37 | """ 38 | 39 | st.expander("View SQL query", expanded=False, icon=":material/code:").code( 40 | SAMPLE_DATAFRAME_SQL 41 | ) 42 | 43 | """ 44 | Now, time to use your own data and build your beautiful data app, **enjoy!** :material/celebration: 45 | """ 46 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/app_pages/home_page.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | 3 | from common.snowflake_connection import SAMPLE_DATAFRAME_SQL, run_query 4 | from common.ui import APP_NAME 5 | 6 | f""" 7 | # {APP_NAME} 8 | 9 | Welcome to the home page of my app! 10 | 11 | Let's collect data from Snowflake and display it in a dataframe. 12 | """ 13 | 14 | df = run_query(SAMPLE_DATAFRAME_SQL) 15 | 16 | 17 | st.dataframe( 18 | df, 19 | column_config={ 20 | "TIMESTAMP": st.column_config.DatetimeColumn( 21 | "Timestamp", format="DD/MM/YY HH:mm" 22 | ), 23 | "CHART_DATA": st.column_config.AreaChartColumn("Chart Data"), 24 | "PROGRESS": st.column_config.ProgressColumn( 25 | "Progress", min_value=0, max_value=1 26 | ), 27 | "STATUS": st.column_config.SelectboxColumn( 28 | "Status", options=["Low", "Medium", "High"] 29 | ), 30 | }, 31 | hide_index=True, 32 | ) 33 | 34 | 35 | """ 36 | Cool, right? You can discover the SQL query by expanding the code block below. 37 | """ 38 | 39 | st.expander("View SQL query", expanded=False, icon=":material/code:").code( 40 | SAMPLE_DATAFRAME_SQL 41 | ) 42 | 43 | """ 44 | Now, time to use your own data and build your beautiful data app, **enjoy!** :material/celebration: 45 | """ 46 | -------------------------------------------------------------------------------- /.tests/test_V2_definition_has_cli_version_limit.py: -------------------------------------------------------------------------------- 1 | import re 2 | from pathlib import Path 3 | 4 | import pytest 5 | 6 | _REPO_ROOT = Path(__file__).parent.parent 7 | 8 | 9 | def iter_all_templates(): 10 | return ( 11 | # "str" to make tests parameters human-readable 12 | str(x.relative_to(_REPO_ROOT).parent) 13 | for x in _REPO_ROOT.rglob("**/template.yml") 14 | ) 15 | 16 | 17 | def template_has_cli_version_limit(template_root: Path) -> bool: 18 | return "minimum_cli_version" in (template_root / "template.yml").read_text() 19 | 20 | 21 | def is_snowflake_yml_V2(template_root: Path) -> bool: 22 | for file in template_root.rglob("snowflake.yml"): 23 | for line in file.read_text().splitlines(): 24 | if re.match(r".*definition_version:\s+.?2.*", line): 25 | return True 26 | return False 27 | 28 | 29 | @pytest.mark.parametrize("template_root", iter_all_templates()) 30 | def test_V2_template_has_cli_version_limit(template_root): 31 | template_path = _REPO_ROOT / template_root 32 | if not is_snowflake_yml_V2(template_path): 33 | pytest.skip("No snowflake.yml in definition version 2 found") 34 | 35 | assert template_has_cli_version_limit( 36 | template_path 37 | ), "snowflake.yml V2 is not supported in Snowflake CLI 2.X. Please add 'minimum_cli_version: 3.0.0' to template.yml" 38 | -------------------------------------------------------------------------------- /app_streamlit_java/src/module-add/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | com.snowflake.add 8 | add 9 | 1.0-SNAPSHOT 10 | 11 | add 12 | 13 | 14 | UTF-8 15 | 1.8 16 | 1.8 17 | 11 18 | 19 | 20 | 21 | 22 | junit 23 | junit 24 | 4.13.1 25 | test 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-compiler-plugin 35 | 3.8.1 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /streamlit_with_external_access/snowflake.yml: -------------------------------------------------------------------------------- 1 | # For more information about structure of snowflake.yml for Streamlit see 2 | # https://docs.snowflake.com/developer-guide/snowflake-cli/streamlit-apps/manage-apps/initialize-app#create-the-project-definition-for-a-streamlit-app 3 | definition_version: '2' 4 | entities: 5 | dashboard: 6 | type: 'streamlit' 7 | # Uses context variables to create fully qualified name of the dashboard 8 | identifier: 9 | name: 'dashboard' 10 | schema: <% ctx.env.schema %> 11 | database: <% ctx.env.database %> 12 | query_warehouse: 13 | artifacts: 14 | - streamlit_app.py 15 | meta: 16 | use_mixins: 17 | - external_access 18 | - deployment_stage 19 | 20 | mixins: 21 | # This mixin defines shared configuration for external access 22 | external_access: 23 | secrets: 24 | # generic_secret is key used by get_secret_value method to reference the secret 25 | generic_secret: 26 | external_access_integrations: 27 | - 28 | 29 | deployment_stage: 30 | # Uses context variables to create fully qualified name of stage 31 | stage: <% ctx.env.database %>.<% ctx.env.schema %>. 32 | 33 | env: 34 | schema: 35 | database: 36 | -------------------------------------------------------------------------------- /streamlit_with_external_access/README.md: -------------------------------------------------------------------------------- 1 | # Streamlit application with external access 2 | 3 | This is a simple example of a Streamlit application that requires external access. 4 | 5 | ## Prerequisites 6 | This project requires a database, API integration and secret. To created them you can execute convenience script 7 | `snow sql -f setup.sql` or run the following SQL commands: 8 | 9 | ```sql 10 | CREATE DATABASE IF NOT EXISTS ; 11 | CREATE SCHEMA IF NOT EXISTS .; 12 | USE SCHEMA .; 13 | 14 | CREATE SECRET IF NOT EXISTS TYPE = GENERIC_STRING SECRET_STRING = 'very_secret_string'; 15 | 16 | CREATE OR REPLACE NETWORK RULE streamlit_example_network_rule 17 | MODE = EGRESS 18 | TYPE = HOST_PORT 19 | VALUE_LIST = ('docs.snowflake.com'); 20 | 21 | CREATE EXTERNAL ACCESS INTEGRATION IF NOT EXISTS 22 | ALLOWED_NETWORK_RULES = (streamlit_example_network_rule) 23 | ALLOWED_AUTHENTICATION_SECRETS = () 24 | ENABLED = true; 25 | ``` 26 | 27 | ## Deploying the streamlit application 28 | _For more information see [deploy documentation](https://docs.snowflake.com/developer-guide/snowflake-cli/streamlit-apps/manage-apps/deploy-app)._ 29 | 30 | To deploy the Streamlit application, you should run: 31 | 32 | ```bash 33 | snow streamlit deploy 34 | ``` 35 | -------------------------------------------------------------------------------- /app_streamlit_js/app/setup_script.sql: -------------------------------------------------------------------------------- 1 | -- This is the setup script that runs while installing a Snowflake Native App in a consumer account. 2 | -- For more information on how to create setup file, visit https://docs.snowflake.com/en/developer-guide/native-apps/creating-setup-script 3 | 4 | -- A general guideline to building this script looks like: 5 | -- 1. Create application roles 6 | CREATE APPLICATION ROLE IF NOT EXISTS app_public; 7 | 8 | -- 2. Create a versioned schema to hold those UDFs/Stored Procedures 9 | CREATE OR ALTER VERSIONED SCHEMA core; 10 | GRANT USAGE ON SCHEMA core TO APPLICATION ROLE app_public; 11 | 12 | -- 3. Create UDFs and Stored Procedures using the JavaScript handler. 13 | CREATE or REPLACE FUNCTION core.add(NUM1 DOUBLE, NUM2 DOUBLE) 14 | RETURNS DOUBLE 15 | LANGUAGE JAVASCRIPT 16 | AS 'return NUM1 + NUM2;'; 17 | 18 | -- 4. Grant appropriate privileges over these objects to your application roles. 19 | GRANT USAGE ON FUNCTION core.add(DOUBLE, DOUBLE) TO APPLICATION ROLE app_public; 20 | 21 | -- 5. Create a streamlit object using the code you wrote in you wrote in src/module-ui, as shown below. 22 | -- The `from` value is derived from the stage path described in snowflake.yml 23 | CREATE OR REPLACE STREAMLIT core.ui 24 | FROM '/streamlit/' 25 | MAIN_FILE = 'ui.py'; 26 | 27 | 28 | -- 6. Grant appropriate privileges over these objects to your application roles. 29 | GRANT USAGE ON STREAMLIT core.ui TO APPLICATION ROLE app_public; 30 | 31 | -- A detailed explanation can be found at https://docs.snowflake.com/en/developer-guide/native-apps/adding-streamlit 32 | -------------------------------------------------------------------------------- /app_basic/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This is the basic project template for a Snowflake Native App project. It contains minimal code meant to help you set up your first application object in your account quickly. 4 | 5 | ### Project Structure 6 | | File Name | Purpose | 7 | | --------- | ------- | 8 | | README.md | The current file you are looking at, meant to guide you through a Snowflake Native App project. | 9 | | app/setup_script.sql | Contains SQL statements that are run when an account installs or upgrades a Snowflake Native App. | 10 | | app/manifest.yml | Defines properties required by the application package. Find more details at the [Manifest Documentation.](https://docs.snowflake.com/en/developer-guide/native-apps/creating-manifest) 11 | | app/README.md | Exposed to the account installing the Snowflake Native App with details on what it does and how to use it. | 12 | | snowflake.yml | Used by the Snowflake CLI tool to discover your project's code and interact with your Snowflake account with all relevant prvileges and grants. | 13 | 14 | ### Adding a snowflake.local.yml file 15 | Though your project directory already comes with a `snowflake.yml` file, an individual developer can choose to customize the behavior of the Snowflake CLI by providing local overrides to `snowflake.yml`, such as a new role to test out your own application package. This is where you can use `snowflake.local.yml`, which is not a version-controlled file. 16 | 17 | For more information, please refer to the Snowflake Documentation on installing and using Snowflake CLI to create a Snowflake Native App. 18 | 19 | -------------------------------------------------------------------------------- /app_streamlit_java/app/setup_script.sql: -------------------------------------------------------------------------------- 1 | -- This is the setup script that runs while installing a Snowflake Native App in a consumer account. 2 | -- For more information on how to create setup file, visit https://docs.snowflake.com/en/developer-guide/native-apps/creating-setup-script 3 | 4 | -- A general guideline to building this script looks like: 5 | -- 1. Create application roles 6 | CREATE APPLICATION ROLE IF NOT EXISTS app_public; 7 | 8 | -- 2. Create a versioned schema to hold those UDFs/Stored Procedures 9 | CREATE OR ALTER VERSIONED SCHEMA core; 10 | GRANT USAGE ON SCHEMA core TO APPLICATION ROLE app_public; 11 | 12 | -- 3. Create UDFs and Stored Procedures using the java code you wrote in src/module-add, as shown below. 13 | CREATE or REPLACE FUNCTION core.add(num1 NUMBER, num2 NUMBER) 14 | RETURNS NUMBER 15 | LANGUAGE JAVA 16 | IMPORTS = ('/module-add/add-1.0-SNAPSHOT.jar') 17 | HANDLER='com.snowflake.add.Add.two'; 18 | 19 | -- 4. Grant appropriate privileges over these objects to your application roles. 20 | GRANT USAGE ON FUNCTION core.add(NUMBER, NUMBER) TO APPLICATION ROLE app_public; 21 | 22 | -- 5. Create a streamlit object using the code you wrote in you wrote in src/module-ui, as shown below. 23 | -- The `from` value is derived from the stage path described in snowflake.yml 24 | CREATE OR REPLACE STREAMLIT core.ui 25 | FROM '/streamlit/' 26 | MAIN_FILE = 'ui.py'; 27 | 28 | 29 | -- 6. Grant appropriate privileges over these objects to your application roles. 30 | GRANT USAGE ON STREAMLIT core.ui TO APPLICATION ROLE app_public; 31 | 32 | -- A detailed explanation can be found at https://docs.snowflake.com/en/developer-guide/native-apps/adding-streamlit 33 | -------------------------------------------------------------------------------- /streamlit_vnext_multi_page/common/snowflake_connection.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Sequence 2 | 3 | import pandas as pd 4 | import streamlit as st 5 | from snowflake.snowpark import Session 6 | from streamlit.connections import SnowflakeConnection 7 | 8 | # This is the duration for which query results are cached (= 1 hour). 9 | # You can set it to None to disable caching. 10 | CACHE_TTL = "1h" 11 | 12 | 13 | def get_connection() -> SnowflakeConnection: 14 | return st.connection("snowflake", type="snowflake") 15 | 16 | 17 | def get_session() -> Session: 18 | if "_snowflake_session" not in st.session_state: 19 | st.session_state._snowflake_session = get_connection().session() 20 | return st.session_state._snowflake_session 21 | 22 | 23 | @st.cache_data(ttl=CACHE_TTL, show_spinner=False) 24 | def run_query(sql: str, params: Sequence[Any] | None = None) -> pd.DataFrame: 25 | """Execute SQL and return a Pandas DataFrame. 26 | 27 | Parameters 28 | ---------- 29 | sql: str 30 | The SQL statement with optional "?" placeholders. 31 | params: Sequence[Any] | None 32 | Positional parameters to bind to placeholders. 33 | """ 34 | session = get_session() 35 | return session.sql(sql, params=params).to_pandas() 36 | 37 | 38 | SAMPLE_DATAFRAME_SQL = """ 39 | SELECT 40 | CURRENT_TIMESTAMP() as timestamp, 41 | ARRAY_CONSTRUCT( 42 | 0, 43 | 25, 44 | 2, 45 | 6, 46 | 10, 47 | 15, 48 | 6, 49 | 1, 50 | 5 51 | ) as chart_data, 52 | .3 as progress, 53 | CASE 54 | WHEN RANDOM() < 0.33 THEN 'Low' 55 | WHEN RANDOM() < 0.66 THEN 'Medium' 56 | ELSE 'High' 57 | END as status 58 | """ 59 | -------------------------------------------------------------------------------- /streamlit_vnext_single_page/common/snowflake_connection.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Sequence 2 | 3 | import pandas as pd 4 | import streamlit as st 5 | from snowflake.snowpark import Session 6 | from streamlit.connections import SnowflakeConnection 7 | 8 | # This is the duration for which query results are cached (= 1 hour). 9 | # You can set it to None to disable caching. 10 | CACHE_TTL = "1h" 11 | 12 | 13 | def get_connection() -> SnowflakeConnection: 14 | return st.connection("snowflake", type="snowflake") 15 | 16 | 17 | def get_session() -> Session: 18 | if "_snowflake_session" not in st.session_state: 19 | st.session_state._snowflake_session = get_connection().session() 20 | return st.session_state._snowflake_session 21 | 22 | 23 | @st.cache_data(ttl=CACHE_TTL, show_spinner=False) 24 | def run_query(sql: str, params: Sequence[Any] | None = None) -> pd.DataFrame: 25 | """Execute SQL and return a Pandas DataFrame. 26 | 27 | Parameters 28 | ---------- 29 | sql: str 30 | The SQL statement with optional "?" placeholders. 31 | params: Sequence[Any] | None 32 | Positional parameters to bind to placeholders. 33 | """ 34 | session = get_session() 35 | return session.sql(sql, params=params).to_pandas() 36 | 37 | 38 | SAMPLE_DATAFRAME_SQL = """ 39 | SELECT 40 | CURRENT_TIMESTAMP() as timestamp, 41 | ARRAY_CONSTRUCT( 42 | 0, 43 | 25, 44 | 2, 45 | 6, 46 | 10, 47 | 15, 48 | 6, 49 | 1, 50 | 5 51 | ) as chart_data, 52 | .3 as progress, 53 | CASE 54 | WHEN RANDOM() < 0.33 THEN 'Low' 55 | WHEN RANDOM() < 0.66 THEN 'Medium' 56 | ELSE 'High' 57 | END as status 58 | """ 59 | -------------------------------------------------------------------------------- /app_streamlit_js/snowflake.yml: -------------------------------------------------------------------------------- 1 | # This is a project definition file, a required component if you intend to use Snowflake CLI in a project directory such as this template. 2 | 3 | definition_version: 1 4 | native_app: 5 | name: 6 | source_stage: app_src.stage 7 | artifacts: 8 | - src: app/* 9 | dest: ./ 10 | - src: src/module-ui/src/* 11 | dest: streamlit/ 12 | 13 | definition_version: 2 14 | entities: 15 | pkg: 16 | type: application package 17 | identifier: <% fn.concat_ids('_pkg', ctx.env.suffix) %> 18 | artifacts: 19 | - src: app/* 20 | dest: ./ 21 | - src: src/module-ui/src/* 22 | dest: streamlit/ 23 | 24 | manifest: app/manifest.yml 25 | 26 | 27 | app: 28 | type: application 29 | from: 30 | target: pkg 31 | identifier: <% fn.concat_ids('', ctx.env.suffix) %> 32 | 33 | env: 34 | suffix: <% fn.concat_ids('_', fn.sanitize_id(fn.get_username('unknown_user')) | lower) %> 35 | 36 | 37 | 38 | # If you added any sql scripts under scripts/, you should add the following snippet after `artifacts` under `native_app`. 39 | # package: 40 | # scripts: 41 | # - scripts/any-provider-setup.sql 42 | # - scripts/shared-content.sql 43 | 44 | # If you added any sql scripts under scripts/, you should add the following snippet after `artifacts` under `entities.pkg`: 45 | # meta: 46 | # post_deploy: 47 | # - sql_script: scripts/any-provider-setup.sql 48 | # - sql_script: scripts/shared-content.sql 49 | 50 | -------------------------------------------------------------------------------- /dcm_project/definitions/raw.sql: -------------------------------------------------------------------------------- 1 | define database DCM_PROJECT_{{db}} 2 | comment = 'This is a Quickstart Demo for DCM Projects Private Preview'; 3 | 4 | define schema DCM_PROJECT_{{db}}.RAW; 5 | 6 | 7 | define table DCM_PROJECT_{{db}}.RAW.ALL_ITEMS( 8 | ITEM_NAME varchar, 9 | ITEM_ID varchar, 10 | ITEM_CATEGORY array 11 | ) 12 | change_tracking = true; 13 | 14 | 15 | define table DCM_PROJECT_{{db}}.RAW.ALL_REGIONS( 16 | REGION varchar, 17 | REGION_ID number, 18 | COUNTRY varchar, 19 | CATEGORIES array, 20 | ONLINE boolean 21 | ) 22 | change_tracking = true; 23 | 24 | 25 | define table DCM_PROJECT_{{db}}.RAW.INVENTORY( 26 | ITEM_ID number, 27 | REGION_ID number, 28 | IN_STOCK number, 29 | COUNTED_ON date 30 | ) 31 | change_tracking = true; 32 | 33 | 34 | 35 | define table DCM_PROJECT_{{db}}.RAW.MENU ( 36 | MENU_ITEM_ID number, 37 | MENU_ITEM_NAME varchar, 38 | ITEM_CATEGORY varchar, 39 | COST_OF_GOODS_USD number(10, 2), 40 | SALE_PRICE_USD number(10, 2) 41 | ) 42 | change_tracking = true; 43 | 44 | define table DCM_PROJECT_{{db}}.RAW.TRUCK ( 45 | TRUCK_ID number, 46 | TRUCK_BRAND_NAME varchar, 47 | MENU_TYPE varchar 48 | ) 49 | change_tracking = true; 50 | 51 | define table DCM_PROJECT_{{db}}.RAW.CUSTOMER ( 52 | CUSTOMER_ID number, 53 | FIRST_NAME varchar, 54 | LAST_NAME varchar, 55 | CITY varchar 56 | ) 57 | change_tracking = true; 58 | 59 | define table DCM_PROJECT_{{db}}.RAW.ORDER_HEADER ( 60 | ORDER_ID number, 61 | CUSTOMER_ID number, 62 | TRUCK_ID number, 63 | ORDER_TS timestamp_ntz -- Using a timezone-neutral timestamp 64 | ) 65 | change_tracking = true 66 | ; 67 | 68 | define table DCM_PROJECT_{{db}}.RAW.ORDER_DETAIL ( 69 | ORDER_ID number, 70 | MENU_ITEM_ID number, 71 | QUANTITY number 72 | ) 73 | change_tracking = true; 74 | -------------------------------------------------------------------------------- /snowpark_with_external_access/snowflake.yml: -------------------------------------------------------------------------------- 1 | # For more information about structure of snowflake.yml for Snowpark see 2 | # https://docs.snowflake.com/en/developer-guide/snowflake-cli/snowpark/create 3 | definition_version: '2' 4 | entities: 5 | request_function: 6 | type: function 7 | # Uses context variables to create fully qualified name of the function 8 | identifier: 9 | name: request_function 10 | schema: <% ctx.env.schema %> 11 | database: <% ctx.env.database %> 12 | handler: functions.request_function 13 | returns: string 14 | # No arguments for this function 15 | signature: "" 16 | meta: 17 | use_mixins: 18 | - external_access 19 | - snowpark_shared 20 | 21 | request_procedure: 22 | type: procedure 23 | # Uses context variables to create fully qualified name of the procedure 24 | identifier: 25 | name: request_procedure 26 | schema: <% ctx.env.schema %> 27 | database: <% ctx.env.database %> 28 | handler: procedures.request_procedure 29 | returns: string 30 | # No arguments for this procedure 31 | signature: "" 32 | meta: 33 | use_mixins: 34 | - external_access 35 | - snowpark_shared 36 | 37 | mixins: 38 | # This mixin defines shared configuration for external access 39 | external_access: 40 | secrets: 41 | # generic_secret is key used by the get_secret_value method to reference the secret 42 | generic_secret: 43 | external_access_integrations: 44 | - 45 | snowpark_shared: 46 | artifacts: 47 | - app/ 48 | stage: <% ctx.env.database %>.<% ctx.env.schema %>. 49 | 50 | env: 51 | schema: 52 | database: 53 | -------------------------------------------------------------------------------- /example_snowpark/snowflake.yml: -------------------------------------------------------------------------------- 1 | definition_version: "1.1" 2 | snowpark: 3 | project_name: "" 4 | stage_name: "" 5 | src: "app/" 6 | functions: 7 | - name: hello_function 8 | handler: "functions.hello_function" 9 | signature: 10 | - name: "name" 11 | type: "string" 12 | returns: string 13 | procedures: 14 | - name: hello_procedure 15 | handler: "procedures.hello_procedure" 16 | signature: 17 | - name: "name" 18 | type: "string" 19 | returns: string 20 | - name: test_procedure 21 | handler: "procedures.test_procedure" 22 | signature: "" 23 | returns: string 24 | definition_version: '2' 25 | 26 | mixins: 27 | snowpark_shared: 28 | artifacts: 29 | - dest: 30 | src: app/ 31 | stage: 32 | 33 | entities: 34 | 35 | hello_function: 36 | type: function 37 | identifier: 38 | name: hello_function 39 | handler: functions.hello_function 40 | signature: 41 | - name: name 42 | type: string 43 | returns: string 44 | meta: 45 | use_mixins: 46 | - snowpark_shared 47 | 48 | hello_procedure: 49 | type: procedure 50 | identifier: 51 | name: hello_procedure 52 | handler: procedures.hello_procedure 53 | signature: 54 | - name: name 55 | type: string 56 | returns: string 57 | meta: 58 | use_mixins: 59 | - snowpark_shared 60 | 61 | test_procedure: 62 | type: procedure 63 | identifier: 64 | name: test_procedure 65 | handler: procedures.test_procedure 66 | signature: '' 67 | returns: string 68 | meta: 69 | use_mixins: 70 | - snowpark_shared 71 | 72 | -------------------------------------------------------------------------------- /app_streamlit_python/snowflake.yml: -------------------------------------------------------------------------------- 1 | # This is a project definition file, a required component if you intend to use Snowflake CLI in a project directory such as this template. 2 | 3 | definition_version: 1 4 | native_app: 5 | name: 6 | source_stage: app_src.stage 7 | artifacts: 8 | - src: app/* 9 | dest: ./ 10 | - src: src/module-add/src/main/python/add.py 11 | dest: module-add/add.py 12 | - src: src/module-ui/src/* 13 | dest: streamlit/ 14 | 15 | definition_version: 2 16 | entities: 17 | pkg: 18 | type: application package 19 | identifier: <% fn.concat_ids('_pkg', ctx.env.suffix) %> 20 | artifacts: 21 | - src: app/* 22 | dest: ./ 23 | - src: src/module-add/src/main/python/add.py 24 | dest: module-add/add.py 25 | - src: src/module-ui/src/* 26 | dest: streamlit/ 27 | 28 | manifest: app/manifest.yml 29 | 30 | 31 | app: 32 | type: application 33 | from: 34 | target: pkg 35 | identifier: <% fn.concat_ids('', ctx.env.suffix) %> 36 | 37 | env: 38 | suffix: <% fn.concat_ids('_', fn.sanitize_id(fn.get_username('unknown_user')) | lower) %> 39 | 40 | 41 | 42 | # If you added any sql scripts under scripts/, you should add the following snippet after `artifacts` under `native_app`. 43 | # package: 44 | # scripts: 45 | # - scripts/any-provider-setup.sql 46 | # - scripts/shared-content.sql 47 | 48 | # If you added any sql scripts under scripts/, you should add the following snippet after `artifacts` under `entities.pkg`: 49 | # meta: 50 | # post_deploy: 51 | # - sql_script: scripts/any-provider-setup.sql 52 | # - sql_script: scripts/shared-content.sql 53 | 54 | -------------------------------------------------------------------------------- /app_streamlit_java/snowflake.yml: -------------------------------------------------------------------------------- 1 | # This is a project definition file, a required component if you intend to use Snowflake CLI in a project directory such as this template. 2 | 3 | definition_version: 1 4 | native_app: 5 | name: 6 | source_stage: app_src.stage 7 | artifacts: 8 | - src: app/* 9 | dest: ./ 10 | - src: src/module-add/target/add-1.0-SNAPSHOT.jar 11 | dest: module-add/add-1.0-SNAPSHOT.jar 12 | - src: src/module-ui/src/* 13 | dest: streamlit/ 14 | 15 | definition_version: 2 16 | entities: 17 | pkg: 18 | type: application package 19 | identifier: <% fn.concat_ids('_pkg', ctx.env.suffix) %> 20 | artifacts: 21 | - src: app/* 22 | dest: ./ 23 | - src: src/module-add/target/add-1.0-SNAPSHOT.jar 24 | dest: module-add/add-1.0-SNAPSHOT.jar 25 | - src: src/module-ui/src/* 26 | dest: streamlit/ 27 | 28 | manifest: app/manifest.yml 29 | 30 | 31 | app: 32 | type: application 33 | from: 34 | target: pkg 35 | identifier: <% fn.concat_ids('', ctx.env.suffix) %> 36 | 37 | env: 38 | suffix: <% fn.concat_ids('_', fn.sanitize_id(fn.get_username('unknown_user')) | lower) %> 39 | 40 | 41 | 42 | # If you added any sql scripts under scripts/, you should add the following snippet after `artifacts` under `native_app`. 43 | # package: 44 | # scripts: 45 | # - scripts/any-provider-setup.sql 46 | # - scripts/shared-content.sql 47 | 48 | # If you added any sql scripts under scripts/, you should add the following snippet after `artifacts` under `entities.pkg`: 49 | # meta: 50 | # post_deploy: 51 | # - sql_script: scripts/any-provider-setup.sql 52 | # - sql_script: scripts/shared-content.sql 53 | 54 | -------------------------------------------------------------------------------- /app_streamlit_python/src/module-ui/src/ui.py: -------------------------------------------------------------------------------- 1 | def run_streamlit(): 2 | # Import python packages 3 | # Streamlit app testing framework requires imports to reside here 4 | # Streamlit app testing documentation: https://docs.streamlit.io/library/api-reference/app-testing 5 | import pandas as pd 6 | import streamlit as st 7 | from snowflake.snowpark.functions import call_udf, col 8 | from snowflake.snowpark import Session 9 | 10 | st.title('Hello Snowflake!') 11 | 12 | 13 | st.header('UDF Example') 14 | 15 | st.write( 16 | """The sum of the two numbers is calculated by the Python add_fn() function 17 | which is called from core.add() UDF defined in your setup_script.sql. 18 | """) 19 | 20 | # Get the current credentials 21 | session = Session.builder.getOrCreate() 22 | 23 | num1 = st.number_input('First number', key='numToAdd1', value=1) 24 | num2 = st.number_input('Second number', key='numToAdd2', value=1) 25 | 26 | # Create an example data frame 27 | data_frame = session.create_dataframe([[num1, num2]], schema=['num1', 'num2']) 28 | data_frame = data_frame.select(call_udf('core.add', col('num1'), col('num2'))) 29 | 30 | # Execute the query and convert it into a Pandas data frame 31 | queried_data = data_frame.to_pandas() 32 | 33 | # Display the Pandas data frame as a Streamlit data frame. 34 | st.dataframe(queried_data, use_container_width=True) 35 | 36 | 37 | st.header('Stored Procedure Example') 38 | 39 | st.write( 40 | """Incrementing a number by one is calculated by the Python increment_by_one_fn() function 41 | which implements the core.increment_by_one() Stored Procedure defined in your setup_script.sql. 42 | """) 43 | 44 | num_to_increment = st.number_input('Number to increment', key='numToIncrement', value=1) 45 | result = session.call('core.increment_by_one', num_to_increment) 46 | 47 | st.dataframe(pd.DataFrame([[result]]), use_container_width=True) 48 | 49 | if __name__ == '__main__': 50 | run_streamlit() 51 | -------------------------------------------------------------------------------- /app_streamlit_python/app/setup_script.sql: -------------------------------------------------------------------------------- 1 | -- This is the setup script that runs while installing a Snowflake Native App in a consumer account. 2 | -- For more information on how to create setup file, visit https://docs.snowflake.com/en/developer-guide/native-apps/creating-setup-script 3 | 4 | -- A general guideline to building this script looks like: 5 | -- 1. Create application roles 6 | CREATE APPLICATION ROLE IF NOT EXISTS app_public; 7 | 8 | -- 2. Create a versioned schema to hold those UDFs/Stored Procedures 9 | CREATE OR ALTER VERSIONED SCHEMA core; 10 | GRANT USAGE ON SCHEMA core TO APPLICATION ROLE app_public; 11 | 12 | -- 3. Create UDFs and Stored Procedures using the python code you wrote in src/module-add, as shown below. 13 | CREATE OR REPLACE FUNCTION core.add(x NUMBER, y NUMBER) 14 | RETURNS NUMBER 15 | LANGUAGE PYTHON 16 | RUNTIME_VERSION=3.8 17 | PACKAGES=('snowflake-snowpark-python') 18 | IMPORTS=('/module-add/add.py') 19 | HANDLER='add.add_fn'; 20 | 21 | CREATE OR REPLACE PROCEDURE core.increment_by_one(x NUMBER) 22 | RETURNS NUMBER 23 | LANGUAGE PYTHON 24 | RUNTIME_VERSION=3.8 25 | PACKAGES=('snowflake-snowpark-python') 26 | IMPORTS=('/module-add/add.py') 27 | HANDLER='add.increment_by_one_fn'; 28 | 29 | -- 4. Grant appropriate privileges over these objects to your application roles. 30 | GRANT USAGE ON FUNCTION core.add(NUMBER, NUMBER) TO APPLICATION ROLE app_public; 31 | GRANT USAGE ON PROCEDURE core.increment_by_one(NUMBER) TO APPLICATION ROLE app_public; 32 | 33 | -- 5. Create a streamlit object using the code you wrote in you wrote in src/module-ui, as shown below. 34 | -- The `from` value is derived from the stage path described in snowflake.yml 35 | CREATE OR REPLACE STREAMLIT core.ui 36 | FROM '/streamlit/' 37 | MAIN_FILE = 'ui.py'; 38 | 39 | -- 6. Grant appropriate privileges over these objects to your application roles. 40 | GRANT USAGE ON STREAMLIT core.ui TO APPLICATION ROLE app_public; 41 | 42 | -- A detailed explanation can be found at https://docs.snowflake.com/en/developer-guide/native-apps/adding-streamlit 43 | -------------------------------------------------------------------------------- /snowpark_with_external_access/README.md: -------------------------------------------------------------------------------- 1 | # Snowpark project using external access 2 | 3 | This is a simple example of a Snowpark project that requires external access. 4 | 5 | ## Prerequisites 6 | This project requires a database, API integration and secret. To created them you can execute convenience script 7 | `snow sql -f setup.sql` or run the following SQL commands: 8 | 9 | ```sql 10 | CREATE DATABASE IF NOT EXISTS ; 11 | CREATE SCHEMA IF NOT EXISTS .; 12 | USE SCHEMA .; 13 | CREATE SECRET IF NOT EXISTS TYPE = GENERIC_STRING SECRET_STRING = 'very_secret_string'; 14 | CREATE OR REPLACE NETWORK RULE snowpark_example_network_rule 15 | MODE = EGRESS 16 | TYPE = HOST_PORT 17 | VALUE_LIST = ('docs.snowflake.com'); 18 | 19 | CREATE EXTERNAL ACCESS INTEGRATION IF NOT EXISTS 20 | ALLOWED_NETWORK_RULES = (snowpark_example_network_rule) 21 | ALLOWED_AUTHENTICATION_SECRETS = () 22 | ENABLED = true; 23 | ``` 24 | 25 | ## Building Snowpark artifacts 26 | _For more information see [build documentation](https://docs.snowflake.com/developer-guide/snowflake-cli/snowpark/build)._ 27 | 28 | First you need to bundle your code by running: 29 | ```bash 30 | snow snowpark build 31 | ``` 32 | 33 | ## Deploying the project 34 | _For more information see [deploy documentation](https://docs.snowflake.com/developer-guide/snowflake-cli/snowpark/deploy)._ 35 | 36 | To deploy the snowpark application: 37 | 38 | ```bash 39 | snow snowpark deploy 40 | ``` 41 | 42 | ## Testing the project 43 | 44 | You can test the deployed snowpark application by running: 45 | 46 | ```bash 47 | snow snowpark execute function "..request_function()"; 48 | snow snowpark execute procedure "..request_procedure()"; 49 | ``` 50 | -------------------------------------------------------------------------------- /dcm_project/definitions/serve.sql: -------------------------------------------------------------------------------- 1 | define schema DCM_PROJECT_{{db}}.SERVE; 2 | 3 | 4 | define view DCM_PROJECT_{{db}}.SERVE.V_DASHBOARD_DAILY_SALES 5 | as 6 | select 7 | date_trunc('DAY', ORDER_TS) as SALE_DATE, 8 | count(DISTINCT ORDER_ID) as DAILY_ORDERS, 9 | sum(LINE_ITEM_REVENUE) as DAILY_REVENUE, 10 | sum(LINE_ITEM_PROFIT) as DAILY_PROFIT 11 | from 12 | DCM_PROJECT_{{db}}.ANALYTICS.V_ENRICHED_ORDER_DETAILS 13 | group by 14 | SALE_DATE 15 | order by 16 | SALE_DATE 17 | ; 18 | 19 | 20 | 21 | define view DCM_PROJECT_{{db}}.SERVE.V_DASHBOARD_KPI_SUMMARY 22 | as 23 | select 24 | sum(TOTAL_SPEND_USD) as TOTAL_LIFETIME_REVENUE, 25 | count(DISTINCT CUSTOMER_ID) as TOTAL_CUSTOMERS, 26 | sum(TOTAL_ORDERS) as TOTAL_ORDERS, 27 | sum(TOTAL_SPEND_USD) / sum(TOTAL_ORDERS) as AVERAGE_ORDER_VALUE 28 | from 29 | DCM_PROJECT_{{db}}.ANALYTICS.V_CUSTOMER_SPENDING_SUMMARY 30 | ; 31 | 32 | 33 | 34 | define view DCM_PROJECT_{{db}}.SERVE.V_DASHBOARD_SALES_BY_CATEGORY_CITY 35 | as 36 | select 37 | ITEM_CATEGORY, 38 | CUSTOMER_CITY, 39 | sum(LINE_ITEM_REVENUE) as TOTAL_REVENUE 40 | from 41 | DCM_PROJECT_{{db}}.ANALYTICS.V_ENRICHED_ORDER_DETAILS 42 | group by 43 | ITEM_CATEGORY, CUSTOMER_CITY 44 | order by 45 | ITEM_CATEGORY, CUSTOMER_CITY 46 | ; 47 | 48 | 49 | define view DCM_PROJECT_{{db}}.SERVE.V_DASHBOARD_NEW_VS_RETURNING_CUSTOMERS 50 | as 51 | with 52 | customer_order_dates as ( 53 | select 54 | e.ORDER_ID, 55 | e.CUSTOMER_ID, 56 | DATE_TRUNC('DAY', e.ORDER_TS) AS ORDER_DATE, 57 | DATE_TRUNC('DAY', s.FIRST_ORDER_DATE) AS CUSTOMER_FIRST_ORDER_DATE, 58 | e.LINE_ITEM_REVENUE 59 | from 60 | DCM_PROJECT_{{db}}.ANALYTICS.V_ENRICHED_ORDER_DETAILS e 61 | join 62 | DCM_PROJECT_{{db}}.ANALYTICS.V_CUSTOMER_SPENDING_SUMMARY s on e.CUSTOMER_ID = s.CUSTOMER_ID 63 | ) 64 | select 65 | ORDER_DATE, 66 | case 67 | when ORDER_DATE = CUSTOMER_FIRST_ORDER_DATE then 'New Customer' 68 | else 'Returning Customer' 69 | end as CUSTOMER_TYPE, 70 | sum(LINE_ITEM_REVENUE) as REVENUE 71 | from 72 | customer_order_dates 73 | group by 74 | ORDER_DATE, CUSTOMER_TYPE 75 | order by 76 | ORDER_DATE, CUSTOMER_TYPE 77 | ; 78 | -------------------------------------------------------------------------------- /dcm_project/definitions/ingest.sql: -------------------------------------------------------------------------------- 1 | define stage DCM_PROJECT_{{db}}.RAW.TASTY_BYTES_ORDERS_STAGE 2 | comment = 'Internal stage for daily incoming Tasty Bytes order files (CSV)'; 3 | 4 | 5 | define table DCM_PROJECT_{{db}}.RAW.DAILY_ORDERS_INCOMING ( 6 | ORDER_ID number, 7 | CUSTOMER_ID number, 8 | TRUCK_ID number, 9 | ORDER_TS TIMESTAMP_NTZ, 10 | MENU_ITEM_ID number, 11 | QUANTITY number 12 | ) 13 | change_tracking = true 14 | ; 15 | 16 | 17 | 18 | define task DCM_PROJECT_{{db}}.ANALYTICS.TSK_INGEST_DAILY_ORDERS 19 | warehouse = 'DCM_PROJECT_WH_{{db}}' 20 | schedule = 'USING CRON 0 4 * * * UTC' 21 | as 22 | begin 23 | -- Copy data from any new files in the stage into our landing table 24 | copy into 25 | DCM_PROJECT_{{db}}.RAW.DAILY_ORDERS_INCOMING 26 | from 27 | @DCM_PROJECT_{{db}}.RAW.TASTY_BYTES_ORDERS_STAGE 28 | file_format = ( 29 | type = 'CSV', 30 | field_delimiter = ',', 31 | skip_header = 1, 32 | null_if = ('NULL', 'null'), 33 | empty_field_as_null = true, 34 | field_optionally_enclosed_by = '"' 35 | ) 36 | on_error = 'CONTINUE'; 37 | 38 | -- Insert new order headers, avoiding duplicates 39 | insert into 40 | DCM_PROJECT_{{db}}.RAW.ORDER_HEADER (ORDER_ID, CUSTOMER_ID, TRUCK_ID, ORDER_TS) 41 | select 42 | distinct ORDER_ID, 43 | CUSTOMER_ID, 44 | TRUCK_ID, 45 | ORDER_TS 46 | from 47 | DCM_PROJECT_{{db}}.RAW.DAILY_ORDERS_INCOMING src 48 | where not exists ( 49 | select 50 | 1 51 | from 52 | DCM_PROJECT_{{db}}.RAW.ORDER_HEADER dest 53 | where 54 | dest.ORDER_ID = src.ORDER_ID 55 | ); 56 | 57 | -- Insert new order details 58 | insert into 59 | DCM_PROJECT_{{db}}.RAW.ORDER_DETAIL (ORDER_ID, MENU_ITEM_ID, QUANTITY) 60 | select 61 | ORDER_ID, MENU_ITEM_ID, QUANTITY 62 | from 63 | DCM_PROJECT_{{db}}.RAW.DAILY_ORDERS_INCOMING; 64 | 65 | -- Clean up the landing table for the next run 66 | truncate table DCM_PROJECT_{{db}}.RAW.DAILY_ORDERS_INCOMING; 67 | 68 | -- Remove the processed files from the stage to prevent re-loading 69 | remove @DCM_PROJECT_{{db}}.RAW.TASTY_BYTES_ORDERS_STAGE pattern='.*.csv'; 70 | end; 71 | -------------------------------------------------------------------------------- /dcm_project/definitions/analytics.sql: -------------------------------------------------------------------------------- 1 | define schema DCM_PROJECT_{{db}}.ANALYTICS; 2 | 3 | define dynamic table DCM_PROJECT_{{db}}.ANALYTICS.V_ENRICHED_ORDER_DETAILS 4 | warehouse = DCM_PROJECT_WH_{{db}} 5 | target_lag = '12 hours' 6 | as 7 | select 8 | oh.ORDER_ID, 9 | oh.ORDER_TS, 10 | od.QUANTITY, 11 | m.MENU_ITEM_NAME, 12 | m.ITEM_CATEGORY, 13 | m.SALE_PRICE_USD, 14 | m.COST_OF_GOODS_USD, 15 | (od.QUANTITY * m.SALE_PRICE_USD) as LINE_ITEM_REVENUE, 16 | (od.QUANTITY * (m.SALE_PRICE_USD - m.COST_OF_GOODS_USD)) as LINE_ITEM_PROFIT, 17 | c.CUSTOMER_ID, 18 | c.FIRST_NAME, 19 | c.LAST_NAME, 20 | c.CITY as CUSTOMER_CITY, 21 | t.TRUCK_ID, 22 | t.TRUCK_BRAND_NAME 23 | from 24 | DCM_PROJECT_{{db}}.RAW.ORDER_HEADER oh 25 | join 26 | DCM_PROJECT_{{db}}.RAW.ORDER_DETAIL od 27 | on oh.ORDER_ID = od.ORDER_ID 28 | join 29 | DCM_PROJECT_{{db}}.RAW.MENU m 30 | on od.MENU_ITEM_ID = m.MENU_ITEM_ID 31 | join 32 | DCM_PROJECT_{{db}}.RAW.CUSTOMER c 33 | on oh.CUSTOMER_ID = c.CUSTOMER_ID 34 | join 35 | DCM_PROJECT_{{db}}.RAW.TRUCK t 36 | on oh.TRUCK_ID = t.TRUCK_ID 37 | ; 38 | 39 | 40 | define dynamic table DCM_PROJECT_{{db}}.ANALYTICS.V_MENU_ITEM_POPULARITY 41 | warehouse = DCM_PROJECT_WH_{{db}} 42 | target_lag = '12 hours' 43 | as 44 | select 45 | MENU_ITEM_NAME, 46 | ITEM_CATEGORY, 47 | count(DISTINCT ORDER_ID) as NUMBER_OF_ORDERS, 48 | sum(QUANTITY) as TOTAL_QUANTITY_SOLD, 49 | sum(LINE_ITEM_REVENUE) as TOTAL_REVENUE 50 | from 51 | DCM_PROJECT_{{db}}.ANALYTICS.V_ENRICHED_ORDER_DETAILS 52 | group by 53 | MENU_ITEM_NAME, ITEM_CATEGORY 54 | order by 55 | TOTAL_REVENUE desc 56 | ; 57 | 58 | 59 | define dynamic table DCM_PROJECT_{{db}}.ANALYTICS.V_CUSTOMER_SPENDING_SUMMARY 60 | warehouse = DCM_PROJECT_WH_{{db}} 61 | target_lag = '12 hours' 62 | as 63 | select 64 | CUSTOMER_ID, 65 | FIRST_NAME, 66 | LAST_NAME, 67 | CUSTOMER_CITY, 68 | count(DISTINCT ORDER_ID) as TOTAL_ORDERS, 69 | sum(LINE_ITEM_REVENUE) as TOTAL_SPEND_USD, 70 | min(ORDER_TS) as FIRST_ORDER_DATE, 71 | max(ORDER_TS) as LATEST_ORDER_DATE 72 | from 73 | DCM_PROJECT_{{db}}.ANALYTICS.V_ENRICHED_ORDER_DETAILS 74 | group by 75 | CUSTOMER_ID, FIRST_NAME, LAST_NAME, CUSTOMER_CITY 76 | order by 77 | TOTAL_SPEND_USD desc 78 | ; 79 | 80 | 81 | define dynamic table DCM_PROJECT_{{db}}.ANALYTICS.V_TRUCK_PERFORMANCE 82 | warehouse = DCM_PROJECT_WH_{{db}} 83 | target_lag = '12 hours' 84 | as 85 | select 86 | TRUCK_BRAND_NAME, 87 | count(DISTINCT ORDER_ID) as TOTAL_ORDERS, 88 | sum(LINE_ITEM_REVENUE) as TOTAL_REVENUE, 89 | sum(LINE_ITEM_PROFIT) as TOTAL_PROFIT 90 | from 91 | DCM_PROJECT_{{db}}.ANALYTICS.V_ENRICHED_ORDER_DETAILS 92 | group by 93 | TRUCK_BRAND_NAME 94 | order by 95 | TOTAL_REVENUE desc 96 | ; 97 | -------------------------------------------------------------------------------- /app_spcs_basic/service/main.py: -------------------------------------------------------------------------------- 1 | from http.server import BaseHTTPRequestHandler, HTTPServer 2 | import os 3 | import json 4 | import traceback 5 | import sys 6 | 7 | PORT = int(os.environ.get("PORT", 8080)) 8 | GET_PATHS = ('/', '/index.html', '/healthcheck') 9 | POST_PATHS = ('/echo') 10 | 11 | class handler(BaseHTTPRequestHandler): 12 | """ 13 | Simple Python HTTP server that acts as both an ingress (GET) 14 | and as a service function endpoint (POST) 15 | """ 16 | 17 | def do_GET(self): 18 | """ 19 | Returns an HTML page bundled with the server 20 | """ 21 | if self.path not in GET_PATHS: 22 | self.send_error(404) 23 | return 24 | 25 | self.send_response(200) 26 | self.send_header('Content-type', 'text/html') 27 | self.end_headers() 28 | 29 | with open('index.html', 'rb') as f: 30 | self.wfile.write(f.read()) 31 | 32 | def do_POST(self): 33 | """ 34 | POSTing to /echo in the external function format will echo the payload back to Snowflake. 35 | See https://docs.snowflake.com/en/sql-reference/external-functions-data-format 36 | """ 37 | if self.path not in POST_PATHS: 38 | self.send_error(404) 39 | return 40 | 41 | self.send_response(200) 42 | self.send_header('Content-type', 'application/json') 43 | self.end_headers() 44 | 45 | try: 46 | # post body looks something like... 47 | # { 48 | # "data": [ 49 | # [0, 10, "Alex", "2014-01-01 16:00:00"], 50 | # [1, 20, "Steve", "2015-01-01 16:00:00"], 51 | # [2, 30, "Alice", "2016-01-01 16:00:00"], 52 | # [3, 40, "Adrian", "2017-01-01 16:00:00"] 53 | # ] 54 | # } 55 | content_len = int(self.headers.get('Content-Length')) 56 | post_body = self.rfile.read(content_len) 57 | parsed = json.loads(post_body) 58 | 59 | # in our case, we only have the one column, so we'll just have [rowid, message] 60 | # and in fact, we're just echoing, so all we have to do is just return the same payload 61 | # so you can see what's happening in logs, we'll echo all the rows we found 62 | for [rowid, message] in parsed["data"]: 63 | print(f"{rowid}: {message}") 64 | 65 | # echo back the exact same data, making sure it's JSON 66 | self.wfile.write(json.dumps(parsed).encode('utf-8')) 67 | except: 68 | tb = traceback.format_exc() 69 | print(tb, file=sys.stderr) 70 | self.send_error(500, "Exception occurred", tb) 71 | 72 | with HTTPServer(('', PORT), handler) as server: 73 | server.serve_forever() 74 | -------------------------------------------------------------------------------- /.tests/test_examples.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | from contextlib import contextmanager 4 | from pathlib import Path 5 | from tempfile import TemporaryDirectory 6 | 7 | import pytest 8 | from snowflake.cli.__about__ import VERSION 9 | 10 | if VERSION < "2.8.0": 11 | pytest.skip("This test requires CLI >= 2.8.0", allow_module_level=True) 12 | 13 | _REPO_ROOT = Path(__file__).parent.parent 14 | 15 | 16 | @pytest.fixture() 17 | def initialize_project(): 18 | @contextmanager 19 | def _initialize_project(template_name): 20 | with TemporaryDirectory() as tmpdir: 21 | project_dir = Path(tmpdir) / "project" 22 | output = subprocess.check_output( 23 | [ 24 | "snow", 25 | "init", 26 | str(project_dir), 27 | "--template", 28 | template_name, 29 | "--no-interactive", 30 | "--template-source", 31 | _REPO_ROOT, 32 | ], 33 | encoding="utf-8", 34 | ) 35 | assert "Initialized the new project in" in output 36 | 37 | old_cwd = os.getcwd() 38 | os.chdir(project_dir) 39 | yield project_dir 40 | os.chdir(old_cwd) 41 | 42 | return _initialize_project 43 | 44 | 45 | def test_snowpark_examples_functions_work_locally(initialize_project): 46 | with initialize_project("example_snowpark") as snowpark_project: 47 | output = subprocess.check_output( 48 | ["python", str(snowpark_project / "app" / "functions.py"), "FooBar"], 49 | encoding="utf-8", 50 | ) 51 | assert output.strip() == "Hello FooBar!" 52 | 53 | output = subprocess.check_output( 54 | ["python", str(snowpark_project / "app" / "procedures.py"), "BazBar"], 55 | encoding="utf-8", 56 | ) 57 | assert output.strip() == "Hello BazBar!" 58 | 59 | 60 | def test_example_snowpark_yml_is_correct(initialize_project): 61 | with initialize_project("example_snowpark") as snowpark_project: 62 | output = subprocess.check_output( 63 | [ 64 | "snow", 65 | "snowpark", 66 | "build", 67 | "--ignore-anaconda", 68 | "--allow-shared-libraries", 69 | ], 70 | encoding="utf-8", 71 | ) 72 | assert "Build done." in output 73 | 74 | 75 | def test_example_streamlit_yml_is_correct(initialize_project): 76 | with initialize_project("example_streamlit") as streamlit_project: 77 | result = subprocess.run( 78 | ["snow", "streamlit", "deploy"], 79 | capture_output=True, 80 | text=True, 81 | encoding="utf-8", 82 | ) 83 | assert not "During evaluation of " in result.stdout + result.stderr 84 | -------------------------------------------------------------------------------- /app_streamlit_js/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This is an example template for a Snowflake Native App project which demonstrates the use of JavaScript extension code and adding Streamlit code. This template is meant to guide developers towards a possible project structure on the basis of functionality, as well as to indicate the contents of some common and useful files. 4 | 5 | 6 | # How to build/test this template 7 | 8 | ## Run the app 9 | Create or update an application package in your Snowflake account, upload application artifacts to a stage in the application package, and create or update an application object in the same account based on the uploaded artifacts. 10 | ``` 11 | snow app run 12 | ``` 13 | 14 | For more information, please refer to the Snowflake Documentation on installing and using Snowflake CLI to create a Snowflake Native App. 15 | 16 | # Directory Structure 17 | ## `/app` 18 | This directory holds your Snowflake Native App files. 19 | 20 | ### `/app/README.md` 21 | Exposed to the account installing the Snowflake Native App with details on what it does and how to use it. 22 | 23 | ### `/app/manifest.yml` 24 | Defines properties required by the application package. Find more details at the [Manifest Documentation.](https://docs.snowflake.com/en/developer-guide/native-apps/creating-manifest) 25 | 26 | ### `/app/setup_script.sql` 27 | Contains SQL statements that are run when an account installs or upgrades a Snowflake Native App. 28 | 29 | ## `/scripts` 30 | You can add any additional scripts such as `.sql` and `.jinja` files here. One of the common use cases for such a script is to be able to add shared content from external databases to your application package, which makes it available to be used in the setup script that runs during Snowflake Native App installation. 31 | _Note: See the note at the end of `snowflake.yml` if you decide to use the scripts. _ 32 | 33 | 34 | ## `/src` 35 | This directory contains code organization by functionality, such as one distinct module for Streamlit related code. The JavaScript code is defined in the UDF from the [setup_script.sql](app/setup_script.sql) file. 36 | ``` 37 | /src 38 | |module-ui 39 | | |-src 40 | | |-ui.py 41 | | |-environment.yml 42 | ``` 43 | 44 | ## `snowflake.yml` 45 | `snowflake.yml` is used by Snowflake CLI to discover your project's code and interact with snowflake with all relevant privileges and grants. 46 | 47 | For more information, please refer to the Snowflake Documentation on installing and using Snowflake CLI to create a Snowflake Native App. 48 | 49 | ### Adding a snowflake.local.yml file 50 | Though your project directory already comes with a `snowflake.yml` file, an individual developer can choose to customize the behavior of the Snowflake CLI by providing local overrides to `snowflake.yml`, such as a new role to test out your own application package. This is where you can use `snowflake.local.yml`, which is not a version-controlled file. 51 | 52 | For more information, please refer to the Snowflake Documentation on installing and using Snowflake CLI to create a Snowflake Native App. 53 | 54 | -------------------------------------------------------------------------------- /example_plugin/src/snowflake_cli_example_plugin/manager.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of SecretManager, presenting an example of running SQL queries in Snowflake 3 | and how to use internal plugin config. 4 | """ 5 | 6 | from enum import Enum 7 | from typing import Optional 8 | 9 | from click import ClickException 10 | from snowflake.cli.api.identifiers import FQN 11 | from snowflake.cli.api.plugins.plugin_config import PluginConfigProvider 12 | from snowflake.cli.api.sql_execution import SqlExecutionMixin 13 | from snowflake.connector.cursor import SnowflakeCursor 14 | 15 | 16 | class SecretType(str, Enum): 17 | """Supported secret types.""" 18 | 19 | PASSWORD = "password" 20 | GENERIC_STRING = "generic_string" 21 | SYMMETRIC_KEY = "symmetric_key" 22 | 23 | @classmethod 24 | def all(cls): 25 | return list(x.value for x in cls) 26 | 27 | @classmethod 28 | def of_string(cls, value): 29 | try: 30 | return cls(value) 31 | except ValueError: 32 | raise ClickException( 33 | f"Invalid secret type: `{value}`. Supported secret types: {', '.join(cls.all())}" 34 | ) 35 | 36 | 37 | class SecretManager(SqlExecutionMixin): 38 | def __init__(self): 39 | super().__init__() 40 | # reading config from [cli.plugins..config] section 41 | config_provider = PluginConfigProvider() 42 | self.config = config_provider.get_config("") 43 | 44 | def _execute_query(self, query: str) -> SnowflakeCursor: 45 | print_query = self.config.internal_config.get("print_queries", False) 46 | if print_query: 47 | print(query) 48 | return self.execute_query(query) 49 | 50 | def create( 51 | self, 52 | secret_type: SecretType, 53 | fqn: FQN, 54 | replace: bool, 55 | if_not_exists: bool, 56 | username: Optional[str] = None, 57 | password: Optional[str] = None, 58 | value: Optional[str] = None, 59 | ): 60 | replace_str = "OR REPLACE " if replace else "" 61 | if_not_exists_str = "IF NOT EXISTS " if if_not_exists else "" 62 | query = ( 63 | f"CREATE {replace_str}SECRET {if_not_exists_str}{fqn.sql_identifier} " 64 | f"TYPE = '{secret_type.upper()}' " 65 | ) 66 | 67 | if secret_type == SecretType.SYMMETRIC_KEY: 68 | query += "ALGORITHM = GENERIC" 69 | if secret_type == SecretType.PASSWORD: 70 | query += f"USERNAME = '{username}' PASSWORD = '{password}'" 71 | if secret_type == SecretType.GENERIC_STRING: 72 | query += f"SECRET_STRING = '{value}'" 73 | 74 | return self._execute_query(query) 75 | 76 | def show(self, like: Optional[str]) -> SnowflakeCursor: 77 | query = "SHOW SECRETS" 78 | if like: 79 | query += f" LIKE '{like}'" 80 | return self._execute_query(query) 81 | 82 | def drop(self, fqn: FQN) -> SnowflakeCursor: 83 | query = f"DROP SECRET {fqn.sql_identifier}" 84 | return self._execute_query(query) 85 | 86 | def describe(self, fqn: FQN) -> SnowflakeCursor: 87 | query = f"DESCRIBE SECRET {fqn.sql_identifier}" 88 | return self._execute_query(query) 89 | -------------------------------------------------------------------------------- /app_spcs_basic/README.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | ## Prerequisites 4 | 5 | 1. Install Docker 6 | - [Windows](https://docs.docker.com/desktop/install/windows-install/) 7 | - [Mac](https://docs.docker.com/desktop/install/mac-install/) 8 | - [Linux](https://docs.docker.com/desktop/install/linux-install/) 9 | 10 | 11 | ## Set your SnowCLI connection (optional) 12 | 13 | We use your default connection to connect to Snowflake and deploy the images / app. Set your 14 | default connection by modifying your `config.toml` file or by exporting the following environment variable: 15 | 16 | ```sh 17 | export SNOWFLAKE_DEFAULT_CONNECTION_NAME= 18 | ``` 19 | 20 | ## Create image repository, build and push your local service image 21 | 22 | The [service/](service/) directory contains a [Dockerfile](service/Dockerfile) that builds a 23 | simple Python server that responds to GET health checks, a GET for `/index.html`, as well as 24 | POSTing to `/echo` in the Snowflake External Function payload format. You can build it and 25 | push it to an image repository called `SPCS_NA.PUBLIC.IMAGES` in your account like so: 26 | 27 | ```sh 28 | ./build-and-push.sh 29 | ``` 30 | 31 | This command will always use your default SnowCLI connection. 32 | 33 | ## Deploy the application 34 | 35 | Deploy the app package and instance as such: 36 | 37 | ```sh 38 | snow app run 39 | ``` 40 | 41 | > Take note of the name of the application, which is based on the name you chose when you initialized this project. The application object and package are, by default, automatically suffixed by your (local) user name (i.e. `$USER`). 42 | 43 | ## Setup the application 44 | 45 | When the application is opened for the first time, you will be prompted to grant the following account-level privileges to it: 46 | 47 | - CREATE COMPUTE POOL 48 | - BIND SERVICE ENDPOINT 49 | 50 | Click on the `Grant` button to proceed. 51 | 52 | ## Activate the application 53 | 54 | Once privileges are granted, a new `Activate` button should appear. Click the button and wait until the application is fully activated. 55 | The `Activate` button invokes the `grant_callback` defined in the [manifest.yml](app/manifest.yml) file, which then creates the `COMPUTE POOL` and `SERVICE` needed to launch the application. 56 | 57 | ## Launch the application 58 | 59 | Once all services and pools are created, you will be able to launch the app by clicking on the `Launch App` button. This will navigate to the URL provided by the `Service` and `Endpoint` defined in the `default_web_endpoint` in the [manifest.yml](app/manifest.yml). You will see the contents of [index.html](service/index.html) as served by the application container. 60 | 61 | ## Test out the echo service 62 | 63 | ```sh 64 | snow sql -q "select .services.echo('Hello world!')" 65 | ``` 66 | 67 | You should see the same text back (Hello world!). 68 | 69 | ## Clean up 70 | 71 | You can stop the service and drop the compute pool without dropping the application by running the following statement: 72 | 73 | ```sh 74 | snow sql -q "call .setup.drop_service_and_pool()" 75 | ``` 76 | 77 | Optionally, you can remove the app + package altogether afterwards: 78 | 79 | ```sh 80 | snow app teardown --cascade 81 | ``` 82 | > Version `2.4.0+` of Snowflake CLI should be installed in order to execute `--cascade` command. 83 | -------------------------------------------------------------------------------- /app_spcs_basic/app/services.sql: -------------------------------------------------------------------------------- 1 | -- namespace under which our services and their functions will live 2 | create schema if not exists services; 3 | 4 | -- namespace for service administration 5 | create or alter versioned schema setup; 6 | 7 | -- creates a compute pool, service, and service function 8 | create or replace procedure setup.create_service(privileges ARRAY) 9 | returns varchar 10 | language sql 11 | execute as owner 12 | as $$ 13 | begin 14 | let pool_name := (select current_database()) || '_app_pool'; 15 | 16 | create compute pool if not exists identifier(:pool_name) 17 | MIN_NODES = 1 18 | MAX_NODES = 1 19 | INSTANCE_FAMILY = CPU_X64_XS; 20 | 21 | create service if not exists services.spcs_na_service 22 | in compute pool identifier(:pool_name) 23 | from spec='service_spec.yml'; 24 | 25 | grant usage on service services.spcs_na_service 26 | to application role app_public; 27 | 28 | create or replace function services.echo(payload varchar) 29 | returns varchar 30 | service = services.spcs_na_service 31 | endpoint = 'my-endpoint' 32 | max_batch_rows = 50 33 | AS '/echo'; 34 | 35 | grant usage on function services.echo(varchar) 36 | to application role app_public; 37 | 38 | return 'Done'; 39 | end; 40 | $$; 41 | grant usage on procedure setup.create_service(ARRAY) 42 | to application role app_public; 43 | 44 | create or replace procedure setup.suspend_service() 45 | returns varchar 46 | language sql 47 | execute as owner 48 | as $$ 49 | begin 50 | alter service services.spcs_na_service suspend; 51 | return 'Done'; 52 | end; 53 | $$; 54 | grant usage on procedure setup.suspend_service() 55 | to application role app_public; 56 | 57 | create or replace procedure setup.resume_service() 58 | returns varchar 59 | language sql 60 | execute as owner 61 | as $$ 62 | begin 63 | alter service services.spcs_na_service resume; 64 | return 'Done'; 65 | end; 66 | $$; 67 | grant usage on procedure setup.resume_service() 68 | to application role app_public; 69 | 70 | create or replace procedure setup.drop_service_and_pool() 71 | returns varchar 72 | language sql 73 | execute as owner 74 | as $$ 75 | begin 76 | let pool_name := (select current_database()) || '_app_pool'; 77 | drop service if exists services.spcs_na_service; 78 | drop compute pool if exists identifier(:pool_name); 79 | return 'Done'; 80 | end; 81 | $$; 82 | grant usage on procedure setup.drop_service_and_pool() 83 | to application role app_public; 84 | 85 | create or replace procedure setup.service_status() 86 | returns varchar 87 | language sql 88 | execute as owner 89 | as $$ 90 | declare 91 | service_status varchar; 92 | begin 93 | call system$get_service_status('services.spcs_na_service') into :service_status; 94 | return parse_json(:service_status)[0]['status']::varchar; 95 | end; 96 | $$; 97 | grant usage on procedure setup.service_status() 98 | to application role app_public; 99 | 100 | grant usage on schema setup to application role app_public; 101 | -------------------------------------------------------------------------------- /.tests/test_render_templates.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from pathlib import Path 3 | from tempfile import TemporaryDirectory 4 | from typing import List 5 | 6 | import pytest 7 | import yaml 8 | from snowflake.cli.__about__ import VERSION 9 | from snowflake.cli.api.project.schemas.template import Template 10 | 11 | _REPO_ROOT = Path(__file__).parent.parent 12 | from packaging.version import parse 13 | 14 | 15 | def _find_all_templates(): 16 | return ( 17 | # "str" to make tests parameters human-readable 18 | str(x.relative_to(_REPO_ROOT).parent) 19 | for x in _REPO_ROOT.rglob("**/template.yml") 20 | ) 21 | 22 | 23 | def _read_template_metadata(template_root: Path) -> Template: 24 | with (template_root / "template.yml").open("r") as fd: 25 | yaml_contents = yaml.safe_load(fd) or {} 26 | return Template(template_root, **yaml_contents) 27 | 28 | 29 | def _gen_input_values(metadata: Template) -> List[str]: 30 | result = [] 31 | for variable in metadata.variables: 32 | value = { 33 | int: 42, 34 | float: 3.14, 35 | str: "a_string", 36 | }[variable.python_type] 37 | result.append(value) 38 | return result 39 | 40 | 41 | @pytest.mark.parametrize("template_root", _find_all_templates()) 42 | def test_render_template(template_root): 43 | template_root = _REPO_ROOT / template_root 44 | metadata = _read_template_metadata(template_root) 45 | if metadata.minimum_cli_version and ( 46 | parse(metadata.minimum_cli_version) > parse(VERSION) 47 | ): 48 | pytest.skip(f"Test requires CLI version >= {metadata.minimum_cli_version}") 49 | 50 | with TemporaryDirectory() as tmpdir: 51 | project_path = Path(tmpdir) / "project" 52 | snow = subprocess.Popen( 53 | [ 54 | "snow", 55 | "init", 56 | str(project_path), 57 | "--template-source", 58 | template_root, 59 | ], 60 | stdin=subprocess.PIPE, 61 | stdout=subprocess.PIPE, 62 | ) 63 | try: 64 | process_input = "\n".join(_gen_input_values(metadata)) 65 | # reasonable 60s timeout 66 | stdout, stderr = snow.communicate(input=process_input.encode(), timeout=60) 67 | except subprocess.TimeoutExpired: 68 | raise AssertionError("Timeout expired") 69 | assert snow.returncode == 0, ( 70 | f"Rendering finished with {snow.returncode}:\n" 71 | f"======= stdout =======\n{stdout.decode()}\n" 72 | f"======= stderr =======\n{stderr.decode()}" 73 | ) 74 | 75 | 76 | @pytest.mark.parametrize("template_root", _find_all_templates()) 77 | def test_too_low_version_error(template_root): 78 | template_root = _REPO_ROOT / template_root 79 | metadata = _read_template_metadata(template_root) 80 | if (not metadata.minimum_cli_version) or ( 81 | parse(metadata.minimum_cli_version) <= parse(VERSION) 82 | ): 83 | pytest.skip("CLI version requirements fulfilled") 84 | 85 | with TemporaryDirectory() as tmpdir: 86 | project_path = Path(tmpdir) / "project" 87 | result = subprocess.run( 88 | ["snow", "init", str(project_path), "--template-source", template_root], 89 | capture_output=True, 90 | text=True, 91 | encoding="utf-8", 92 | ) 93 | assert result.returncode == 1 94 | assert result.stdout == "" 95 | assert ( 96 | f"Snowflake CLI version ({VERSION}) is too low - minimum version required by" 97 | in result.stderr 98 | ) 99 | assert ( 100 | f"template is {metadata.minimum_cli_version}. Please upgrade before continuing." 101 | in result.stderr 102 | ) 103 | -------------------------------------------------------------------------------- /app_streamlit_java/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This is an example template for a Snowflake Native App project which demonstrates the use of Java extension code and adding Streamlit code. This template is meant to guide developers towards a possible project structure on the basis of functionality, as well as to indicate the contents of some common and useful files. 4 | 5 | 6 | # How to build/test this template 7 | ## Build the jar 8 | You need to build the Java application (module-add) to get the .jar file, assuming JDK and Maven are installed and properly configured. 9 | ``` 10 | cd src/module-add/ 11 | mvn clean install 12 | mvn package 13 | ``` 14 | 15 | Similarly, you can also use your own build steps for any other languages supported by Snowflake that you wish to write your code in, and any build automation tools you prefer. For more information on supported languages, visit [docs](https://docs.snowflake.com/en/developer-guide/stored-procedures-vs-udfs#label-sp-udf-languages). 16 | 17 | ## Run the app 18 | Create or update an application package in your Snowflake account, upload application artifacts to a stage in the application package, and create or update an application object in the same account based on the uploaded artifacts. 19 | ``` 20 | snow app run 21 | ``` 22 | 23 | For more information, please refer to the Snowflake Documentation on installing and using Snowflake CLI to create a Snowflake Native App. 24 | 25 | # Directory Structure 26 | ## `/app` 27 | This directory holds your Snowflake Native App files. 28 | 29 | ### `/app/README.md` 30 | Exposed to the account installing the Snowflake Native App with details on what it does and how to use it. 31 | 32 | ### `/app/manifest.yml` 33 | Defines properties required by the application package. Find more details at the [Manifest Documentation.](https://docs.snowflake.com/en/developer-guide/native-apps/creating-manifest) 34 | 35 | ### `/app/setup_script.sql` 36 | Contains SQL statements that are run when an account installs or upgrades a Snowflake Native App. 37 | 38 | ## `/scripts` 39 | You can add any additional scripts such as `.sql` and `.jinja` files here. One of the common use cases for such a script is to be able to add shared content from external databases to your application package, which makes it available to be used in the setup script that runs during Snowflake Native App installation. 40 | _Note: See the note at the end of `snowflake.yml` if you decide to use the scripts. _ 41 | 42 | 43 | ## `/src` 44 | This directory contains code organization by functionality, such as one distinct module for Streamlit related code, and another module for "number add" functionality, which is used an example in this template. 45 | ``` 46 | /src 47 | |-module-add 48 | | |-main 49 | | | |-java/com/snowflake/add 50 | | | |-Add.java 51 | | | 52 | | |-test 53 | | |-java/com/snowflake/add 54 | | |-AddTest.java 55 | |module-ui 56 | | |-src 57 | | |-ui.py 58 | | |-environment.yml 59 | ``` 60 | 61 | ## `snowflake.yml` 62 | `snowflake.yml` is used by Snowflake CLI to discover your project's code and interact with snowflake with all relevant privileges and grants. 63 | 64 | For more information, please refer to the Snowflake Documentation on installing and using Snowflake CLI to create a Snowflake Native App. 65 | 66 | ### Adding a snowflake.local.yml file 67 | Though your project directory already comes with a `snowflake.yml` file, an individual developer can choose to customize the behavior of the Snowflake CLI by providing local overrides to `snowflake.yml`, such as a new role to test out your own application package. This is where you can use `snowflake.local.yml`, which is not a version-controlled file. 68 | 69 | For more information, please refer to the Snowflake Documentation on installing and using Snowflake CLI to create a Snowflake Native App. 70 | 71 | -------------------------------------------------------------------------------- /example_plugin/src/snowflake_cli_example_plugin/commands.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file contains implementation of "secret" command group containing three commands (create, list and drop). 3 | 4 | It presents you usage examples of snowflake.cli.api commands utils. 5 | """ 6 | 7 | from typing import Optional 8 | 9 | import typer 10 | from click import ClickException 11 | from snowflake.cli.api.commands.flags import ( 12 | IdentifierType, 13 | IfNotExistsOption, 14 | ReplaceOption, 15 | like_option, 16 | ) 17 | from snowflake.cli.api.commands.snow_typer import SnowTyperFactory 18 | from snowflake.cli.api.identifiers import FQN 19 | from snowflake.cli.api.output.types import ( 20 | CommandResult, 21 | QueryResult, 22 | SingleQueryResult, 23 | ) 24 | 25 | from snowflake_cli_example_plugin.manager import SecretManager, SecretType 26 | 27 | # If you choose CommandType.SINGLE_COMMAND in plugin_spec.py, SnowTyperFactory instance still need to be created, 28 | # but it should register (via @app.command) only one command. 29 | # In that case [name] and [help] of the SnowTyperFactory will be ignored. 30 | 31 | app = SnowTyperFactory( 32 | name="secret", # name of the command group - commands will be available as "snow object secret X" 33 | help="(plugin) Manage secrets in Snowflake.", 34 | ) 35 | 36 | NameArgument = typer.Argument( 37 | help="Name of the secret.", 38 | show_default=False, 39 | click_type=IdentifierType(), 40 | ) 41 | 42 | 43 | @app.command( 44 | "list", 45 | requires_connection=True, 46 | ) 47 | def list_( 48 | like: str = like_option( 49 | help_example='`list --like "my%"` lists all secrets that begin with “my”' 50 | ), 51 | **options, 52 | ): 53 | """Lists all available secrets.""" 54 | sm = SecretManager() 55 | return QueryResult(sm.show(like=like)) 56 | 57 | 58 | @app.command(requires_connection=True) 59 | def drop(name: FQN = NameArgument, **options): 60 | """Drops secret.""" 61 | sm = SecretManager() 62 | return SingleQueryResult(sm.drop(fqn=name)) 63 | 64 | 65 | @app.command(requires_connection=True) 66 | def describe(name: FQN = NameArgument, **options): 67 | """Describes secret.""" 68 | sm = SecretManager() 69 | return SingleQueryResult(sm.describe(fqn=name)) 70 | 71 | 72 | @app.command(requires_connection=True) 73 | def create( 74 | secret_type: str = typer.Argument( 75 | help=f"Secret type. Should be one of {', '.join(SecretType.all())}", 76 | show_default=False, 77 | ), 78 | name: FQN = NameArgument, 79 | # '_' at the end of the name as 'user' and 'password' are connection arguments 80 | username_: Optional[str] = typer.Option( 81 | None, "--secret-username", help="Username for secret of type 'password'" 82 | ), 83 | password_: Optional[str] = typer.Option( 84 | None, "--secret-password", help="Password for secret of type 'password'" 85 | ), 86 | value: Optional[str] = typer.Option( 87 | None, "--value", help="Value for secret of type 'generic_string'" 88 | ), 89 | # replace_option and if_not_exists option automatically throw an error if used together 90 | if_not_exists: bool = IfNotExistsOption(), 91 | replace: bool = ReplaceOption(), 92 | **options, 93 | ) -> CommandResult: 94 | """ 95 | Creates a secret object in Snowflake. 96 | """ 97 | # validate flags 98 | _type = SecretType.of_string(secret_type.lower()) 99 | if _type == SecretType.PASSWORD and (not username_ or not password_): 100 | raise ClickException( 101 | "Both `--secret-username` and `--secret-password` must be provided for secret of type `password`." 102 | ) 103 | if _type == SecretType.GENERIC_STRING and not value: 104 | raise ClickException( 105 | "`--value` must be provided for secret of type `generic_string`." 106 | ) 107 | 108 | sm = SecretManager() 109 | return SingleQueryResult( 110 | sm.create( 111 | secret_type=_type, 112 | fqn=name, 113 | if_not_exists=if_not_exists, 114 | replace=replace, 115 | username=username_, 116 | password=password_, 117 | value=value, 118 | ) 119 | ) 120 | -------------------------------------------------------------------------------- /example_plugin/README.md: -------------------------------------------------------------------------------- 1 | # Example Snowflake CLI plugin 2 | 3 | This is a simple plugin adding basic management commands for [secret objects](https://docs.snowflake.com/en/user-guide/api-authentication#managing-secrets): 4 | ``` 5 | snow object secret create 6 | snow object secret list 7 | snow object secret describe 8 | snow object secret drop 9 | ``` 10 | It also serves as a boilerplate for developing your own plugin. 11 | 12 | ## Installation and usage 13 | 14 | To install and use the plugin you simply need to install it in the same python environment 15 | Snowflake CLI is installed in. For example, if the CLI was installed via pip, call 16 | ``` 17 | pip install ./ 18 | ``` 19 | You can verify that the plugin is installed by running 20 | ``` 21 | snow plugin list 22 | 23 | +--------------------------+ 24 | | plugin name | enabled | 25 | |----------------+---------| 26 | | example-plugin | False | 27 | +--------------------------+ 28 | ``` 29 | Each plugin needs to be separately enabled. To enable the plugin, call 30 | ``` 31 | snow plugin enable example-plugin 32 | 33 | Plugin example-plugin successfully enabled. 34 | ``` 35 | 36 | After that, you should see `secret` command in `snow object` command group: 37 | ``` 38 | snow object --help 39 | 40 | ... 41 | +- Commands -------------------------------------------------------------------------+ 42 | | create Create an object of a given type. Check documentation for the list of | 43 | | supported objects and parameters. | 44 | | describe Provides description of an object of given type. | 45 | | drop Drops Snowflake object of given name and type. | 46 | | list Lists all available Snowflake objects of given type. | 47 | | secret (plugin) Manage secrets in Snowflake. | 48 | +------------------------------------------------------------------------------------+ 49 | ``` 50 | 51 | To uninstall the plugin, uninstall its package using the same package manager used for installation: 52 | ``` 53 | pip uninstall 54 | ``` 55 | 56 | ### Config 57 | 58 | The plugin has an example configuration containing single boolean argument `print_queries`. 59 | You can modify it in `config.toml`: 60 | ```toml 61 | [cli.plugins.example-plugin.config] 62 | print_queries = true 63 | ``` 64 | 65 | ## Development from a boilerplate 66 | 67 | This plugin consists of 5 files: 68 | ``` 69 | - pyproject.toml 70 | - src/snowflake_cli_example_plugin/ 71 | - __init__.py 72 | - commands.py 73 | - manager.py 74 | - plugin_spec.py 75 | ``` 76 | 77 | ### pyproject.toml 78 | It is a configuration file for python package installers. Each plugin need to be defined as entrypoint 79 | in `"snowflake.cli.plugin.command"` namespace to be detected by CLI. Entrypoint's name defined here is treated 80 | by the CLI as a plugin name for various contexts (reading config, enabling plugin etc.). The entrypoint need to point 81 | to the module with `plugin_spec` implementation. 82 | ```toml 83 | [project.entry-points."snowflake.cli.plugin.command"] 84 | = "snowflake_cli_example_plugin.plugin_spec" 85 | ``` 86 | 87 | ### plugin_spec.py 88 | This file contains a function returning `snowflake.cli.api.plugins.command.CommandSpec` instance, which defines 89 | what commands are registered by the plugin. 90 | 91 | ```python 92 | @plugin_hook_impl 93 | def command_spec(): 94 | return CommandSpec( 95 | parent_command_path=CommandPath(["object"]), 96 | command_type=CommandType.COMMAND_GROUP, 97 | typer_instance=commands.app.create_instance(), 98 | ) 99 | ``` 100 | 101 | | argument | description | 102 | |---------------------|--------------------------------------------------------| 103 | | parent_command_path | command path to which the new command will be appended | 104 | | command type | `SINGLE_COMMAND` or `COMMAND_GROUP` | 105 | | typer_instance | instance of the command implementation | 106 | 107 | 108 | ### commands.py and manager.py 109 | 110 | These files contain an example implementation of the command group, showing usage examples of 111 | `snowflake.cli.api` command utils, and example communication with Snowflake using `SQL` interface. 112 | Feel free to use it, or replace it with another method of communicating with Snowflake 113 | (for example Snowflake Python API). 114 | `manager.py` file also shows a basic example of using custom config for your plugin. 115 | -------------------------------------------------------------------------------- /app_streamlit_python/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This is an example template for a Snowflake Native App project which demonstrates the use of Python extension code and adding Streamlit code. This template is meant to guide developers towards a possible project structure on the basis of functionality, as well as to indicate the contents of some common and useful files. 4 | 5 | Since this template contains Python files only, you do not need to perform any additional steps to build the source code. You can directly go to the next section. However, if there were any source code that needed to be built, you must manually perform the build steps here before proceeding to the next section. 6 | 7 | Similarly, you can also use your own build steps for any other languages supported by Snowflake that you wish to write your code in. For more information on supported languages, visit [docs](https://docs.snowflake.com/en/developer-guide/stored-procedures-vs-udfs#label-sp-udf-languages). 8 | 9 | ## Run the app 10 | Create or update an application package in your Snowflake account, upload application artifacts to a stage in the application package, and create or update an application object in the same account based on the uploaded artifacts. 11 | ``` 12 | snow app run 13 | ``` 14 | 15 | For more information, please refer to the Snowflake Documentation on installing and using Snowflake CLI to create a Snowflake Native App. 16 | # Directory Structure 17 | ## `/app` 18 | This directory holds your Snowflake Native App files. 19 | 20 | ### `/app/README.md` 21 | Exposed to the account installing the application with details on what it does and how to use it. 22 | 23 | ### `/app/manifest.yml` 24 | Defines properties required by the application package. Find more details at the [Manifest Documentation.](https://docs.snowflake.com/en/developer-guide/native-apps/creating-manifest) 25 | 26 | ### `/app/setup_script.sql` 27 | Contains SQL statements that are run when a consumer installs or upgrades a Snowflake Native App in their account. 28 | 29 | ## `/scripts` 30 | You can add any additional scripts such as `.sql` and `.jinja` files here. One common use case for such a script is to add shared content from external databases to your application package. This allows you to refer to the external database in the setup script that runs when a Snowflake Native App is installed. 31 | _Note: See the note at the end of `snowflake.yml` if you decide to use the scripts. _ 32 | 33 | 34 | ## `/src` 35 | This directory contains code organization by functionality, such as one distinct module for Streamlit related code, and another module for "number add" functionality, which is used an example in this template. 36 | ``` 37 | /src 38 | |-module-add 39 | | |-main 40 | | | |-python 41 | | | |-add.py 42 | | | 43 | | |-test 44 | | |-python 45 | | |-add_test.py 46 | | 47 | |-module-ui 48 | | |-src 49 | | |-ui.py 50 | | |-environment.yml 51 | | |-test 52 | | |-test_ui.py 53 | ``` 54 | 55 | ## `snowflake.yml` 56 | Snowflake CLI uses the `snowflake.yml` file to discover your project's code and interact with Snowflake using all relevant privileges and grants. 57 | 58 | For more information, please refer to the Snowflake Documentation on installing and using Snowflake CLI to create a Snowflake Native App. 59 | 60 | ### Adding a snowflake.local.yml file 61 | Though your project directory already comes with a `snowflake.yml` file, an individual developer can choose to customize the behavior of the Snowflake CLI by providing local overrides to `snowflake.yml`, such as a new role to test out your own application package. This is where you can use `snowflake.local.yml`, which is not a version-controlled file. 62 | 63 | For more information, please refer to the Snowflake Documentation on installing and using Snowflake CLI to create a Snowflake Native App. 64 | 65 | 66 | ## Unit tests 67 | To set up and run unit tests, please follow the steps below. 68 | 69 | ### Set up testing conda environment (First Time setup) 70 | 71 | Go to the project's root directory where you can find `local_test_env.yml` and run the following command once to set up a conda environment with the correct packages. Please note that the version of test packages may differ from the version of packages in Snowflake, so you will need to be careful with any differences in behavior. 72 | 73 | ``` 74 | conda env create --file local_test_env.yml 75 | ``` 76 | 77 | This will create a conda environment with the name `streamlit-python-testing`. 78 | 79 | ### Run unit tests 80 | To run unit tests, follow these steps: 81 | 82 | #### Activate conda environment 83 | You will need to activate this conda environment once per command line session: 84 | ``` 85 | conda activate streamlit-python-testing 86 | ``` 87 | To deactivate and use your current command line session for other tasks, run the following: 88 | ``` 89 | conda deactivate 90 | ``` 91 | #### Run Pytest 92 | To run the example tests provided, execute the following command from the project's root: 93 | ``` 94 | pytest 95 | ``` 96 | Note that there is a pytest.ini file specifying the location of the source code that we are testing. 97 | -------------------------------------------------------------------------------- /dcm_project/README.md: -------------------------------------------------------------------------------- 1 | # DCM Project template 2 | 3 | ## Introduction 4 | 5 | You can use this template as a starter project for a Snowflake DCM Project. 6 | 7 | DCM Projects enable declarative infrastructure management, presenting a less error-prone paradigm 8 | that integrates better with Git than imperative approaches. Through automated change detection, DCM 9 | Projects keep the Snowflake environment synchronized with the definition files from different supported 10 | sources (SnowGIT repositories, Workspaces, Stages). DCM Projects automatically create new objects, 11 | modify existing objects, and delete objects that are no longer needed, which supports CI/CD best 12 | practices when working with Snowflake environments. 13 | 14 | ## Directory Structure 15 | 16 | ``` 17 | (4) 18 | ├── definitions (2) 19 | │   ├────── access.sql 20 | │   ├────── ingest.sql 21 | │   ├────── raw.sql (3) 22 | │   ├────── serve.sql 23 | │  └────── [...] 24 | └── manifest.yml (1) 25 | ``` 26 | 27 | 1. [manifest.yml][manifest] - is the file that defines: 28 | * what files should be included in the project definition. In the `include_definitions` list, you can pass items that are Java regex patterns. The default value is `- definitions/.*`, meaning that all files in the `definitions` folder and its subfolders will be included. 29 | * configurations that group template variables with their default values. Configurations can be specified here as a series of key-value entries, where the key is a case-insensitive configuration name, and the value is a series of key-value entries, mapping the template variable name to its value. Each configuration contains a set of key-value pairs, e.g. `example_db_name: "db1"`. 30 | 2. `definitions` - is the default directory as defined in the [manifest.yml][manifest] for all .sql files containing project entity definitions. You can use an arbitrarily nested directory structure. 31 | 3. [raw.sql][raw.sql] - this is the file that contains some example definitions of project entities. You define particular entities with a `DEFINE` keyword which behaves similar to `CREATE OR ALTER`, e.g. `DEFINE DATABASE d1 COMMENT = 'some comment'`. Removing a `DEFINE` statement results in the entity being dropped. 32 | 4. `` - is the repository project folder. 33 | 34 | ### How to organize definition files structure 35 | 36 | Once you initialize a project from the template, you create the definitions that will set up your 37 | account. The template doesn't impose any file structure of definition files, but keep in mind that you 38 | don't need to keep all definition statements in a single file. You can organize the code in multiple 39 | files divided into different directories, such as single object type per file. The following 40 | example uses a more complex file structure: 41 | 42 | ``` 43 | 44 | ├── definitions 45 | │ ├────── wh_db_roles.sql 46 | │ ├────── load 47 | │ ├────── transform 48 | │ └────── serve 49 | │ ├────── dashboard_views.sql 50 | │ ├────── annual_agg.sql 51 | │ └────── team_metrics.sql 52 | └── manifest.yml 53 | ``` 54 | 55 | You must include all files from the `definitions` directory in the `manifest.yaml` file: 56 | 57 | ```yaml 58 | manifest_version: 1.0 59 | 60 | include_definitions: 61 | - definitions/.* 62 | ``` 63 | 64 | ## Working on DCM Projects with Snowflake CLI 65 | 66 | ### 1. Initialize a DCM Project from the template 67 | 68 | To initialize a new DCM Project from this template, execute the following command and provide the 69 | data required in command prompts. This command creates a new directory with DCM Project files. 70 | Replace `` with the desired name for the project directory. 71 | 72 | ```bash 73 | snow init --template dcm_project 74 | ``` 75 | 76 | example usage: 77 | 78 | ```bash 79 | snow init MY_PROJECT --template dcm_project 80 | ``` 81 | 82 | ### 2. Define entities in `.sql` files 83 | 84 | In this step, you define the entities you want the DCM Project to manage. You can define these entities 85 | in the prepared `definitions/*.sql` files, but you can also create your own files. If you 86 | decide to add more `.sql` files, make sure that they will be included in the DCM Project execution process 87 | by adding their paths to `include_definitions` list in the [manifest.yaml][manifest] file. 88 | 89 | An example content of the definition file: 90 | ```sql 91 | DEFINE ROLE role1; 92 | DEFINE DATABASE ROLE role2; 93 | 94 | DEFINE DATABASE db1; 95 | DEFINE DATABASE db2; 96 | 97 | DEFINE SCHEMA db1.sch1; 98 | DEFINE SCHEMA db2.sch2; 99 | 100 | DEFINE TABLE db1.sch1.tb1 (col_1 integer, col_2 varchar); 101 | DEFINE TABLE db2.sch2.tb2 (col_3 integer, col_4 varchar); 102 | ``` 103 | 104 | ### 3. Create the DCM Project 105 | 106 | After entity definitions included in definition files are ready to be applied to your infrastructure, 107 | you must create a DCM Project. You can perform this operation by executing the command below: 108 | 109 | ```bash 110 | snow dcm create EXAMPLE_PROJECT 111 | ``` 112 | 113 | The DCM Project will be created in the current sessions' 114 | database and schema or in these, which are specified in the flags of `snow` command. 115 | 116 | ### 4. DCM Plan 117 | 118 | After creating a new DCM Project, you can validate what changes will be applied to your Snowflake 119 | account with this command. It will perform all the same validations and consistency checks 120 | like a regular `snow dcm deploy`, but will not persist any changes to your Snowflake account objects. 121 | 122 | ```bash 123 | snow dcm plan --configuration 124 | ``` 125 | 126 | example usage: 127 | 128 | ```bash 129 | snow dcm plan EXAMPLE_PROJECT --configuration "PROD" 130 | ``` 131 | 132 | #### DCM Plan from prepared project files in Snowflake storage 133 | 134 | Alternatively if you synchronize your project files with a [SNOWGIT REPOSITORY][snowgit_docs], develop 135 | the DCM Project with [a WORKSPACE][workspaces_docs], or simply you have your project files prepared in 136 | a [USER STAGE][stages_docs], you can specify the source storage with `--from` option, from which you 137 | would like to use the project files for DCM Project `PLAN` commands. 138 | 139 | ```bash 140 | snow dcm plan --from --configuration 141 | ``` 142 | 143 | example usage: 144 | 145 | ```bash 146 | snow dcm plan EXAMPLE_PROJECT --from "@DB.SCH.SOURCE_STAGE/dcm_project" --configuration "PROD" 147 | ``` 148 | 149 | ### 5. Deploy DCM Project 150 | 151 | In order to apply changes to your Snowflake account you need to deploy the current definition 152 | the DCM Project. It is recommended to first review a plan of the changes. You can deploy the changes 153 | with the following command: 154 | 155 | ```bash 156 | snow dcm deploy --configuration 157 | ``` 158 | 159 | example usage: 160 | 161 | ```bash 162 | snow dcm deploy EXAMPLE_PROJECT --configuration "DEV" 163 | ``` 164 | 165 | #### DCM Deploy from prepared project files in Snowflake storage 166 | 167 | Alternatively if you synchronize your project files with a [SNOWGIT REPOSITORY][snowgit_docs], develop 168 | the DCM Project with [a WORKSPACE][workspaces_docs], or simply you have your project files prepared in 169 | a [USER STAGE][stages_docs], you can specify the source storage with `--from` option, from which you 170 | would like to use the project files for DCM Project `DEPLOY` command. 171 | 172 | ```bash 173 | snow dcm deploy --from --configuration 174 | ``` 175 | 176 | example usage: 177 | 178 | ```bash 179 | snow dcm deploy EXAMPLE_PROJECT --from "DB.SCH.SOURCE_STAGE/dcm_project" --configuration "PROD" 180 | ``` 181 | 182 | [manifest]: ./manifest.yml 183 | [raw.sql]: ./definitions/raw.sql 184 | [template]: ./template.yml 185 | [workspaces_docs]: https://docs.snowflake.com/en/user-guide/ui-snowsight/workspaces 186 | [stages_docs]: https://docs.snowflake.com/en/user-guide/data-load-local-file-system-create-stage 187 | [snowgit_docs]: https://docs.snowflake.com/en/developer-guide/git/git-overview 188 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------