Skip to content

Commit 072f458

Browse files
feat: [SNOW-2326971] implement dcm preview command
1 parent 5d08a11 commit 072f458

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
@@ -24,6 +24,7 @@
2424
from snowflake.cli._plugins.object.commands import scope_option
2525
from snowflake.cli._plugins.object.manager import ObjectManager
2626
from snowflake.cli.api.commands.flags import (
27+
IdentifierType,
2728
IfExistsOption,
2829
IfNotExistsOption,
2930
OverrideableOption,
@@ -127,13 +128,12 @@ def deploy(
127128

128129
with cli_console.spinner() as spinner:
129130
spinner.add_task(description=f"Deploying dcm project {identifier}", total=None)
130-
result = manager.execute(
131+
result = manager.deploy(
131132
project_identifier=identifier,
132133
configuration=configuration,
133134
from_stage=effective_stage,
134135
variables=variables,
135136
alias=alias,
136-
output_path=None,
137137
)
138138
return QueryJsonValueResult(result)
139139

@@ -157,11 +157,10 @@ def plan(
157157

158158
with cli_console.spinner() as spinner:
159159
spinner.add_task(description=f"Planning dcm project {identifier}", total=None)
160-
result = manager.execute(
160+
result = manager.plan(
161161
project_identifier=identifier,
162162
configuration=configuration,
163163
from_stage=effective_stage,
164-
dry_run=True,
165164
variables=variables,
166165
output_path=output_path,
167166
)
@@ -308,6 +307,53 @@ def refresh(
308307
return MessageResult(message)
309308

310309

310+
@app.command(requires_connection=True)
311+
def preview(
312+
identifier: FQN = dcm_identifier,
313+
object_identifier: FQN = typer.Option(
314+
...,
315+
"--object",
316+
help="FQN of table/view/etc to be previewed.",
317+
show_default=False,
318+
click_type=IdentifierType(),
319+
),
320+
from_location: Optional[str] = from_option,
321+
variables: Optional[List[str]] = variables_flag,
322+
configuration: Optional[str] = configuration_flag,
323+
limit: Optional[int] = typer.Option(
324+
None,
325+
"--limit",
326+
help="The maximum number of rows to be returned.",
327+
show_default=False,
328+
),
329+
**options,
330+
):
331+
"""
332+
Returns rows from any table, view, dynamic table.
333+
334+
Examples:
335+
\nsnow dcm preview MY_PROJECT --configuration DEV --object MY_DB.PUBLIC.MY_VIEW --limit 2
336+
"""
337+
manager = DCMProjectManager()
338+
effective_stage = _get_effective_stage(identifier, from_location)
339+
340+
with cli_console.spinner() as spinner:
341+
spinner.add_task(
342+
description=f"Previewing {object_identifier}.",
343+
total=None,
344+
)
345+
result = manager.preview(
346+
project_identifier=identifier,
347+
object_identifier=object_identifier,
348+
configuration=configuration,
349+
from_stage=effective_stage,
350+
variables=variables,
351+
limit=limit,
352+
)
353+
354+
return QueryResult(result)
355+
356+
311357
def _get_effective_stage(identifier: FQN, from_location: Optional[str]):
312358
manager = DCMProjectManager()
313359
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)