├── 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 |
--------------------------------------------------------------------------------