Skip to content

Commit 925c9f4

Browse files
feat: [SNOW-2326971] implement dcm preview command
1 parent 1ed1b08 commit 925c9f4

File tree

6 files changed

+673
-97
lines changed

6 files changed

+673
-97
lines changed

src/snowflake/cli/_plugins/dcm/commands.py

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from snowflake.cli._plugins.object.commands import scope_option
2828
from snowflake.cli._plugins.object.manager import ObjectManager
2929
from snowflake.cli.api.commands.flags import (
30+
IdentifierType,
3031
IfExistsOption,
3132
IfNotExistsOption,
3233
OverrideableOption,
@@ -137,13 +138,12 @@ def deploy(
137138
spinner.add_task(description=f"Deploying dcm project {identifier}", total=None)
138139
if skip_plan:
139140
cli_console.warning("Skipping planning step")
140-
result = manager.execute(
141+
result = manager.deploy(
141142
project_identifier=identifier,
142143
configuration=configuration,
143144
from_stage=effective_stage,
144145
variables=variables,
145146
alias=alias,
146-
output_path=None,
147147
skip_plan=skip_plan,
148148
)
149149
return QueryJsonValueResult(result)
@@ -168,11 +168,10 @@ def plan(
168168

169169
with cli_console.spinner() as spinner:
170170
spinner.add_task(description=f"Planning dcm project {identifier}", total=None)
171-
result = manager.execute(
171+
result = manager.plan(
172172
project_identifier=identifier,
173173
configuration=configuration,
174174
from_stage=effective_stage,
175-
dry_run=True,
176175
variables=variables,
177176
output_path=output_path,
178177
)
@@ -338,6 +337,53 @@ def refresh(
338337
return MessageResult(message)
339338

340339

340+
@app.command(requires_connection=True)
341+
def preview(
342+
identifier: FQN = dcm_identifier,
343+
object_identifier: FQN = typer.Option(
344+
...,
345+
"--object",
346+
help="FQN of table/view/etc to be previewed.",
347+
show_default=False,
348+
click_type=IdentifierType(),
349+
),
350+
from_location: Optional[str] = from_option,
351+
variables: Optional[List[str]] = variables_flag,
352+
configuration: Optional[str] = configuration_flag,
353+
limit: Optional[int] = typer.Option(
354+
None,
355+
"--limit",
356+
help="The maximum number of rows to be returned.",
357+
show_default=False,
358+
),
359+
**options,
360+
):
361+
"""
362+
Returns rows from any table, view, dynamic table.
363+
364+
Examples:
365+
\nsnow dcm preview MY_PROJECT --configuration DEV --object MY_DB.PUBLIC.MY_VIEW --limit 2
366+
"""
367+
manager = DCMProjectManager()
368+
effective_stage = _get_effective_stage(identifier, from_location)
369+
370+
with cli_console.spinner() as spinner:
371+
spinner.add_task(
372+
description=f"Previewing {object_identifier}.",
373+
total=None,
374+
)
375+
result = manager.preview(
376+
project_identifier=identifier,
377+
object_identifier=object_identifier,
378+
configuration=configuration,
379+
from_stage=effective_stage,
380+
variables=variables,
381+
limit=limit,
382+
)
383+
384+
return QueryResult(result)
385+
386+
341387
def _get_effective_stage(identifier: FQN, from_location: Optional[str]):
342388
manager = DCMProjectManager()
343389
if not from_location:

src/snowflake/cli/_plugins/dcm/manager.py

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -77,41 +77,42 @@ def _collect_output(
7777
else:
7878
cli_console.step(f"Plan output saved to: {output_path}")
7979

80-
def execute(
80+
def deploy(
8181
self,
8282
project_identifier: FQN,
8383
from_stage: str,
8484
configuration: str | None = None,
8585
variables: List[str] | None = None,
86-
dry_run: bool = False,
8786
alias: str | None = None,
88-
output_path: str | None = None,
8987
skip_plan: bool = False,
9088
):
91-
with self._collect_output(project_identifier, output_path) if (
92-
output_path and dry_run
93-
) else nullcontext() as output_stage:
94-
query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier}"
95-
if dry_run:
96-
query += " PLAN"
97-
else:
98-
query += " DEPLOY"
99-
if alias:
100-
query += f' AS "{alias}"'
101-
if configuration or variables:
102-
query += f" USING"
103-
if configuration:
104-
query += f" CONFIGURATION {configuration}"
105-
if variables:
106-
query += StageManager.parse_execute_variables(
107-
parse_key_value_variables(variables)
108-
).removeprefix(" using")
109-
stage_path = StagePath.from_stage_str(from_stage)
110-
query += f" FROM {stage_path.absolute_path()}"
89+
query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier} DEPLOY"
90+
if alias:
91+
query += f' AS "{alias}"'
92+
query += self._get_configuration_and_variables_query(configuration, variables)
93+
query += self._get_from_stage_query(from_stage)
94+
if skip_plan:
95+
query += f" SKIP PLAN"
96+
return self.execute_query(query=query)
97+
98+
def plan(
99+
self,
100+
project_identifier: FQN,
101+
from_stage: str,
102+
configuration: str | None = None,
103+
variables: List[str] | None = None,
104+
output_path: str | None = None,
105+
):
106+
with self._collect_output(
107+
project_identifier, output_path
108+
) if output_path else nullcontext() as output_stage:
109+
query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier} PLAN"
110+
query += self._get_configuration_and_variables_query(
111+
configuration, variables
112+
)
113+
query += self._get_from_stage_query(from_stage)
111114
if output_stage is not None:
112115
query += f" OUTPUT_PATH {output_stage}"
113-
if skip_plan:
114-
query += f" SKIP PLAN"
115116
result = self.execute_query(query=query)
116117

117118
return result
@@ -147,6 +148,42 @@ def refresh(self, project_identifier: FQN):
147148
query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier} REFRESH ALL"
148149
return self.execute_query(query=query)
149150

151+
def preview(
152+
self,
153+
project_identifier: FQN,
154+
object_identifier: FQN,
155+
from_stage: str,
156+
configuration: str | None = None,
157+
variables: List[str] | None = None,
158+
limit: int | None = None,
159+
):
160+
query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier} PREVIEW {object_identifier.sql_identifier}"
161+
query += self._get_configuration_and_variables_query(configuration, variables)
162+
query += self._get_from_stage_query(from_stage)
163+
if limit is not None:
164+
query += f" LIMIT {limit}"
165+
return self.execute_query(query=query)
166+
167+
@staticmethod
168+
def _get_from_stage_query(from_stage: str) -> str:
169+
stage_path = StagePath.from_stage_str(from_stage)
170+
return f" FROM {stage_path.absolute_path()}"
171+
172+
@staticmethod
173+
def _get_configuration_and_variables_query(
174+
configuration: str | None, variables: List[str] | None
175+
) -> str:
176+
query = ""
177+
if configuration or variables:
178+
query += f" USING"
179+
if configuration:
180+
query += f" CONFIGURATION {configuration}"
181+
if variables:
182+
query += StageManager.parse_execute_variables(
183+
parse_key_value_variables(variables)
184+
).removeprefix(" using")
185+
return query
186+
150187
@staticmethod
151188
def sync_local_files(
152189
project_identifier: FQN, source_directory: str | None = None

0 commit comments

Comments
 (0)