Add BigQueryToPostgresOperator - #30658

Merged
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator
May 16, 2023
Merged

Add BigQueryToPostgresOperator#30658
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator

Conversation

@jbbqqf

Copy link
Copy Markdown
Contributor

Yet another operator.

I added that transfer operator by mimicry with the existing BigQueryToMySqlOperator.

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

I noticed the BigQueryToMySqlOperator is referenced in airflow/contrib/operators/__init__.py (__deprecated_classes) and in tests/always/test_project_structure.py (MISSING_EXAMPLES_FOR_CLASSES). I am not 100% sure of what those references mean but I guess the new BigQueryToPostgresOperator doesn't need to be referenced here.

@boring-cyborgboring-cyborgBot added area:providers kind:documentation provider:google Google (including GCP) related issues labels Apr 15, 2023
@boring-cyborg

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst)
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our pre-commits will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example DAG that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

@pankajastropankajastro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might not catch something like dataset.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored the implementation. I am now using a BaseBigQueryToSqlOperator. In order to remain as backward compatible as possible, I used the old implementation tied to the MySQL operator.

If the user does not provide a correct input it will fail at runtime anyway (in the execute method).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why fmt off?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I initially copy/pasted the MySQL implementation without thinking too much about it. After digging in the commit history it looks like those fmt directives are old artifacts that can be removed with no side effect, which I did.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also add a test to check bigquery_get_data has been called correctly

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The current assertion already ensures bigquery_get_data has been called as a side effect:

 mock_hook.return_value.list_rows.assert_called_once_with(

list_rows comes from bigquery_get_data.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

missing docs string for this param

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I fixed those missing docstrings

@eladkal

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it?
but even if the parameter stays moving to generalized solution makes this a no concern.

@shahar1

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it? but even if the parameter stays moving to generalized solution makes this a no concern.

I'm up to it, will happen during this week

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

@potiuk

potiuk commented Apr 16, 2023

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:
    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 9458e98 to 6aeb2d1CompareApril 16, 2023 23:02
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

@eladkal ok, deal. I refactored the two twin operators with a BaseBigQueryToSqlOperator and used it to implement the new BigQueryToPostgresOperator. I had to make some tweaks though to remain backward compatible because of subtle differences.

I took the opportunity to factorize docstrings. That said, I'm not 100% sure that documenting only two parameters in BigQueryToPostgresOperator is the way to go, considering some mandatory parameters handled (and documented) in the parent class, BaseBigQueryToSqlOperator, are required. You tell me.

The generated documentation looks fine. Here is an example (I also checked the other impacted pages):
image

The only tests I have not been able to run with Breeze are the example dags in tests/system/providers/google/cloud/bigquery/. The command breeze testing tests tests/system/providers/google/cloud/bigquery/ doesn't seem to do the trick.

@jbbqqf
jbbqqf requested a review from pankajastroApril 16, 2023 23:19

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @jbbqqf - just noticed we are getting the class name split across multiple lines in the documentation, is there anything we could do to fix it?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@phanikumv I don't want to fix this issue in this PR. The diff is not the cause of the issue from what I can see on Airflow's latest online documentation (https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/transfers/bigquery_to_mysql/index.html).

That said, this is how I would have done it:

image

@pankajastro

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:

    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

thanks for the detailed explanation makes sense 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

does it makes sense to combine Postgres and MySQL system test here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I don't understand what you'd suggest

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I left as is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep. Better to keep them separate. In this case usability of those examples trumps DRY

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Putting request changes just to make sure #30748 is merged before this PR so the delegate_to parameter won't be in BaseBigQueryToSqlOperator

@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf you can now rebase and the delegate_to won't be an issue as it was removed in main

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 6aeb2d1 to c744f08CompareApril 23, 2023 09:29

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This was removed from main. This parameter doesn't exist any more

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 6e711ea to eaecfb1CompareApril 23, 2023 17:44
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

I made everything I could with the feedback I've received on this PR.

The code is factorized so that the new PostgresOperator is not a copy/paste version of the Mysql one. The documentation is also as factorized as it can be.

I rebased and removed the delegate_to parameter. I eventually managed to make static checks + build pass thanks to breeze. All CI checks designed to make sure no doc / tests are forgotten do pass.

I built the documentation locally. It looks fine.

I tested operators with a local airflow / postgresql / mysql + test gcp project. Basic operations work.

By basic operation I mean I tested those tasks:

 bigquery_to_mysql = BigQueryToMySqlOperator(
task_id="bigquery_to_mysql",
dataset_table="dataset.table_42",
mysql_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)
bigquery_to_postgres = BigQueryToPostgresOperator(
task_id="bigquery_to_postgres",
dataset_table="dataset.table_42",
postgres_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)

During my tests I noticed there was an error with template_fields. It should now be fixed.

I performed my local tests with a postgres and a mysql database. I didn't manually test the mssql operator.

Is there some additional tests I should perform that would cover common pitfalls?

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

@potiuk

potiuk commented Apr 23, 2023

Copy link
Copy Markdown
Member

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

To start - maybe get all the tests succeed :D (they are failing currently)?

@potiuk

Copy link
Copy Markdown
Member

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks OK to me.
left one comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it's best to deprecate this parameter and replace it with a unified parameter in the base class (target_table_name)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure. I changed that.

Comment on lines 35 to 36

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd emphasize here that it's a base operator

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done

Comment on lines 99 to 100

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring and remove the pass

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

In my opinion it is unnecessary because concrete implementations are self-explanatory.

I have nonetheless taken into account your remark by adding a docstring.

@shahar1shahar1Apr 29, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Edited to explain myself better

I understand your opinion that it might seem redundant, however:

  1. Sometimes methods that look trivial might do something completely different than what you think they do - especially in an open source where many people with different code styles take part.
  2. Putting opinions aside, it's required by PEP 257, at least for public methods :)

Therefore, I suggest getting used to writing docstrings starting with self-explanatory methods, even as a preparation for more complicated functions. That being said, for simple methods - one line could do.

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Public methods (including the init constructor) should also have docstrings.

The wording of PEP 257 implies it's optional.

In Clean Code, Robert Martin enumerates a collection of smells and heuristics including:

C3: Redundant Comment

A comment is redundant if it describes something that adequately describes itself. For example:
i++; // increment i

Another example is a Javadoc that says nothing more than (or even less than) the function signature.

Comments should say things that the code cannot say for itself.

As suggested, I put my opinion aside and described persist_links with """This function persists the connection to the SQL provider""".

Comment on lines 102 to 103

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As is it trivial to reference all children implementation / calls to this function the best added value I could provide was to inform future readers what the history of this method is.

If you have another opinion, can you propose a docstring you think would fit?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I didn't mean to overcomplicate :)
A one-liner describing what this function does would do better (e.g.,: This function persists the connection to the SQL provider). The history of this method in this context seems irrelevant.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You could pass source_project_dataset_table directly to dataset_table

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

If you compare the old vs new version, it would introduce a slight difference of behavior between the two versions. It can lead to production issues.

I'd keep it this way because, unless I am mistaken, this version achieves 100% backward compatibility.

I agree that it doesn't make sense to have two distinct parameters for this use case. I searched in the google provider for helper functions to parse project.dataset.table vs dataset.table. I didn't find any.

If you insist on deprecating something here I'd vote to deprecate it in another PR because this one is already becoming quite complex to manage / review ✌️

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, now I realize that I missed the project definition in the dataset_table :)
It could wait for another time.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thank you 🙏

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from eaecfb1 to 38fc173CompareApril 29, 2023 13:14
@jbbqqf

jbbqqf commented Apr 29, 2023

Copy link
Copy Markdown
ContributorAuthor

To start - maybe get all the tests succeed :D (they are failing currently)?

Touché 😉

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

Sure 👍

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

I appreciate your efforts to demonstrate diplomacy.

Reference:

https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst

Ping @ #development slack, comment @people. Be annoying. Be considerate.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

@jbbqqf
jbbqqf requested a review from eladkalApril 29, 2023 13:27
@jbbqqf
jbbqqf requested a review from shahar1April 29, 2023 13:27
@potiuk

Copy link
Copy Markdown
Member

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

Complain to GitHub - not to us, this is an isue I reported to them ~ 2 years ago and there is no fix in sight.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

All the test types of airflow, including the way how to distribute them is decribed in https://github.com/apache/airflow/blob/main/TESTING.rst

Generally speaking - seems that unit tests are failing for you and you should be able to follow "unit test" chapter there. If you follow the instructions there, it should help.

Also Breeze commands are described in https://github.com/apache/airflow/blob/main/BREEZE.rst - including help and screen outputs. You can also run --help and --dry-run with every breeze command. The first will tell you what options you have, the second will tell you exactly what command breeze runs under the hood and it will print copy-pasteable command that you can run and modify to replicate what you do. in CI you can see what is being run by unfolding the steps you see and you will see what is going on and which command is run.

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

There is a word "considerate". Have you considered that people responding here have likley even 100s of PRs to look at, while you have one to contribute? and that they are often doing it in their free time and people are demanding attention becasue they think they have to get response NOW? If not - you can take a look at my talk about empathy:

https://airflowsummit.org/sessions/2022/hey-maintainer-exercise-your-empathy/

Mildly annoying does not mean unempathettic.

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 38fc173 to c459c42CompareMay 1, 2023 09:56
Comment on lines 62 to 70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets use AirflowProviderDeprecationWarning

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lets not do target_table_name or mssql_table
it makes it harder to understand where the "real" value is.
we should handle the value as part of the deprecation check. If user passed mssql_table then we also assign it to self. target_table_name

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm not sure to understand what you have in mind. Something like this?

 selected_target_table_name = target_table_name
if mssql_table is not None:
selected_target_table_name = mssql_table
warnings.warn(
"The `mssql_table` parameter has been deprecated. Use `target_table_name` instead.",
DeprecationWarning,
)
super().__init__(
target_table_name=selected_target_table_name,
dataset_table=f"{dataset_id}.{table_id}",
**kwargs,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Something like

ifchannel:
warnings.warn(
"Argument `channel` is deprecated and will removed in a future releases. "
"Please use `channels` instead.",
DeprecationWarning,
stacklevel=2,
)
ifchannels:
raiseValueError(f"Cannot set both arguments: channel={channel!r} and channels={channels!r}.")
channels=channel
self.channels=channels

basically once you pass that block

New parameter takes precedence but if older parameter is supplied we will assign it to the new parameter + raise warning.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This class is missing from the added docs. is this intentional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I was inspired by the implementation of BaseSQLToGCSOperator. This is also an abstract class which is not documented either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the BigQueryToMsSqlOperator not on the base class :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is intentional. There was a slight difference between the MySQL documentation and the MsSQL documentation. I standardized the location of the example snippet. I used the MsSQL version. It did not require to change the MsSQL version, but this is why there is a change on the MySQL version.

As for the new interface (s/mssql_table/target_table_name/), it has been changed directly in example_bigquery_to_mssql.py.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the rst files.

docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
Is missing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 3 times, most recently from b50b591 to d483676CompareMay 4, 2023 19:28
@jbbqqf
jbbqqf requested a review from eladkalMay 4, 2023 19:30

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Copying data from one BigQuery table to another is performed with the
Copying data from BigQuery table to Postgres table is performed with the

@potiukpotiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Small NIT: in the docs, otherwise it looks good to me - @eladkal ?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from d483676 to 4948e8aCompareMay 8, 2023 19:23
@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 4948e8a to 0bed8a8CompareMay 14, 2023 08:34
@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@eladkal I don't understand what you mean. This file already exist. I let it as is.

@eladkal

Copy link
Copy Markdown
Contributor

@eladkal I don't understand what you mean. This file already exist. I let it as is.

Right. sorry!
Note to self: not review code when it's late!

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

will merge when CI is green

@eladkal
eladkal merged commit cf1e26b into apache:mainMay 16, 2023
@boring-cyborg

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request! You are invited to check our Issue Tracker for additional contributions.

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

@potiuk

Copy link
Copy Markdown
Member

looking for next ones :)

@shahar1

Copy link
Copy Markdown
Contributor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

Welcome to the club, well done :)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:providerskind:documentationprovider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jbbqqf@eladkal@shahar1@potiuk@pankajastro@phanikumv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add BigQueryToPostgresOperator - #30658

Merged
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator
May 16, 2023
Merged

Add BigQueryToPostgresOperator#30658
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator

Conversation

@jbbqqf

Copy link
Copy Markdown
Contributor

Yet another operator.

I added that transfer operator by mimicry with the existing BigQueryToMySqlOperator.

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

I noticed the BigQueryToMySqlOperator is referenced in airflow/contrib/operators/__init__.py (__deprecated_classes) and in tests/always/test_project_structure.py (MISSING_EXAMPLES_FOR_CLASSES). I am not 100% sure of what those references mean but I guess the new BigQueryToPostgresOperator doesn't need to be referenced here.

@boring-cyborgboring-cyborgBot added area:providers kind:documentation provider:google Google (including GCP) related issues labels Apr 15, 2023
@boring-cyborg

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst)
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our pre-commits will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example DAG that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

@pankajastropankajastro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might not catch something like dataset.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored the implementation. I am now using a BaseBigQueryToSqlOperator. In order to remain as backward compatible as possible, I used the old implementation tied to the MySQL operator.

If the user does not provide a correct input it will fail at runtime anyway (in the execute method).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why fmt off?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I initially copy/pasted the MySQL implementation without thinking too much about it. After digging in the commit history it looks like those fmt directives are old artifacts that can be removed with no side effect, which I did.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also add a test to check bigquery_get_data has been called correctly

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The current assertion already ensures bigquery_get_data has been called as a side effect:

 mock_hook.return_value.list_rows.assert_called_once_with(

list_rows comes from bigquery_get_data.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

missing docs string for this param

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I fixed those missing docstrings

@eladkal

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it?
but even if the parameter stays moving to generalized solution makes this a no concern.

@shahar1

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it? but even if the parameter stays moving to generalized solution makes this a no concern.

I'm up to it, will happen during this week

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

@potiuk

potiuk commented Apr 16, 2023

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:
    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 9458e98 to 6aeb2d1CompareApril 16, 2023 23:02
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

@eladkal ok, deal. I refactored the two twin operators with a BaseBigQueryToSqlOperator and used it to implement the new BigQueryToPostgresOperator. I had to make some tweaks though to remain backward compatible because of subtle differences.

I took the opportunity to factorize docstrings. That said, I'm not 100% sure that documenting only two parameters in BigQueryToPostgresOperator is the way to go, considering some mandatory parameters handled (and documented) in the parent class, BaseBigQueryToSqlOperator, are required. You tell me.

The generated documentation looks fine. Here is an example (I also checked the other impacted pages):
image

The only tests I have not been able to run with Breeze are the example dags in tests/system/providers/google/cloud/bigquery/. The command breeze testing tests tests/system/providers/google/cloud/bigquery/ doesn't seem to do the trick.

@jbbqqf
jbbqqf requested a review from pankajastroApril 16, 2023 23:19

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @jbbqqf - just noticed we are getting the class name split across multiple lines in the documentation, is there anything we could do to fix it?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@phanikumv I don't want to fix this issue in this PR. The diff is not the cause of the issue from what I can see on Airflow's latest online documentation (https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/transfers/bigquery_to_mysql/index.html).

That said, this is how I would have done it:

image

@pankajastro

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:

    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

thanks for the detailed explanation makes sense 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

does it makes sense to combine Postgres and MySQL system test here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I don't understand what you'd suggest

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I left as is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep. Better to keep them separate. In this case usability of those examples trumps DRY

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Putting request changes just to make sure #30748 is merged before this PR so the delegate_to parameter won't be in BaseBigQueryToSqlOperator

@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf you can now rebase and the delegate_to won't be an issue as it was removed in main

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 6aeb2d1 to c744f08CompareApril 23, 2023 09:29

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This was removed from main. This parameter doesn't exist any more

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 6e711ea to eaecfb1CompareApril 23, 2023 17:44
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

I made everything I could with the feedback I've received on this PR.

The code is factorized so that the new PostgresOperator is not a copy/paste version of the Mysql one. The documentation is also as factorized as it can be.

I rebased and removed the delegate_to parameter. I eventually managed to make static checks + build pass thanks to breeze. All CI checks designed to make sure no doc / tests are forgotten do pass.

I built the documentation locally. It looks fine.

I tested operators with a local airflow / postgresql / mysql + test gcp project. Basic operations work.

By basic operation I mean I tested those tasks:

 bigquery_to_mysql = BigQueryToMySqlOperator(
task_id="bigquery_to_mysql",
dataset_table="dataset.table_42",
mysql_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)
bigquery_to_postgres = BigQueryToPostgresOperator(
task_id="bigquery_to_postgres",
dataset_table="dataset.table_42",
postgres_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)

During my tests I noticed there was an error with template_fields. It should now be fixed.

I performed my local tests with a postgres and a mysql database. I didn't manually test the mssql operator.

Is there some additional tests I should perform that would cover common pitfalls?

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

@potiuk

potiuk commented Apr 23, 2023

Copy link
Copy Markdown
Member

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

To start - maybe get all the tests succeed :D (they are failing currently)?

@potiuk

Copy link
Copy Markdown
Member

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks OK to me.
left one comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it's best to deprecate this parameter and replace it with a unified parameter in the base class (target_table_name)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure. I changed that.

Comment on lines 35 to 36

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd emphasize here that it's a base operator

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done

Comment on lines 99 to 100

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring and remove the pass

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

In my opinion it is unnecessary because concrete implementations are self-explanatory.

I have nonetheless taken into account your remark by adding a docstring.

@shahar1shahar1Apr 29, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Edited to explain myself better

I understand your opinion that it might seem redundant, however:

  1. Sometimes methods that look trivial might do something completely different than what you think they do - especially in an open source where many people with different code styles take part.
  2. Putting opinions aside, it's required by PEP 257, at least for public methods :)

Therefore, I suggest getting used to writing docstrings starting with self-explanatory methods, even as a preparation for more complicated functions. That being said, for simple methods - one line could do.

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Public methods (including the init constructor) should also have docstrings.

The wording of PEP 257 implies it's optional.

In Clean Code, Robert Martin enumerates a collection of smells and heuristics including:

C3: Redundant Comment

A comment is redundant if it describes something that adequately describes itself. For example:
i++; // increment i

Another example is a Javadoc that says nothing more than (or even less than) the function signature.

Comments should say things that the code cannot say for itself.

As suggested, I put my opinion aside and described persist_links with """This function persists the connection to the SQL provider""".

Comment on lines 102 to 103

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As is it trivial to reference all children implementation / calls to this function the best added value I could provide was to inform future readers what the history of this method is.

If you have another opinion, can you propose a docstring you think would fit?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I didn't mean to overcomplicate :)
A one-liner describing what this function does would do better (e.g.,: This function persists the connection to the SQL provider). The history of this method in this context seems irrelevant.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You could pass source_project_dataset_table directly to dataset_table

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

If you compare the old vs new version, it would introduce a slight difference of behavior between the two versions. It can lead to production issues.

I'd keep it this way because, unless I am mistaken, this version achieves 100% backward compatibility.

I agree that it doesn't make sense to have two distinct parameters for this use case. I searched in the google provider for helper functions to parse project.dataset.table vs dataset.table. I didn't find any.

If you insist on deprecating something here I'd vote to deprecate it in another PR because this one is already becoming quite complex to manage / review ✌️

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, now I realize that I missed the project definition in the dataset_table :)
It could wait for another time.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thank you 🙏

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from eaecfb1 to 38fc173CompareApril 29, 2023 13:14
@jbbqqf

jbbqqf commented Apr 29, 2023

Copy link
Copy Markdown
ContributorAuthor

To start - maybe get all the tests succeed :D (they are failing currently)?

Touché 😉

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

Sure 👍

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

I appreciate your efforts to demonstrate diplomacy.

Reference:

https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst

Ping @ #development slack, comment @people. Be annoying. Be considerate.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

@jbbqqf
jbbqqf requested a review from eladkalApril 29, 2023 13:27
@jbbqqf
jbbqqf requested a review from shahar1April 29, 2023 13:27
@potiuk

Copy link
Copy Markdown
Member

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

Complain to GitHub - not to us, this is an isue I reported to them ~ 2 years ago and there is no fix in sight.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

All the test types of airflow, including the way how to distribute them is decribed in https://github.com/apache/airflow/blob/main/TESTING.rst

Generally speaking - seems that unit tests are failing for you and you should be able to follow "unit test" chapter there. If you follow the instructions there, it should help.

Also Breeze commands are described in https://github.com/apache/airflow/blob/main/BREEZE.rst - including help and screen outputs. You can also run --help and --dry-run with every breeze command. The first will tell you what options you have, the second will tell you exactly what command breeze runs under the hood and it will print copy-pasteable command that you can run and modify to replicate what you do. in CI you can see what is being run by unfolding the steps you see and you will see what is going on and which command is run.

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

There is a word "considerate". Have you considered that people responding here have likley even 100s of PRs to look at, while you have one to contribute? and that they are often doing it in their free time and people are demanding attention becasue they think they have to get response NOW? If not - you can take a look at my talk about empathy:

https://airflowsummit.org/sessions/2022/hey-maintainer-exercise-your-empathy/

Mildly annoying does not mean unempathettic.

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 38fc173 to c459c42CompareMay 1, 2023 09:56
Comment on lines 62 to 70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets use AirflowProviderDeprecationWarning

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lets not do target_table_name or mssql_table
it makes it harder to understand where the "real" value is.
we should handle the value as part of the deprecation check. If user passed mssql_table then we also assign it to self. target_table_name

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm not sure to understand what you have in mind. Something like this?

 selected_target_table_name = target_table_name
if mssql_table is not None:
selected_target_table_name = mssql_table
warnings.warn(
"The `mssql_table` parameter has been deprecated. Use `target_table_name` instead.",
DeprecationWarning,
)
super().__init__(
target_table_name=selected_target_table_name,
dataset_table=f"{dataset_id}.{table_id}",
**kwargs,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Something like

ifchannel:
warnings.warn(
"Argument `channel` is deprecated and will removed in a future releases. "
"Please use `channels` instead.",
DeprecationWarning,
stacklevel=2,
)
ifchannels:
raiseValueError(f"Cannot set both arguments: channel={channel!r} and channels={channels!r}.")
channels=channel
self.channels=channels

basically once you pass that block

New parameter takes precedence but if older parameter is supplied we will assign it to the new parameter + raise warning.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This class is missing from the added docs. is this intentional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I was inspired by the implementation of BaseSQLToGCSOperator. This is also an abstract class which is not documented either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the BigQueryToMsSqlOperator not on the base class :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is intentional. There was a slight difference between the MySQL documentation and the MsSQL documentation. I standardized the location of the example snippet. I used the MsSQL version. It did not require to change the MsSQL version, but this is why there is a change on the MySQL version.

As for the new interface (s/mssql_table/target_table_name/), it has been changed directly in example_bigquery_to_mssql.py.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the rst files.

docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
Is missing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 3 times, most recently from b50b591 to d483676CompareMay 4, 2023 19:28
@jbbqqf
jbbqqf requested a review from eladkalMay 4, 2023 19:30

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Copying data from one BigQuery table to another is performed with the
Copying data from BigQuery table to Postgres table is performed with the

@potiukpotiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Small NIT: in the docs, otherwise it looks good to me - @eladkal ?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from d483676 to 4948e8aCompareMay 8, 2023 19:23
@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 4948e8a to 0bed8a8CompareMay 14, 2023 08:34
@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@eladkal I don't understand what you mean. This file already exist. I let it as is.

@eladkal

Copy link
Copy Markdown
Contributor

@eladkal I don't understand what you mean. This file already exist. I let it as is.

Right. sorry!
Note to self: not review code when it's late!

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

will merge when CI is green

@eladkal
eladkal merged commit cf1e26b into apache:mainMay 16, 2023
@boring-cyborg

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request! You are invited to check our Issue Tracker for additional contributions.

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

@potiuk

Copy link
Copy Markdown
Member

looking for next ones :)

@shahar1

Copy link
Copy Markdown
Contributor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

Welcome to the club, well done :)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:providerskind:documentationprovider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jbbqqf@eladkal@shahar1@potiuk@pankajastro@phanikumv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add BigQueryToPostgresOperator - #30658

Merged
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator
May 16, 2023
Merged

Add BigQueryToPostgresOperator#30658
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator

Conversation

@jbbqqf

Copy link
Copy Markdown
Contributor

Yet another operator.

I added that transfer operator by mimicry with the existing BigQueryToMySqlOperator.

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

I noticed the BigQueryToMySqlOperator is referenced in airflow/contrib/operators/__init__.py (__deprecated_classes) and in tests/always/test_project_structure.py (MISSING_EXAMPLES_FOR_CLASSES). I am not 100% sure of what those references mean but I guess the new BigQueryToPostgresOperator doesn't need to be referenced here.

@boring-cyborgboring-cyborgBot added area:providers kind:documentation provider:google Google (including GCP) related issues labels Apr 15, 2023
@boring-cyborg

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst)
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our pre-commits will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example DAG that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

@pankajastropankajastro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might not catch something like dataset.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored the implementation. I am now using a BaseBigQueryToSqlOperator. In order to remain as backward compatible as possible, I used the old implementation tied to the MySQL operator.

If the user does not provide a correct input it will fail at runtime anyway (in the execute method).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why fmt off?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I initially copy/pasted the MySQL implementation without thinking too much about it. After digging in the commit history it looks like those fmt directives are old artifacts that can be removed with no side effect, which I did.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also add a test to check bigquery_get_data has been called correctly

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The current assertion already ensures bigquery_get_data has been called as a side effect:

 mock_hook.return_value.list_rows.assert_called_once_with(

list_rows comes from bigquery_get_data.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

missing docs string for this param

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I fixed those missing docstrings

@eladkal

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it?
but even if the parameter stays moving to generalized solution makes this a no concern.

@shahar1

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it? but even if the parameter stays moving to generalized solution makes this a no concern.

I'm up to it, will happen during this week

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

@potiuk

potiuk commented Apr 16, 2023

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:
    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 9458e98 to 6aeb2d1CompareApril 16, 2023 23:02
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

@eladkal ok, deal. I refactored the two twin operators with a BaseBigQueryToSqlOperator and used it to implement the new BigQueryToPostgresOperator. I had to make some tweaks though to remain backward compatible because of subtle differences.

I took the opportunity to factorize docstrings. That said, I'm not 100% sure that documenting only two parameters in BigQueryToPostgresOperator is the way to go, considering some mandatory parameters handled (and documented) in the parent class, BaseBigQueryToSqlOperator, are required. You tell me.

The generated documentation looks fine. Here is an example (I also checked the other impacted pages):
image

The only tests I have not been able to run with Breeze are the example dags in tests/system/providers/google/cloud/bigquery/. The command breeze testing tests tests/system/providers/google/cloud/bigquery/ doesn't seem to do the trick.

@jbbqqf
jbbqqf requested a review from pankajastroApril 16, 2023 23:19

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @jbbqqf - just noticed we are getting the class name split across multiple lines in the documentation, is there anything we could do to fix it?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@phanikumv I don't want to fix this issue in this PR. The diff is not the cause of the issue from what I can see on Airflow's latest online documentation (https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/transfers/bigquery_to_mysql/index.html).

That said, this is how I would have done it:

image

@pankajastro

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:

    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

thanks for the detailed explanation makes sense 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

does it makes sense to combine Postgres and MySQL system test here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I don't understand what you'd suggest

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I left as is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep. Better to keep them separate. In this case usability of those examples trumps DRY

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Putting request changes just to make sure #30748 is merged before this PR so the delegate_to parameter won't be in BaseBigQueryToSqlOperator

@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf you can now rebase and the delegate_to won't be an issue as it was removed in main

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 6aeb2d1 to c744f08CompareApril 23, 2023 09:29

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This was removed from main. This parameter doesn't exist any more

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 6e711ea to eaecfb1CompareApril 23, 2023 17:44
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

I made everything I could with the feedback I've received on this PR.

The code is factorized so that the new PostgresOperator is not a copy/paste version of the Mysql one. The documentation is also as factorized as it can be.

I rebased and removed the delegate_to parameter. I eventually managed to make static checks + build pass thanks to breeze. All CI checks designed to make sure no doc / tests are forgotten do pass.

I built the documentation locally. It looks fine.

I tested operators with a local airflow / postgresql / mysql + test gcp project. Basic operations work.

By basic operation I mean I tested those tasks:

 bigquery_to_mysql = BigQueryToMySqlOperator(
task_id="bigquery_to_mysql",
dataset_table="dataset.table_42",
mysql_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)
bigquery_to_postgres = BigQueryToPostgresOperator(
task_id="bigquery_to_postgres",
dataset_table="dataset.table_42",
postgres_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)

During my tests I noticed there was an error with template_fields. It should now be fixed.

I performed my local tests with a postgres and a mysql database. I didn't manually test the mssql operator.

Is there some additional tests I should perform that would cover common pitfalls?

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

@potiuk

potiuk commented Apr 23, 2023

Copy link
Copy Markdown
Member

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

To start - maybe get all the tests succeed :D (they are failing currently)?

@potiuk

Copy link
Copy Markdown
Member

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks OK to me.
left one comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it's best to deprecate this parameter and replace it with a unified parameter in the base class (target_table_name)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure. I changed that.

Comment on lines 35 to 36

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd emphasize here that it's a base operator

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done

Comment on lines 99 to 100

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring and remove the pass

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

In my opinion it is unnecessary because concrete implementations are self-explanatory.

I have nonetheless taken into account your remark by adding a docstring.

@shahar1shahar1Apr 29, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Edited to explain myself better

I understand your opinion that it might seem redundant, however:

  1. Sometimes methods that look trivial might do something completely different than what you think they do - especially in an open source where many people with different code styles take part.
  2. Putting opinions aside, it's required by PEP 257, at least for public methods :)

Therefore, I suggest getting used to writing docstrings starting with self-explanatory methods, even as a preparation for more complicated functions. That being said, for simple methods - one line could do.

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Public methods (including the init constructor) should also have docstrings.

The wording of PEP 257 implies it's optional.

In Clean Code, Robert Martin enumerates a collection of smells and heuristics including:

C3: Redundant Comment

A comment is redundant if it describes something that adequately describes itself. For example:
i++; // increment i

Another example is a Javadoc that says nothing more than (or even less than) the function signature.

Comments should say things that the code cannot say for itself.

As suggested, I put my opinion aside and described persist_links with """This function persists the connection to the SQL provider""".

Comment on lines 102 to 103

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As is it trivial to reference all children implementation / calls to this function the best added value I could provide was to inform future readers what the history of this method is.

If you have another opinion, can you propose a docstring you think would fit?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I didn't mean to overcomplicate :)
A one-liner describing what this function does would do better (e.g.,: This function persists the connection to the SQL provider). The history of this method in this context seems irrelevant.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You could pass source_project_dataset_table directly to dataset_table

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

If you compare the old vs new version, it would introduce a slight difference of behavior between the two versions. It can lead to production issues.

I'd keep it this way because, unless I am mistaken, this version achieves 100% backward compatibility.

I agree that it doesn't make sense to have two distinct parameters for this use case. I searched in the google provider for helper functions to parse project.dataset.table vs dataset.table. I didn't find any.

If you insist on deprecating something here I'd vote to deprecate it in another PR because this one is already becoming quite complex to manage / review ✌️

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, now I realize that I missed the project definition in the dataset_table :)
It could wait for another time.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thank you 🙏

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from eaecfb1 to 38fc173CompareApril 29, 2023 13:14
@jbbqqf

jbbqqf commented Apr 29, 2023

Copy link
Copy Markdown
ContributorAuthor

To start - maybe get all the tests succeed :D (they are failing currently)?

Touché 😉

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

Sure 👍

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

I appreciate your efforts to demonstrate diplomacy.

Reference:

https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst

Ping @ #development slack, comment @people. Be annoying. Be considerate.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

@jbbqqf
jbbqqf requested a review from eladkalApril 29, 2023 13:27
@jbbqqf
jbbqqf requested a review from shahar1April 29, 2023 13:27
@potiuk

Copy link
Copy Markdown
Member

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

Complain to GitHub - not to us, this is an isue I reported to them ~ 2 years ago and there is no fix in sight.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

All the test types of airflow, including the way how to distribute them is decribed in https://github.com/apache/airflow/blob/main/TESTING.rst

Generally speaking - seems that unit tests are failing for you and you should be able to follow "unit test" chapter there. If you follow the instructions there, it should help.

Also Breeze commands are described in https://github.com/apache/airflow/blob/main/BREEZE.rst - including help and screen outputs. You can also run --help and --dry-run with every breeze command. The first will tell you what options you have, the second will tell you exactly what command breeze runs under the hood and it will print copy-pasteable command that you can run and modify to replicate what you do. in CI you can see what is being run by unfolding the steps you see and you will see what is going on and which command is run.

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

There is a word "considerate". Have you considered that people responding here have likley even 100s of PRs to look at, while you have one to contribute? and that they are often doing it in their free time and people are demanding attention becasue they think they have to get response NOW? If not - you can take a look at my talk about empathy:

https://airflowsummit.org/sessions/2022/hey-maintainer-exercise-your-empathy/

Mildly annoying does not mean unempathettic.

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 38fc173 to c459c42CompareMay 1, 2023 09:56
Comment on lines 62 to 70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets use AirflowProviderDeprecationWarning

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lets not do target_table_name or mssql_table
it makes it harder to understand where the "real" value is.
we should handle the value as part of the deprecation check. If user passed mssql_table then we also assign it to self. target_table_name

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm not sure to understand what you have in mind. Something like this?

 selected_target_table_name = target_table_name
if mssql_table is not None:
selected_target_table_name = mssql_table
warnings.warn(
"The `mssql_table` parameter has been deprecated. Use `target_table_name` instead.",
DeprecationWarning,
)
super().__init__(
target_table_name=selected_target_table_name,
dataset_table=f"{dataset_id}.{table_id}",
**kwargs,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Something like

ifchannel:
warnings.warn(
"Argument `channel` is deprecated and will removed in a future releases. "
"Please use `channels` instead.",
DeprecationWarning,
stacklevel=2,
)
ifchannels:
raiseValueError(f"Cannot set both arguments: channel={channel!r} and channels={channels!r}.")
channels=channel
self.channels=channels

basically once you pass that block

New parameter takes precedence but if older parameter is supplied we will assign it to the new parameter + raise warning.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This class is missing from the added docs. is this intentional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I was inspired by the implementation of BaseSQLToGCSOperator. This is also an abstract class which is not documented either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the BigQueryToMsSqlOperator not on the base class :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is intentional. There was a slight difference between the MySQL documentation and the MsSQL documentation. I standardized the location of the example snippet. I used the MsSQL version. It did not require to change the MsSQL version, but this is why there is a change on the MySQL version.

As for the new interface (s/mssql_table/target_table_name/), it has been changed directly in example_bigquery_to_mssql.py.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the rst files.

docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
Is missing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 3 times, most recently from b50b591 to d483676CompareMay 4, 2023 19:28
@jbbqqf
jbbqqf requested a review from eladkalMay 4, 2023 19:30

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Copying data from one BigQuery table to another is performed with the
Copying data from BigQuery table to Postgres table is performed with the

@potiukpotiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Small NIT: in the docs, otherwise it looks good to me - @eladkal ?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from d483676 to 4948e8aCompareMay 8, 2023 19:23
@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 4948e8a to 0bed8a8CompareMay 14, 2023 08:34
@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@eladkal I don't understand what you mean. This file already exist. I let it as is.

@eladkal

Copy link
Copy Markdown
Contributor

@eladkal I don't understand what you mean. This file already exist. I let it as is.

Right. sorry!
Note to self: not review code when it's late!

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

will merge when CI is green

@eladkal
eladkal merged commit cf1e26b into apache:mainMay 16, 2023
@boring-cyborg

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request! You are invited to check our Issue Tracker for additional contributions.

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

@potiuk

Copy link
Copy Markdown
Member

looking for next ones :)

@shahar1

Copy link
Copy Markdown
Contributor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

Welcome to the club, well done :)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:providerskind:documentationprovider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jbbqqf@eladkal@shahar1@potiuk@pankajastro@phanikumv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add BigQueryToPostgresOperator - #30658

Merged
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator
May 16, 2023
Merged

Add BigQueryToPostgresOperator#30658
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator

Conversation

@jbbqqf

Copy link
Copy Markdown
Contributor

Yet another operator.

I added that transfer operator by mimicry with the existing BigQueryToMySqlOperator.

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

I noticed the BigQueryToMySqlOperator is referenced in airflow/contrib/operators/__init__.py (__deprecated_classes) and in tests/always/test_project_structure.py (MISSING_EXAMPLES_FOR_CLASSES). I am not 100% sure of what those references mean but I guess the new BigQueryToPostgresOperator doesn't need to be referenced here.

@boring-cyborgboring-cyborgBot added area:providers kind:documentation provider:google Google (including GCP) related issues labels Apr 15, 2023
@boring-cyborg

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst)
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our pre-commits will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example DAG that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

@pankajastropankajastro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might not catch something like dataset.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored the implementation. I am now using a BaseBigQueryToSqlOperator. In order to remain as backward compatible as possible, I used the old implementation tied to the MySQL operator.

If the user does not provide a correct input it will fail at runtime anyway (in the execute method).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why fmt off?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I initially copy/pasted the MySQL implementation without thinking too much about it. After digging in the commit history it looks like those fmt directives are old artifacts that can be removed with no side effect, which I did.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also add a test to check bigquery_get_data has been called correctly

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The current assertion already ensures bigquery_get_data has been called as a side effect:

 mock_hook.return_value.list_rows.assert_called_once_with(

list_rows comes from bigquery_get_data.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

missing docs string for this param

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I fixed those missing docstrings

@eladkal

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it?
but even if the parameter stays moving to generalized solution makes this a no concern.

@shahar1

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it? but even if the parameter stays moving to generalized solution makes this a no concern.

I'm up to it, will happen during this week

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

@potiuk

potiuk commented Apr 16, 2023

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:
    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 9458e98 to 6aeb2d1CompareApril 16, 2023 23:02
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

@eladkal ok, deal. I refactored the two twin operators with a BaseBigQueryToSqlOperator and used it to implement the new BigQueryToPostgresOperator. I had to make some tweaks though to remain backward compatible because of subtle differences.

I took the opportunity to factorize docstrings. That said, I'm not 100% sure that documenting only two parameters in BigQueryToPostgresOperator is the way to go, considering some mandatory parameters handled (and documented) in the parent class, BaseBigQueryToSqlOperator, are required. You tell me.

The generated documentation looks fine. Here is an example (I also checked the other impacted pages):
image

The only tests I have not been able to run with Breeze are the example dags in tests/system/providers/google/cloud/bigquery/. The command breeze testing tests tests/system/providers/google/cloud/bigquery/ doesn't seem to do the trick.

@jbbqqf
jbbqqf requested a review from pankajastroApril 16, 2023 23:19

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @jbbqqf - just noticed we are getting the class name split across multiple lines in the documentation, is there anything we could do to fix it?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@phanikumv I don't want to fix this issue in this PR. The diff is not the cause of the issue from what I can see on Airflow's latest online documentation (https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/transfers/bigquery_to_mysql/index.html).

That said, this is how I would have done it:

image

@pankajastro

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:

    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

thanks for the detailed explanation makes sense 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

does it makes sense to combine Postgres and MySQL system test here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I don't understand what you'd suggest

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I left as is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep. Better to keep them separate. In this case usability of those examples trumps DRY

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Putting request changes just to make sure #30748 is merged before this PR so the delegate_to parameter won't be in BaseBigQueryToSqlOperator

@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf you can now rebase and the delegate_to won't be an issue as it was removed in main

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 6aeb2d1 to c744f08CompareApril 23, 2023 09:29

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This was removed from main. This parameter doesn't exist any more

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 6e711ea to eaecfb1CompareApril 23, 2023 17:44
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

I made everything I could with the feedback I've received on this PR.

The code is factorized so that the new PostgresOperator is not a copy/paste version of the Mysql one. The documentation is also as factorized as it can be.

I rebased and removed the delegate_to parameter. I eventually managed to make static checks + build pass thanks to breeze. All CI checks designed to make sure no doc / tests are forgotten do pass.

I built the documentation locally. It looks fine.

I tested operators with a local airflow / postgresql / mysql + test gcp project. Basic operations work.

By basic operation I mean I tested those tasks:

 bigquery_to_mysql = BigQueryToMySqlOperator(
task_id="bigquery_to_mysql",
dataset_table="dataset.table_42",
mysql_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)
bigquery_to_postgres = BigQueryToPostgresOperator(
task_id="bigquery_to_postgres",
dataset_table="dataset.table_42",
postgres_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)

During my tests I noticed there was an error with template_fields. It should now be fixed.

I performed my local tests with a postgres and a mysql database. I didn't manually test the mssql operator.

Is there some additional tests I should perform that would cover common pitfalls?

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

@potiuk

potiuk commented Apr 23, 2023

Copy link
Copy Markdown
Member

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

To start - maybe get all the tests succeed :D (they are failing currently)?

@potiuk

Copy link
Copy Markdown
Member

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks OK to me.
left one comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it's best to deprecate this parameter and replace it with a unified parameter in the base class (target_table_name)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure. I changed that.

Comment on lines 35 to 36

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd emphasize here that it's a base operator

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done

Comment on lines 99 to 100

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring and remove the pass

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

In my opinion it is unnecessary because concrete implementations are self-explanatory.

I have nonetheless taken into account your remark by adding a docstring.

@shahar1shahar1Apr 29, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Edited to explain myself better

I understand your opinion that it might seem redundant, however:

  1. Sometimes methods that look trivial might do something completely different than what you think they do - especially in an open source where many people with different code styles take part.
  2. Putting opinions aside, it's required by PEP 257, at least for public methods :)

Therefore, I suggest getting used to writing docstrings starting with self-explanatory methods, even as a preparation for more complicated functions. That being said, for simple methods - one line could do.

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Public methods (including the init constructor) should also have docstrings.

The wording of PEP 257 implies it's optional.

In Clean Code, Robert Martin enumerates a collection of smells and heuristics including:

C3: Redundant Comment

A comment is redundant if it describes something that adequately describes itself. For example:
i++; // increment i

Another example is a Javadoc that says nothing more than (or even less than) the function signature.

Comments should say things that the code cannot say for itself.

As suggested, I put my opinion aside and described persist_links with """This function persists the connection to the SQL provider""".

Comment on lines 102 to 103

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As is it trivial to reference all children implementation / calls to this function the best added value I could provide was to inform future readers what the history of this method is.

If you have another opinion, can you propose a docstring you think would fit?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I didn't mean to overcomplicate :)
A one-liner describing what this function does would do better (e.g.,: This function persists the connection to the SQL provider). The history of this method in this context seems irrelevant.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You could pass source_project_dataset_table directly to dataset_table

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

If you compare the old vs new version, it would introduce a slight difference of behavior between the two versions. It can lead to production issues.

I'd keep it this way because, unless I am mistaken, this version achieves 100% backward compatibility.

I agree that it doesn't make sense to have two distinct parameters for this use case. I searched in the google provider for helper functions to parse project.dataset.table vs dataset.table. I didn't find any.

If you insist on deprecating something here I'd vote to deprecate it in another PR because this one is already becoming quite complex to manage / review ✌️

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, now I realize that I missed the project definition in the dataset_table :)
It could wait for another time.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thank you 🙏

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from eaecfb1 to 38fc173CompareApril 29, 2023 13:14
@jbbqqf

jbbqqf commented Apr 29, 2023

Copy link
Copy Markdown
ContributorAuthor

To start - maybe get all the tests succeed :D (they are failing currently)?

Touché 😉

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

Sure 👍

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

I appreciate your efforts to demonstrate diplomacy.

Reference:

https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst

Ping @ #development slack, comment @people. Be annoying. Be considerate.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

@jbbqqf
jbbqqf requested a review from eladkalApril 29, 2023 13:27
@jbbqqf
jbbqqf requested a review from shahar1April 29, 2023 13:27
@potiuk

Copy link
Copy Markdown
Member

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

Complain to GitHub - not to us, this is an isue I reported to them ~ 2 years ago and there is no fix in sight.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

All the test types of airflow, including the way how to distribute them is decribed in https://github.com/apache/airflow/blob/main/TESTING.rst

Generally speaking - seems that unit tests are failing for you and you should be able to follow "unit test" chapter there. If you follow the instructions there, it should help.

Also Breeze commands are described in https://github.com/apache/airflow/blob/main/BREEZE.rst - including help and screen outputs. You can also run --help and --dry-run with every breeze command. The first will tell you what options you have, the second will tell you exactly what command breeze runs under the hood and it will print copy-pasteable command that you can run and modify to replicate what you do. in CI you can see what is being run by unfolding the steps you see and you will see what is going on and which command is run.

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

There is a word "considerate". Have you considered that people responding here have likley even 100s of PRs to look at, while you have one to contribute? and that they are often doing it in their free time and people are demanding attention becasue they think they have to get response NOW? If not - you can take a look at my talk about empathy:

https://airflowsummit.org/sessions/2022/hey-maintainer-exercise-your-empathy/

Mildly annoying does not mean unempathettic.

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 38fc173 to c459c42CompareMay 1, 2023 09:56
Comment on lines 62 to 70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets use AirflowProviderDeprecationWarning

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lets not do target_table_name or mssql_table
it makes it harder to understand where the "real" value is.
we should handle the value as part of the deprecation check. If user passed mssql_table then we also assign it to self. target_table_name

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm not sure to understand what you have in mind. Something like this?

 selected_target_table_name = target_table_name
if mssql_table is not None:
selected_target_table_name = mssql_table
warnings.warn(
"The `mssql_table` parameter has been deprecated. Use `target_table_name` instead.",
DeprecationWarning,
)
super().__init__(
target_table_name=selected_target_table_name,
dataset_table=f"{dataset_id}.{table_id}",
**kwargs,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Something like

ifchannel:
warnings.warn(
"Argument `channel` is deprecated and will removed in a future releases. "
"Please use `channels` instead.",
DeprecationWarning,
stacklevel=2,
)
ifchannels:
raiseValueError(f"Cannot set both arguments: channel={channel!r} and channels={channels!r}.")
channels=channel
self.channels=channels

basically once you pass that block

New parameter takes precedence but if older parameter is supplied we will assign it to the new parameter + raise warning.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This class is missing from the added docs. is this intentional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I was inspired by the implementation of BaseSQLToGCSOperator. This is also an abstract class which is not documented either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the BigQueryToMsSqlOperator not on the base class :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is intentional. There was a slight difference between the MySQL documentation and the MsSQL documentation. I standardized the location of the example snippet. I used the MsSQL version. It did not require to change the MsSQL version, but this is why there is a change on the MySQL version.

As for the new interface (s/mssql_table/target_table_name/), it has been changed directly in example_bigquery_to_mssql.py.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the rst files.

docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
Is missing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 3 times, most recently from b50b591 to d483676CompareMay 4, 2023 19:28
@jbbqqf
jbbqqf requested a review from eladkalMay 4, 2023 19:30

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Copying data from one BigQuery table to another is performed with the
Copying data from BigQuery table to Postgres table is performed with the

@potiukpotiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Small NIT: in the docs, otherwise it looks good to me - @eladkal ?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from d483676 to 4948e8aCompareMay 8, 2023 19:23
@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 4948e8a to 0bed8a8CompareMay 14, 2023 08:34
@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@eladkal I don't understand what you mean. This file already exist. I let it as is.

@eladkal

Copy link
Copy Markdown
Contributor

@eladkal I don't understand what you mean. This file already exist. I let it as is.

Right. sorry!
Note to self: not review code when it's late!

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

will merge when CI is green

@eladkal
eladkal merged commit cf1e26b into apache:mainMay 16, 2023
@boring-cyborg

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request! You are invited to check our Issue Tracker for additional contributions.

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

@potiuk

Copy link
Copy Markdown
Member

looking for next ones :)

@shahar1

Copy link
Copy Markdown
Contributor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

Welcome to the club, well done :)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:providerskind:documentationprovider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jbbqqf@eladkal@shahar1@potiuk@pankajastro@phanikumv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add BigQueryToPostgresOperator - #30658

Merged
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator
May 16, 2023
Merged

Add BigQueryToPostgresOperator#30658
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator

Conversation

@jbbqqf

Copy link
Copy Markdown
Contributor

Yet another operator.

I added that transfer operator by mimicry with the existing BigQueryToMySqlOperator.

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

I noticed the BigQueryToMySqlOperator is referenced in airflow/contrib/operators/__init__.py (__deprecated_classes) and in tests/always/test_project_structure.py (MISSING_EXAMPLES_FOR_CLASSES). I am not 100% sure of what those references mean but I guess the new BigQueryToPostgresOperator doesn't need to be referenced here.

@boring-cyborgboring-cyborgBot added area:providers kind:documentation provider:google Google (including GCP) related issues labels Apr 15, 2023
@boring-cyborg

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst)
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our pre-commits will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example DAG that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

@pankajastropankajastro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might not catch something like dataset.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored the implementation. I am now using a BaseBigQueryToSqlOperator. In order to remain as backward compatible as possible, I used the old implementation tied to the MySQL operator.

If the user does not provide a correct input it will fail at runtime anyway (in the execute method).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why fmt off?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I initially copy/pasted the MySQL implementation without thinking too much about it. After digging in the commit history it looks like those fmt directives are old artifacts that can be removed with no side effect, which I did.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also add a test to check bigquery_get_data has been called correctly

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The current assertion already ensures bigquery_get_data has been called as a side effect:

 mock_hook.return_value.list_rows.assert_called_once_with(

list_rows comes from bigquery_get_data.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

missing docs string for this param

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I fixed those missing docstrings

@eladkal

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it?
but even if the parameter stays moving to generalized solution makes this a no concern.

@shahar1

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it? but even if the parameter stays moving to generalized solution makes this a no concern.

I'm up to it, will happen during this week

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

@potiuk

potiuk commented Apr 16, 2023

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:
    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 9458e98 to 6aeb2d1CompareApril 16, 2023 23:02
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

@eladkal ok, deal. I refactored the two twin operators with a BaseBigQueryToSqlOperator and used it to implement the new BigQueryToPostgresOperator. I had to make some tweaks though to remain backward compatible because of subtle differences.

I took the opportunity to factorize docstrings. That said, I'm not 100% sure that documenting only two parameters in BigQueryToPostgresOperator is the way to go, considering some mandatory parameters handled (and documented) in the parent class, BaseBigQueryToSqlOperator, are required. You tell me.

The generated documentation looks fine. Here is an example (I also checked the other impacted pages):
image

The only tests I have not been able to run with Breeze are the example dags in tests/system/providers/google/cloud/bigquery/. The command breeze testing tests tests/system/providers/google/cloud/bigquery/ doesn't seem to do the trick.

@jbbqqf
jbbqqf requested a review from pankajastroApril 16, 2023 23:19

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @jbbqqf - just noticed we are getting the class name split across multiple lines in the documentation, is there anything we could do to fix it?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@phanikumv I don't want to fix this issue in this PR. The diff is not the cause of the issue from what I can see on Airflow's latest online documentation (https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/transfers/bigquery_to_mysql/index.html).

That said, this is how I would have done it:

image

@pankajastro

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:

    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

thanks for the detailed explanation makes sense 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

does it makes sense to combine Postgres and MySQL system test here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I don't understand what you'd suggest

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I left as is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep. Better to keep them separate. In this case usability of those examples trumps DRY

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Putting request changes just to make sure #30748 is merged before this PR so the delegate_to parameter won't be in BaseBigQueryToSqlOperator

@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf you can now rebase and the delegate_to won't be an issue as it was removed in main

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 6aeb2d1 to c744f08CompareApril 23, 2023 09:29

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This was removed from main. This parameter doesn't exist any more

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 6e711ea to eaecfb1CompareApril 23, 2023 17:44
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

I made everything I could with the feedback I've received on this PR.

The code is factorized so that the new PostgresOperator is not a copy/paste version of the Mysql one. The documentation is also as factorized as it can be.

I rebased and removed the delegate_to parameter. I eventually managed to make static checks + build pass thanks to breeze. All CI checks designed to make sure no doc / tests are forgotten do pass.

I built the documentation locally. It looks fine.

I tested operators with a local airflow / postgresql / mysql + test gcp project. Basic operations work.

By basic operation I mean I tested those tasks:

 bigquery_to_mysql = BigQueryToMySqlOperator(
task_id="bigquery_to_mysql",
dataset_table="dataset.table_42",
mysql_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)
bigquery_to_postgres = BigQueryToPostgresOperator(
task_id="bigquery_to_postgres",
dataset_table="dataset.table_42",
postgres_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)

During my tests I noticed there was an error with template_fields. It should now be fixed.

I performed my local tests with a postgres and a mysql database. I didn't manually test the mssql operator.

Is there some additional tests I should perform that would cover common pitfalls?

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

@potiuk

potiuk commented Apr 23, 2023

Copy link
Copy Markdown
Member

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

To start - maybe get all the tests succeed :D (they are failing currently)?

@potiuk

Copy link
Copy Markdown
Member

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks OK to me.
left one comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it's best to deprecate this parameter and replace it with a unified parameter in the base class (target_table_name)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure. I changed that.

Comment on lines 35 to 36

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd emphasize here that it's a base operator

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done

Comment on lines 99 to 100

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring and remove the pass

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

In my opinion it is unnecessary because concrete implementations are self-explanatory.

I have nonetheless taken into account your remark by adding a docstring.

@shahar1shahar1Apr 29, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Edited to explain myself better

I understand your opinion that it might seem redundant, however:

  1. Sometimes methods that look trivial might do something completely different than what you think they do - especially in an open source where many people with different code styles take part.
  2. Putting opinions aside, it's required by PEP 257, at least for public methods :)

Therefore, I suggest getting used to writing docstrings starting with self-explanatory methods, even as a preparation for more complicated functions. That being said, for simple methods - one line could do.

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Public methods (including the init constructor) should also have docstrings.

The wording of PEP 257 implies it's optional.

In Clean Code, Robert Martin enumerates a collection of smells and heuristics including:

C3: Redundant Comment

A comment is redundant if it describes something that adequately describes itself. For example:
i++; // increment i

Another example is a Javadoc that says nothing more than (or even less than) the function signature.

Comments should say things that the code cannot say for itself.

As suggested, I put my opinion aside and described persist_links with """This function persists the connection to the SQL provider""".

Comment on lines 102 to 103

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As is it trivial to reference all children implementation / calls to this function the best added value I could provide was to inform future readers what the history of this method is.

If you have another opinion, can you propose a docstring you think would fit?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I didn't mean to overcomplicate :)
A one-liner describing what this function does would do better (e.g.,: This function persists the connection to the SQL provider). The history of this method in this context seems irrelevant.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You could pass source_project_dataset_table directly to dataset_table

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

If you compare the old vs new version, it would introduce a slight difference of behavior between the two versions. It can lead to production issues.

I'd keep it this way because, unless I am mistaken, this version achieves 100% backward compatibility.

I agree that it doesn't make sense to have two distinct parameters for this use case. I searched in the google provider for helper functions to parse project.dataset.table vs dataset.table. I didn't find any.

If you insist on deprecating something here I'd vote to deprecate it in another PR because this one is already becoming quite complex to manage / review ✌️

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, now I realize that I missed the project definition in the dataset_table :)
It could wait for another time.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thank you 🙏

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from eaecfb1 to 38fc173CompareApril 29, 2023 13:14
@jbbqqf

jbbqqf commented Apr 29, 2023

Copy link
Copy Markdown
ContributorAuthor

To start - maybe get all the tests succeed :D (they are failing currently)?

Touché 😉

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

Sure 👍

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

I appreciate your efforts to demonstrate diplomacy.

Reference:

https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst

Ping @ #development slack, comment @people. Be annoying. Be considerate.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

@jbbqqf
jbbqqf requested a review from eladkalApril 29, 2023 13:27
@jbbqqf
jbbqqf requested a review from shahar1April 29, 2023 13:27
@potiuk

Copy link
Copy Markdown
Member

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

Complain to GitHub - not to us, this is an isue I reported to them ~ 2 years ago and there is no fix in sight.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

All the test types of airflow, including the way how to distribute them is decribed in https://github.com/apache/airflow/blob/main/TESTING.rst

Generally speaking - seems that unit tests are failing for you and you should be able to follow "unit test" chapter there. If you follow the instructions there, it should help.

Also Breeze commands are described in https://github.com/apache/airflow/blob/main/BREEZE.rst - including help and screen outputs. You can also run --help and --dry-run with every breeze command. The first will tell you what options you have, the second will tell you exactly what command breeze runs under the hood and it will print copy-pasteable command that you can run and modify to replicate what you do. in CI you can see what is being run by unfolding the steps you see and you will see what is going on and which command is run.

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

There is a word "considerate". Have you considered that people responding here have likley even 100s of PRs to look at, while you have one to contribute? and that they are often doing it in their free time and people are demanding attention becasue they think they have to get response NOW? If not - you can take a look at my talk about empathy:

https://airflowsummit.org/sessions/2022/hey-maintainer-exercise-your-empathy/

Mildly annoying does not mean unempathettic.

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 38fc173 to c459c42CompareMay 1, 2023 09:56
Comment on lines 62 to 70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets use AirflowProviderDeprecationWarning

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lets not do target_table_name or mssql_table
it makes it harder to understand where the "real" value is.
we should handle the value as part of the deprecation check. If user passed mssql_table then we also assign it to self. target_table_name

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm not sure to understand what you have in mind. Something like this?

 selected_target_table_name = target_table_name
if mssql_table is not None:
selected_target_table_name = mssql_table
warnings.warn(
"The `mssql_table` parameter has been deprecated. Use `target_table_name` instead.",
DeprecationWarning,
)
super().__init__(
target_table_name=selected_target_table_name,
dataset_table=f"{dataset_id}.{table_id}",
**kwargs,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Something like

ifchannel:
warnings.warn(
"Argument `channel` is deprecated and will removed in a future releases. "
"Please use `channels` instead.",
DeprecationWarning,
stacklevel=2,
)
ifchannels:
raiseValueError(f"Cannot set both arguments: channel={channel!r} and channels={channels!r}.")
channels=channel
self.channels=channels

basically once you pass that block

New parameter takes precedence but if older parameter is supplied we will assign it to the new parameter + raise warning.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This class is missing from the added docs. is this intentional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I was inspired by the implementation of BaseSQLToGCSOperator. This is also an abstract class which is not documented either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the BigQueryToMsSqlOperator not on the base class :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is intentional. There was a slight difference between the MySQL documentation and the MsSQL documentation. I standardized the location of the example snippet. I used the MsSQL version. It did not require to change the MsSQL version, but this is why there is a change on the MySQL version.

As for the new interface (s/mssql_table/target_table_name/), it has been changed directly in example_bigquery_to_mssql.py.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the rst files.

docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
Is missing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 3 times, most recently from b50b591 to d483676CompareMay 4, 2023 19:28
@jbbqqf
jbbqqf requested a review from eladkalMay 4, 2023 19:30

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Copying data from one BigQuery table to another is performed with the
Copying data from BigQuery table to Postgres table is performed with the

@potiukpotiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Small NIT: in the docs, otherwise it looks good to me - @eladkal ?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from d483676 to 4948e8aCompareMay 8, 2023 19:23
@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 4948e8a to 0bed8a8CompareMay 14, 2023 08:34
@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@eladkal I don't understand what you mean. This file already exist. I let it as is.

@eladkal

Copy link
Copy Markdown
Contributor

@eladkal I don't understand what you mean. This file already exist. I let it as is.

Right. sorry!
Note to self: not review code when it's late!

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

will merge when CI is green

@eladkal
eladkal merged commit cf1e26b into apache:mainMay 16, 2023
@boring-cyborg

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request! You are invited to check our Issue Tracker for additional contributions.

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

@potiuk

Copy link
Copy Markdown
Member

looking for next ones :)

@shahar1

Copy link
Copy Markdown
Contributor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

Welcome to the club, well done :)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:providerskind:documentationprovider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jbbqqf@eladkal@shahar1@potiuk@pankajastro@phanikumv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add BigQueryToPostgresOperator - #30658

Merged
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator
May 16, 2023
Merged

Add BigQueryToPostgresOperator#30658
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator

Conversation

@jbbqqf

Copy link
Copy Markdown
Contributor

Yet another operator.

I added that transfer operator by mimicry with the existing BigQueryToMySqlOperator.

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

I noticed the BigQueryToMySqlOperator is referenced in airflow/contrib/operators/__init__.py (__deprecated_classes) and in tests/always/test_project_structure.py (MISSING_EXAMPLES_FOR_CLASSES). I am not 100% sure of what those references mean but I guess the new BigQueryToPostgresOperator doesn't need to be referenced here.

@boring-cyborgboring-cyborgBot added area:providers kind:documentation provider:google Google (including GCP) related issues labels Apr 15, 2023
@boring-cyborg

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst)
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our pre-commits will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example DAG that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

@pankajastropankajastro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might not catch something like dataset.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored the implementation. I am now using a BaseBigQueryToSqlOperator. In order to remain as backward compatible as possible, I used the old implementation tied to the MySQL operator.

If the user does not provide a correct input it will fail at runtime anyway (in the execute method).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why fmt off?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I initially copy/pasted the MySQL implementation without thinking too much about it. After digging in the commit history it looks like those fmt directives are old artifacts that can be removed with no side effect, which I did.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also add a test to check bigquery_get_data has been called correctly

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The current assertion already ensures bigquery_get_data has been called as a side effect:

 mock_hook.return_value.list_rows.assert_called_once_with(

list_rows comes from bigquery_get_data.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

missing docs string for this param

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I fixed those missing docstrings

@eladkal

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it?
but even if the parameter stays moving to generalized solution makes this a no concern.

@shahar1

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it? but even if the parameter stays moving to generalized solution makes this a no concern.

I'm up to it, will happen during this week

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

@potiuk

potiuk commented Apr 16, 2023

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:
    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 9458e98 to 6aeb2d1CompareApril 16, 2023 23:02
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

@eladkal ok, deal. I refactored the two twin operators with a BaseBigQueryToSqlOperator and used it to implement the new BigQueryToPostgresOperator. I had to make some tweaks though to remain backward compatible because of subtle differences.

I took the opportunity to factorize docstrings. That said, I'm not 100% sure that documenting only two parameters in BigQueryToPostgresOperator is the way to go, considering some mandatory parameters handled (and documented) in the parent class, BaseBigQueryToSqlOperator, are required. You tell me.

The generated documentation looks fine. Here is an example (I also checked the other impacted pages):
image

The only tests I have not been able to run with Breeze are the example dags in tests/system/providers/google/cloud/bigquery/. The command breeze testing tests tests/system/providers/google/cloud/bigquery/ doesn't seem to do the trick.

@jbbqqf
jbbqqf requested a review from pankajastroApril 16, 2023 23:19

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @jbbqqf - just noticed we are getting the class name split across multiple lines in the documentation, is there anything we could do to fix it?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@phanikumv I don't want to fix this issue in this PR. The diff is not the cause of the issue from what I can see on Airflow's latest online documentation (https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/transfers/bigquery_to_mysql/index.html).

That said, this is how I would have done it:

image

@pankajastro

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:

    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

thanks for the detailed explanation makes sense 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

does it makes sense to combine Postgres and MySQL system test here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I don't understand what you'd suggest

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I left as is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep. Better to keep them separate. In this case usability of those examples trumps DRY

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Putting request changes just to make sure #30748 is merged before this PR so the delegate_to parameter won't be in BaseBigQueryToSqlOperator

@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf you can now rebase and the delegate_to won't be an issue as it was removed in main

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 6aeb2d1 to c744f08CompareApril 23, 2023 09:29

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This was removed from main. This parameter doesn't exist any more

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 6e711ea to eaecfb1CompareApril 23, 2023 17:44
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

I made everything I could with the feedback I've received on this PR.

The code is factorized so that the new PostgresOperator is not a copy/paste version of the Mysql one. The documentation is also as factorized as it can be.

I rebased and removed the delegate_to parameter. I eventually managed to make static checks + build pass thanks to breeze. All CI checks designed to make sure no doc / tests are forgotten do pass.

I built the documentation locally. It looks fine.

I tested operators with a local airflow / postgresql / mysql + test gcp project. Basic operations work.

By basic operation I mean I tested those tasks:

 bigquery_to_mysql = BigQueryToMySqlOperator(
task_id="bigquery_to_mysql",
dataset_table="dataset.table_42",
mysql_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)
bigquery_to_postgres = BigQueryToPostgresOperator(
task_id="bigquery_to_postgres",
dataset_table="dataset.table_42",
postgres_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)

During my tests I noticed there was an error with template_fields. It should now be fixed.

I performed my local tests with a postgres and a mysql database. I didn't manually test the mssql operator.

Is there some additional tests I should perform that would cover common pitfalls?

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

@potiuk

potiuk commented Apr 23, 2023

Copy link
Copy Markdown
Member

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

To start - maybe get all the tests succeed :D (they are failing currently)?

@potiuk

Copy link
Copy Markdown
Member

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks OK to me.
left one comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it's best to deprecate this parameter and replace it with a unified parameter in the base class (target_table_name)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure. I changed that.

Comment on lines 35 to 36

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd emphasize here that it's a base operator

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done

Comment on lines 99 to 100

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring and remove the pass

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

In my opinion it is unnecessary because concrete implementations are self-explanatory.

I have nonetheless taken into account your remark by adding a docstring.

@shahar1shahar1Apr 29, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Edited to explain myself better

I understand your opinion that it might seem redundant, however:

  1. Sometimes methods that look trivial might do something completely different than what you think they do - especially in an open source where many people with different code styles take part.
  2. Putting opinions aside, it's required by PEP 257, at least for public methods :)

Therefore, I suggest getting used to writing docstrings starting with self-explanatory methods, even as a preparation for more complicated functions. That being said, for simple methods - one line could do.

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Public methods (including the init constructor) should also have docstrings.

The wording of PEP 257 implies it's optional.

In Clean Code, Robert Martin enumerates a collection of smells and heuristics including:

C3: Redundant Comment

A comment is redundant if it describes something that adequately describes itself. For example:
i++; // increment i

Another example is a Javadoc that says nothing more than (or even less than) the function signature.

Comments should say things that the code cannot say for itself.

As suggested, I put my opinion aside and described persist_links with """This function persists the connection to the SQL provider""".

Comment on lines 102 to 103

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As is it trivial to reference all children implementation / calls to this function the best added value I could provide was to inform future readers what the history of this method is.

If you have another opinion, can you propose a docstring you think would fit?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I didn't mean to overcomplicate :)
A one-liner describing what this function does would do better (e.g.,: This function persists the connection to the SQL provider). The history of this method in this context seems irrelevant.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You could pass source_project_dataset_table directly to dataset_table

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

If you compare the old vs new version, it would introduce a slight difference of behavior between the two versions. It can lead to production issues.

I'd keep it this way because, unless I am mistaken, this version achieves 100% backward compatibility.

I agree that it doesn't make sense to have two distinct parameters for this use case. I searched in the google provider for helper functions to parse project.dataset.table vs dataset.table. I didn't find any.

If you insist on deprecating something here I'd vote to deprecate it in another PR because this one is already becoming quite complex to manage / review ✌️

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, now I realize that I missed the project definition in the dataset_table :)
It could wait for another time.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thank you 🙏

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from eaecfb1 to 38fc173CompareApril 29, 2023 13:14
@jbbqqf

jbbqqf commented Apr 29, 2023

Copy link
Copy Markdown
ContributorAuthor

To start - maybe get all the tests succeed :D (they are failing currently)?

Touché 😉

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

Sure 👍

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

I appreciate your efforts to demonstrate diplomacy.

Reference:

https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst

Ping @ #development slack, comment @people. Be annoying. Be considerate.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

@jbbqqf
jbbqqf requested a review from eladkalApril 29, 2023 13:27
@jbbqqf
jbbqqf requested a review from shahar1April 29, 2023 13:27
@potiuk

Copy link
Copy Markdown
Member

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

Complain to GitHub - not to us, this is an isue I reported to them ~ 2 years ago and there is no fix in sight.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

All the test types of airflow, including the way how to distribute them is decribed in https://github.com/apache/airflow/blob/main/TESTING.rst

Generally speaking - seems that unit tests are failing for you and you should be able to follow "unit test" chapter there. If you follow the instructions there, it should help.

Also Breeze commands are described in https://github.com/apache/airflow/blob/main/BREEZE.rst - including help and screen outputs. You can also run --help and --dry-run with every breeze command. The first will tell you what options you have, the second will tell you exactly what command breeze runs under the hood and it will print copy-pasteable command that you can run and modify to replicate what you do. in CI you can see what is being run by unfolding the steps you see and you will see what is going on and which command is run.

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

There is a word "considerate". Have you considered that people responding here have likley even 100s of PRs to look at, while you have one to contribute? and that they are often doing it in their free time and people are demanding attention becasue they think they have to get response NOW? If not - you can take a look at my talk about empathy:

https://airflowsummit.org/sessions/2022/hey-maintainer-exercise-your-empathy/

Mildly annoying does not mean unempathettic.

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 38fc173 to c459c42CompareMay 1, 2023 09:56
Comment on lines 62 to 70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets use AirflowProviderDeprecationWarning

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lets not do target_table_name or mssql_table
it makes it harder to understand where the "real" value is.
we should handle the value as part of the deprecation check. If user passed mssql_table then we also assign it to self. target_table_name

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm not sure to understand what you have in mind. Something like this?

 selected_target_table_name = target_table_name
if mssql_table is not None:
selected_target_table_name = mssql_table
warnings.warn(
"The `mssql_table` parameter has been deprecated. Use `target_table_name` instead.",
DeprecationWarning,
)
super().__init__(
target_table_name=selected_target_table_name,
dataset_table=f"{dataset_id}.{table_id}",
**kwargs,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Something like

ifchannel:
warnings.warn(
"Argument `channel` is deprecated and will removed in a future releases. "
"Please use `channels` instead.",
DeprecationWarning,
stacklevel=2,
)
ifchannels:
raiseValueError(f"Cannot set both arguments: channel={channel!r} and channels={channels!r}.")
channels=channel
self.channels=channels

basically once you pass that block

New parameter takes precedence but if older parameter is supplied we will assign it to the new parameter + raise warning.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This class is missing from the added docs. is this intentional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I was inspired by the implementation of BaseSQLToGCSOperator. This is also an abstract class which is not documented either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the BigQueryToMsSqlOperator not on the base class :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is intentional. There was a slight difference between the MySQL documentation and the MsSQL documentation. I standardized the location of the example snippet. I used the MsSQL version. It did not require to change the MsSQL version, but this is why there is a change on the MySQL version.

As for the new interface (s/mssql_table/target_table_name/), it has been changed directly in example_bigquery_to_mssql.py.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the rst files.

docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
Is missing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 3 times, most recently from b50b591 to d483676CompareMay 4, 2023 19:28
@jbbqqf
jbbqqf requested a review from eladkalMay 4, 2023 19:30

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Copying data from one BigQuery table to another is performed with the
Copying data from BigQuery table to Postgres table is performed with the

@potiukpotiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Small NIT: in the docs, otherwise it looks good to me - @eladkal ?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from d483676 to 4948e8aCompareMay 8, 2023 19:23
@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 4948e8a to 0bed8a8CompareMay 14, 2023 08:34
@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@eladkal I don't understand what you mean. This file already exist. I let it as is.

@eladkal

Copy link
Copy Markdown
Contributor

@eladkal I don't understand what you mean. This file already exist. I let it as is.

Right. sorry!
Note to self: not review code when it's late!

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

will merge when CI is green

@eladkal
eladkal merged commit cf1e26b into apache:mainMay 16, 2023
@boring-cyborg

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request! You are invited to check our Issue Tracker for additional contributions.

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

@potiuk

Copy link
Copy Markdown
Member

looking for next ones :)

@shahar1

Copy link
Copy Markdown
Contributor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

Welcome to the club, well done :)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:providerskind:documentationprovider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jbbqqf@eladkal@shahar1@potiuk@pankajastro@phanikumv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add BigQueryToPostgresOperator - #30658

Merged
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator
May 16, 2023
Merged

Add BigQueryToPostgresOperator#30658
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator

Conversation

@jbbqqf

Copy link
Copy Markdown
Contributor

Yet another operator.

I added that transfer operator by mimicry with the existing BigQueryToMySqlOperator.

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

I noticed the BigQueryToMySqlOperator is referenced in airflow/contrib/operators/__init__.py (__deprecated_classes) and in tests/always/test_project_structure.py (MISSING_EXAMPLES_FOR_CLASSES). I am not 100% sure of what those references mean but I guess the new BigQueryToPostgresOperator doesn't need to be referenced here.

@boring-cyborgboring-cyborgBot added area:providers kind:documentation provider:google Google (including GCP) related issues labels Apr 15, 2023
@boring-cyborg

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst)
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our pre-commits will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example DAG that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

@pankajastropankajastro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might not catch something like dataset.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored the implementation. I am now using a BaseBigQueryToSqlOperator. In order to remain as backward compatible as possible, I used the old implementation tied to the MySQL operator.

If the user does not provide a correct input it will fail at runtime anyway (in the execute method).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why fmt off?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I initially copy/pasted the MySQL implementation without thinking too much about it. After digging in the commit history it looks like those fmt directives are old artifacts that can be removed with no side effect, which I did.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also add a test to check bigquery_get_data has been called correctly

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The current assertion already ensures bigquery_get_data has been called as a side effect:

 mock_hook.return_value.list_rows.assert_called_once_with(

list_rows comes from bigquery_get_data.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

missing docs string for this param

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I fixed those missing docstrings

@eladkal

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it?
but even if the parameter stays moving to generalized solution makes this a no concern.

@shahar1

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it? but even if the parameter stays moving to generalized solution makes this a no concern.

I'm up to it, will happen during this week

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

@potiuk

potiuk commented Apr 16, 2023

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:
    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 9458e98 to 6aeb2d1CompareApril 16, 2023 23:02
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

@eladkal ok, deal. I refactored the two twin operators with a BaseBigQueryToSqlOperator and used it to implement the new BigQueryToPostgresOperator. I had to make some tweaks though to remain backward compatible because of subtle differences.

I took the opportunity to factorize docstrings. That said, I'm not 100% sure that documenting only two parameters in BigQueryToPostgresOperator is the way to go, considering some mandatory parameters handled (and documented) in the parent class, BaseBigQueryToSqlOperator, are required. You tell me.

The generated documentation looks fine. Here is an example (I also checked the other impacted pages):
image

The only tests I have not been able to run with Breeze are the example dags in tests/system/providers/google/cloud/bigquery/. The command breeze testing tests tests/system/providers/google/cloud/bigquery/ doesn't seem to do the trick.

@jbbqqf
jbbqqf requested a review from pankajastroApril 16, 2023 23:19

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @jbbqqf - just noticed we are getting the class name split across multiple lines in the documentation, is there anything we could do to fix it?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@phanikumv I don't want to fix this issue in this PR. The diff is not the cause of the issue from what I can see on Airflow's latest online documentation (https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/transfers/bigquery_to_mysql/index.html).

That said, this is how I would have done it:

image

@pankajastro

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:

    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

thanks for the detailed explanation makes sense 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

does it makes sense to combine Postgres and MySQL system test here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I don't understand what you'd suggest

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I left as is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep. Better to keep them separate. In this case usability of those examples trumps DRY

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Putting request changes just to make sure #30748 is merged before this PR so the delegate_to parameter won't be in BaseBigQueryToSqlOperator

@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf you can now rebase and the delegate_to won't be an issue as it was removed in main

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 6aeb2d1 to c744f08CompareApril 23, 2023 09:29

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This was removed from main. This parameter doesn't exist any more

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 6e711ea to eaecfb1CompareApril 23, 2023 17:44
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

I made everything I could with the feedback I've received on this PR.

The code is factorized so that the new PostgresOperator is not a copy/paste version of the Mysql one. The documentation is also as factorized as it can be.

I rebased and removed the delegate_to parameter. I eventually managed to make static checks + build pass thanks to breeze. All CI checks designed to make sure no doc / tests are forgotten do pass.

I built the documentation locally. It looks fine.

I tested operators with a local airflow / postgresql / mysql + test gcp project. Basic operations work.

By basic operation I mean I tested those tasks:

 bigquery_to_mysql = BigQueryToMySqlOperator(
task_id="bigquery_to_mysql",
dataset_table="dataset.table_42",
mysql_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)
bigquery_to_postgres = BigQueryToPostgresOperator(
task_id="bigquery_to_postgres",
dataset_table="dataset.table_42",
postgres_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)

During my tests I noticed there was an error with template_fields. It should now be fixed.

I performed my local tests with a postgres and a mysql database. I didn't manually test the mssql operator.

Is there some additional tests I should perform that would cover common pitfalls?

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

@potiuk

potiuk commented Apr 23, 2023

Copy link
Copy Markdown
Member

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

To start - maybe get all the tests succeed :D (they are failing currently)?

@potiuk

Copy link
Copy Markdown
Member

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks OK to me.
left one comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it's best to deprecate this parameter and replace it with a unified parameter in the base class (target_table_name)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure. I changed that.

Comment on lines 35 to 36

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd emphasize here that it's a base operator

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done

Comment on lines 99 to 100

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring and remove the pass

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

In my opinion it is unnecessary because concrete implementations are self-explanatory.

I have nonetheless taken into account your remark by adding a docstring.

@shahar1shahar1Apr 29, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Edited to explain myself better

I understand your opinion that it might seem redundant, however:

  1. Sometimes methods that look trivial might do something completely different than what you think they do - especially in an open source where many people with different code styles take part.
  2. Putting opinions aside, it's required by PEP 257, at least for public methods :)

Therefore, I suggest getting used to writing docstrings starting with self-explanatory methods, even as a preparation for more complicated functions. That being said, for simple methods - one line could do.

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Public methods (including the init constructor) should also have docstrings.

The wording of PEP 257 implies it's optional.

In Clean Code, Robert Martin enumerates a collection of smells and heuristics including:

C3: Redundant Comment

A comment is redundant if it describes something that adequately describes itself. For example:
i++; // increment i

Another example is a Javadoc that says nothing more than (or even less than) the function signature.

Comments should say things that the code cannot say for itself.

As suggested, I put my opinion aside and described persist_links with """This function persists the connection to the SQL provider""".

Comment on lines 102 to 103

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As is it trivial to reference all children implementation / calls to this function the best added value I could provide was to inform future readers what the history of this method is.

If you have another opinion, can you propose a docstring you think would fit?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I didn't mean to overcomplicate :)
A one-liner describing what this function does would do better (e.g.,: This function persists the connection to the SQL provider). The history of this method in this context seems irrelevant.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You could pass source_project_dataset_table directly to dataset_table

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

If you compare the old vs new version, it would introduce a slight difference of behavior between the two versions. It can lead to production issues.

I'd keep it this way because, unless I am mistaken, this version achieves 100% backward compatibility.

I agree that it doesn't make sense to have two distinct parameters for this use case. I searched in the google provider for helper functions to parse project.dataset.table vs dataset.table. I didn't find any.

If you insist on deprecating something here I'd vote to deprecate it in another PR because this one is already becoming quite complex to manage / review ✌️

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, now I realize that I missed the project definition in the dataset_table :)
It could wait for another time.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thank you 🙏

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from eaecfb1 to 38fc173CompareApril 29, 2023 13:14
@jbbqqf

jbbqqf commented Apr 29, 2023

Copy link
Copy Markdown
ContributorAuthor

To start - maybe get all the tests succeed :D (they are failing currently)?

Touché 😉

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

Sure 👍

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

I appreciate your efforts to demonstrate diplomacy.

Reference:

https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst

Ping @ #development slack, comment @people. Be annoying. Be considerate.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

@jbbqqf
jbbqqf requested a review from eladkalApril 29, 2023 13:27
@jbbqqf
jbbqqf requested a review from shahar1April 29, 2023 13:27
@potiuk

Copy link
Copy Markdown
Member

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

Complain to GitHub - not to us, this is an isue I reported to them ~ 2 years ago and there is no fix in sight.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

All the test types of airflow, including the way how to distribute them is decribed in https://github.com/apache/airflow/blob/main/TESTING.rst

Generally speaking - seems that unit tests are failing for you and you should be able to follow "unit test" chapter there. If you follow the instructions there, it should help.

Also Breeze commands are described in https://github.com/apache/airflow/blob/main/BREEZE.rst - including help and screen outputs. You can also run --help and --dry-run with every breeze command. The first will tell you what options you have, the second will tell you exactly what command breeze runs under the hood and it will print copy-pasteable command that you can run and modify to replicate what you do. in CI you can see what is being run by unfolding the steps you see and you will see what is going on and which command is run.

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

There is a word "considerate". Have you considered that people responding here have likley even 100s of PRs to look at, while you have one to contribute? and that they are often doing it in their free time and people are demanding attention becasue they think they have to get response NOW? If not - you can take a look at my talk about empathy:

https://airflowsummit.org/sessions/2022/hey-maintainer-exercise-your-empathy/

Mildly annoying does not mean unempathettic.

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 38fc173 to c459c42CompareMay 1, 2023 09:56
Comment on lines 62 to 70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets use AirflowProviderDeprecationWarning

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lets not do target_table_name or mssql_table
it makes it harder to understand where the "real" value is.
we should handle the value as part of the deprecation check. If user passed mssql_table then we also assign it to self. target_table_name

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm not sure to understand what you have in mind. Something like this?

 selected_target_table_name = target_table_name
if mssql_table is not None:
selected_target_table_name = mssql_table
warnings.warn(
"The `mssql_table` parameter has been deprecated. Use `target_table_name` instead.",
DeprecationWarning,
)
super().__init__(
target_table_name=selected_target_table_name,
dataset_table=f"{dataset_id}.{table_id}",
**kwargs,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Something like

ifchannel:
warnings.warn(
"Argument `channel` is deprecated and will removed in a future releases. "
"Please use `channels` instead.",
DeprecationWarning,
stacklevel=2,
)
ifchannels:
raiseValueError(f"Cannot set both arguments: channel={channel!r} and channels={channels!r}.")
channels=channel
self.channels=channels

basically once you pass that block

New parameter takes precedence but if older parameter is supplied we will assign it to the new parameter + raise warning.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This class is missing from the added docs. is this intentional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I was inspired by the implementation of BaseSQLToGCSOperator. This is also an abstract class which is not documented either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the BigQueryToMsSqlOperator not on the base class :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is intentional. There was a slight difference between the MySQL documentation and the MsSQL documentation. I standardized the location of the example snippet. I used the MsSQL version. It did not require to change the MsSQL version, but this is why there is a change on the MySQL version.

As for the new interface (s/mssql_table/target_table_name/), it has been changed directly in example_bigquery_to_mssql.py.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the rst files.

docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
Is missing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 3 times, most recently from b50b591 to d483676CompareMay 4, 2023 19:28
@jbbqqf
jbbqqf requested a review from eladkalMay 4, 2023 19:30

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Copying data from one BigQuery table to another is performed with the
Copying data from BigQuery table to Postgres table is performed with the

@potiukpotiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Small NIT: in the docs, otherwise it looks good to me - @eladkal ?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from d483676 to 4948e8aCompareMay 8, 2023 19:23
@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 4948e8a to 0bed8a8CompareMay 14, 2023 08:34
@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@eladkal I don't understand what you mean. This file already exist. I let it as is.

@eladkal

Copy link
Copy Markdown
Contributor

@eladkal I don't understand what you mean. This file already exist. I let it as is.

Right. sorry!
Note to self: not review code when it's late!

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

will merge when CI is green

@eladkal
eladkal merged commit cf1e26b into apache:mainMay 16, 2023
@boring-cyborg

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request! You are invited to check our Issue Tracker for additional contributions.

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

@potiuk

Copy link
Copy Markdown
Member

looking for next ones :)

@shahar1

Copy link
Copy Markdown
Contributor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

Welcome to the club, well done :)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:providerskind:documentationprovider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jbbqqf@eladkal@shahar1@potiuk@pankajastro@phanikumv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add BigQueryToPostgresOperator - #30658

Merged
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator
May 16, 2023
Merged

Add BigQueryToPostgresOperator#30658
eladkal merged 2 commits into
apache:mainfrom
jbbqqf:add-bigquery-to-postgres-operator

Conversation

@jbbqqf

Copy link
Copy Markdown
Contributor

Yet another operator.

I added that transfer operator by mimicry with the existing BigQueryToMySqlOperator.

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

I noticed the BigQueryToMySqlOperator is referenced in airflow/contrib/operators/__init__.py (__deprecated_classes) and in tests/always/test_project_structure.py (MISSING_EXAMPLES_FOR_CLASSES). I am not 100% sure of what those references mean but I guess the new BigQueryToPostgresOperator doesn't need to be referenced here.

@boring-cyborgboring-cyborgBot added area:providers kind:documentation provider:google Google (including GCP) related issues labels Apr 15, 2023
@boring-cyborg

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst)
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our pre-commits will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example DAG that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

@pankajastropankajastro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might not catch something like dataset.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I refactored the implementation. I am now using a BaseBigQueryToSqlOperator. In order to remain as backward compatible as possible, I used the old implementation tied to the MySQL operator.

If the user does not provide a correct input it will fail at runtime anyway (in the execute method).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why fmt off?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I initially copy/pasted the MySQL implementation without thinking too much about it. After digging in the commit history it looks like those fmt directives are old artifacts that can be removed with no side effect, which I did.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also add a test to check bigquery_get_data has been called correctly

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The current assertion already ensures bigquery_get_data has been called as a side effect:

 mock_hook.return_value.list_rows.assert_called_once_with(

list_rows comes from bigquery_get_data.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

missing docs string for this param

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I fixed those missing docstrings

@eladkal

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it?
but even if the parameter stays moving to generalized solution makes this a no concern.

@shahar1

Copy link
Copy Markdown
Contributor

I am aware this operator adds duplication with BigQueryToMySqlOperator and BigQueryToMsSqlOperator. The implementation is basically the same. On the other hand, I feel that factorizing that code would make it unreadable.

The BigQueryToMySqlOperator had a deprecated argument: delegate_to. I removed it from the Postgres adaptation.

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

As for the delegate_to. The next provider release is a breaking one. We can handle it now. It's simple as removing the warnings added in #29088 and remove the parameter all together @shahar1 maybe you are up for it? but even if the parameter stays moving to generalized solution makes this a no concern.

I'm up to it, will happen during this week

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

@potiuk

potiuk commented Apr 16, 2023

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:
    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 9458e98 to 6aeb2d1CompareApril 16, 2023 23:02
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

We should not duplicate code.

We should have either BaseBigQueryToSqlOperator then each flavour DB can inherit and do the specific things or preferably have a single BigQueryToSqlOperator that knows to handle any db hook that uses DbApiHook.

@eladkal ok, deal. I refactored the two twin operators with a BaseBigQueryToSqlOperator and used it to implement the new BigQueryToPostgresOperator. I had to make some tweaks though to remain backward compatible because of subtle differences.

I took the opportunity to factorize docstrings. That said, I'm not 100% sure that documenting only two parameters in BigQueryToPostgresOperator is the way to go, considering some mandatory parameters handled (and documented) in the parent class, BaseBigQueryToSqlOperator, are required. You tell me.

The generated documentation looks fine. Here is an example (I also checked the other impacted pages):
image

The only tests I have not been able to run with Breeze are the example dags in tests/system/providers/google/cloud/bigquery/. The command breeze testing tests tests/system/providers/google/cloud/bigquery/ doesn't seem to do the trick.

@jbbqqf
jbbqqf requested a review from pankajastroApril 16, 2023 23:19

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @jbbqqf - just noticed we are getting the class name split across multiple lines in the documentation, is there anything we could do to fix it?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@phanikumv I don't want to fix this issue in this PR. The diff is not the cause of the issue from what I can see on Airflow's latest online documentation (https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/transfers/bigquery_to_mysql/index.html).

That said, this is how I would have done it:

image

@pankajastro

Copy link
Copy Markdown
Member

usually, we keep a transfer operator in Google provider if data move from some services to Google services like from Postgres to Bigquery or from s3 to Bigquery/GCS so not sure if Google provider is the right place for this transfer operator.

I am new to AirFlow so I don't have an opinion on this. I added the module next to other similar operators (BigQueryToMySqlOperator and BigQueryToMsSqlOperator). Did you notice those operators?

Summarizing: yes the current location is good.

cc: @pankajastro : The rule is a bit more complex here and not only based on whether the provider is on the "To" or "From" side of the transfer. In most cases, yes, the "To" side is more important, but not for the reason you think.

The reason is that usually the "To" side (means - service) is more interested in receiving the data and is more lilely to be maintained by whoever puts the focus on the "to" provider. But it only makes sense if you have provider like "S3 <=> GCS" - where you have Amazon on one side and Google on the other. In this case Google is more insterested to maintain S3 To GCS and Amazon is more interested in GCS to S3 for obvious reasons. That's why the first one should be in Google provider and the other in the Amazon one - because respectively Google and Amazon will be interested in maintaining those.

For Bigquery to MySQL or Postgres , this is not as easy - because there is no "service provider" who would be interested in getting data to Postgres / MySQL, because those are generic databases, and while they have soime "stakeholders" those stakeholders do not own the service that they would be interested to get data in. And in this case Google is determined to be the "more likely to maintain it".

This is succintly described in our CONTRIBUTING.rst:

  • It is often debatable where to put transfer operators but we agreed to the following criteria:

    • We use "maintainability" of the operators as the main criteria - so the transfer operator
      should be kept at the provider which has highest "interest" in the transfer operator
    • For Cloud Providers or Service providers that usually means that the transfer operators
      should land at the "target" side of the transfer

thanks for the detailed explanation makes sense 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

does it makes sense to combine Postgres and MySQL system test here?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I don't understand what you'd suggest

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I left as is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep. Better to keep them separate. In this case usability of those examples trumps DRY

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Putting request changes just to make sure #30748 is merged before this PR so the delegate_to parameter won't be in BaseBigQueryToSqlOperator

@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf you can now rebase and the delegate_to won't be an issue as it was removed in main

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 6aeb2d1 to c744f08CompareApril 23, 2023 09:29

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This was removed from main. This parameter doesn't exist any more

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 2 times, most recently from 6e711ea to eaecfb1CompareApril 23, 2023 17:44
@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

I made everything I could with the feedback I've received on this PR.

The code is factorized so that the new PostgresOperator is not a copy/paste version of the Mysql one. The documentation is also as factorized as it can be.

I rebased and removed the delegate_to parameter. I eventually managed to make static checks + build pass thanks to breeze. All CI checks designed to make sure no doc / tests are forgotten do pass.

I built the documentation locally. It looks fine.

I tested operators with a local airflow / postgresql / mysql + test gcp project. Basic operations work.

By basic operation I mean I tested those tasks:

 bigquery_to_mysql = BigQueryToMySqlOperator(
task_id="bigquery_to_mysql",
dataset_table="dataset.table_42",
mysql_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)
bigquery_to_postgres = BigQueryToPostgresOperator(
task_id="bigquery_to_postgres",
dataset_table="dataset.table_42",
postgres_table="{{ var.value.get('my_var', 'test') }}",
replace=False,
)

During my tests I noticed there was an error with template_fields. It should now be fixed.

I performed my local tests with a postgres and a mysql database. I didn't manually test the mssql operator.

Is there some additional tests I should perform that would cover common pitfalls?

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

@potiuk

potiuk commented Apr 23, 2023

Copy link
Copy Markdown
Member

@eladkal you seem to have some perspective on the airflow project. What is the next step? How many people should validate the PR so that it can be merged? 🙂

To start - maybe get all the tests succeed :D (they are failing currently)?

@potiuk

Copy link
Copy Markdown
Member

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks OK to me.
left one comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it's best to deprecate this parameter and replace it with a unified parameter in the base class (target_table_name)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure. I changed that.

Comment on lines 35 to 36

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd emphasize here that it's a base operator

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done

Comment on lines 99 to 100

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring and remove the pass

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

In my opinion it is unnecessary because concrete implementations are self-explanatory.

I have nonetheless taken into account your remark by adding a docstring.

@shahar1shahar1Apr 29, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Edited to explain myself better

I understand your opinion that it might seem redundant, however:

  1. Sometimes methods that look trivial might do something completely different than what you think they do - especially in an open source where many people with different code styles take part.
  2. Putting opinions aside, it's required by PEP 257, at least for public methods :)

Therefore, I suggest getting used to writing docstrings starting with self-explanatory methods, even as a preparation for more complicated functions. That being said, for simple methods - one line could do.

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Public methods (including the init constructor) should also have docstrings.

The wording of PEP 257 implies it's optional.

In Clean Code, Robert Martin enumerates a collection of smells and heuristics including:

C3: Redundant Comment

A comment is redundant if it describes something that adequately describes itself. For example:
i++; // increment i

Another example is a Javadoc that says nothing more than (or even less than) the function signature.

Comments should say things that the code cannot say for itself.

As suggested, I put my opinion aside and described persist_links with """This function persists the connection to the SQL provider""".

Comment on lines 102 to 103

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add a docstring

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As is it trivial to reference all children implementation / calls to this function the best added value I could provide was to inform future readers what the history of this method is.

If you have another opinion, can you propose a docstring you think would fit?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I didn't mean to overcomplicate :)
A one-liner describing what this function does would do better (e.g.,: This function persists the connection to the SQL provider). The history of this method in this context seems irrelevant.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you suggesting it due to the similarities between the files?
While it may improve running time, I would rather keep the test files specific to their intended purpose. I believe that combining different SQL providers into a single file may cause confusion when trying to identify the source of an operator failure during debugging.
Separating them into distinct files should make the debugging process more manageable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You could pass source_project_dataset_table directly to dataset_table

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

If you compare the old vs new version, it would introduce a slight difference of behavior between the two versions. It can lead to production issues.

I'd keep it this way because, unless I am mistaken, this version achieves 100% backward compatibility.

I agree that it doesn't make sense to have two distinct parameters for this use case. I searched in the google provider for helper functions to parse project.dataset.table vs dataset.table. I didn't find any.

If you insist on deprecating something here I'd vote to deprecate it in another PR because this one is already becoming quite complex to manage / review ✌️

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, now I realize that I missed the project definition in the dataset_table :)
It could wait for another time.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thank you 🙏

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from eaecfb1 to 38fc173CompareApril 29, 2023 13:14
@jbbqqf

jbbqqf commented Apr 29, 2023

Copy link
Copy Markdown
ContributorAuthor

To start - maybe get all the tests succeed :D (they are failing currently)?

Touché 😉

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

And the second thing -> wait for a maintainer to merge it. And sometimes be patient with it @jbbqqf. Yes it takes sometimes a number of passes, multiple builds, conflict resolving and sometimes even few positive reviews to pass.

All that so that your change will be good, reviewed, tested, and being ready for anyone else to take over and develop further. Yes it can be annoying but if you consider that you might disappear tomorrow and there are a number of people here who will take over the maintenance of the code with confidence.

I hope you understand all that.

Sure 👍

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

I appreciate your efforts to demonstrate diplomacy.

Reference:

https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst

Ping @ #development slack, comment @people. Be annoying. Be considerate.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

@jbbqqf
jbbqqf requested a review from eladkalApril 29, 2023 13:27
@jbbqqf
jbbqqf requested a review from shahar1April 29, 2023 13:27
@potiuk

Copy link
Copy Markdown
Member

@potiuk Actually when I posted my comment, CI was all green and I thought for a moment I had solved the issue. As I can see it takes time so that all pipelines finish.

Complain to GitHub - not to us, this is an isue I reported to them ~ 2 years ago and there is no fix in sight.

I tried to run those tests with breeze but I can't manage to find the appropriate command that would specifically target the modified operators (running static checks with breeze is OK though). Can you suggest arguments I should pass to this tool to understand locally what's going on ? (CI failures don't seem to output verbose enough logs)

All the test types of airflow, including the way how to distribute them is decribed in https://github.com/apache/airflow/blob/main/TESTING.rst

Generally speaking - seems that unit tests are failing for you and you should be able to follow "unit test" chapter there. If you follow the instructions there, it should help.

Also Breeze commands are described in https://github.com/apache/airflow/blob/main/BREEZE.rst - including help and screen outputs. You can also run --help and --dry-run with every breeze command. The first will tell you what options you have, the second will tell you exactly what command breeze runs under the hood and it will print copy-pasteable command that you can run and modify to replicate what you do. in CI you can see what is being run by unfolding the steps you see and you will see what is going on and which command is run.

I read in Airflow's contributing guide that being pushy with maintainers was interpreted well, as a sign of interest. This was my intent. I will be patient as long as necessary.

It's your responsibility as an author to ping committers to review your PR - be mildly annoying sometimes, it's OK to be slightly annoying with your change - it is also a sign for committers that you care

There is a word "considerate". Have you considered that people responding here have likley even 100s of PRs to look at, while you have one to contribute? and that they are often doing it in their free time and people are demanding attention becasue they think they have to get response NOW? If not - you can take a look at my talk about empathy:

https://airflowsummit.org/sessions/2022/hey-maintainer-exercise-your-empathy/

Mildly annoying does not mean unempathettic.

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 38fc173 to c459c42CompareMay 1, 2023 09:56
Comment on lines 62 to 70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets use AirflowProviderDeprecationWarning

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lets not do target_table_name or mssql_table
it makes it harder to understand where the "real" value is.
we should handle the value as part of the deprecation check. If user passed mssql_table then we also assign it to self. target_table_name

@jbbqqfjbbqqfMay 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm not sure to understand what you have in mind. Something like this?

 selected_target_table_name = target_table_name
if mssql_table is not None:
selected_target_table_name = mssql_table
warnings.warn(
"The `mssql_table` parameter has been deprecated. Use `target_table_name` instead.",
DeprecationWarning,
)
super().__init__(
target_table_name=selected_target_table_name,
dataset_table=f"{dataset_id}.{table_id}",
**kwargs,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Something like

ifchannel:
warnings.warn(
"Argument `channel` is deprecated and will removed in a future releases. "
"Please use `channels` instead.",
DeprecationWarning,
stacklevel=2,
)
ifchannels:
raiseValueError(f"Cannot set both arguments: channel={channel!r} and channels={channels!r}.")
channels=channel
self.channels=channels

basically once you pass that block

New parameter takes precedence but if older parameter is supplied we will assign it to the new parameter + raise warning.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This class is missing from the added docs. is this intentional?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I was inspired by the implementation of BaseSQLToGCSOperator. This is also an abstract class which is not documented either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the BigQueryToMsSqlOperator not on the base class :)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is intentional. There was a slight difference between the MySQL documentation and the MsSQL documentation. I standardized the location of the example snippet. I used the MsSQL version. It did not require to change the MsSQL version, but this is why there is a change on the MySQL version.

As for the new interface (s/mssql_table/target_table_name/), it has been changed directly in example_bigquery_to_mssql.py.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm asking about the rst files.

docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
Is missing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst
?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch 3 times, most recently from b50b591 to d483676CompareMay 4, 2023 19:28
@jbbqqf
jbbqqf requested a review from eladkalMay 4, 2023 19:30

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Copying data from one BigQuery table to another is performed with the
Copying data from BigQuery table to Postgres table is performed with the

@potiukpotiuk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Small NIT: in the docs, otherwise it looks good to me - @eladkal ?

@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from d483676 to 4948e8aCompareMay 8, 2023 19:23
@jbbqqf
jbbqqfforce-pushed the add-bigquery-to-postgres-operator branch from 4948e8a to 0bed8a8CompareMay 14, 2023 08:34
@eladkal

Copy link
Copy Markdown
Contributor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

@jbbqqf can you add docs/apache-airflow-providers-google/operators/transfer/bigquery_to_mssql.rst

@eladkal I don't understand what you mean. This file already exist. I let it as is.

@eladkal

Copy link
Copy Markdown
Contributor

@eladkal I don't understand what you mean. This file already exist. I let it as is.

Right. sorry!
Note to self: not review code when it's late!

@eladkaleladkal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

will merge when CI is green

@eladkal
eladkal merged commit cf1e26b into apache:mainMay 16, 2023
@boring-cyborg

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request! You are invited to check our Issue Tracker for additional contributions.

@jbbqqf

Copy link
Copy Markdown
ContributorAuthor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

@potiuk

Copy link
Copy Markdown
Member

looking for next ones :)

@shahar1

Copy link
Copy Markdown
Contributor

So glad to officially become an Airflow contributor ❤️

My thank to you guys. Special mention to @eladkal@potiuk@shahar1

Welcome to the club, well done :)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:providerskind:documentationprovider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jbbqqf@eladkal@shahar1@potiuk@pankajastro@phanikumv