diff --git a/src/snowcli/app/commands_registration/builtin_plugins.py b/src/snowcli/app/commands_registration/builtin_plugins.py index 720865427b..f77fd56def 100644 --- a/src/snowcli/app/commands_registration/builtin_plugins.py +++ b/src/snowcli/app/commands_registration/builtin_plugins.py @@ -1,6 +1,7 @@ from snowcli.cli.connection import plugin_spec as connection_plugin_spec from snowcli.cli.containers import plugin_spec as containers_plugin_spec from snowcli.cli.nativeapp import plugin_spec as nativeapp_plugin_spec +from snowcli.cli.appify import plugin_spec as appify_plugin_spec from snowcli.cli.object import plugin_spec as object_plugin_spec from snowcli.cli.registry import plugin_spec as registry_plugins_spec from snowcli.cli.render import plugin_spec as render_plugin_spec @@ -13,6 +14,7 @@ "connection": connection_plugin_spec, "containers": containers_plugin_spec, "nativeapp": nativeapp_plugin_spec, + "appify": appify_plugin_spec, "object": object_plugin_spec, "registry": registry_plugins_spec, "render": render_plugin_spec, diff --git a/src/snowcli/cli/appify/__init__.py b/src/snowcli/cli/appify/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/snowcli/cli/appify/commands.py b/src/snowcli/cli/appify/commands.py new file mode 100644 index 0000000000..443e5b2066 --- /dev/null +++ b/src/snowcli/cli/appify/commands.py @@ -0,0 +1,53 @@ +import logging +from typing import Optional + +import typer +from snowcli.cli.common.decorators import ( + global_options, + global_options_with_connection, +) +from snowcli.cli.common.flags import DEFAULT_CONTEXT_SETTINGS +from snowcli.cli.nativeapp.init import nativeapp_init +from snowcli.output.decorators import with_output +from snowcli.output.types import CommandResult, MessageResult + +from snowcli.cli.appify.metadata import MetadataDumper + +# from snowcli.cli.appify.generate import ... + +app = typer.Typer( + context_settings=DEFAULT_CONTEXT_SETTINGS, + name="appify", + help="Generate a Native Application project from an existing database", +) + +log = logging.getLogger(__name__) + + +@app.command() +@with_output +@global_options_with_connection +def appify( + db: str = typer.Argument( + ..., + help="The database to extract metadata from and turn into an app.", + ), + name: str = typer.Option( + None, + help=f"""The name of the native application project to include in snowflake.yml. When not specified, it is + generated from the name of the database. Names are assumed to be unquoted identifiers whenever possible, but + can be forced to be quoted by including the surrounding quote characters in the provided value.""", + ), + **options, +) -> CommandResult: + """ + Initializes a Native Apps project from a database. + """ + return MessageResult(f"Creating from {db}.") + + # project = nativeapp_init(path=db, name=name) + # metadata_path = project.path / "metadata" + # dumper = MetadataDumper(db, metadata_path) + + # for stage in dumper.stages: + # pass diff --git a/src/snowcli/cli/appify/generate.py b/src/snowcli/cli/appify/generate.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/snowcli/cli/appify/metadata.py b/src/snowcli/cli/appify/metadata.py new file mode 100644 index 0000000000..845093a037 --- /dev/null +++ b/src/snowcli/cli/appify/metadata.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +import logging +from functools import cached_property +from pathlib import Path +from typing import Callable, List, Literal, Optional + +from click.exceptions import ClickException +from snowcli.cli.common.sql_execution import SqlExecutionMixin +from snowcli.cli.object.stage.manager import StageManager +from snowcli.cli.project.definition_manager import DefinitionManager + + +log = logging.getLogger(__name__) + +REFERENCES_BY_NAME_JSON = "references_by_name.json" +REFERENCES_OBJECT_TYPES = ["function", "table", "view"] + + +class MetadataDumper(SqlExecutionMixin): + """ + Dumps a Snowflake database as folders and files in a local filesystem. + Schemas become directories, and other objects become sql files with their DDL. + Dependencies between objects that use the reference framework are stored in a JSON file. + Stages are dumped in entirety and become directories. + """ + + database: str + target_path: DefinitionManager + + def __init__(self, database: str, target_path: Path): + super().__init__() + self.database = database + self.target_path = target_path diff --git a/src/snowcli/cli/appify/plugin_spec.py b/src/snowcli/cli/appify/plugin_spec.py new file mode 100644 index 0000000000..e822659e6c --- /dev/null +++ b/src/snowcli/cli/appify/plugin_spec.py @@ -0,0 +1,16 @@ +from snowcli.api.plugin.command import ( + SNOWCLI_ROOT_COMMAND_PATH, + CommandSpec, + CommandType, + plugin_hook_impl, +) +from snowcli.cli.appify import commands + + +@plugin_hook_impl +def command_spec(): + return CommandSpec( + parent_command_path=SNOWCLI_ROOT_COMMAND_PATH, + command_type=CommandType.SINGLE_COMMAND, + typer_instance=commands.app, + )