Skip to content

Commit f00a3fb

Browse files
feat: [SNOW-2326971] implement dcm preview command
1 parent 1cec2b0 commit f00a3fb

File tree

6 files changed

+670
-94
lines changed

6 files changed

+670
-94
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,
@@ -130,13 +131,12 @@ def deploy(
130131

131132
with cli_console.spinner() as spinner:
132133
spinner.add_task(description=f"Deploying dcm project {identifier}", total=None)
133-
result = manager.execute(
134+
result = manager.deploy(
134135
project_identifier=identifier,
135136
configuration=configuration,
136137
from_stage=effective_stage,
137138
variables=variables,
138139
alias=alias,
139-
output_path=None,
140140
)
141141
return QueryJsonValueResult(result)
142142

@@ -160,11 +160,10 @@ def plan(
160160

161161
with cli_console.spinner() as spinner:
162162
spinner.add_task(description=f"Planning dcm project {identifier}", total=None)
163-
result = manager.execute(
163+
result = manager.plan(
164164
project_identifier=identifier,
165165
configuration=configuration,
166166
from_stage=effective_stage,
167-
dry_run=True,
168167
variables=variables,
169168
output_path=output_path,
170169
)
@@ -330,6 +329,53 @@ def refresh(
330329
return MessageResult(message)
331330

332331

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

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

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,36 +77,37 @@ 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,
87+
):
88+
query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier} DEPLOY"
89+
if alias:
90+
query += f' AS "{alias}"'
91+
query += self._get_configuration_and_variables_query(configuration, variables)
92+
query += self._get_from_stage_query(from_stage)
93+
return self.execute_query(query=query)
94+
95+
def plan(
96+
self,
97+
project_identifier: FQN,
98+
from_stage: str,
99+
configuration: str | None = None,
100+
variables: List[str] | None = None,
88101
output_path: str | None = None,
89102
):
90-
with self._collect_output(project_identifier, output_path) if (
91-
output_path and dry_run
92-
) else nullcontext() as output_stage:
93-
query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier}"
94-
if dry_run:
95-
query += " PLAN"
96-
else:
97-
query += " DEPLOY"
98-
if alias:
99-
query += f' AS "{alias}"'
100-
if configuration or variables:
101-
query += f" USING"
102-
if configuration:
103-
query += f" CONFIGURATION {configuration}"
104-
if variables:
105-
query += StageManager.parse_execute_variables(
106-
parse_key_value_variables(variables)
107-
).removeprefix(" using")
108-
stage_path = StagePath.from_stage_str(from_stage)
109-
query += f" FROM {stage_path.absolute_path()}"
103+
with self._collect_output(
104+
project_identifier, output_path
105+
) if output_path else nullcontext() as output_stage:
106+
query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier} PLAN"
107+
query += self._get_configuration_and_variables_query(
108+
configuration, variables
109+
)
110+
query += self._get_from_stage_query(from_stage)
110111
if output_stage is not None:
111112
query += f" OUTPUT_PATH {output_stage}"
112113
result = self.execute_query(query=query)
@@ -144,6 +145,42 @@ def refresh(self, project_identifier: FQN):
144145
query = f"EXECUTE DCM PROJECT {project_identifier.sql_identifier} REFRESH ALL"
145146
return self.execute_query(query=query)
146147

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

0 commit comments

Comments
 (0)