Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Execute user script refactor #1695

Closed

Conversation

sfc-gh-pjafari
Copy link
Contributor

@sfc-gh-pjafari sfc-gh-pjafari commented Oct 9, 2024

Pre-review checklist

  • I've confirmed that instructions included in README.md are still correct after my changes in the codebase.
  • I've added or updated automated unit tests to verify correctness of my new code.
  • I've added or updated integration tests to verify correctness of my new code.
  • I've confirmed that my changes are working by executing CLI's commands manually on MacOS.
  • I've confirmed that my changes are working by executing CLI's commands manually on Windows.
  • I've confirmed that my changes are up-to-date with the target branch.
  • I've described my changes in the release notes.
  • I've described my changes in the section below.

Changes description

NOTE - This is a PR against @sfc-gh-mchok's telemetry branch, since I use some error types he's introduced

Started a SQLService abstraction layer. The goal is to extract execute_query calls that are embedded in the logic out to their own unit. This PR uses package scripts to show an example of the restructuring.
use role, warehouse, and database calls are moved to this layer. See test_package_scripts_with_conn_warehouse for and example of an updated test.

NOTE - Since the start of this work, apply_package_scripts is no longer invoked by any commands (in favor of post-deploy hooks). That's why there are no integration tests associated with this change, even though some error handling has changed.
Exhaustive test cases for execute_user_script as well as integ tests to be added when making similar change for running post_deploy hooks in an upcoming PR.
...

@sfc-gh-pjafari sfc-gh-pjafari marked this pull request as ready for review October 9, 2024 17:39
@sfc-gh-pjafari sfc-gh-pjafari requested review from a team as code owners October 9, 2024 17:39
Copy link
Contributor

@sfc-gh-fcampbell sfc-gh-fcampbell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just some drive-by suggestions

src/snowflake/cli/api/sql_contract.py Outdated Show resolved Hide resolved
src/snowflake/cli/api/sql_contract.py Outdated Show resolved Hide resolved
src/snowflake/cli/api/sql_contract.py Outdated Show resolved Hide resolved
src/snowflake/cli/api/sql_contract.py Outdated Show resolved Hide resolved
src/snowflake/cli/api/sql_contract.py Outdated Show resolved Hide resolved
src/snowflake/cli/api/sql_contract.py Outdated Show resolved Hide resolved
src/snowflake/cli/api/sql_contract.py Outdated Show resolved Hide resolved
src/snowflake/cli/api/sql_contract.py Outdated Show resolved Hide resolved
@sfc-gh-pjafari sfc-gh-pjafari marked this pull request as draft October 9, 2024 19:02
@sfc-gh-pjafari sfc-gh-pjafari changed the base branch from mchok-improve-ProgrammingError to main October 11, 2024 19:47
@sfc-gh-pjafari sfc-gh-pjafari changed the base branch from main to mchok-improve-ProgrammingError October 11, 2024 19:47
@sfc-gh-pjafari sfc-gh-pjafari force-pushed the pj-user-script-refactor branch from 0519636 to ddf215c Compare October 11, 2024 19:49
@sfc-gh-pjafari sfc-gh-pjafari marked this pull request as ready for review October 11, 2024 19:52
src/snowflake/cli/_plugins/nativeapp/sf_sql_facade.py Outdated Show resolved Hide resolved
Comment on lines 5 to 7
def get_snowflake_facade(sql_executor: SqlExecutor | None) -> SnowflakeSQLFacade:
"""Returns a Snowflake Facade"""
return SnowflakeSQLFacade(sql_executor)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why require an executor at all? At least we should use None by default IMHO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see @sfc-gh-fcampbell's comment here #1695 (comment)
Though we are currently always creating a new instance of sql_executor where we need it. imo the way we are using it rn either way ends up the same. But we can make a design decision as to if we want to pass the sql executor in or instantiate it in SnowflakeSQLFacade.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO the executor is pretty much an implementation detail here, and I'd only expect it to be replaced for tests so we can inspect our interaction with a low-level executor. I do like the simplicity of just acquiring a facade object (could be a global or per-thread singleton) from anywhere in the code, as long as we can easily mock it out when we need to test code that interacts with the facade.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment on lines +77 to +79
wh_result = self._sql_executor.execute_query(
f"select current_warehouse()"
).fetchone()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what should be the behaviour if this fails? It shouldn't fail, I know, but we should control the contract if it ever does. Right now we'd probably just let a ProgrammingError bubble up. Is that what we want?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think with our error classifications now bubbbling it up as a ProgrammingError is fair (categorizes it as not 100% the user's fault). Would you say if we get a failure here it's fair to assume we need act on it and see what's wrong?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a weird state for sure if something fails, but I'm not convinced that ProgrammingError is the right contract. We know what failed here, and it's not wrong SQL.

finally:
if is_different_wh and prev_wh is not None:
self._log.debug(f"Switching back to warehouse:{prev_wh}")
self._sql_executor.execute_query(f"use warehouse {prev_wh}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, what happens if this fails? Technically the user script could drop the warehouse or otherwise make it inaccessible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point. and the same can be said about the use database case. See update. made a _use_object method that has the error handling it and using it for all use object_type object_name calls.

tests/nativeapp/test_package_scripts.py Outdated Show resolved Hide resolved
Comment on lines 26 to 27
# TODO: Add more test coverage + define contract
# TODO: Add test for non-identifier names
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-follow PRs? What's the plan here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, see note on my PR description. This class is not used in any code path (since Frank has removed apply_package_script in the meantime). So more tests and integ tests to be added in the upcoming PR for post deploy hooks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to cover the facade in isolation though...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added tests

role = "mock_role"
wh = "mock_wh"
database = "mock_db"
side_effects, expected = mock_execute_helper(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you have a better pattern, use it instead. This is pretty much NADE legacy at this point. We could also create a new abstraction / helper for SQL testing in this file, since it will be used here almost exclusively.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using this helper is OK for when we actually want to test the sql.
And its usage in other tests will be reduced and removed as I refactor more SQL calls into this class.
Of course there are small improvements I can do to it like switching the order of expected call and side_effect but not sure how much we'll gain from that.

@sfc-gh-pjafari
Copy link
Contributor Author

closing this PR, new PR on main here #1732

@sfc-gh-pjafari sfc-gh-pjafari deleted the pj-user-script-refactor branch October 23, 2024 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants