From f49beff48d7d602274335c1abe4f7dca090debb7 Mon Sep 17 00:00:00 2001 From: Mario Molina Date: Thu, 3 Nov 2022 07:46:31 -0600 Subject: [PATCH 01/73] =?UTF-8?q?=F0=9F=8E=89=20New=20Source:=20Datadog=20?= =?UTF-8?q?[python=20cdk]=20(#18150)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New Source: Datadog * Updating doc * Adding unit tests * Renaming limit var * Updating description in spec * add source def to seed * add datadog to source def seed * run format * auto-bump connector version Co-authored-by: marcosmarxm Co-authored-by: Octavia Squidington III --- .../resources/seed/source_definitions.yaml | 7 + .../src/main/resources/seed/source_specs.yaml | 62 +++ .../connectors/source-datadog/.dockerignore | 6 + .../connectors/source-datadog/Dockerfile | 16 + .../connectors/source-datadog/README.md | 109 +++++ .../source-datadog/acceptance-test-config.yml | 25 ++ .../source-datadog/acceptance-test-docker.sh | 15 + .../connectors/source-datadog/build.gradle | 13 + .../integration_tests/__init__.py | 3 + .../integration_tests/abnormal_state.json | 5 + .../integration_tests/acceptance.py | 14 + .../integration_tests/configured_catalog.json | 73 ++++ .../inc_configured_catalog.json | 17 + .../integration_tests/invalid_config.json | 7 + .../integration_tests/sample_config.json | 8 + .../connectors/source-datadog/main.py | 13 + .../source-datadog/requirements.txt | 3 + .../connectors/source-datadog/setup.py | 26 ++ .../source-datadog/source_datadog/__init__.py | 8 + .../source_datadog/schemas/audit_logs.json | 49 +++ .../source_datadog/schemas/dashboards.json | 55 +++ .../source_datadog/schemas/downtimes.json | 103 +++++ .../schemas/incident_teams.json | 92 ++++ .../source_datadog/schemas/incidents.json | 135 ++++++ .../source_datadog/schemas/logs.json | 61 +++ .../source_datadog/schemas/metrics.json | 5 + .../schemas/synthetic_tests.json | 105 +++++ .../source_datadog/schemas/users.json | 76 ++++ .../source-datadog/source_datadog/source.py | 64 +++ .../source-datadog/source_datadog/spec.yaml | 56 +++ .../source-datadog/source_datadog/streams.py | 288 +++++++++++++ .../source-datadog/unit_tests/__init__.py | 3 + .../source-datadog/unit_tests/conftest.py | 392 ++++++++++++++++++ .../source-datadog/unit_tests/test_source.py | 58 +++ .../source-datadog/unit_tests/test_streams.py | 100 +++++ docs/integrations/README.md | 1 + docs/integrations/sources/datadog.md | 65 +++ 37 files changed, 2138 insertions(+) create mode 100644 airbyte-integrations/connectors/source-datadog/.dockerignore create mode 100644 airbyte-integrations/connectors/source-datadog/Dockerfile create mode 100644 airbyte-integrations/connectors/source-datadog/README.md create mode 100644 airbyte-integrations/connectors/source-datadog/acceptance-test-config.yml create mode 100644 airbyte-integrations/connectors/source-datadog/acceptance-test-docker.sh create mode 100644 airbyte-integrations/connectors/source-datadog/build.gradle create mode 100644 airbyte-integrations/connectors/source-datadog/integration_tests/__init__.py create mode 100644 airbyte-integrations/connectors/source-datadog/integration_tests/abnormal_state.json create mode 100644 airbyte-integrations/connectors/source-datadog/integration_tests/acceptance.py create mode 100644 airbyte-integrations/connectors/source-datadog/integration_tests/configured_catalog.json create mode 100644 airbyte-integrations/connectors/source-datadog/integration_tests/inc_configured_catalog.json create mode 100644 airbyte-integrations/connectors/source-datadog/integration_tests/invalid_config.json create mode 100644 airbyte-integrations/connectors/source-datadog/integration_tests/sample_config.json create mode 100644 airbyte-integrations/connectors/source-datadog/main.py create mode 100644 airbyte-integrations/connectors/source-datadog/requirements.txt create mode 100644 airbyte-integrations/connectors/source-datadog/setup.py create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/__init__.py create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/schemas/audit_logs.json create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/schemas/dashboards.json create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/schemas/downtimes.json create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/schemas/incident_teams.json create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/schemas/incidents.json create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/schemas/logs.json create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/schemas/metrics.json create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/schemas/synthetic_tests.json create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/schemas/users.json create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/source.py create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/spec.yaml create mode 100644 airbyte-integrations/connectors/source-datadog/source_datadog/streams.py create mode 100644 airbyte-integrations/connectors/source-datadog/unit_tests/__init__.py create mode 100644 airbyte-integrations/connectors/source-datadog/unit_tests/conftest.py create mode 100644 airbyte-integrations/connectors/source-datadog/unit_tests/test_source.py create mode 100644 airbyte-integrations/connectors/source-datadog/unit_tests/test_streams.py create mode 100644 docs/integrations/sources/datadog.md diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index ecd980b86228..61e6e8109357 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -278,6 +278,13 @@ icon: customer-io.svg sourceType: api releaseStage: alpha +- name: Datadog + sourceDefinitionId: 1cfc30c7-82db-43f4-9fd7-ac1b42312cda + dockerRepository: airbyte/source-datadog + dockerImageTag: 0.1.0 + documentationUrl: https://docs.airbyte.com/integrations/sources/datadog + sourceType: api + releaseStage: alpha - name: Delighted sourceDefinitionId: cc88c43f-6f53-4e8a-8c4d-b284baaf9635 dockerRepository: airbyte/source-delighted diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 7e9a42bd6113..6ba01d53a1de 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -2485,6 +2485,68 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] +- dockerImage: "airbyte/source-datadog:0.1.0" + spec: + documentationUrl: "https://docs.airbyte.com/integrations/sources/datadog" + connectionSpecification: + $schema: "http://json-schema.org/draft-07/schema#" + title: "Datadog Source Spec" + type: "object" + required: + - "api_key" + - "application_key" + additionalProperties: true + properties: + api_key: + title: "API Key" + description: "Datadog API key" + type: "string" + airbyte_secret: true + order: 1 + application_key: + title: "Application Key" + description: "Datadog application key" + type: "string" + airbyte_secret: true + order: 2 + query: + title: "Query" + description: "The search query. This just applies to Incremental syncs.\ + \ If empty, it'll collect all logs." + type: "string" + order: 3 + max_records_per_request: + type: "integer" + title: "Max records per requests" + default: 5000 + minimum: 1 + maximum: 5000 + description: "Maximum number of records to collect per request." + order: 4 + start_date: + title: "Start date" + pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$" + description: "UTC date and time in the format 2017-01-25T00:00:00Z. Any\ + \ data before this date will not be replicated. This just applies to Incremental\ + \ syncs." + type: "string" + examples: + - "2022-10-01T00:00:00Z" + order: 5 + end_date: + title: "End date" + pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$" + description: "UTC date and time in the format 2017-01-25T00:00:00Z. Data\ + \ after this date will not be replicated. An empty value will represent\ + \ the current datetime for each execution. This just applies to Incremental\ + \ syncs." + examples: + - "2022-10-01T00:00:00Z" + type: "string" + order: 6 + supportsNormalization: false + supportsDBT: false + supported_destination_sync_modes: [] - dockerImage: "airbyte/source-delighted:0.1.4" spec: documentationUrl: "https://docsurl.com" diff --git a/airbyte-integrations/connectors/source-datadog/.dockerignore b/airbyte-integrations/connectors/source-datadog/.dockerignore new file mode 100644 index 000000000000..6807347e1915 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/.dockerignore @@ -0,0 +1,6 @@ +* +!Dockerfile +!main.py +!source_datadog +!setup.py +!secrets diff --git a/airbyte-integrations/connectors/source-datadog/Dockerfile b/airbyte-integrations/connectors/source-datadog/Dockerfile new file mode 100644 index 000000000000..bdb53751e867 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/Dockerfile @@ -0,0 +1,16 @@ +FROM python:3.9-slim + +# Bash is installed for more convenient debugging. +RUN apt-get update && apt-get install -y bash && rm -rf /var/lib/apt/lists/* + +WORKDIR /airbyte/integration_code +COPY source_datadog ./source_datadog +COPY main.py ./ +COPY setup.py ./ +RUN pip install . + +ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" +ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] + +LABEL io.airbyte.version=0.1.0 +LABEL io.airbyte.name=airbyte/source-datadog diff --git a/airbyte-integrations/connectors/source-datadog/README.md b/airbyte-integrations/connectors/source-datadog/README.md new file mode 100644 index 000000000000..a0d9e1192749 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/README.md @@ -0,0 +1,109 @@ +# Datadog Source + +This is the repository for the Datadog source connector, written in Python. +For information about how to use this connector within Airbyte, see [the documentation](https://docs.airbyte.io/integrations/sources/datadog). + +## Local development + +### Prerequisites +**To iterate on this connector, make sure to complete this prerequisites section.** + +#### Minimum Python version required `= 3.9.0` + +#### Build & Activate Virtual Environment and install dependencies +From this connector directory, create a virtual environment: +``` +python -m venv .venv +``` + +This will generate a virtualenv for this module in `.venv/`. Make sure this venv is active in your +development environment of choice. To activate it from the terminal, run: +``` +source .venv/bin/activate +pip install -r requirements.txt +``` +If you are in an IDE, follow your IDE's instructions to activate the virtualenv. + +Note that while we are installing dependencies from `requirements.txt`, you should only edit `setup.py` for your dependencies. `requirements.txt` is +used for editable installs (`pip install -e`) to pull in Python dependencies from the monorepo and will call `setup.py`. +If this is mumbo jumbo to you, don't worry about it, just put your deps in `setup.py` but install using `pip install -r requirements.txt` and everything +should work as you expect. + +#### Building via Gradle +From the Airbyte repository root, run: +``` +./gradlew :airbyte-integrations:connectors:source-datadog:build +``` + +#### Create credentials +**If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.io/integrations/sources/datadog) +to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `source_datadog/spec.json` file. +Note that the `secrets` directory is gitignored by default, so there is no danger of accidentally checking in sensitive information. +See `integration_tests/sample_config.json` for a sample config file. + +**If you are an Airbyte core member**, copy the credentials in Lastpass under the secret name `source datadog test creds` +and place them into `secrets/config.json`. + + +### Locally running the connector +``` +python main.py spec +python main.py check --config secrets/config.json +python main.py discover --config secrets/config.json +python main.py read --config secrets/config.json --catalog integration_tests/configured_catalog.json +``` + +### Locally running the connector docker image + +#### Build +First, make sure you build the latest Docker image: +``` +docker build . -t airbyte/source-datadog:dev +``` + +You can also build the connector image via Gradle: +``` +./gradlew :airbyte-integrations:connectors:source-datadog:airbyteDocker +``` +When building via Gradle, the docker image name and tag, respectively, are the values of the `io.airbyte.name` and `io.airbyte.version` `LABEL`s in +the Dockerfile. + +#### Run +Then run any of the connector commands as follows: +``` +docker run --rm airbyte/source-datadog:dev spec +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-datadog:dev check --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-datadog:dev discover --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/source-datadog:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json +``` + +#### Acceptance Tests +Customize `acceptance-test-config.yml` file to configure tests. See [Source Acceptance Tests](https://docs.airbyte.io/connector-development/testing-connectors/source-acceptance-tests-reference) for more information. +If your connector requires to create or destroy resources for use during acceptance tests create fixtures for it and place them inside integration_tests/acceptance.py. +To run your integration tests with acceptance tests, from the connector root, run +``` +docker build . --no-cache -t airbyte/source-datadog:dev \ +&& python -m pytest -p source_acceptance_test.plugin +``` + +### Unit Tests +To run unit tests locally, from the connector directory run: +``` +python -m pytest unit_tests +``` + +### Integration Tests +1. From the airbyte project root, run `./gradlew :airbyte-integrations:connectors:source-datadog:integrationTest` to run the standard integration test suite. +1. To run additional integration tests, place your integration tests in a new directory `integration_tests` and run them with `python -m pytest -s integration_tests`. + Make sure to familiarize yourself with [pytest test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) to know how your test files and methods should be named. + +## Dependency Management +All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development. + +### Publishing a new version of the connector +You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what? +1. Make sure your changes are passing unit and integration tests +1. Bump the connector version in `Dockerfile` -- just increment the value of the `LABEL io.airbyte.version` appropriately (we use SemVer). +1. Create a Pull Request +1. Pat yourself on the back for being an awesome contributor +1. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master diff --git a/airbyte-integrations/connectors/source-datadog/acceptance-test-config.yml b/airbyte-integrations/connectors/source-datadog/acceptance-test-config.yml new file mode 100644 index 000000000000..6e1df480373e --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/acceptance-test-config.yml @@ -0,0 +1,25 @@ +# See [Source Acceptance Tests](https://docs.airbyte.com/connector-development/testing-connectors/source-acceptance-tests-reference) +# for more information about how to configure these tests +connector_image: airbyte/source-datadog:dev +tests: + spec: + - spec_path: "source_datadog/spec.yaml" + connection: + - config_path: "secrets/config.json" + status: "succeed" + - config_path: "integration_tests/invalid_config.json" + status: "failed" + discovery: + - config_path: "secrets/config.json" + basic_read: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" + empty_streams: + - incident_teams + incremental: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/inc_configured_catalog.json" + future_state_path: "integration_tests/abnormal_state.json" + full_refresh: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" diff --git a/airbyte-integrations/connectors/source-datadog/acceptance-test-docker.sh b/airbyte-integrations/connectors/source-datadog/acceptance-test-docker.sh new file mode 100644 index 000000000000..c522eebbd94e --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/acceptance-test-docker.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh + +# Build latest connector image +docker build . -t $(cat acceptance-test-config.yml | grep "connector_image" | head -n 1 | cut -d: -f2) + +# Pull latest acctest image +docker pull airbyte/source-acceptance-test:latest + +# Run +docker run --rm -it \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /tmp:/tmp \ + -v $(pwd):/test_input \ + airbyte/source-acceptance-test \ + --acceptance-test-config /test_input diff --git a/airbyte-integrations/connectors/source-datadog/build.gradle b/airbyte-integrations/connectors/source-datadog/build.gradle new file mode 100644 index 000000000000..7d7e44963718 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/build.gradle @@ -0,0 +1,13 @@ +plugins { + id 'airbyte-python' + id 'airbyte-docker' + id 'airbyte-source-acceptance-test' +} + +airbytePython { + moduleDirectory 'source_datadog' +} + +dependencies { + implementation files(project(':airbyte-integrations:bases:source-acceptance-test').airbyteDocker.outputs) +} diff --git a/airbyte-integrations/connectors/source-datadog/integration_tests/__init__.py b/airbyte-integrations/connectors/source-datadog/integration_tests/__init__.py new file mode 100644 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/integration_tests/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-datadog/integration_tests/abnormal_state.json b/airbyte-integrations/connectors/source-datadog/integration_tests/abnormal_state.json new file mode 100644 index 000000000000..b93902698218 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/integration_tests/abnormal_state.json @@ -0,0 +1,5 @@ +{ + "logs": { + "sync_date": "2024-10-10T00:10:00Z" + } +} diff --git a/airbyte-integrations/connectors/source-datadog/integration_tests/acceptance.py b/airbyte-integrations/connectors/source-datadog/integration_tests/acceptance.py new file mode 100644 index 000000000000..950b53b59d41 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/integration_tests/acceptance.py @@ -0,0 +1,14 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import pytest + +pytest_plugins = ("source_acceptance_test.plugin",) + + +@pytest.fixture(scope="session", autouse=True) +def connector_setup(): + """This fixture is a placeholder for external resources that acceptance test might require.""" + yield diff --git a/airbyte-integrations/connectors/source-datadog/integration_tests/configured_catalog.json b/airbyte-integrations/connectors/source-datadog/integration_tests/configured_catalog.json new file mode 100644 index 000000000000..b8a33996b8d4 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/integration_tests/configured_catalog.json @@ -0,0 +1,73 @@ +{ + "streams": [ + { + "stream": { + "name": "dashboards", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "downtimes", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "incident_teams", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"], + "source_defined_primary_key": [["id"]] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "logs", + "json_schema": {}, + "supported_sync_modes": ["full_refresh", "incremental"], + "source_defined_cursor": true, + "default_cursor_field": ["sync_date"], + "source_defined_primary_key": [["id"]] + }, + "sync_mode": "full_refresh", + "cursor_field": ["sync_date"], + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "metrics", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "synthetic_tests", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "users", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"], + "source_defined_primary_key": [["id"]] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-datadog/integration_tests/inc_configured_catalog.json b/airbyte-integrations/connectors/source-datadog/integration_tests/inc_configured_catalog.json new file mode 100644 index 000000000000..ee26bd107c2e --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/integration_tests/inc_configured_catalog.json @@ -0,0 +1,17 @@ +{ + "streams": [ + { + "stream": { + "name": "logs", + "json_schema": {}, + "supported_sync_modes": ["full_refresh", "incremental"], + "source_defined_cursor": true, + "default_cursor_field": ["sync_date"], + "source_defined_primary_key": [["id"]] + }, + "sync_mode": "incremental", + "cursor_field": ["sync_date"], + "destination_sync_mode": "append" + } + ] +} diff --git a/airbyte-integrations/connectors/source-datadog/integration_tests/invalid_config.json b/airbyte-integrations/connectors/source-datadog/integration_tests/invalid_config.json new file mode 100644 index 000000000000..6e27d0fcd606 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/integration_tests/invalid_config.json @@ -0,0 +1,7 @@ +{ + "api_key": "", + "application_key": "", + "query": "sample query", + "limit": 100, + "start_date": "2222-10-10T00:00:00Z" +} diff --git a/airbyte-integrations/connectors/source-datadog/integration_tests/sample_config.json b/airbyte-integrations/connectors/source-datadog/integration_tests/sample_config.json new file mode 100644 index 000000000000..9be54f53bd05 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/integration_tests/sample_config.json @@ -0,0 +1,8 @@ +{ + "api_key": "", + "application_key": "", + "query": "sample query", + "limit": 100, + "start_date": "2022-10-10T00:00:00Z", + "end_date": "2022-10-10T00:10:00Z" +} diff --git a/airbyte-integrations/connectors/source-datadog/main.py b/airbyte-integrations/connectors/source-datadog/main.py new file mode 100644 index 000000000000..55bd46911b4f --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/main.py @@ -0,0 +1,13 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import sys + +from airbyte_cdk.entrypoint import launch +from source_datadog import SourceDatadog + +if __name__ == "__main__": + source = SourceDatadog() + launch(source, sys.argv[1:]) diff --git a/airbyte-integrations/connectors/source-datadog/requirements.txt b/airbyte-integrations/connectors/source-datadog/requirements.txt new file mode 100644 index 000000000000..7be17a56d745 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/requirements.txt @@ -0,0 +1,3 @@ +# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. +-e ../../bases/source-acceptance-test +-e . diff --git a/airbyte-integrations/connectors/source-datadog/setup.py b/airbyte-integrations/connectors/source-datadog/setup.py new file mode 100644 index 000000000000..3156ffa7e737 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/setup.py @@ -0,0 +1,26 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from setuptools import find_packages, setup + +MAIN_REQUIREMENTS = ["airbyte-cdk~=0.1", "requests==2.25.1"] + +TEST_REQUIREMENTS = [ + "pytest==6.1.2", + "source-acceptance-test", +] + +setup( + name="source_datadog", + description="Source implementation for Datadog.", + author="Airbyte", + author_email="contact@airbyte.io", + packages=find_packages(), + install_requires=MAIN_REQUIREMENTS, + package_data={"": ["*.json", "schemas/*.json"]}, + extras_require={ + "tests": TEST_REQUIREMENTS, + }, +) diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/__init__.py b/airbyte-integrations/connectors/source-datadog/source_datadog/__init__.py new file mode 100644 index 000000000000..e7b9d6ba7582 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/__init__.py @@ -0,0 +1,8 @@ +# +# Copyright (c) 2021 Airbyte, Inc., all rights reserved. +# + + +from .source import SourceDatadog + +__all__ = ["SourceDatadog"] diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/audit_logs.json b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/audit_logs.json new file mode 100644 index 000000000000..f4d05f4a807f --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/audit_logs.json @@ -0,0 +1,49 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "attributes": { + "type": ["object", "null"], + "description": "JSON object containing all event attributes and their associated values.", + "properties": { + "attributes": { + "type": ["object", "null"], + "description": "JSON object of attributes from Audit Logs events.", + "additionalProperties": true + }, + "service": { + "type": ["string", "null"], + "description": "Name of the application or service generating Audit Logs events." + }, + "tags": { + "type": ["array", "null"], + "items": { + "type": "string" + }, + "description": "Array of tags associated with your event." + }, + "timestamp": { + "type": ["string", "null"], + "format": "date-time", + "description": "Timestamp of your event." + } + }, + "additionalProperties": true + }, + "id": { + "type": ["string", "null"], + "description": "Unique ID of the event.", + "readOnly": true + }, + "sync_date": { + "type": ["null", "string"] + }, + "type": { + "type": ["string", "null"], + "enum": ["audit"], + "description": "Type of the event. Allowed enum values: audit", + "readOnly": true + } + }, + "additionalProperties": true +} diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/dashboards.json b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/dashboards.json new file mode 100644 index 000000000000..c767d3fadc03 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/dashboards.json @@ -0,0 +1,55 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "author_handle": { + "type": ["string", "null"], + "description": "Identifier of the dashboard author.", + "readOnly": true + }, + "created_at": { + "type": ["string", "null"], + "format": "date-time", + "description": "Creation date of the dashboard.", + "readOnly": true + }, + "description": { + "type": ["string", "null"], + "description": "Description of the dashboard.", + "readOnly": true + }, + "id": { + "type": ["string", "null"], + "description": "Dashboard identifier.", + "readOnly": true + }, + "is_read_only": { + "type": ["boolean", "null"], + "description": "Whether this dashboard is read-only. If True, only the author and admins can make changes to it.", + "readOnly": true + }, + "layout_type": { + "type": ["string", "null"], + "enum": ["ordered", "free"], + "description": "Layout type of the dashboard", + "readOnly": true + }, + "modified_at": { + "type": ["string", "null"], + "format": "date-time", + "description": "Modification date of the dashboard.", + "readOnly": true + }, + "title": { + "type": ["string", "null"], + "description": "Title of the dashboard.", + "readOnly": true + }, + "url": { + "type": ["string", "null"], + "description": "URL of the dashboard.", + "readOnly": true + } + }, + "additionalProperties": true +} diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/downtimes.json b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/downtimes.json new file mode 100644 index 000000000000..a996968a6ecd --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/downtimes.json @@ -0,0 +1,103 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "active": { + "type": ["boolean", "null"], + "description": "If a scheduled downtime currently exists.", + "readOnly": true + }, + "active_child": { + "type": ["object", "null"], + "description": "The downtime object definition of the active child for the original parent recurring downtime.", + "additionalProperties": true + }, + "canceled": { + "type": ["integer", "null"], + "description": "If a scheduled downtime is canceled.", + "readOnly": true + }, + "creator_id": { + "type": ["integer", "null"], + "description": "User ID of the downtime creator.", + "readOnly": true + }, + "disabled": { + "type": ["boolean", "null"], + "description": "If a downtime has been disabled.", + "readOnly": true + }, + "downtime_type": { + "type": ["integer", "null"], + "description": "0 for a downtime applied on * or all, 1 when the downtime is only scoped to hosts, or 2 when the downtime is scoped to anything but hosts.", + "readOnly": true + }, + "end": { + "type": ["integer", "null"], + "description": "POSIX timestamp to end the downtime. If not provided, the downtime is in effect indefinitely until you cancel it.", + "readOnly": true + }, + "id": { + "type": ["integer", "null"], + "description": "The downtime ID.", + "readOnly": true + }, + "message": { + "type": ["string", "null"], + "description": "A message to include with notifications for this downtime.", + "readOnly": true + }, + "monitor_id": { + "type": ["integer", "null"], + "description": "A single monitor to which the downtime applies. If not provided, the downtime applies to all monitors.", + "readOnly": true + }, + "monitor_tags": { + "type": ["array", "null"], + "items": { + "type": "string" + }, + "description": "A comma-separated list of monitor tags.", + "readOnly": true + }, + "mute_first_recovery_notification": { + "type": ["boolean", "null"], + "description": "If the first recovery notification during a downtime should be muted.", + "readOnly": true + }, + "parent_id": { + "type": ["integer", "null"], + "description": "ID of the parent Downtime.", + "readOnly": true + }, + "recurrence": { + "type": ["object", "null"], + "description": "An object defining the recurrence of the downtime.", + "additionalProperties": true + }, + "scope": { + "type": ["array", "null"], + "items": { + "type": "string" + }, + "description": "The scope(s) to which the downtime applies.", + "readOnly": true + }, + "start": { + "type": ["integer", "null"], + "description": "POSIX timestamp to start the downtime. If not provided, the downtime starts the moment it is created.", + "readOnly": true + }, + "timezone": { + "type": ["string", "null"], + "description": "The timezone in which to display the downtime's start and end times in Datadog applications.", + "readOnly": true + }, + "updater_id": { + "type": ["integer", "null"], + "description": "ID of the last user that updated the downtime.", + "readOnly": true + } + }, + "additionalProperties": true +} diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/incident_teams.json b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/incident_teams.json new file mode 100644 index 000000000000..3411ac94cfb4 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/incident_teams.json @@ -0,0 +1,92 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "attributes": { + "type": ["object", "null"], + "description": "The incident team's attributes from a response.", + "properties": { + "created": { + "type": ["string", "null"], + "format": "date-time", + "description": "Timestamp of when the incident team was created." + }, + "modified": { + "type": ["string", "null"], + "format": "date-time", + "description": "Timestamp of when the incident team was modified." + }, + "name": { + "type": ["string", "null"], + "description": "Name of the incident team." + } + }, + "additionalProperties": true + }, + "id": { + "type": ["string", "null"], + "description": "The incident team's ID.", + "readOnly": true + }, + "relationships": { + "type": ["object", "null"], + "description": "The incident team's relationships.", + "properties": { + "created_by": { + "type": ["object", "null"], + "description": "Relationship to user.", + "properties": { + "data": { + "type": ["object"], + "description": "Relationship to user object.", + "properties": { + "id": { + "type": ["string"], + "description": "A unique identifier that represents the user." + }, + "type": { + "type": ["string"], + "enum": ["users"], + "description": "Users resource type. Allowed enum values: users" + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + }, + "last_modified_by": { + "type": ["object", "null"], + "description": "Relationship to user.", + "properties": { + "data": { + "type": ["object"], + "description": "Relationship to user object.", + "properties": { + "id": { + "type": ["string"], + "description": "A unique identifier that represents the user." + }, + "type": { + "type": ["string"], + "enum": ["users"], + "description": "Users resource type. Allowed enum values: users" + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + }, + "type": { + "type": ["string", "null"], + "enum": ["teams"], + "description": "Incident Team resource type. Allowed enum values: teams", + "readOnly": true + } + }, + "additionalProperties": true +} diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/incidents.json b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/incidents.json new file mode 100644 index 000000000000..91b29ea4a799 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/incidents.json @@ -0,0 +1,135 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "attributes": { + "type": ["object", "null"], + "description": "The incident's attributes from a response.", + "properties": { + "created": { + "type": ["string", "null"], + "format": "date-time", + "description": "Timestamp when the incident was created." + }, + "customer_impact_duration": { + "type": ["integer", "null"], + "description": "Length of the incident's customer impact in seconds. Equals the difference between customer_impact_start and customer_impact_end." + }, + "customer_impact_end": { + "type": ["string", "null"], + "format": "date-time", + "description": "Timestamp when customers were no longer impacted by the incident." + }, + "customer_impact_scope": { + "type": ["string", "null"], + "description": "A summary of the impact customers experienced during the incident." + }, + "customer_impact_start": { + "type": ["string", "null"], + "format": "date-time", + "description": "Timestamp when customers began being impacted by the incident." + }, + "customer_impacted": { + "type": ["boolean", "null"], + "description": "A flag indicating whether the incident caused customer impact." + }, + "detected": { + "type": ["string", "null"], + "format": "date-time", + "description": "Timestamp when the incident was detected." + }, + "fields": { + "type": ["object", "null"], + "description": "A condensed view of the user-defined fields attached to incidents.", + "additionalProperties": true + }, + "modified": { + "type": ["string", "null"], + "format": "date-time", + "description": "Timestamp when the incident was last modified." + }, + "notification_handles": { + "type": ["array", "null"], + "items": { + "type": "object" + }, + "description": "Notification handles that will be notified of the incident during update." + }, + "public_id": { + "type": ["integer", "null"], + "description": "The monotonically increasing integer ID for the incident." + }, + "resolved": { + "type": ["string", "null"], + "format": "date-time", + "description": "Timestamp when the incident's state was last changed from active or stable to resolved or completed." + }, + "time_to_detect": { + "type": ["integer", "null"], + "description": "The amount of time in seconds to detect the incident. Equals the difference between customer_impact_start and detected." + }, + "time_to_internal_response": { + "type": ["integer", "null"], + "description": "The amount of time in seconds to call incident after detection. Equals the difference of detected and created." + }, + "time_to_repair": { + "type": ["integer", "null"], + "description": "The amount of time in seconds to resolve customer impact after detecting the issue. Equals the difference between customer_impact_end and detected." + }, + "time_to_resolve": { + "type": ["integer", "null"], + "description": "The amount of time in seconds to resolve the incident after it was created. Equals the difference between created and resolved." + }, + "title": { + "type": ["string"], + "description": "The title of the incident, which summarizes what happened." + } + }, + "additionalProperties": true + }, + "id": { + "type": ["string"], + "description": "The incident's ID.", + "readOnly": true + }, + "relationships": { + "type": ["object", "null"], + "description": "The incident's relationships from a response.", + "properties": { + "attachments": { + "type": ["object", "null"], + "description": "A relationship reference for attachments.", + "additionalProperties": true + }, + "commander_user": { + "type": ["object", "null"], + "description": "Relationship to user.", + "additionalProperties": true + }, + "created_by_user": { + "type": ["object", "null"], + "description": "Relationship to user.", + "additionalProperties": true + }, + "integrations": { + "type": ["object", "null"], + "description": "A relationship reference for multiple integration metadata objects.", + "additionalProperties": true + }, + "last_modified_by_user": { + "type": ["object", "null"], + "description": "Relationship to user.", + "additionalProperties": true + } + }, + "additionalProperties": true + }, + "type": { + "type": ["string"], + "enum": ["incidents"], + "description": "Incident resource type. Allowed enum values: incidents", + "readOnly": true + } + }, + "additionalProperties": true +} diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/logs.json b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/logs.json new file mode 100644 index 000000000000..1e1d2bc70818 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/logs.json @@ -0,0 +1,61 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "attributes": { + "type": ["object", "null"], + "description": "JSON object containing all log attributes and their associated values.", + "properties": { + "attributes": { + "type": ["object", "null"], + "description": "JSON object of attributes from your log.", + "additionalProperties": true + }, + "host": { + "type": ["string", "null"], + "description": "Name of the machine from where the logs are being sent." + }, + "message": { + "type": ["string", "null"], + "description": "The message reserved attribute of your log." + }, + "service": { + "type": ["string", "null"], + "description": "The name of the application or service generating the log events." + }, + "status": { + "type": ["string", "null"], + "description": "Status of the message associated with your log." + }, + "tags": { + "type": ["array", "null"], + "items": { + "type": "string" + }, + "description": "Array of tags associated with your log." + }, + "timestamp": { + "type": ["string", "null"], + "format": "date-time", + "description": "Timestamp of your log." + } + }, + "additionalProperties": true + }, + "id": { + "type": ["string", "null"], + "description": "Unique ID of the Log.", + "readOnly": true + }, + "sync_date": { + "type": ["null", "string"] + }, + "type": { + "type": ["string", "null"], + "enum": ["log"], + "description": "Type of the event. Allowed enum values: log", + "readOnly": true + } + }, + "additionalProperties": true +} diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/metrics.json b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/metrics.json new file mode 100644 index 000000000000..c74e6c5a5915 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/metrics.json @@ -0,0 +1,5 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": true +} diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/synthetic_tests.json b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/synthetic_tests.json new file mode 100644 index 000000000000..a2b7d0e0d91b --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/synthetic_tests.json @@ -0,0 +1,105 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "config": { + "type": ["object", "null"], + "description": "Configuration object for a Synthetic test.", + "additionalProperties": true + }, + "creator": { + "type": ["object", "null"], + "description": "Object describing the creator of the shared element.", + "properties": { + "email": { + "type": ["string", "null"], + "description": "Email of the creator." + }, + "handle": { + "type": ["string", "null"], + "description": "Handle of the creator." + }, + "name": { + "type": ["string", "null"], + "description": "Name of the creator." + } + }, + "additionalProperties": true + }, + "locations": { + "type": ["array", "null"], + "items": { + "type": "string" + }, + "description": "Array of locations used to run the test.", + "readOnly": true + }, + "message": { + "type": ["string", "null"], + "description": "Notification message associated with the test.", + "readOnly": true + }, + "monitor_id": { + "type": ["integer", "null"], + "description": "The associated monitor ID.", + "readOnly": true + }, + "name": { + "type": ["string", "null"], + "description": "Name of the test.", + "readOnly": true + }, + "options": { + "type": ["object", "null"], + "description": "Object describing the extra options for a Synthetic test.", + "additionalProperties": true + }, + "public_id": { + "type": ["string", "null"], + "description": "The test public ID.", + "readOnly": true + }, + "status": { + "type": ["string", "null"], + "enum": ["live", "paused"], + "description": "Define whether you want to start (live) or pause (paused) a Synthetic test. Allowed enum values: live,paused", + "readOnly": true + }, + "steps": { + "type": ["object", "null"], + "description": "For browser test, the steps of the test.", + "additionalProperties": true + }, + "subtype": { + "type": ["string", "null"], + "enum": [ + "http", + "ssl", + "tcp", + "dns", + "multi", + "icmp", + "udp", + "websocket", + "grpc" + ], + "description": "The subtype of the Synthetic API test, http, ssl, tcp, dns, icmp, udp, websocket, grpc or multi. Allowed enum values: http,ssl,tcp,dns,multi,icmp,udp,websocket,grpc", + "readOnly": true + }, + "tags": { + "type": ["array", "null"], + "items": { + "type": "string" + }, + "description": "Array of tags attached to the test.", + "readOnly": true + }, + "type": { + "type": ["string", "null"], + "enum": ["api", "browser"], + "description": "Type of the Synthetic test, either api or browser. Allowed enum values: api,browser", + "readOnly": true + } + }, + "additionalProperties": true +} diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/users.json b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/users.json new file mode 100644 index 000000000000..d9d80590a4f4 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/schemas/users.json @@ -0,0 +1,76 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "attributes": { + "type": ["object", "null"], + "description": "Attributes of user object returned by the API.", + "properties": { + "created_at": { + "type": ["string", "null"], + "format": "date-time", + "description": "Creation time of the user." + }, + "disabled": { + "type": ["boolean", "null"], + "description": "Whether the user is disabled." + }, + "email": { + "type": ["string", "null"], + "description": "Email of the user." + }, + "handle": { + "type": ["string", "null"], + "description": "Handle of the user." + }, + "icon": { + "type": ["string", "null"], + "description": "URL of the user's icon." + }, + "modified_at": { + "type": ["string", "null"], + "format": "date-time", + "description": "Time that the user was last modified." + }, + "name": { + "type": ["string", "null"], + "description": "Name of the user." + }, + "service_account": { + "type": ["boolean", "null"], + "description": "Whether the user is a service account." + }, + "status": { + "type": ["string", "null"], + "description": "Status of the user." + }, + "title": { + "type": ["string", "null"], + "description": "Title of the user." + }, + "verified": { + "type": ["boolean", "null"], + "description": "Whether the user is verified." + } + }, + "additionalProperties": true + }, + "id": { + "type": ["string", "null"], + "description": "ID of the user.", + "readOnly": true + }, + "relationships": { + "type": ["object", "null"], + "description": "Relationships of the user object returned by the API.", + "readOnly": true + }, + "type": { + "type": ["string", "null"], + "enum": ["users"], + "description": "Users resource type. Allowed enum values: users", + "readOnly": true + } + }, + "additionalProperties": true +} diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/source.py b/airbyte-integrations/connectors/source-datadog/source_datadog/source.py new file mode 100644 index 000000000000..164c2be2ae5a --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/source.py @@ -0,0 +1,64 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from datetime import datetime +from typing import Any, List, Mapping, Optional, Tuple + +import requests +from airbyte_cdk import AirbyteLogger +from airbyte_cdk.models import SyncMode +from airbyte_cdk.sources import AbstractSource +from airbyte_cdk.sources.streams import Stream +from pydantic.datetime_parse import timedelta +from source_datadog.streams import AuditLogs, Dashboards, Downtimes, Incidents, IncidentTeams, Logs, Metrics, SyntheticTests, Users + + +class SourceDatadog(AbstractSource): + @staticmethod + def _get_authenticator(config: Mapping[str, Any]): + return DatadogAuthenticator(api_key=config["api_key"], application_key=config["application_key"]) + + def check_connection(self, logger: AirbyteLogger, config: Mapping[str, Any]) -> Tuple[bool, Optional[Any]]: + try: + args = self.connector_config(config) + dashboards_stream = Dashboards(**args) + records = dashboards_stream.read_records(sync_mode=SyncMode.full_refresh) + next(records, None) + return True, None + except Exception as e: + return False, e + + def streams(self, config: Mapping[str, Any]) -> List[Stream]: + args = self.connector_config(config) + return [ + AuditLogs(**args), + Dashboards(**args), + Downtimes(**args), + Incidents(**args), + IncidentTeams(**args), + Logs(**args), + Metrics(**args), + SyntheticTests(**args), + Users(**args), + ] + + def connector_config(self, config: Mapping[str, Any]) -> Mapping[str, Any]: + return { + "authenticator": self._get_authenticator(config), + "query": config.get("query", ""), + "max_records_per_request": config.get("max_records_per_request", 5000), + "start_date": config.get("start_date", datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")), + "end_date": config.get("end_date", (datetime.now() + timedelta(seconds=1)).strftime("%Y-%m-%dT%H:%M:%SZ")), + } + + +class DatadogAuthenticator(requests.auth.AuthBase): + def __init__(self, api_key: str, application_key: str): + self.api_key = api_key + self.application_key = application_key + + def __call__(self, r): + r.headers["DD-API-KEY"] = self.api_key + r.headers["DD-APPLICATION-KEY"] = self.application_key + return r diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/spec.yaml b/airbyte-integrations/connectors/source-datadog/source_datadog/spec.yaml new file mode 100644 index 000000000000..de0e69d3aa9f --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/spec.yaml @@ -0,0 +1,56 @@ +documentationUrl: https://docs.airbyte.com/integrations/sources/datadog +connectionSpecification: + $schema: http://json-schema.org/draft-07/schema# + title: Datadog Source Spec + type: object + required: + - api_key + - application_key + additionalProperties: true + properties: + api_key: + title: API Key + description: Datadog API key + type: string + airbyte_secret: true + order: 1 + application_key: + title: Application Key + description: Datadog application key + type: string + airbyte_secret: true + order: 2 + query: + title: Query + description: The search query. This just applies to Incremental syncs. If empty, it'll collect all logs. + type: string + order: 3 + max_records_per_request: + type: integer + title: Max records per requests + default: 5000 + minimum: 1 + maximum: 5000 + description: Maximum number of records to collect per request. + order: 4 + start_date: + title: Start date + pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ + description: >- + UTC date and time in the format 2017-01-25T00:00:00Z. Any data before this date will + not be replicated. This just applies to Incremental syncs. + type: string + examples: + - "2022-10-01T00:00:00Z" + order: 5 + end_date: + title: End date + pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ + description: >- + UTC date and time in the format 2017-01-25T00:00:00Z. Data after this date will + not be replicated. An empty value will represent the current datetime for each + execution. This just applies to Incremental syncs. + examples: + - "2022-10-01T00:00:00Z" + type: string + order: 6 diff --git a/airbyte-integrations/connectors/source-datadog/source_datadog/streams.py b/airbyte-integrations/connectors/source-datadog/source_datadog/streams.py new file mode 100644 index 000000000000..9099a47b0fef --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/source_datadog/streams.py @@ -0,0 +1,288 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from abc import ABC, abstractmethod +from typing import Any, Dict, Iterable, List, Mapping, MutableMapping, Optional, Union + +import requests +from airbyte_cdk.models import SyncMode +from airbyte_cdk.sources.streams import IncrementalMixin +from airbyte_cdk.sources.streams.http import HttpStream + + +class DatadogStream(HttpStream, ABC): + """ + Datadog API Reference: https://docs.datadoghq.com/api/latest/ + """ + + primary_key: Optional[str] = None + parse_response_root: Optional[str] = None + + def __init__(self, query: str, max_records_per_request: int, start_date: str, end_date: str, **kwargs): + super().__init__(**kwargs) + self.query = query + self.max_records_per_request = max_records_per_request + self.start_date = start_date + self.end_date = end_date + self._cursor_value = None + + @property + def url_base(self) -> str: + return "https://api.datadoghq.com/api" + + def request_headers(self, **kwargs) -> Mapping[str, Any]: + return { + "Accept": "application/json", + "Content-Type": "application/json", + } + + def request_params( + self, stream_state: Mapping[str, Any], stream_slice: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None + ) -> MutableMapping[str, Any]: + params: Dict[str, str] = {} + + if next_page_token: + params.update(next_page_token) + + return params + + def parse_response(self, response: requests.Response, **kwargs) -> Iterable[Mapping]: + response_json = response.json() + records = response_json if not self.parse_response_root else response_json.get(self.parse_response_root, []) + for record in records: + yield self.transform(record=record, **kwargs) + + def transform(self, record: MutableMapping[str, Any], stream_slice: Mapping[str, Any], **kwargs) -> MutableMapping[str, Any]: + return record + + +class V1ApiDatadogStream(DatadogStream, ABC): + @property + def url_base(self) -> str: + return f"{super().url_base}/v1/" + + @property + def http_method(self) -> str: + return "GET" + + def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]: + return None + + +class Dashboards(V1ApiDatadogStream): + """ + https://docs.datadoghq.com/api/latest/dashboards/#get-all-dashboards + """ + + parse_response_root: Optional[str] = "dashboards" + + def path(self, **kwargs) -> str: + return "dashboard" + + +class Downtimes(V1ApiDatadogStream): + """ + https://docs.datadoghq.com/api/latest/downtimes/#get-all-downtimes + """ + + def path(self, **kwargs) -> str: + return "downtime" + + +class SyntheticTests(V1ApiDatadogStream): + """ + https://docs.datadoghq.com/api/latest/synthetics/#get-the-list-of-all-tests + """ + + parse_response_root: Optional[str] = "tests" + + def path(self, **kwargs) -> str: + return "synthetics/tests" + + +class V2ApiDatadogStream(DatadogStream, ABC): + @property + def url_base(self) -> str: + return f"{super().url_base}/v2/" + + +class IncrementalSearchableStream(V2ApiDatadogStream, IncrementalMixin, ABC): + primary_key: Optional[str] = "id" + parse_response_root: Optional[str] = "data" + + def __init__(self, query: str, max_records_per_request: int, start_date: str, end_date: str, **kwargs): + super().__init__(query, max_records_per_request, start_date, end_date, **kwargs) + self._cursor_value = "" + + @property + def http_method(self) -> str: + return "POST" + + @property + def state(self) -> Mapping[str, Any]: + if self._cursor_value: + return {self.cursor_field: self._cursor_value} + else: + return {self.cursor_field: self.start_date} + + @state.setter + def state(self, value: Mapping[str, Any]): + self._cursor_value = value[self.cursor_field] + + @property + def cursor_field(self) -> Union[str, List[str]]: + return "sync_date" + + def request_body_json( + self, + stream_state: Mapping[str, Any], + stream_slice: Mapping[str, Any] = None, + next_page_token: Mapping[str, Any] = None, + ) -> Optional[Mapping]: + cursor = None + if next_page_token: + cursor = next_page_token.get("page", {}).get("cursor", {}) + return self.get_payload(cursor) + + def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]: + response_json = response.json() + cursor = response_json.get("meta", {}).get("page", {}).get("after", {}) + if not cursor: + self._cursor_value = self.end_date + else: + return self.get_payload(cursor) + + def transform(self, record: MutableMapping[str, Any], stream_slice: Mapping[str, Any], **kwargs) -> MutableMapping[str, Any]: + record[self.cursor_field] = self._cursor_value if self._cursor_value else self.end_date + return record + + def read_records( + self, + sync_mode: SyncMode, + cursor_field: List[str] = None, + stream_slice: Mapping[str, Any] = None, + stream_state: Mapping[str, Any] = None, + ) -> Iterable[Mapping[str, Any]]: + if self.start_date >= self.end_date or self.end_date <= self._cursor_value: + return [] + return super().read_records(sync_mode, cursor_field, stream_slice, stream_state) + + def get_payload(self, cursor: Optional[str]) -> Mapping[str, Any]: + payload = { + "filter": {"query": self.query, "from": self._cursor_value if self._cursor_value else self.start_date, "to": self.end_date}, + "page": {"limit": self.max_records_per_request}, + } + if cursor: + payload["page"]["cursor"] = cursor + + return payload + + +class AuditLogs(IncrementalSearchableStream): + """ + https://docs.datadoghq.com/api/latest/audit/#search-audit-logs-events + """ + + def path(self, **kwargs) -> str: + return "audit/events/search" + + +class Logs(IncrementalSearchableStream): + """ + https://docs.datadoghq.com/api/latest/logs/#search-logs + """ + + def path(self, **kwargs) -> str: + return "logs/events/search" + + +class BasedListStream(V2ApiDatadogStream, ABC): + parse_response_root: Optional[str] = "data" + + @property + def http_method(self) -> str: + return "GET" + + +class Metrics(BasedListStream): + """ + https://docs.datadoghq.com/api/latest/metrics/#get-a-list-of-metrics + """ + + def path(self, **kwargs) -> str: + return "metrics?window[seconds]=1209600" # max value allowed (2 weeks) + + def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]: + return None + + +class PaginatedBasedListStream(BasedListStream, ABC): + primary_key: Optional[str] = "id" + + def path( + self, + *, + stream_state: Mapping[str, Any] = None, + stream_slice: Mapping[str, Any] = None, + next_page_token: Mapping[str, Any] = None, + ) -> str: + offset = None + if next_page_token: + offset = next_page_token.get("offset") + return self.get_url_path(offset) + + @abstractmethod + def get_url_path(self, offset: Optional[str]) -> str: + """ + Returns the relative URL with the corresponding offset + """ + + def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]: + response_json = response.json() + next_offset = response_json.get("meta", {}).get("pagination", {}).get("next_offset", -1) + current_offset = response_json.get("meta", {}).get("pagination", {}).get("offset", -1) + next_page_token = None + if next_offset != current_offset: + next_page_token = {"offset": next_offset} + return next_page_token + + +class Incidents(PaginatedBasedListStream): + """ + https://docs.datadoghq.com/api/latest/incidents/#get-a-list-of-incidents + """ + + def get_url_path(self, offset: Optional[str]) -> str: + params = f"&page[offset]={offset}" if offset else "" + return f"incidents?page[size]={self.max_records_per_request}{params}" + + +class IncidentTeams(PaginatedBasedListStream): + """ + https://docs.datadoghq.com/api/latest/incident-teams/#get-a-list-of-all-incident-teams + """ + + def get_url_path(self, offset: Optional[str]) -> str: + params = f"&page[offset]={offset}" if offset else "" + return f"teams?page[size]={self.max_records_per_request}{params}" + + +class Users(PaginatedBasedListStream): + """ + https://docs.datadoghq.com/api/latest/users/#list-all-users + """ + + current_page = 0 + + def get_url_path(self, offset: Optional[int]) -> str: + params = f"&page[number]={offset}" if offset else "" + return f"users?page[size]={self.max_records_per_request}{params}" + + def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]: + response_json = response.json() + next_page_token = None + if len(response_json.get("data", [])) > 0: + self.current_page += 1 + next_page_token = {"offset": self.current_page} + return next_page_token diff --git a/airbyte-integrations/connectors/source-datadog/unit_tests/__init__.py b/airbyte-integrations/connectors/source-datadog/unit_tests/__init__.py new file mode 100644 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/unit_tests/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-datadog/unit_tests/conftest.py b/airbyte-integrations/connectors/source-datadog/unit_tests/conftest.py new file mode 100644 index 000000000000..8a149e2666cd --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/unit_tests/conftest.py @@ -0,0 +1,392 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from pytest import fixture + + +@fixture(name="config") +def config_fixture(): + return { + "api_key": "test_api_key", + "application_key": "test_application_key", + "query": "", + "max_records_per_request": 5000, + "start_date": "2022-10-10T00:00:00Z", + "end_date": "2022-10-10T00:10:00Z", + } + + +@fixture(name="mock_responses") +def mock_responses(): + return { + "Dashboards": { + "dashboards": [ + { + "author_handle": "string", + "created_at": "2019-09-19T10:00:00.000Z", + "description": "string", + "id": "string", + "is_read_only": False, + "layout_type": "ordered", + "modified_at": "2019-09-19T10:00:00.000Z", + "title": "string", + "url": "string", + } + ], + }, + "Downtimes": { + "active": True, + "active_child": { + "active": True, + "canceled": 1412799983, + "creator_id": 123456, + "disabled": False, + "downtime_type": 2, + "end": 1412793983, + "id": 1626, + "message": "Message on the downtime", + "monitor_id": 123456, + "monitor_tags": ["*"], + "mute_first_recovery_notification": False, + "parent_id": 123, + "recurrence": { + "period": 1, + "rrule": "FREQ=MONTHLY;BYSETPOS=3;BYDAY=WE;INTERVAL=1", + "type": "weeks", + "until_date": 1447786293, + "until_occurrences": 2, + "week_days": ["Mon", "Tue"], + }, + "scope": ["env:staging"], + "start": 1412792983, + "timezone": "America/New_York", + "updater_id": 123456, + }, + "canceled": 1412799983, + "creator_id": 123456, + "disabled": False, + "downtime_type": 2, + "end": 1412793983, + "id": 1625, + "message": "Message on the downtime", + "monitor_id": 123456, + "monitor_tags": ["*"], + "mute_first_recovery_notification": False, + "parent_id": 123, + "recurrence": { + "period": 1, + "rrule": "FREQ=MONTHLY;BYSETPOS=3;BYDAY=WE;INTERVAL=1", + "type": "weeks", + "until_date": 1447786293, + "until_occurrences": 2, + "week_days": ["Mon", "Tue"], + }, + "scope": ["env:staging"], + "start": 1412792983, + "timezone": "America/New_York", + "updater_id": 123456, + }, + "SyntheticTests": { + "tests": [ + { + "config": { + "assertions": [{"operator": "contains", "property": "string", "target": 123456, "type": "statusCode"}], + "configVariables": [ + {"example": "string", "id": "string", "name": "VARIABLE_NAME", "pattern": "string", "type": "text"} + ], + "request": { + "allow_insecure": False, + "basicAuth": {"password": "PaSSw0RD!", "type": "web", "username": "my_username"}, + "body": "string", + "certificate": { + "cert": {"content": "string", "filename": "string", "updatedAt": "string"}, + "key": {"content": "string", "filename": "string", "updatedAt": "string"}, + }, + "certificateDomains": [], + "dnsServer": "string", + "dnsServerPort": "integer", + "follow_redirects": False, + "headers": {"": "string"}, + "host": "string", + "message": "string", + "metadata": {"": "string"}, + "method": "GET", + "noSavingResponseBody": False, + "numberOfPackets": "integer", + "port": "integer", + "proxy": {"headers": {"": "string"}, "url": "https://example.com"}, + "query": {}, + "servername": "string", + "service": "string", + "shouldTrackHops": False, + "timeout": "number", + "url": "https://example.com", + }, + "variables": [{"example": "string", "id": "string", "name": "VARIABLE_NAME", "pattern": "string", "type": "text"}], + }, + "creator": {"email": "string", "handle": "string", "name": "string"}, + "locations": ["aws:eu-west-3"], + "message": "string", + "monitor_id": "integer", + "name": "string", + "options": { + "accept_self_signed": False, + "allow_insecure": False, + "checkCertificateRevocation": False, + "ci": {"executionRule": "string"}, + "device_ids": ["laptop_large"], + "disableCors": False, + "disableCsp": False, + "follow_redirects": False, + "ignoreServerCertificateError": False, + "initialNavigationTimeout": "integer", + "min_failure_duration": "integer", + "min_location_failed": "integer", + "monitor_name": "string", + "monitor_options": {"renotify_interval": "integer"}, + "monitor_priority": "integer", + "noScreenshot": False, + "restricted_roles": ["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"], + "retry": {"count": "integer", "interval": "number"}, + "rumSettings": {"applicationId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "clientTokenId": 12345, "isEnabled": True}, + "tick_every": "integer", + }, + "public_id": "string", + "status": "live", + "steps": [ + { + "allowFailure": False, + "isCritical": False, + "name": "string", + "params": {}, + "timeout": "integer", + "type": "assertElementContent", + } + ], + "subtype": "http", + "tags": [], + "type": "string", + } + ] + }, + "Metrics": {"data": [{"id": "test.metric.latency", "type": "metrics"}]}, + "Incidents": { + "data": [ + { + "attributes": { + "created": "2019-09-19T10:00:00.000Z", + "customer_impact_duration": "integer", + "customer_impact_end": "2019-09-19T10:00:00.000Z", + "customer_impact_scope": "An example customer impact scope", + "customer_impact_start": "2019-09-19T10:00:00.000Z", + "customer_impacted": False, + "detected": "2019-09-19T10:00:00.000Z", + "fields": {"": {}}, + "modified": "2019-09-19T10:00:00.000Z", + "notification_handles": [{"display_name": "Jane Doe", "handle": "@test.user@test.com"}], + "public_id": 1, + "resolved": "2019-09-19T10:00:00.000Z", + "time_to_detect": "integer", + "time_to_internal_response": "integer", + "time_to_repair": "integer", + "time_to_resolve": "integer", + "title": "A test incident title", + }, + "id": "00000000-0000-0000-1234-000000000000", + "relationships": { + "attachments": {"data": [{"id": "00000000-0000-abcd-1000-000000000000", "type": "incident_attachments"}]}, + "commander_user": {"data": {"id": "00000000-0000-0000-0000-000000000000", "type": "users"}}, + "created_by_user": {"data": {"id": "00000000-0000-0000-2345-000000000000", "type": "users"}}, + "integrations": {"data": [{"id": "00000000-abcd-0001-0000-000000000000", "type": "incident_integrations"}]}, + "last_modified_by_user": {"data": {"id": "00000000-0000-0000-2345-000000000000", "type": "users"}}, + }, + "type": "incidents", + } + ], + "included": [ + { + "attributes": { + "created_at": "2019-09-19T10:00:00.000Z", + "disabled": False, + "email": "string", + "handle": "string", + "icon": "string", + "modified_at": "2019-09-19T10:00:00.000Z", + "name": "string", + "service_account": False, + "status": "string", + "title": "string", + "verified": False, + }, + "id": "string", + "relationships": { + "org": {"data": {"id": "00000000-0000-beef-0000-000000000000", "type": "orgs"}}, + "other_orgs": {"data": [{"id": "00000000-0000-beef-0000-000000000000", "type": "orgs"}]}, + "other_users": {"data": [{"id": "00000000-0000-0000-2345-000000000000", "type": "users"}]}, + "roles": {"data": [{"id": "3653d3c6-0c75-11ea-ad28-fb5701eabc7d", "type": "roles"}]}, + }, + "type": "users", + } + ], + "meta": {"pagination": {"next_offset": 1000, "offset": 10, "size": 1000}}, + }, + "IncidentTeams": { + "data": [ + { + "attributes": {"created": "2019-09-19T10:00:00.000Z", "modified": "2019-09-19T10:00:00.000Z", "name": "team name"}, + "id": "00000000-7ea3-0000-000a-000000000000", + "relationships": { + "created_by": {"data": {"id": "00000000-0000-0000-2345-000000000000", "type": "users"}}, + "last_modified_by": {"data": {"id": "00000000-0000-0000-2345-000000000000", "type": "users"}}, + }, + "type": "teams", + } + ], + "included": [ + { + "attributes": { + "created_at": "2019-09-19T10:00:00.000Z", + "disabled": False, + "email": "string", + "handle": "string", + "icon": "string", + "modified_at": "2019-09-19T10:00:00.000Z", + "name": "string", + "service_account": False, + "status": "string", + "title": "string", + "verified": False, + }, + "id": "string", + "relationships": { + "org": {"data": {"id": "00000000-0000-beef-0000-000000000000", "type": "orgs"}}, + "other_orgs": {"data": [{"id": "00000000-0000-beef-0000-000000000000", "type": "orgs"}]}, + "other_users": {"data": [{"id": "00000000-0000-0000-2345-000000000000", "type": "users"}]}, + "roles": {"data": [{"id": "3653d3c6-0c75-11ea-ad28-fb5701eabc7d", "type": "roles"}]}, + }, + "type": "users", + } + ], + "meta": {"pagination": {"next_offset": 1000, "offset": 10, "size": 1000}}, + }, + "Users": { + "data": [ + { + "attributes": { + "created_at": "2019-09-19T10:00:00.000Z", + "disabled": False, + "email": "string", + "handle": "string", + "icon": "string", + "modified_at": "2019-09-19T10:00:00.000Z", + "name": "string", + "service_account": False, + "status": "string", + "title": "string", + "verified": False, + }, + "id": "string", + "relationships": { + "org": {"data": {"id": "00000000-0000-beef-0000-000000000000", "type": "orgs"}}, + "other_orgs": {"data": [{"id": "00000000-0000-beef-0000-000000000000", "type": "orgs"}]}, + "other_users": {"data": [{"id": "00000000-0000-0000-2345-000000000000", "type": "users"}]}, + "roles": {"data": [{"id": "3653d3c6-0c75-11ea-ad28-fb5701eabc7d", "type": "roles"}]}, + }, + "type": "users", + } + ], + "included": [ + { + "attributes": { + "created_at": "2019-09-19T10:00:00.000Z", + "description": "string", + "disabled": False, + "modified_at": "2019-09-19T10:00:00.000Z", + "name": "string", + "public_id": "string", + "sharing": "string", + "url": "string", + }, + "id": "string", + "type": "orgs", + } + ], + "meta": {"page": {"total_count": "integer", "total_filtered_count": "integer"}}, + }, + "Logs": { + "data": [ + { + "attributes": { + "attributes": {"customAttribute": 123, "duration": 2345}, + "host": "i-0123", + "message": "Host connected to remote", + "service": "agent", + "status": "INFO", + "tags": ["team:A"], + "timestamp": "2019-01-02T09:42:36.320Z", + }, + "id": "AAAAAWgN8Xwgr1vKDQAAAABBV2dOOFh3ZzZobm1mWXJFYTR0OA", + "type": "log", + } + ], + "links": { + "next": "https://app.datadoghq.com/api/v2/logs/event?filter[query]=foo\u0026page[cursor]=eyJzdGFydEF0IjoiQVFBQUFYS2tMS3pPbm40NGV3QUFBQUJCV0V0clRFdDZVbG8zY3pCRmNsbHJiVmxDWlEifQ==" + }, + "meta": { + "elapsed": 132, + "page": {"after": "eyJzdGFydEF0IjoiQVFBQUFYS2tMS3pPbm40NGV3QUFBQUJCV0V0clRFdDZVbG8zY3pCRmNsbHJiVmxDWlEifQ=="}, + "request_id": "MWlFUjVaWGZTTTZPYzM0VXp1OXU2d3xLSVpEMjZKQ0VKUTI0dEYtM3RSOFVR", + "status": "done", + "warnings": [ + { + "code": "unknown_index", + "detail": "indexes: foo, bar", + "title": "One or several indexes are missing or invalid, results hold data from the other indexes", + } + ], + }, + }, + "AuditLogs": { + "data": [ + { + "attributes": { + "attributes": {"customAttribute": 123, "duration": 2345}, + "service": "web-app", + "tags": ["team:A"], + "timestamp": "2019-01-02T09:42:36.320Z", + }, + "id": "AAAAAWgN8Xwgr1vKDQAAAABBV2dOOFh3ZzZobm1mWXJFYTR0OA", + "type": "audit", + } + ], + "links": { + "next": "https://app.datadoghq.com/api/v2/audit/event?filter[query]=foo\u0026page[cursor]=eyJzdGFydEF0IjoiQVFBQUFYS2tMS3pPbm40NGV3QUFBQUJCV0V0clRFdDZVbG8zY3pCRmNsbHJiVmxDWlEifQ==" + }, + "meta": { + "elapsed": 132, + "page": {"after": "eyJzdGFydEF0IjoiQVFBQUFYS2tMS3pPbm40NGV3QUFBQUJCV0V0clRFdDZVbG8zY3pCRmNsbHJiVmxDWlEifQ=="}, + "request_id": "MWlFUjVaWGZTTTZPYzM0VXp1OXU2d3xLSVpEMjZKQ0VKUTI0dEYtM3RSOFVR", + "status": "done", + "warnings": [ + { + "code": "unknown_index", + "detail": "indexes: foo, bar", + "title": "One or several indexes are missing or invalid, results hold data from the other indexes", + } + ], + }, + }, + } + + +@fixture(name="mock_stream") +def mock_stream_fixture(requests_mock): + def _mock_stream(path, response=None): + if response is None: + response = {} + + url = f"https://api.datadoghq.com/api/v1/{path}" + requests_mock.get(url, json=response) + + return _mock_stream diff --git a/airbyte-integrations/connectors/source-datadog/unit_tests/test_source.py b/airbyte-integrations/connectors/source-datadog/unit_tests/test_source.py new file mode 100644 index 000000000000..c2d4067f14e4 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/unit_tests/test_source.py @@ -0,0 +1,58 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from unittest.mock import MagicMock + +from airbyte_cdk.logger import AirbyteLogger +from airbyte_cdk.models import ConnectorSpecification +from source_datadog.source import SourceDatadog + +logger = AirbyteLogger() + + +def test_check_connection_ok(config, mock_stream, mock_responses): + mock_stream("dashboard", response=mock_responses.get("Dashboards")) + ok, error_msg = SourceDatadog().check_connection(logger, config=config) + + assert ok + assert not error_msg + + +def test_check_connection_exception(config, mock_stream, mock_responses): + mock_stream("invalid_path", response=mock_responses.get("Dashboards")) + ok, error_msg = SourceDatadog().check_connection(logger, config=config) + + assert not ok + assert error_msg + + +def test_check_connection_empty_config(config): + config = {} + + ok, error_msg = SourceDatadog().check_connection(logger, config=config) + + assert not ok + assert error_msg + + +def test_check_connection_invalid_config(config): + config.pop("api_key") + + ok, error_msg = SourceDatadog().check_connection(logger, config=config) + + assert not ok + assert error_msg + + +def test_streams(config): + streams = SourceDatadog().streams(config) + + assert len(streams) == 9 + + +def test_spec(): + logger_mock = MagicMock() + spec = SourceDatadog().spec(logger_mock) + + assert isinstance(spec, ConnectorSpecification) diff --git a/airbyte-integrations/connectors/source-datadog/unit_tests/test_streams.py b/airbyte-integrations/connectors/source-datadog/unit_tests/test_streams.py new file mode 100644 index 000000000000..c20e60872421 --- /dev/null +++ b/airbyte-integrations/connectors/source-datadog/unit_tests/test_streams.py @@ -0,0 +1,100 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +import json +from unittest.mock import MagicMock, patch + +import pytest +import requests +import requests_mock as req_mock +from airbyte_cdk.models import SyncMode +from source_datadog.source import SourceDatadog +from source_datadog.streams import ( + AuditLogs, + Dashboards, + DatadogStream, + Downtimes, + Incidents, + IncidentTeams, + Logs, + Metrics, + SyntheticTests, + Users, +) + + +@pytest.mark.parametrize( + "stream", + [AuditLogs, Dashboards, Downtimes, Incidents, IncidentTeams, Logs, Metrics, SyntheticTests, Users], +) +def test_task_stream(requests_mock, stream, config, mock_responses): + requests_mock.get(req_mock.ANY, json=mock_responses.get(stream.__name__)) + requests_mock.post(req_mock.ANY, json=mock_responses.get(stream.__name__)) + args = SourceDatadog().connector_config(config) + instance = stream(**args) + + stream_slice = instance.stream_slices(sync_mode=SyncMode.full_refresh) + record = next(instance.read_records(sync_mode=SyncMode.full_refresh, stream_slice=stream_slice)) + + assert record + + +@patch.multiple(DatadogStream, __abstractmethods__=set()) +def test_next_page_token(config): + stream = DatadogStream( + query=config["query"], + max_records_per_request=config["max_records_per_request"], + start_date=config["start_date"], + end_date=config["end_date"], + ) + inputs = {"response": MagicMock()} + assert stream.next_page_token(**inputs) is None + + +@pytest.mark.parametrize( + "stream", + [AuditLogs, Dashboards, Downtimes, Incidents, IncidentTeams, Logs, Metrics, SyntheticTests, Users], +) +def test_next_page_token_empty_response(stream, config): + expected_token = None + args = SourceDatadog().connector_config(config) + instance = stream(**args) + response = requests.Response() + response._content = json.dumps({}).encode("utf-8") + assert instance.next_page_token(response=response) == expected_token + + +@pytest.mark.parametrize( + "stream", + [AuditLogs, Logs], +) +def test_next_page_token_inc(stream, config): + args = SourceDatadog().connector_config(config) + instance = stream(**args) + response = requests.Response() + body_content = {"meta": {"page": {"after": "test_cursor"}}} + response._content = json.dumps(body_content).encode("utf-8") + result = instance.next_page_token(response=response) + assert result.get("page").get("cursor") == "test_cursor" + + +@pytest.mark.parametrize( + "stream", + [Incidents, IncidentTeams], +) +def test_next_page_token_paginated(stream, config): + args = SourceDatadog().connector_config(config) + instance = stream(**args) + response = requests.Response() + body_content = { + "meta": { + "pagination": { + "offset": 998, + "next_offset": 999, + } + } + } + response._content = json.dumps(body_content).encode("utf-8") + result = instance.next_page_token(response=response) + assert result.get("offset") == 999 diff --git a/docs/integrations/README.md b/docs/integrations/README.md index e8b1b5712383..34d0e7fbf4d8 100644 --- a/docs/integrations/README.md +++ b/docs/integrations/README.md @@ -50,6 +50,7 @@ For more information about the grading system, see [Product Release Stages](http | [ConvertKit](sources/convertkit.md) | Alpha | No | | [Courier](sources/courier.md) | Alpha | No | | [Customer.io](sources/customer-io.md) | Alpha | No | +| [Datadog](sources/datadog.md) | Alpha | No | | [Db2](sources/db2.md) | Alpha | No | | [Delighted](sources/delighted.md) | Alpha | Yes | | [Dixa](sources/dixa.md) | Alpha | Yes | diff --git a/docs/integrations/sources/datadog.md b/docs/integrations/sources/datadog.md new file mode 100644 index 000000000000..ab858915feb9 --- /dev/null +++ b/docs/integrations/sources/datadog.md @@ -0,0 +1,65 @@ +# Airbyte Source Connector for Datadog + +This is a setup guide for the Datadog source connector which collects data from [its API](https://docs.datadoghq.com/api/latest/). + +## Prerequisites + +An API key is required as well as an API application key. See the [Datadog API and Application Keys section](https://docs.datadoghq.com/account_management/api-app-keys/) for more information. + +## Setup guide + +## Step 1: Set up the Datadog connector in Airbyte + +### For Airbyte Cloud: + +1. [Log into your Airbyte Cloud](https://cloud.airbyte.io/workspaces) account. +2. In the left navigation bar, click **Sources**. In the top-right corner, click **+new source**. +3. On the Set up the source page, enter the name for the Datadog connector and select **Datadog** from the Source type dropdown. +4. Enter your `api_key` - Datadog API key. +5. Enter your `application_key` - Datadog application key. +6. Enter your `query` - Optional. Type your query to filter records when collecting data from Logs and AuditLogs stream. +7. Enter your `limit` - Number of records to collect per request. +8. Enter your `start_date` - Optional. Start date to filter records when collecting data from Logs and AuditLogs stream. +9. Enter your `end_date` - Optional. End date to filter records when collecting data from Logs and AuditLogs stream. +10. Click **Set up source**. + +### For Airbyte OSS: + +1. Navigate to the Airbyte Open Source dashboard. +2. Set the name for your source. +4. Enter your `api_key` - Datadog API key. +5. Enter your `application_key` - Datadog application key. +6. Enter your `query` - Optional. Type your query to filter records when collecting data from Logs and AuditLogs stream. +7. Enter your `limit` - Number of records to collect per request. +8. Enter your `start_date` - Optional. Start date to filter records when collecting data from Logs and AuditLogs stream. +9. Enter your `end_date` - Optional. End date to filter records when collecting data from Logs and AuditLogs stream. +10. Click **Set up source**. + +## Supported sync modes + +The Datadog source connector supports the following [sync modes](https://docs.airbyte.com/cloud/core-concepts#connection-sync-modes): + +| Feature | Supported? | +| :---------------- |:-----------| +| Full Refresh Sync | Yes | +| Incremental Sync | Yes | +| SSL connection | Yes | +| Namespaces | No | + +## Supported Streams + +* [AuditLogs](https://docs.datadoghq.com/api/latest/audit/#search-audit-logs-events) +* [Dashboards](https://docs.datadoghq.com/api/latest/dashboards/#get-all-dashboards) +* [Downtimes](https://docs.datadoghq.com/api/latest/downtimes/#get-all-downtimes) +* [IncidentTeams](https://docs.datadoghq.com/api/latest/incident-teams/#get-a-list-of-all-incident-teams) +* [Incidents](https://docs.datadoghq.com/api/latest/incidents/#get-a-list-of-incidents) +* [Logs](https://docs.datadoghq.com/api/latest/logs/#search-logs) +* [Metrics](https://docs.datadoghq.com/api/latest/metrics/#get-a-list-of-metrics) +* [SyntheticTests](https://docs.datadoghq.com/api/latest/synthetics/#get-the-list-of-all-tests) +* [Users](https://docs.datadoghq.com/api/latest/users/#list-all-users) + +## Changelog + +| Version | Date | Pull Request | Subject | +|:--------|:-----------|:----------------------------------------------------------|:--------------------| +| 0.1.0 | 2022-10-18 | [18150](https://github.com/airbytehq/airbyte/pull/18150) | New Source: Datadog | From 3feda06a145d9b80be646582f8584b6a68d9bd26 Mon Sep 17 00:00:00 2001 From: Augustin Date: Thu, 3 Nov 2022 14:54:32 +0100 Subject: [PATCH 02/73] ci_integration_test.sh: cut GITHUB_STEP_SUMMARY (#18895) --- tools/bin/ci_integration_test.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/bin/ci_integration_test.sh b/tools/bin/ci_integration_test.sh index 0d2b0ed90ab0..8fb208fdf83a 100755 --- a/tools/bin/ci_integration_test.sh +++ b/tools/bin/ci_integration_test.sh @@ -135,6 +135,9 @@ write_logs() { echo "# $connector" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY +# Cut the $GITHUB_STEP_SUMMARY with head if its larger than 1MB +echo "$GITHUB_STEP_SUMMARY" | head -c 1048576 >> $GITHUB_STEP_SUMMARY + # Copy command output to extract gradle scan link. run | tee build.out # return status of "run" command, not "tee" From 606534ddbc04ded6462e1de0b950e35f7a6017ad Mon Sep 17 00:00:00 2001 From: Isaac Harris-Holt <47423046+isaacharrisholt@users.noreply.github.com> Date: Thu, 3 Nov 2022 13:57:27 +0000 Subject: [PATCH 03/73] =?UTF-8?q?=F0=9F=8E=89=20New=20Source:=20Alpha=20Va?= =?UTF-8?q?ntage=20(#18320)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial commit * Tidy and add custom dpath extractor * Get acceptance tests passing * Improve dict-checking for ObjectDpathExtractor * Improve dict-checking for ObjectDpathExtractor * Add more tests to ObjectDpathExtractor * Add docs * Address comments * Update docs * Add sample and invalid configs * format * add alpha vantage to source def * auto-bump connector version Co-authored-by: marcosmarxm Co-authored-by: Octavia Squidington III Co-authored-by: Marcos Marx --- .../resources/seed/source_definitions.yaml | 7 + .../src/main/resources/seed/source_specs.yaml | 57 ++++++ .../source-alpha-vantage/.dockerignore | 6 + .../source-alpha-vantage/Dockerfile | 38 ++++ .../connectors/source-alpha-vantage/README.md | 79 ++++++++ .../source-alpha-vantage/__init__.py | 3 + .../acceptance-test-config.yml | 21 +++ .../acceptance-test-docker.sh | 16 ++ .../source-alpha-vantage/build.gradle | 9 + .../integration_tests/__init__.py | 3 + .../integration_tests/abnormal_state.json | 5 + .../integration_tests/acceptance.py | 16 ++ .../integration_tests/configured_catalog.json | 31 ++++ .../integration_tests/invalid_config.json | 8 + .../integration_tests/sample_config.json | 8 + .../integration_tests/sample_state.json | 5 + .../connectors/source-alpha-vantage/main.py | 13 ++ .../source-alpha-vantage/requirements.txt | 2 + .../connectors/source-alpha-vantage/setup.py | 29 +++ .../source_alpha_vantage/__init__.py | 8 + .../source_alpha_vantage/alpha_vantage.yaml | 107 +++++++++++ .../object_dpath_extractor.py | 88 +++++++++ .../schemas/time_series_daily.json | 21 +++ .../schemas/time_series_daily_adjusted.json | 30 +++ .../schemas/time_series_intraday.json | 21 +++ .../schemas/time_series_monthly.json | 21 +++ .../schemas/time_series_monthly_adjusted.json | 27 +++ .../schemas/time_series_weekly.json | 21 +++ .../schemas/time_series_weekly_adjusted.json | 27 +++ .../source_alpha_vantage/source.py | 18 ++ .../source_alpha_vantage/spec.yaml | 53 ++++++ .../unit_tests/__init__.py | 0 .../unit_tests/test_object_dpath_extractor.py | 172 ++++++++++++++++++ docs/integrations/sources/alpha-vantage.md | 62 +++++++ 34 files changed, 1032 insertions(+) create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/.dockerignore create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/Dockerfile create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/README.md create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/__init__.py create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/acceptance-test-config.yml create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/acceptance-test-docker.sh create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/build.gradle create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/integration_tests/__init__.py create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/integration_tests/abnormal_state.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/integration_tests/acceptance.py create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/integration_tests/configured_catalog.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/integration_tests/invalid_config.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/integration_tests/sample_config.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/integration_tests/sample_state.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/main.py create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/requirements.txt create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/setup.py create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/__init__.py create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/alpha_vantage.yaml create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/object_dpath_extractor.py create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_daily.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_daily_adjusted.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_intraday.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_monthly.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_monthly_adjusted.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_weekly.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_weekly_adjusted.json create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/source.py create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/spec.yaml create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/unit_tests/__init__.py create mode 100644 airbyte-integrations/connectors/source-alpha-vantage/unit_tests/test_object_dpath_extractor.py create mode 100644 docs/integrations/sources/alpha-vantage.md diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index 61e6e8109357..19077ecf6aeb 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -21,6 +21,13 @@ icon: airtable.svg sourceType: api releaseStage: alpha +- name: Alpha Vantage + sourceDefinitionId: db385323-9333-4fec-bec3-9e0ca9326c90 + dockerRepository: airbyte/source-alpha-vantage + dockerImageTag: 0.1.0 + documentationUrl: https://docs.airbyte.com/integrations/sources/alpha-vantage + sourceType: api + releaseStage: alpha - name: AlloyDB for PostgreSQL sourceDefinitionId: 1fa90628-2b9e-11ed-a261-0242ac120002 dockerRepository: airbyte/source-alloydb diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 6ba01d53a1de..965c8acb1e86 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -219,6 +219,63 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] +- dockerImage: "airbyte/source-alpha-vantage:0.1.0" + spec: + documentationUrl: "https://docs.airbyte.io/integrations/sources/alpha-vantage" + connectionSpecification: + $schema: "http://json-schema.org/draft-07/schema#" + title: "Alpha Vantage Spec" + type: "object" + required: + - "api_key" + - "symbol" + properties: + api_key: + title: "API Key" + type: "string" + description: "API Key" + airbyte_secret: true + order: 0 + symbol: + title: "Symbol" + type: "string" + description: "Stock symbol (with exchange code)" + examples: + - "AAPL" + - "TSCO.LON" + order: 1 + interval: + title: "Interval" + type: "string" + description: "Time-series data point interval. Required for intraday endpoints.\n" + enum: + - "1min" + - "5min" + - "15min" + - "30min" + - "60min" + default: "1min" + order: 2 + adjusted: + title: "Adjusted?" + type: "boolean" + description: "Whether to return adjusted data. Only applicable to intraday\ + \ endpoints.\n" + default: false + order: 4 + outputsize: + title: "Output Size" + type: "string" + description: "Whether to return full or compact data (the last 100 data\ + \ points).\n" + enum: + - "compact" + - "full" + default: "compact" + order: 5 + supportsNormalization: false + supportsDBT: false + supported_destination_sync_modes: [] - dockerImage: "airbyte/source-alloydb:1.0.17" spec: documentationUrl: "https://docs.airbyte.com/integrations/sources/postgres" diff --git a/airbyte-integrations/connectors/source-alpha-vantage/.dockerignore b/airbyte-integrations/connectors/source-alpha-vantage/.dockerignore new file mode 100644 index 000000000000..5a1cff6bff4a --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/.dockerignore @@ -0,0 +1,6 @@ +* +!Dockerfile +!main.py +!source_alpha_vantage +!setup.py +!secrets diff --git a/airbyte-integrations/connectors/source-alpha-vantage/Dockerfile b/airbyte-integrations/connectors/source-alpha-vantage/Dockerfile new file mode 100644 index 000000000000..7735d2dd4e93 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/Dockerfile @@ -0,0 +1,38 @@ +FROM python:3.9.11-alpine3.15 as base + +# build and load all requirements +FROM base as builder +WORKDIR /airbyte/integration_code + +# upgrade pip to the latest version +RUN apk --no-cache upgrade \ + && pip install --upgrade pip \ + && apk --no-cache add tzdata build-base + + +COPY setup.py ./ +# install necessary packages to a temporary folder +RUN pip install --prefix=/install . + +# build a clean environment +FROM base +WORKDIR /airbyte/integration_code + +# copy all loaded and built libraries to a pure basic image +COPY --from=builder /install /usr/local +# add default timezone settings +COPY --from=builder /usr/share/zoneinfo/Etc/UTC /etc/localtime +RUN echo "Etc/UTC" > /etc/timezone + +# bash is installed for more convenient debugging. +RUN apk --no-cache add bash + +# copy payload code only +COPY main.py ./ +COPY source_alpha_vantage ./source_alpha_vantage + +ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" +ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] + +LABEL io.airbyte.version=0.1.0 +LABEL io.airbyte.name=airbyte/source-alpha-vantage diff --git a/airbyte-integrations/connectors/source-alpha-vantage/README.md b/airbyte-integrations/connectors/source-alpha-vantage/README.md new file mode 100644 index 000000000000..bb054c73dec7 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/README.md @@ -0,0 +1,79 @@ +# Alpha Vantage Source + +This is the repository for the Alpha Vantage configuration based source connector. +For information about how to use this connector within Airbyte, see [the documentation](https://docs.airbyte.io/integrations/sources/alpha-vantage). + +## Local development + +#### Building via Gradle +You can also build the connector in Gradle. This is typically used in CI and not needed for your development workflow. + +To build using Gradle, from the Airbyte repository root, run: +``` +./gradlew :airbyte-integrations:connectors:source-alpha-vantage:build +``` + +#### Create credentials +**If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.io/integrations/sources/alpha-vantage) +to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `source_alpha_vantage/spec.yaml` file. +Note that any directory named `secrets` is gitignored across the entire Airbyte repo, so there is no danger of accidentally checking in sensitive information. +See `integration_tests/sample_config.json` for a sample config file. + +**If you are an Airbyte core member**, copy the credentials in Lastpass under the secret name `source alpha-vantage test creds` +and place them into `secrets/config.json`. + +### Locally running the connector docker image + +#### Build +First, make sure you build the latest Docker image: +``` +docker build . -t airbyte/source-alpha-vantage:dev +``` + +You can also build the connector image via Gradle: +``` +./gradlew :airbyte-integrations:connectors:source-alpha-vantage:airbyteDocker +``` +When building via Gradle, the docker image name and tag, respectively, are the values of the `io.airbyte.name` and `io.airbyte.version` `LABEL`s in +the Dockerfile. + +#### Run +Then run any of the connector commands as follows: +``` +docker run --rm airbyte/source-alpha-vantage:dev spec +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-alpha-vantage:dev check --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-alpha-vantage:dev discover --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/source-alpha-vantage:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json +``` +## Testing + +#### Acceptance Tests +Customize `acceptance-test-config.yml` file to configure tests. See [Source Acceptance Tests](https://docs.airbyte.io/connector-development/testing-connectors/source-acceptance-tests-reference) for more information. +If your connector requires to create or destroy resources for use during acceptance tests create fixtures for it and place them inside integration_tests/acceptance.py. + +To run your integration tests with docker + +### Using gradle to run tests +All commands should be run from airbyte project root. +To run unit tests: +``` +./gradlew :airbyte-integrations:connectors:source-alpha-vantage:unitTest +``` +To run acceptance and custom integration tests: +``` +./gradlew :airbyte-integrations:connectors:source-alpha-vantage:integrationTest +``` + +## Dependency Management +All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development. +We split dependencies between two groups, dependencies that are: +* required for your connector to work need to go to `MAIN_REQUIREMENTS` list. +* required for the testing need to go to `TEST_REQUIREMENTS` list + +### Publishing a new version of the connector +You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what? +1. Make sure your changes are passing unit and integration tests. +1. Bump the connector version in `Dockerfile` -- just increment the value of the `LABEL io.airbyte.version` appropriately (we use [SemVer](https://semver.org/)). +1. Create a Pull Request. +1. Pat yourself on the back for being an awesome contributor. +1. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master. diff --git a/airbyte-integrations/connectors/source-alpha-vantage/__init__.py b/airbyte-integrations/connectors/source-alpha-vantage/__init__.py new file mode 100644 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-alpha-vantage/acceptance-test-config.yml b/airbyte-integrations/connectors/source-alpha-vantage/acceptance-test-config.yml new file mode 100644 index 000000000000..daf327f8c10e --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/acceptance-test-config.yml @@ -0,0 +1,21 @@ +# See [Source Acceptance Tests](https://docs.airbyte.io/connector-development/testing-connectors/source-acceptance-tests-reference) +# for more information about how to configure these tests +connector_image: airbyte/source-alpha-vantage:dev +tests: + spec: + - spec_path: "source_alpha_vantage/spec.yaml" + connection: + - config_path: "secrets/config.json" + status: "succeed" + - config_path: "integration_tests/invalid_config.json" + status: "failed" + discovery: + - config_path: "secrets/config.json" + basic_read: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" + empty_streams: + - "time_series_monthly" + full_refresh: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" diff --git a/airbyte-integrations/connectors/source-alpha-vantage/acceptance-test-docker.sh b/airbyte-integrations/connectors/source-alpha-vantage/acceptance-test-docker.sh new file mode 100644 index 000000000000..c51577d10690 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/acceptance-test-docker.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +# Build latest connector image +docker build . -t $(cat acceptance-test-config.yml | grep "connector_image" | head -n 1 | cut -d: -f2-) + +# Pull latest acctest image +docker pull airbyte/source-acceptance-test:latest + +# Run +docker run --rm -it \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /tmp:/tmp \ + -v $(pwd):/test_input \ + airbyte/source-acceptance-test \ + --acceptance-test-config /test_input + diff --git a/airbyte-integrations/connectors/source-alpha-vantage/build.gradle b/airbyte-integrations/connectors/source-alpha-vantage/build.gradle new file mode 100644 index 000000000000..f8d1a7d118a1 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/build.gradle @@ -0,0 +1,9 @@ +plugins { + id 'airbyte-python' + id 'airbyte-docker' + id 'airbyte-source-acceptance-test' +} + +airbytePython { + moduleDirectory 'source_alpha_vantage' +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/__init__.py b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/__init__.py new file mode 100644 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/abnormal_state.json b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/abnormal_state.json new file mode 100644 index 000000000000..52b0f2c2118f --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/abnormal_state.json @@ -0,0 +1,5 @@ +{ + "todo-stream-name": { + "todo-field-name": "todo-abnormal-value" + } +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/acceptance.py b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/acceptance.py new file mode 100644 index 000000000000..1302b2f57e10 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/acceptance.py @@ -0,0 +1,16 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import pytest + +pytest_plugins = ("source_acceptance_test.plugin",) + + +@pytest.fixture(scope="session", autouse=True) +def connector_setup(): + """This fixture is a placeholder for external resources that acceptance test might require.""" + # TODO: setup test dependencies if needed. otherwise remove the TODO comments + yield + # TODO: clean up test dependencies diff --git a/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/configured_catalog.json b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/configured_catalog.json new file mode 100644 index 000000000000..dfafcb1e168f --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/configured_catalog.json @@ -0,0 +1,31 @@ +{ + "streams": [ + { + "stream": { + "name": "time_series_daily", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "time_series_weekly", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "time_series_monthly", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/invalid_config.json b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/invalid_config.json new file mode 100644 index 000000000000..b8e7d27bcb7d --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/invalid_config.json @@ -0,0 +1,8 @@ +{ + "api_key": "INVALID_KEY", + "symbol": "FAKE_SYMBOL", + "interval": "60min", + "outputsize": "compact", + "slice": "incorrect_slice", + "adjusted": false +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/sample_config.json b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/sample_config.json new file mode 100644 index 000000000000..1f1be557c956 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/sample_config.json @@ -0,0 +1,8 @@ +{ + "api_key": "YOUR_API_KEY", + "symbol": "TSLA", + "interval": "60min", + "outputsize": "compact", + "slice": "year1month1", + "adjusted": false +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/sample_state.json b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/sample_state.json new file mode 100644 index 000000000000..3587e579822d --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/integration_tests/sample_state.json @@ -0,0 +1,5 @@ +{ + "todo-stream-name": { + "todo-field-name": "value" + } +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/main.py b/airbyte-integrations/connectors/source-alpha-vantage/main.py new file mode 100644 index 000000000000..c4d96e59a041 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/main.py @@ -0,0 +1,13 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import sys + +from airbyte_cdk.entrypoint import launch +from source_alpha_vantage import SourceAlphaVantage + +if __name__ == "__main__": + source = SourceAlphaVantage() + launch(source, sys.argv[1:]) diff --git a/airbyte-integrations/connectors/source-alpha-vantage/requirements.txt b/airbyte-integrations/connectors/source-alpha-vantage/requirements.txt new file mode 100644 index 000000000000..0411042aa091 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/requirements.txt @@ -0,0 +1,2 @@ +-e ../../bases/source-acceptance-test +-e . diff --git a/airbyte-integrations/connectors/source-alpha-vantage/setup.py b/airbyte-integrations/connectors/source-alpha-vantage/setup.py new file mode 100644 index 000000000000..5bc457370080 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/setup.py @@ -0,0 +1,29 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from setuptools import find_packages, setup + +MAIN_REQUIREMENTS = [ + "airbyte-cdk~=0.4", +] + +TEST_REQUIREMENTS = [ + "pytest~=6.1", + "pytest-mock~=3.6.1", + "source-acceptance-test", +] + +setup( + name="source_alpha_vantage", + description="Source implementation for Alpha Vantage.", + author="Airbyte", + author_email="contact@airbyte.io", + packages=find_packages(), + install_requires=MAIN_REQUIREMENTS, + package_data={"": ["*.json", "*.yaml", "schemas/*.json", "schemas/shared/*.json"]}, + extras_require={ + "tests": TEST_REQUIREMENTS, + }, +) diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/__init__.py b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/__init__.py new file mode 100644 index 000000000000..086d696c81dd --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/__init__.py @@ -0,0 +1,8 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from .source import SourceAlphaVantage + +__all__ = ["SourceAlphaVantage"] diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/alpha_vantage.yaml b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/alpha_vantage.yaml new file mode 100644 index 000000000000..027e51ef11f3 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/alpha_vantage.yaml @@ -0,0 +1,107 @@ +version: "0.1.0" + +definitions: + schema_loader: + type: JsonSchema + file_path: "./source_alpha_vantage/schemas/{{ options['name'] }}.json" + selector: + type: RecordSelector + extractor: + class_name: source_alpha_vantage.object_dpath_extractor.ObjectDpathExtractor + field_pointer: + - "{{ options['dpath'] }}" + inject_key_as_field: "{{ options['key_field'] }}" + requester: + url_base: "https://www.alphavantage.co" + http_method: "GET" + authenticator: + type: NoAuth + request_options_provider: + request_parameters: + apikey: "{{ config['api_key'] }}" + symbol: "{{ config['symbol'] }}" + function: "{{ options['function'] }}" + datatype: json + outputsize: "{{ config['outputsize'] }}" + interval: "{{ config['interval'] }}" + adjusted: "{{ config['adjusted'] }}" + retriever: + record_selector: + $ref: "*ref(definitions.selector)" + paginator: + type: NoPagination + requester: + $ref: "*ref(definitions.requester)" + base_stream: + retriever: + $ref: "*ref(definitions.retriever)" + time_series_intraday_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "time_series_intraday" + dpath: "Time Series ({{ config['interval'] }})" + function: "TIME_SERIES_INTRADAY" + path: "/query" + key_field: "timestamp" + time_series_daily_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "time_series_daily" + dpath: "Time Series (Daily)" + function: "TIME_SERIES_DAILY" + path: "/query" + key_field: "date" + time_series_daily_adjusted_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "time_series_daily_adjusted" + dpath: "Time Series (Daily)" + function: "TIME_SERIES_DAILY_ADJUSTED" + path: "/query" + key_field: "date" + time_series_weekly_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "time_series_weekly" + dpath: "Weekly Time Series" + function: "TIME_SERIES_WEEKLY" + path: "/query" + key_field: "date" + time_series_weekly_adjusted_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "time_series_weekly_adjusted" + dpath: "Weekly Adjusted Time Series" + function: "TIME_SERIES_WEEKLY_ADJUSTED" + path: "/query" + key_field: "date" + time_series_monthly_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "time_series_monthly" + dpath: "Monthly Time Series" + function: "TIME_SERIES_MONTHLY" + path: "/query" + key_field: "date" + time_series_monthly_adjusted_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "time_series_monthly_adjusted" + dpath: "Monthly Adjusted Time Series" + function: "TIME_SERIES_MONTHLY_ADJUSTED" + path: "/query" + key_field: "date" + +streams: + - "*ref(definitions.time_series_intraday_stream)" + - "*ref(definitions.time_series_daily_stream)" + - "*ref(definitions.time_series_daily_adjusted_stream)" + - "*ref(definitions.time_series_weekly_stream)" + - "*ref(definitions.time_series_weekly_adjusted_stream)" + - "*ref(definitions.time_series_monthly_stream)" + - "*ref(definitions.time_series_monthly_adjusted_stream)" + +check: + stream_names: + - "time_series_weekly" + - "time_series_weekly_adjusted" diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/object_dpath_extractor.py b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/object_dpath_extractor.py new file mode 100644 index 000000000000..1ee461ba13a3 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/object_dpath_extractor.py @@ -0,0 +1,88 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from dataclasses import dataclass +from typing import Any, Mapping, Union + +import dpath.util +import requests +from airbyte_cdk.sources.declarative.extractors.dpath_extractor import DpathExtractor +from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString +from airbyte_cdk.sources.declarative.types import Record + + +@dataclass +class ObjectDpathExtractor(DpathExtractor): + """ + Record extractor that searches a decoded response over a path defined as an array of fields. + + Extends the DpathExtractor to allow for a list of records to be generated from a dpath that points + to an object, where the object's values are individual records. + + Example data: + ``` + { + "data": { + "2022-01-01": { + "id": "id1", + "name": "name1", + ... + }, + "2022-01-02": { + "id": "id2", + "name": "name2", + ... + }, + ... + } + ``` + + There is an optional `inject_key_as_field` parameter that can be used to inject the key of the object + as a field in the record. For example, if `inject_key_as_field` is set to `date`, the above data would + be transformed to: + ``` + [ + { + "date": "2022-01-01", + "id": "id1", + "name": "name1", + ... + }, + { + "date": "2022-01-02", + "id": "id2", + "name": "name2", + ... + }, + ... + ] + """ + + inject_key_as_field: Union[str, InterpolatedString] = None + + def __post_init__(self, options: Mapping[str, Any]): + self.inject_key_as_field = InterpolatedString.create(self.inject_key_as_field, options=options) + for pointer_index in range(len(self.field_pointer)): + if isinstance(self.field_pointer[pointer_index], str): + self.field_pointer[pointer_index] = InterpolatedString.create(self.field_pointer[pointer_index], options=options) + + def extract_records(self, response: requests.Response) -> list[Record]: + response_body = self.decoder.decode(response) + if len(self.field_pointer) == 0: + extracted = response_body + else: + pointer = [pointer.eval(self.config) for pointer in self.field_pointer] + extracted = dpath.util.get(response_body, pointer, default=[]) + if isinstance(extracted, list): + return extracted + elif isinstance(extracted, dict) and all(isinstance(v, dict) for v in extracted.values()): # Ensure object is dict[Hashable, dict] + if not self.inject_key_as_field: + return [value for _, value in extracted.items()] + else: + key_field = self.inject_key_as_field.eval(self.config) + return [{key_field: key, **value} for key, value in extracted.items()] + elif extracted: + return [extracted] + else: + return [] diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_daily.json b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_daily.json new file mode 100644 index 000000000000..666425ebf3dd --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_daily.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "1. open": { + "type": ["string", "null"] + }, + "2. high": { + "type": ["string", "null"] + }, + "3. low": { + "type": ["string", "null"] + }, + "4. close": { + "type": ["string", "null"] + }, + "5. volume": { + "type": ["string", "null"] + } + } +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_daily_adjusted.json b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_daily_adjusted.json new file mode 100644 index 000000000000..49f6c50c55eb --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_daily_adjusted.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "1. open": { + "type": "string" + }, + "2. high": { + "type": "string" + }, + "3. low": { + "type": "string" + }, + "4. close": { + "type": "string" + }, + "5. adjusted close": { + "type": "string" + }, + "6. volume": { + "type": "string" + }, + "7. dividend amount": { + "type": "string" + }, + "8. split coefficient": { + "type": "string" + } + } +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_intraday.json b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_intraday.json new file mode 100644 index 000000000000..666425ebf3dd --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_intraday.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "1. open": { + "type": ["string", "null"] + }, + "2. high": { + "type": ["string", "null"] + }, + "3. low": { + "type": ["string", "null"] + }, + "4. close": { + "type": ["string", "null"] + }, + "5. volume": { + "type": ["string", "null"] + } + } +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_monthly.json b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_monthly.json new file mode 100644 index 000000000000..666425ebf3dd --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_monthly.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "1. open": { + "type": ["string", "null"] + }, + "2. high": { + "type": ["string", "null"] + }, + "3. low": { + "type": ["string", "null"] + }, + "4. close": { + "type": ["string", "null"] + }, + "5. volume": { + "type": ["string", "null"] + } + } +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_monthly_adjusted.json b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_monthly_adjusted.json new file mode 100644 index 000000000000..962674bfc903 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_monthly_adjusted.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "1. open": { + "type": "string" + }, + "2. high": { + "type": "string" + }, + "3. low": { + "type": "string" + }, + "4. close": { + "type": "string" + }, + "5. adjusted close": { + "type": "string" + }, + "6. volume": { + "type": "string" + }, + "7. dividend amount": { + "type": "string" + } + } +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_weekly.json b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_weekly.json new file mode 100644 index 000000000000..666425ebf3dd --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_weekly.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "1. open": { + "type": ["string", "null"] + }, + "2. high": { + "type": ["string", "null"] + }, + "3. low": { + "type": ["string", "null"] + }, + "4. close": { + "type": ["string", "null"] + }, + "5. volume": { + "type": ["string", "null"] + } + } +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_weekly_adjusted.json b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_weekly_adjusted.json new file mode 100644 index 000000000000..962674bfc903 --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/schemas/time_series_weekly_adjusted.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "1. open": { + "type": "string" + }, + "2. high": { + "type": "string" + }, + "3. low": { + "type": "string" + }, + "4. close": { + "type": "string" + }, + "5. adjusted close": { + "type": "string" + }, + "6. volume": { + "type": "string" + }, + "7. dividend amount": { + "type": "string" + } + } +} diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/source.py b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/source.py new file mode 100644 index 000000000000..b8e22cf0db5d --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/source.py @@ -0,0 +1,18 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from airbyte_cdk.sources.declarative.yaml_declarative_source import YamlDeclarativeSource + +""" +This file provides the necessary constructs to interpret a provided declarative YAML configuration file into +source connector. + +WARNING: Do not modify this file. +""" + + +# Declarative Source +class SourceAlphaVantage(YamlDeclarativeSource): + def __init__(self): + super().__init__(**{"path_to_yaml": "alpha_vantage.yaml"}) diff --git a/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/spec.yaml b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/spec.yaml new file mode 100644 index 000000000000..cc8a1401b28f --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/source_alpha_vantage/spec.yaml @@ -0,0 +1,53 @@ +documentationUrl: https://docs.airbyte.io/integrations/sources/alpha-vantage +connectionSpecification: + $schema: http://json-schema.org/draft-07/schema# + title: Alpha Vantage Spec + type: object + required: + - api_key + - symbol + properties: + api_key: + title: API Key + type: string + description: API Key + airbyte_secret: true + order: 0 + symbol: + title: Symbol + type: string + description: Stock symbol (with exchange code) + examples: + - AAPL + - TSCO.LON + order: 1 + interval: + title: Interval + type: string + description: | + Time-series data point interval. Required for intraday endpoints. + enum: + - 1min + - 5min + - 15min + - 30min + - 60min + default: 1min + order: 2 + adjusted: + title: Adjusted? + type: boolean + description: | + Whether to return adjusted data. Only applicable to intraday endpoints. + default: false + order: 4 + outputsize: + title: Output Size + type: string + description: | + Whether to return full or compact data (the last 100 data points). + enum: + - compact + - full + default: compact + order: 5 diff --git a/airbyte-integrations/connectors/source-alpha-vantage/unit_tests/__init__.py b/airbyte-integrations/connectors/source-alpha-vantage/unit_tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/airbyte-integrations/connectors/source-alpha-vantage/unit_tests/test_object_dpath_extractor.py b/airbyte-integrations/connectors/source-alpha-vantage/unit_tests/test_object_dpath_extractor.py new file mode 100644 index 000000000000..3324ed175a7b --- /dev/null +++ b/airbyte-integrations/connectors/source-alpha-vantage/unit_tests/test_object_dpath_extractor.py @@ -0,0 +1,172 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +import json +from typing import Any + +from requests import Response +from source_alpha_vantage.object_dpath_extractor import ObjectDpathExtractor + + +def _create_response_with_body(body: Any) -> Response: + response = Response() + response._content = json.dumps(body).encode("utf-8") + return response + + +def _create_response_with_dict_of_records() -> Response: + response_body = { + "data": { + "2022-01-01": { + "id": "id1", + "name": "name1", + }, + "2022-01-02": { + "id": "id2", + "name": "name2", + }, + } + } + return _create_response_with_body(response_body) + + +def _create_response_with_list_of_records() -> Response: + response_body = { + "data": [ + { + "id": "id1", + "name": "name1", + }, + { + "id": "id2", + "name": "name2", + }, + ] + } + return _create_response_with_body(response_body) + + +def test_no_key_injection(): + extractor = ObjectDpathExtractor( + field_pointer=["data"], + config={}, + options={}, + ) + + response = _create_response_with_dict_of_records() + records = extractor.extract_records(response) + + assert records == [ + { + "id": "id1", + "name": "name1", + }, + { + "id": "id2", + "name": "name2", + }, + ] + + +def test_key_injection(): + extractor = ObjectDpathExtractor( + field_pointer=["data"], + inject_key_as_field="date", + config={}, + options={}, + ) + + response = _create_response_with_dict_of_records() + records = extractor.extract_records(response) + + assert records == [ + { + "date": "2022-01-01", + "id": "id1", + "name": "name1", + }, + { + "date": "2022-01-02", + "id": "id2", + "name": "name2", + }, + ] + + +def test_key_injection_with_interpolation(): + extractor = ObjectDpathExtractor( + field_pointer=["data"], + inject_key_as_field="{{ config['key_field'] }}", + config={"key_field": "date"}, + options={}, + ) + + response = _create_response_with_dict_of_records() + records = extractor.extract_records(response) + + assert records == [ + { + "date": "2022-01-01", + "id": "id1", + "name": "name1", + }, + { + "date": "2022-01-02", + "id": "id2", + "name": "name2", + }, + ] + + +def test_list_of_records(): + extractor = ObjectDpathExtractor( + field_pointer=["data"], + config={}, + options={}, + ) + + response = _create_response_with_dict_of_records() + records = extractor.extract_records(response) + + assert records == [ + { + "id": "id1", + "name": "name1", + }, + { + "id": "id2", + "name": "name2", + }, + ] + + +def test_no_records(): + extractor = ObjectDpathExtractor( + field_pointer=["data"], + config={}, + options={}, + ) + + obj_response = _create_response_with_body({"data": {}}) + obj_records = extractor.extract_records(obj_response) + + assert obj_records == [] + + list_response = _create_response_with_body({"data": []}) + list_records = extractor.extract_records(list_response) + + assert list_records == [] + + +def test_single_record(): + extractor = ObjectDpathExtractor( + field_pointer=["data"], + config={}, + options={}, + ) + + response = _create_response_with_body({"data": {"id": "id1", "name": "name1"}}) + records = extractor.extract_records(response) + + assert records == [{"id": "id1", "name": "name1"}] diff --git a/docs/integrations/sources/alpha-vantage.md b/docs/integrations/sources/alpha-vantage.md new file mode 100644 index 000000000000..17dc5daea00f --- /dev/null +++ b/docs/integrations/sources/alpha-vantage.md @@ -0,0 +1,62 @@ +# Alpha Vantage + +## Sync overview + +This source retrieves time series data from the free +[Alpha Vantage](https://www.alphavantage.co/) API. It supports intraday, daily, +weekly and monthly time series data. + + +### Output schema + +This source is capable of syncing the following streams: + +* `time_series_intraday` +* `time_series_daily` +* `time_series_daily_adjusted` (premium only) +* `time_series_weekly` +* `time_series_weekly_adjusted` +* `time_series_monthly` +* `time_series_monthly_adjusted` + +### Features + +| Feature | Supported? \(Yes/No\) | Notes | +|:------------------|:----------------------|:--------------------------------------------------------| +| Full Refresh Sync | Yes | | +| Incremental Sync | No | | +| API Environments | Yes | Both sandbox and production environments are supported. | + +### Performance considerations + +Since a single API call returns the full history of a time series if +configured, it is recommended to use `Full Refresh` with `Overwrite` to avoid +storing duplicate data. + +Also, the data returned can be quite large. + +## Getting started + +### Requirements + +1. Obtain an API key from [Alpha Vantage](https://www.alphavantage.co/support/#api-key). + +### Setup guide + +The following fields are required fields for the connector to work: + +- `api_key`: Your Alpha Vantage API key. +- `symbol`: The symbol of the time series to retrieve, with exchange code if + applicable. For example, `MSFT` or `TSCO.LON`. +- (optional) `interval`: The time-series data point interval. Defaults to 1 minute. +- (optional) `Adjusted?`: Whether the `intraday` endpoint should return adjusted + data. Defaults to `false`. +- (optional) `outputsize`: The size of the time series to retrieve. Defaults to + `compact`, which returns the last 100 data points. `full` returns the full + history. + +## Changelog + +| Version | Date | Pull Request | Subject | +|:--------|:-----------|:---------------------------------------------------------|:-----------| +| 0.1.0 | 2022-10-21 | [18320](https://github.com/airbytehq/airbyte/pull/18320) | New source | From f156be94bd0ccac912177e80008d821ddb98b8c0 Mon Sep 17 00:00:00 2001 From: Tan Ho Date: Thu, 3 Nov 2022 21:39:51 +0700 Subject: [PATCH 04/73] New Source: Gridly (#18342) * Add source-gridly * Correct current_page init value * The first batch was fetching twice * Remove `integration_tests/catalog.json` from source-gridly * Allow select any view on grid to sync records * Correct documentationUrl for source gridly * use class property for source endpoint instead of local variable * Add tests and format code * Add gridly.md docs file * add gridly to source def * auto-bump connector version Co-authored-by: Tan Ho Co-authored-by: marcosmarxm Co-authored-by: Octavia Squidington III --- .../resources/seed/source_definitions.yaml | 7 + .../src/main/resources/seed/source_specs.yaml | 21 +++ .../connectors/source-gridly/.dockerignore | 6 + .../connectors/source-gridly/Dockerfile | 38 +++++ .../connectors/source-gridly/README.md | 132 +++++++++++++++++ .../source-gridly/acceptance-test-config.yml | 20 +++ .../source-gridly/acceptance-test-docker.sh | 16 +++ .../connectors/source-gridly/build.gradle | 9 ++ .../integration_tests/__init__.py | 3 + .../integration_tests/abnormal_state.json | 5 + .../integration_tests/acceptance.py | 16 +++ .../integration_tests/configured_catalog.json | 13 ++ .../integration_tests/invalid_config.json | 3 + .../integration_tests/sample_config.json | 4 + .../integration_tests/sample_state.json | 5 + .../connectors/source-gridly/main.py | 13 ++ .../connectors/source-gridly/requirements.txt | 2 + .../connectors/source-gridly/setup.py | 29 ++++ .../source-gridly/source_gridly/__init__.py | 8 ++ .../source-gridly/source_gridly/helpers.py | 136 ++++++++++++++++++ .../source-gridly/source_gridly/source.py | 125 ++++++++++++++++ .../source-gridly/source_gridly/spec.yaml | 16 +++ .../source-gridly/unit_tests/__init__.py | 3 + .../source-gridly/unit_tests/test_helpers.py | 74 ++++++++++ .../source-gridly/unit_tests/test_source.py | 23 +++ docs/.gitbook/assets/gridly_api_key1.png | Bin 0 -> 302170 bytes docs/.gitbook/assets/gridly_api_key2.png | Bin 0 -> 850052 bytes docs/.gitbook/assets/gridly_grid_id.png | Bin 0 -> 614784 bytes docs/integrations/README.md | 1 + docs/integrations/sources/gridly.md | 35 +++++ 30 files changed, 763 insertions(+) create mode 100644 airbyte-integrations/connectors/source-gridly/.dockerignore create mode 100644 airbyte-integrations/connectors/source-gridly/Dockerfile create mode 100644 airbyte-integrations/connectors/source-gridly/README.md create mode 100644 airbyte-integrations/connectors/source-gridly/acceptance-test-config.yml create mode 100644 airbyte-integrations/connectors/source-gridly/acceptance-test-docker.sh create mode 100644 airbyte-integrations/connectors/source-gridly/build.gradle create mode 100644 airbyte-integrations/connectors/source-gridly/integration_tests/__init__.py create mode 100644 airbyte-integrations/connectors/source-gridly/integration_tests/abnormal_state.json create mode 100644 airbyte-integrations/connectors/source-gridly/integration_tests/acceptance.py create mode 100644 airbyte-integrations/connectors/source-gridly/integration_tests/configured_catalog.json create mode 100644 airbyte-integrations/connectors/source-gridly/integration_tests/invalid_config.json create mode 100644 airbyte-integrations/connectors/source-gridly/integration_tests/sample_config.json create mode 100644 airbyte-integrations/connectors/source-gridly/integration_tests/sample_state.json create mode 100644 airbyte-integrations/connectors/source-gridly/main.py create mode 100644 airbyte-integrations/connectors/source-gridly/requirements.txt create mode 100644 airbyte-integrations/connectors/source-gridly/setup.py create mode 100644 airbyte-integrations/connectors/source-gridly/source_gridly/__init__.py create mode 100644 airbyte-integrations/connectors/source-gridly/source_gridly/helpers.py create mode 100644 airbyte-integrations/connectors/source-gridly/source_gridly/source.py create mode 100644 airbyte-integrations/connectors/source-gridly/source_gridly/spec.yaml create mode 100644 airbyte-integrations/connectors/source-gridly/unit_tests/__init__.py create mode 100644 airbyte-integrations/connectors/source-gridly/unit_tests/test_helpers.py create mode 100644 airbyte-integrations/connectors/source-gridly/unit_tests/test_source.py create mode 100644 docs/.gitbook/assets/gridly_api_key1.png create mode 100644 docs/.gitbook/assets/gridly_api_key2.png create mode 100644 docs/.gitbook/assets/gridly_grid_id.png create mode 100644 docs/integrations/sources/gridly.md diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index 19077ecf6aeb..2b53633ed09f 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -422,6 +422,13 @@ icon: freshservice.svg sourceType: api releaseStage: alpha +- name: Gridly + sourceDefinitionId: 6cbea164-3237-433b-9abb-36d384ee4cbf + dockerRepository: airbyte/source-gridly + dockerImageTag: 0.1.0 + documentationUrl: https://docs.airbyte.com/integrations/sources/gridly + sourceType: api + releaseStage: alpha - name: GitHub sourceDefinitionId: ef69ef6e-aa7f-4af1-a01d-ef775033524e dockerRepository: airbyte/source-github diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 965c8acb1e86..7edad5248d6d 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -3937,6 +3937,27 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] +- dockerImage: "airbyte/source-gridly:0.1.0" + spec: + documentationUrl: "https://docs.airbyte.com/integrations/sources/gridly" + connectionSpecification: + $schema: "http://json-schema.org/draft-07/schema#" + title: "Gridly Spec" + type: "object" + required: + - "api_key" + properties: + api_key: + type: "string" + title: "API Key" + airbyte_secret: true + grid_id: + type: "string" + title: "Grid ID" + description: "ID of a grid, or can be ID of a branch" + supportsNormalization: false + supportsDBT: false + supported_destination_sync_modes: [] - dockerImage: "airbyte/source-github:0.3.7" spec: documentationUrl: "https://docs.airbyte.com/integrations/sources/github" diff --git a/airbyte-integrations/connectors/source-gridly/.dockerignore b/airbyte-integrations/connectors/source-gridly/.dockerignore new file mode 100644 index 000000000000..f86364dadaf3 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/.dockerignore @@ -0,0 +1,6 @@ +* +!Dockerfile +!main.py +!source_gridly +!setup.py +!secrets diff --git a/airbyte-integrations/connectors/source-gridly/Dockerfile b/airbyte-integrations/connectors/source-gridly/Dockerfile new file mode 100644 index 000000000000..f8f0fba5a280 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/Dockerfile @@ -0,0 +1,38 @@ +FROM python:3.9.13-alpine3.15 as base + +# build and load all requirements +FROM base as builder +WORKDIR /airbyte/integration_code + +# upgrade pip to the latest version +RUN apk --no-cache upgrade \ + && pip install --upgrade pip \ + && apk --no-cache add tzdata build-base + + +COPY setup.py ./ +# install necessary packages to a temporary folder +RUN pip install --prefix=/install . + +# build a clean environment +FROM base +WORKDIR /airbyte/integration_code + +# copy all loaded and built libraries to a pure basic image +COPY --from=builder /install /usr/local +# add default timezone settings +COPY --from=builder /usr/share/zoneinfo/Etc/UTC /etc/localtime +RUN echo "Etc/UTC" > /etc/timezone + +# bash is installed for more convenient debugging. +RUN apk --no-cache add bash + +# copy payload code only +COPY main.py ./ +COPY source_gridly ./source_gridly + +ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" +ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] + +LABEL io.airbyte.version=0.1.0 +LABEL io.airbyte.name=airbyte/source-gridly diff --git a/airbyte-integrations/connectors/source-gridly/README.md b/airbyte-integrations/connectors/source-gridly/README.md new file mode 100644 index 000000000000..375f788f5b32 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/README.md @@ -0,0 +1,132 @@ +# Gridly Source + +This is the repository for the Gridly source connector, written in Python. +For information about how to use this connector within Airbyte, see [the documentation](https://docs.airbyte.io/integrations/sources/gridly). + +## Local development + +### Prerequisites +**To iterate on this connector, make sure to complete this prerequisites section.** + +#### Minimum Python version required `= 3.9.0` + +#### Build & Activate Virtual Environment and install dependencies +From this connector directory, create a virtual environment: +``` +python -m venv .venv +``` + +This will generate a virtualenv for this module in `.venv/`. Make sure this venv is active in your +development environment of choice. To activate it from the terminal, run: +``` +source .venv/bin/activate +pip install -r requirements.txt +pip install '.[tests]' +``` +If you are in an IDE, follow your IDE's instructions to activate the virtualenv. + +Note that while we are installing dependencies from `requirements.txt`, you should only edit `setup.py` for your dependencies. `requirements.txt` is +used for editable installs (`pip install -e`) to pull in Python dependencies from the monorepo and will call `setup.py`. +If this is mumbo jumbo to you, don't worry about it, just put your deps in `setup.py` but install using `pip install -r requirements.txt` and everything +should work as you expect. + +#### Building via Gradle +You can also build the connector in Gradle. This is typically used in CI and not needed for your development workflow. + +To build using Gradle, from the Airbyte repository root, run: +``` +./gradlew :airbyte-integrations:connectors:source-gridly:build +``` + +#### Create credentials +**If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.io/integrations/sources/gridly) +to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `source_gridly/spec.yaml` file. +Note that any directory named `secrets` is gitignored across the entire Airbyte repo, so there is no danger of accidentally checking in sensitive information. +See `integration_tests/sample_config.json` for a sample config file. + +**If you are an Airbyte core member**, copy the credentials in Lastpass under the secret name `source gridly test creds` +and place them into `secrets/config.json`. + +### Locally running the connector +``` +python main.py spec +python main.py check --config secrets/config.json +python main.py discover --config secrets/config.json +python main.py read --config secrets/config.json --catalog integration_tests/configured_catalog.json +``` + +### Locally running the connector docker image + +#### Build +First, make sure you build the latest Docker image: +``` +docker build . -t airbyte/source-gridly:dev +``` + +You can also build the connector image via Gradle: +``` +./gradlew :airbyte-integrations:connectors:source-gridly:airbyteDocker +``` +When building via Gradle, the docker image name and tag, respectively, are the values of the `io.airbyte.name` and `io.airbyte.version` `LABEL`s in +the Dockerfile. + +#### Run +Then run any of the connector commands as follows: +``` +docker run --rm airbyte/source-gridly:dev spec +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-gridly:dev check --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-gridly:dev discover --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/source-gridly:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json +``` +## Testing +Make sure to familiarize yourself with [pytest test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) to know how your test files and methods should be named. +First install test dependencies into your virtual environment: +``` +pip install .[tests] +``` +### Unit Tests +To run unit tests locally, from the connector directory run: +``` +python -m pytest unit_tests +``` + +### Integration Tests +There are two types of integration tests: Acceptance Tests (Airbyte's test suite for all source connectors) and custom integration tests (which are specific to this connector). +#### Custom Integration tests +Place custom tests inside `integration_tests/` folder, then, from the connector root, run +``` +python -m pytest integration_tests +``` +#### Acceptance Tests +Customize `acceptance-test-config.yml` file to configure tests. See [Source Acceptance Tests](https://docs.airbyte.io/connector-development/testing-connectors/source-acceptance-tests-reference) for more information. +If your connector requires to create or destroy resources for use during acceptance tests create fixtures for it and place them inside integration_tests/acceptance.py. +To run your integration tests with acceptance tests, from the connector root, run +``` +python -m pytest integration_tests -p integration_tests.acceptance +``` +To run your integration tests with docker + +### Using gradle to run tests +All commands should be run from airbyte project root. +To run unit tests: +``` +./gradlew :airbyte-integrations:connectors:source-gridly:unitTest +``` +To run acceptance and custom integration tests: +``` +./gradlew :airbyte-integrations:connectors:source-gridly:integrationTest +``` + +## Dependency Management +All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development. +We split dependencies between two groups, dependencies that are: +* required for your connector to work need to go to `MAIN_REQUIREMENTS` list. +* required for the testing need to go to `TEST_REQUIREMENTS` list + +### Publishing a new version of the connector +You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what? +1. Make sure your changes are passing unit and integration tests. +1. Bump the connector version in `Dockerfile` -- just increment the value of the `LABEL io.airbyte.version` appropriately (we use [SemVer](https://semver.org/)). +1. Create a Pull Request. +1. Pat yourself on the back for being an awesome contributor. +1. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master. diff --git a/airbyte-integrations/connectors/source-gridly/acceptance-test-config.yml b/airbyte-integrations/connectors/source-gridly/acceptance-test-config.yml new file mode 100644 index 000000000000..db3e7174fe01 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/acceptance-test-config.yml @@ -0,0 +1,20 @@ +# See [Source Acceptance Tests](https://docs.airbyte.com/connector-development/testing-connectors/source-acceptance-tests-reference) +# for more information about how to configure these tests +connector_image: airbyte/source-gridly:dev +tests: + spec: + - spec_path: "source_gridly/spec.yaml" + connection: + - config_path: "secrets/config.json" + status: "succeed" + - config_path: "integration_tests/invalid_config.json" + status: "failed" + discovery: + - config_path: "secrets/config.json" + basic_read: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" + empty_streams: [] + full_refresh: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" diff --git a/airbyte-integrations/connectors/source-gridly/acceptance-test-docker.sh b/airbyte-integrations/connectors/source-gridly/acceptance-test-docker.sh new file mode 100644 index 000000000000..c51577d10690 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/acceptance-test-docker.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +# Build latest connector image +docker build . -t $(cat acceptance-test-config.yml | grep "connector_image" | head -n 1 | cut -d: -f2-) + +# Pull latest acctest image +docker pull airbyte/source-acceptance-test:latest + +# Run +docker run --rm -it \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /tmp:/tmp \ + -v $(pwd):/test_input \ + airbyte/source-acceptance-test \ + --acceptance-test-config /test_input + diff --git a/airbyte-integrations/connectors/source-gridly/build.gradle b/airbyte-integrations/connectors/source-gridly/build.gradle new file mode 100644 index 000000000000..fa61deefe078 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/build.gradle @@ -0,0 +1,9 @@ +plugins { + id 'airbyte-python' + id 'airbyte-docker' + id 'airbyte-source-acceptance-test' +} + +airbytePython { + moduleDirectory 'source_gridly' +} diff --git a/airbyte-integrations/connectors/source-gridly/integration_tests/__init__.py b/airbyte-integrations/connectors/source-gridly/integration_tests/__init__.py new file mode 100644 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/integration_tests/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-gridly/integration_tests/abnormal_state.json b/airbyte-integrations/connectors/source-gridly/integration_tests/abnormal_state.json new file mode 100644 index 000000000000..52b0f2c2118f --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/integration_tests/abnormal_state.json @@ -0,0 +1,5 @@ +{ + "todo-stream-name": { + "todo-field-name": "todo-abnormal-value" + } +} diff --git a/airbyte-integrations/connectors/source-gridly/integration_tests/acceptance.py b/airbyte-integrations/connectors/source-gridly/integration_tests/acceptance.py new file mode 100644 index 000000000000..1302b2f57e10 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/integration_tests/acceptance.py @@ -0,0 +1,16 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import pytest + +pytest_plugins = ("source_acceptance_test.plugin",) + + +@pytest.fixture(scope="session", autouse=True) +def connector_setup(): + """This fixture is a placeholder for external resources that acceptance test might require.""" + # TODO: setup test dependencies if needed. otherwise remove the TODO comments + yield + # TODO: clean up test dependencies diff --git a/airbyte-integrations/connectors/source-gridly/integration_tests/configured_catalog.json b/airbyte-integrations/connectors/source-gridly/integration_tests/configured_catalog.json new file mode 100644 index 000000000000..4ddbb011b027 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/integration_tests/configured_catalog.json @@ -0,0 +1,13 @@ +{ + "streams": [ + { + "stream": { + "name": "Default view", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-gridly/integration_tests/invalid_config.json b/airbyte-integrations/connectors/source-gridly/integration_tests/invalid_config.json new file mode 100644 index 000000000000..f3732995784f --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/integration_tests/invalid_config.json @@ -0,0 +1,3 @@ +{ + "todo-wrong-field": "this should be an incomplete config file, used in standard tests" +} diff --git a/airbyte-integrations/connectors/source-gridly/integration_tests/sample_config.json b/airbyte-integrations/connectors/source-gridly/integration_tests/sample_config.json new file mode 100644 index 000000000000..236d2d817085 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/integration_tests/sample_config.json @@ -0,0 +1,4 @@ +{ + "api_key": "IbuIBdkFjrJps6", + "grid_id": "4539o52kmdjmzwp" +} \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-gridly/integration_tests/sample_state.json b/airbyte-integrations/connectors/source-gridly/integration_tests/sample_state.json new file mode 100644 index 000000000000..3587e579822d --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/integration_tests/sample_state.json @@ -0,0 +1,5 @@ +{ + "todo-stream-name": { + "todo-field-name": "value" + } +} diff --git a/airbyte-integrations/connectors/source-gridly/main.py b/airbyte-integrations/connectors/source-gridly/main.py new file mode 100644 index 000000000000..00d2562d8b72 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/main.py @@ -0,0 +1,13 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import sys + +from airbyte_cdk.entrypoint import launch +from source_gridly import SourceGridly + +if __name__ == "__main__": + source = SourceGridly() + launch(source, sys.argv[1:]) diff --git a/airbyte-integrations/connectors/source-gridly/requirements.txt b/airbyte-integrations/connectors/source-gridly/requirements.txt new file mode 100644 index 000000000000..0411042aa091 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/requirements.txt @@ -0,0 +1,2 @@ +-e ../../bases/source-acceptance-test +-e . diff --git a/airbyte-integrations/connectors/source-gridly/setup.py b/airbyte-integrations/connectors/source-gridly/setup.py new file mode 100644 index 000000000000..60ae90355d17 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/setup.py @@ -0,0 +1,29 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from setuptools import find_packages, setup + +MAIN_REQUIREMENTS = [ + "airbyte-cdk", +] + +TEST_REQUIREMENTS = [ + "pytest~=6.1", + "pytest-mock~=3.6.1", + "source-acceptance-test", +] + +setup( + name="source_gridly", + description="Source implementation for Gridly.", + author="Airbyte", + author_email="contact@airbyte.io", + packages=find_packages(), + install_requires=MAIN_REQUIREMENTS, + package_data={"": ["*.json", "*.yaml", "schemas/*.json", "schemas/shared/*.json"]}, + extras_require={ + "tests": TEST_REQUIREMENTS, + }, +) diff --git a/airbyte-integrations/connectors/source-gridly/source_gridly/__init__.py b/airbyte-integrations/connectors/source-gridly/source_gridly/__init__.py new file mode 100644 index 000000000000..7eedbd6d1c51 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/source_gridly/__init__.py @@ -0,0 +1,8 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from .source import SourceGridly + +__all__ = ["SourceGridly"] diff --git a/airbyte-integrations/connectors/source-gridly/source_gridly/helpers.py b/airbyte-integrations/connectors/source-gridly/source_gridly/helpers.py new file mode 100644 index 000000000000..fc3de2bc9644 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/source_gridly/helpers.py @@ -0,0 +1,136 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from typing import Any, Dict + +import requests +from airbyte_cdk.models import AirbyteStream +from airbyte_cdk.models.airbyte_protocol import DestinationSyncMode, SyncMode +from airbyte_cdk.sources.streams.http.requests_native_auth import TokenAuthenticator + + +class Helpers(object): + base_url = "https://api.gridly.com/v1/" + + @staticmethod + def view_detail_url(view_id: str) -> str: + return Helpers.base_url + f"views/{view_id}" + + @staticmethod + def view_list_url(grid_id: str) -> str: + return Helpers.base_url + f"views?gridId={grid_id}" + + @staticmethod + def grid_detail_url(grid_id: str) -> str: + return Helpers.base_url + f"grids/{grid_id}" + + @staticmethod + def get_views(auth: TokenAuthenticator, grid_id: str) -> Dict[str, Any]: + url = Helpers.view_list_url(grid_id) + try: + response = requests.get(url, headers=auth.get_auth_header()) + response.raise_for_status() + except requests.exceptions.HTTPError as e: + if e.response.status_code == 401: + raise Exception("Invalid API Key") + elif e.response.status_code == 404: + raise Exception(f"Grid id '{grid_id}' not found") + else: + raise Exception(f"Error getting listing views of grid '{grid_id}'") + + return response.json() + + @staticmethod + def get_grid(auth: TokenAuthenticator, grid_id: str) -> Dict[str, Any]: + url = Helpers.grid_detail_url(grid_id) + try: + response = requests.get(url, headers=auth.get_auth_header()) + response.raise_for_status() + except requests.exceptions.HTTPError as e: + if e.response.status_code == 401: + raise Exception("Invalid API Key") + elif e.response.status_code == 404: + raise Exception(f"Grid '{grid_id}' not found") + else: + raise Exception(f"Error getting grid {grid_id}: {e}") + return response.json() + + @staticmethod + def get_view(auth: TokenAuthenticator, view_id: str) -> Dict[str, Any]: + url = Helpers.view_detail_url(view_id) + try: + response = requests.get(url, headers=auth.get_auth_header()) + response.raise_for_status() + except requests.exceptions.HTTPError as e: + if e.response.status_code == 401: + raise Exception("Invalid API Key") + elif e.response.status_code == 404: + raise Exception(f"View '{view_id}' not found") + else: + raise Exception(f"Error getting view {view_id}: {e}") + return response.json() + + @staticmethod + def to_airbyte_data_type(column_type: str) -> str: + if column_type == "number": + return "number" + elif column_type == "boolean": + return "boolean" + else: + return "string" + + @staticmethod + def get_json_schema(view: Dict[str, Any]) -> Dict[str, str]: + columns = view.get("columns", {}) + properties = {} + + for column in columns: + column_id = column.get("id") + column_type = column.get("type", "singleLine") + properties[column_id] = {"type": ["null", Helpers.to_airbyte_data_type(column_type)]} + + json_schema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": properties, + } + return json_schema + + @staticmethod + def get_airbyte_stream(view: Dict[str, Any]) -> AirbyteStream: + view_name = view.get("name") + columns = view.get("columns", {}) + properties = {} + + for column in columns: + column_id = column.get("id") + column_type = column.get("type", "singleLine") + properties[column_id] = {"type": ["null", Helpers.to_airbyte_data_type(column_type)]} + + json_schema = Helpers.get_json_schema(view) + + return AirbyteStream( + name=view_name, + json_schema=json_schema, + supported_sync_modes=[SyncMode.full_refresh], + supported_destination_sync_modes=[DestinationSyncMode.overwrite, DestinationSyncMode.append_dedup], + ) + + @staticmethod + def transform_record(record: Dict[str, Any], schema: Dict[str, Any]) -> Dict[str, Any]: + schema_properties = schema.get("properties") + columns = [k for k, v in schema_properties.items()] + + cells = record.get("cells") + + transformed_record = {} + if "_recordId" in columns: + transformed_record["_recordId"] = record.get("id") + if "_path" in columns: + transformed_record["_path"] = record.get("path", "") + + for cell in cells: + transformed_record[cell.get("columnId")] = cell.get("value") + + return transformed_record diff --git a/airbyte-integrations/connectors/source-gridly/source_gridly/source.py b/airbyte-integrations/connectors/source-gridly/source_gridly/source.py new file mode 100644 index 000000000000..f96d8dcb7e22 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/source_gridly/source.py @@ -0,0 +1,125 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import logging +import math +from abc import ABC +from typing import Any, Dict, Iterable, List, Mapping, MutableMapping, Optional, Tuple + +import requests +from airbyte_cdk.models import AirbyteCatalog +from airbyte_cdk.sources import AbstractSource +from airbyte_cdk.sources.streams import Stream +from airbyte_cdk.sources.streams.http import HttpStream +from airbyte_cdk.sources.streams.http.auth import TokenAuthenticator +from source_gridly.helpers import Helpers + + +# Basic full refresh stream +class GridlyStream(HttpStream, ABC): + url_base = Helpers.base_url + primary_key = "id" + current_page = 1 + limit = 100 + + def __init__(self, view_id: str, view_name: str, schema: Dict[str, Any], **kwargs): + super().__init__(**kwargs) + self.view_id = view_id + self.view_name = view_name + self.schema = schema + + @property + def name(self): + return self.view_name + + def get_json_schema(self) -> Mapping[str, Any]: + return self.schema + + def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]: + total_count = response.headers.get("x-total-count") + total_page = math.ceil(int(total_count) / self.limit) + + self.logger.info("Total page: " + str(total_page)) + + if self.current_page >= total_page: + self.logger.info("No more page to load " + str(self.current_page)) + return None + + page_token = {"offset": self.current_page * self.limit, "limit": self.limit} + self.current_page += 1 + + return page_token + + def request_params( + self, stream_state: Mapping[str, Any], stream_slice: Mapping[str, any] = None, next_page_token: Mapping[str, Any] = None + ) -> MutableMapping[str, Any]: + if next_page_token is None: + return {} + + offset = next_page_token.get("offset") + limit = next_page_token.get("limit") + + page = '{"offset":' + str(offset) + ',"limit":' + str(limit) + "}" + + self.logger.info("Fetching page: " + page) + + return {"page": page} + + def parse_response(self, response: requests.Response, **kwargs) -> Iterable[Mapping]: + records = response.json() + if isinstance(records, list): + for record in records: + yield Helpers.transform_record(record, self.schema) + else: + Exception(f"Unsupported type of response data for stream {self.name}") + + def path( + self, stream_state: Mapping[str, Any] = None, stream_slice: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None + ) -> str: + return f"views/{self.view_id}/records" + + +# Source +class SourceGridly(AbstractSource): + def check_connection(self, logger, config) -> Tuple[bool, any]: + api_key = config.get("api_key") + grid_id = config.get("grid_id") + auth = TokenAuthenticator(auth_method="ApiKey", token=api_key) + + logger.info(f"Checking connection on grid {grid_id}") + Helpers.get_grid(auth=auth, grid_id=grid_id) + + return True, None + + def discover(self, logger: logging.Logger, config: Mapping[str, Any]) -> AirbyteCatalog: + api_key = config.get("api_key") + grid_id = config.get("grid_id") + auth = TokenAuthenticator(auth_method="ApiKey", token=api_key) + + logger.info(f"Running discovery on grid {grid_id}") + views = Helpers.get_views(auth=auth, grid_id=grid_id) + + streams = [] + for view in views: + stream = Helpers.get_airbyte_stream(view) + streams.append(stream) + + return AirbyteCatalog(streams=streams) + + def streams(self, config: Mapping[str, Any]) -> List[Stream]: + api_key = config.get("api_key") + grid_id = config.get("grid_id") + auth = TokenAuthenticator(auth_method="ApiKey", token=api_key) + views = Helpers.get_views(auth=auth, grid_id=grid_id) + + streams = [] + for view in views: + view_id = view.get("id") + view_name = view.get("name") + schema = Helpers.get_json_schema(view) + stream = GridlyStream(view_id=view_id, view_name=view_name, schema=schema, authenticator=auth) + streams.append(stream) + + return streams diff --git a/airbyte-integrations/connectors/source-gridly/source_gridly/spec.yaml b/airbyte-integrations/connectors/source-gridly/source_gridly/spec.yaml new file mode 100644 index 000000000000..f03e53aca457 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/source_gridly/spec.yaml @@ -0,0 +1,16 @@ +documentationUrl: https://docs.airbyte.com/integrations/sources/gridly +connectionSpecification: + $schema: http://json-schema.org/draft-07/schema# + title: Gridly Spec + type: object + required: + - api_key + properties: + api_key: + type: string + title: API Key + airbyte_secret: true + grid_id: + type: string + title: Grid ID + description: ID of a grid, or can be ID of a branch diff --git a/airbyte-integrations/connectors/source-gridly/unit_tests/__init__.py b/airbyte-integrations/connectors/source-gridly/unit_tests/__init__.py new file mode 100644 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/unit_tests/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-gridly/unit_tests/test_helpers.py b/airbyte-integrations/connectors/source-gridly/unit_tests/test_helpers.py new file mode 100644 index 000000000000..c6c7b577dae0 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/unit_tests/test_helpers.py @@ -0,0 +1,74 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +import pytest +from source_gridly.helpers import Helpers + + +@pytest.fixture +def gridly_column_type(): + return "singleLine" + + +@pytest.fixture +def expected_data_type(): + return "string" + + +@pytest.fixture +def view_response(): + return { + "id": "view1", + "name": "Default view", + "columns": [{"id": "_recordId"}, {"id": "column1", "type": "singleLine"}, {"id": "column2", "type": "number"}], + } + + +@pytest.fixture +def record_response(): + return [ + {"id": "record1", "cells": [{"columnId": "column1", "value": "Value 1"}, {"columnId": "column2", "value": 1}]}, + {"id": "record2", "cells": [{"columnId": "column1", "value": "Value 2"}, {"columnId": "column2", "value": 2}]}, + ] + + +@pytest.fixture +def expected_json_schema(): + return { + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "_recordId": {"type": ["null", "string"]}, + "column1": {"type": ["null", "string"]}, + "column2": {"type": ["null", "number"]}, + }, + "type": "object", + } + + +@pytest.fixture +def expected_transformed_record(): + return {"_recordId": "record1", "column1": "Value 1", "column2": 1} + + +def test_to_airbyte_data_type(gridly_column_type, expected_data_type): + assert expected_data_type == Helpers.to_airbyte_data_type(gridly_column_type) + + +def test_get_json_schema(view_response, expected_json_schema): + json_schema = Helpers.get_json_schema(view_response) + assert json_schema == expected_json_schema + + +def test_get_airbyte_stream(view_response, expected_json_schema): + stream = Helpers.get_airbyte_stream(view_response) + assert stream + assert stream.name == view_response.get("name") + assert stream.json_schema == expected_json_schema + + +def test_transform_record(view_response, record_response, expected_transformed_record): + json_schema = Helpers.get_json_schema(view_response) + record1 = record_response[0] + transformed_record = Helpers.transform_record(record1, json_schema) + assert expected_transformed_record == transformed_record diff --git a/airbyte-integrations/connectors/source-gridly/unit_tests/test_source.py b/airbyte-integrations/connectors/source-gridly/unit_tests/test_source.py new file mode 100644 index 000000000000..30d09ffcfe94 --- /dev/null +++ b/airbyte-integrations/connectors/source-gridly/unit_tests/test_source.py @@ -0,0 +1,23 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from unittest.mock import MagicMock + +from source_gridly.source import SourceGridly + +CONFIG = {"api_key": "IbuIBdkFjrJps6", "grid_id": "4539o52kmdjmzwp"} + + +def test_check_connection(mocker): + source = SourceGridly() + logger_mock, config_mock = MagicMock(), CONFIG + assert source.check_connection(logger_mock, config_mock) == (True, None) + + +def test_streams(mocker): + source = SourceGridly() + config_mock = CONFIG + streams = source.streams(config_mock) + expected_streams_number = 2 + assert len(streams) == expected_streams_number diff --git a/docs/.gitbook/assets/gridly_api_key1.png b/docs/.gitbook/assets/gridly_api_key1.png new file mode 100644 index 0000000000000000000000000000000000000000..0b29ffbe9ec703f37edd7f6c2500fba722e472a8 GIT binary patch literal 302170 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%0D}#iC7pS#A}u((If3E!Y4g29dk@ccWJ~|F?SlB*` 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 literal 0 HcmV?d00001 diff --git a/docs/.gitbook/assets/gridly_api_key2.png b/docs/.gitbook/assets/gridly_api_key2.png new file mode 100644 index 0000000000000000000000000000000000000000..0efd4b3e2d1b7ebbb35d0b44b7b64350d8639234 GIT binary patch literal 850052 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


;-G+q%@wKYYEi!Tx} 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

uwwcsfa(iW%mKz8vI<0WPGYw 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Ξ+zB! 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

p%sdOAi%lT)qEjL+-MC-mYh3d+7F~??m;h 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 z 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�|6H&Lf>Be8&IWwrk2;jGK(3tss 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℞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ʂ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%0Dn}T$%+H8Ap~TJ>R#{){8o%+iu`qu3q)-C=s<=sV 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

w%8DCaG28w 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

4~*0BDxrT%`)D=$PtrX! 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 literal 0 HcmV?d00001 diff --git a/docs/.gitbook/assets/gridly_grid_id.png b/docs/.gitbook/assets/gridly_grid_id.png new file mode 100644 index 0000000000000000000000000000000000000000..20f5cf703c60468b57401430f431d543d003a12d GIT binary patch literal 614784 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

QfQM>CE(k#JqvFct$@vJf>`>zx^pGE# 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Ⓢ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

jFmy<p? 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
cgYF${b2fBKC_w(j(CAVKFj%tp65#_5K4IHr@dC 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
J`<FF7!z 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 z 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�(W46&ls=C@gz9 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 K(W}#OjQJmEQzIt; literal 0 HcmV?d00001 diff --git a/docs/integrations/README.md b/docs/integrations/README.md index 34d0e7fbf4d8..66f9edf425b1 100644 --- a/docs/integrations/README.md +++ b/docs/integrations/README.md @@ -82,6 +82,7 @@ For more information about the grading system, see [Product Release Stages](http | [Google Webfonts](sources/google-webfonts.md) | Alpha | Yes | | [Google Workspace Admin Reports](sources/google-workspace-admin-reports.md) | Alpha | Yes | | [Greenhouse](sources/greenhouse.md) | Beta | Yes | +| [Gridly](sources/gridly.md) | Alpha | No | | [Gutendex](sources/gutendex.md) | Alpha | No | | [Harness](sources/harness.md) | Alpha | No | | [Harvest](sources/harvest.md) | Generally Available | Yes | diff --git a/docs/integrations/sources/gridly.md b/docs/integrations/sources/gridly.md new file mode 100644 index 000000000000..1f98968588b6 --- /dev/null +++ b/docs/integrations/sources/gridly.md @@ -0,0 +1,35 @@ +# Gridly + +This page contains the setup guide and reference information for the Gridly source connector. + +## Prerequisites + +A Gridly account. + +## Setup guide + +### Get api Key +1. To quickly get your API key, access your Gridly Dashboard, then select a Grid View and you can find the key in API quick start right panel. +![img.png](../../.gitbook/assets/gridly_api_key1.png) +2. Owner and Administrators can go to Settings/API keys to create company-level API keys with scoped privileges and accesses. +![img.png](../../.gitbook/assets/gridly_api_key2.png) + +### Get grid id +The grid id is available in the url. +Gridly support version control, by default the `grid id` is the same to the `branch id` when `Master` branch is selected. For fetching records on other branches, use `branch id` instead. +![img.png](../../.gitbook/assets/gridly_grid_id.png) + + +## Supported sync modes + +| Feature | Supported? | +| :---------------------------- |:-----------| +| Full Refresh Sync | Yes | +| Incremental Sync | No | + + +## Supported Streams + +* [Records](https://www.gridly.com/docs/api/#record) + +## Changelog From 022fca824f0cd018c0f48fb6ec2fe3526317f331 Mon Sep 17 00:00:00 2001 From: Tyler B <104733644+TBernstein4@users.noreply.github.com> Date: Thu, 3 Nov 2022 10:52:47 -0400 Subject: [PATCH 05/73] Embed Metabase Connector Catalog (#18864) Replaces static connector catalog with the embedded Metabase connector catalog --- docs/integrations/README.md | 251 ++---------------------------------- 1 file changed, 14 insertions(+), 237 deletions(-) diff --git a/docs/integrations/README.md b/docs/integrations/README.md index 66f9edf425b1..6bc336f5af06 100644 --- a/docs/integrations/README.md +++ b/docs/integrations/README.md @@ -14,243 +14,20 @@ For more information about the grading system, see [Product Release Stages](http ## Sources -| Connector | Product Release Stage| Available in Cloud? | -|:--------------------------------------------------------------------------------------------| :------------------- | :------------------ | -| [3PL Central](sources/tplcentral.md) | Alpha | No | -| [ActiveCampaign](sources/activecampaign.md) | Alpha | No | -| [Adjust](sources/adjust.md) | Alpha | No | -| [Airtable](sources/airtable.md) | Alpha | Yes | -| [AlloyDB](sources/alloydb.md) | Generally Available | Yes | -| [Amazon Ads](sources/amazon-ads.md) | Generally Available | Yes | -| [Amazon Seller Partner](sources/amazon-seller-partner.md) | Alpha | Yes | -| [Amazon SQS](sources/amazon-sqs.md) | Alpha | Yes | -| [Amplitude](sources/amplitude.md) | Generally Available | Yes | -| [Apify Dataset](sources/apify-dataset.md) | Alpha | Yes | -| [Appstore](sources/appstore.md) | Alpha | No | -| [Asana](sources/asana.md) | Alpha | No | -| [Ashby](sources/ashby.md) | Alpha | No | -| [AWS CloudTrail](sources/aws-cloudtrail.md) | Alpha | Yes | -| [Azure Table Storage](sources/azure-table.md) | Alpha | Yes | -| [BambooHR](sources/bamboo-hr.md) | Generally Available | Yes | -| [Baton](sources/hellobaton.md) | Alpha | No | -| [BigCommerce](sources/bigcommerce.md) | Alpha | Yes | -| [BigQuery](sources/bigquery.md) | Alpha | Yes | -| [Bing Ads](sources/bing-ads.md) | Generally Available | Yes | -| [Braintree](sources/braintree.md) | Alpha | Yes | -| [Cart.com](sources/cart.md) | Alpha | No | -| [Chargebee](sources/chargebee.md) | Generally Available | Yes | -| [Chargify](sources/chargify.md) | Alpha | No | -| [Chartmogul](sources/chartmogul.md) | Alpha | Yes | -| [ClickHouse](sources/clickhouse.md) | Alpha | Yes | -| [Close.com](sources/close-com.md) | Alpha | Yes | -| [CockroachDB](sources/cockroachdb.md) | Alpha | No | -| [Coinmarketcap](sources/coinmarketcap.md) | Alpha | Yes | -| [Commercetools](sources/commercetools.md) | Alpha | No | -| [Confluence](sources/confluence.md) | Alpha | No | -| [ConvertKit](sources/convertkit.md) | Alpha | No | -| [Courier](sources/courier.md) | Alpha | No | -| [Customer.io](sources/customer-io.md) | Alpha | No | -| [Datadog](sources/datadog.md) | Alpha | No | -| [Db2](sources/db2.md) | Alpha | No | -| [Delighted](sources/delighted.md) | Alpha | Yes | -| [Dixa](sources/dixa.md) | Alpha | Yes | -| [Dockerhub](sources/dockerhub.md) | Alpha | Yes | -| [Drift](sources/drift.md) | Alpha | No | -| [Drupal](sources/drupal.md) | Alpha | No | -| [Elasticsearch](sources/elasticsearch.md) | Alpha | No | -| [End-to-End Testing](sources/e2e-test.md) | Alpha | Yes | -| [Exchange Rates API](sources/exchangeratesapi.md) | Alpha | Yes | -| [Facebook Marketing](sources/facebook-marketing.md) | Generally Available | Yes | -| [Facebook Pages](sources/facebook-pages.md) | Alpha | No | -| [Faker](sources/faker.md) | Alpha | Yes | -| [Fauna](sources/fauna.md) | Beta | No | -| [File](sources/file.md) | Beta | Yes | -| [Firebolt](sources/firebolt.md) | Alpha | Yes | -| [Flexport](sources/flexport.md) | Alpha | No | -| [Freshdesk](sources/freshdesk.md) | Generally Available | Yes | -| [Freshsales](sources/freshsales.md) | Alpha | No | -| [Freshservice](sources/freshservice.md) | Alpha | No | -| [GitHub](sources/github.md) | Generally Available | Yes | -| [GitLab](sources/gitlab.md) | Alpha | Yes | -| [Glassfrog](sources/glassfrog.md) | Alpha | No | -| [Google Ads](sources/google-ads.md) | Generally Available | Yes | -| [Google Analytics (v4)](sources/google-analytics-v4.md) | Alpha | Yes | -| [Google Analytics (Universal Analytics)](sources/google-analytics-universal-analytics.md) | Generally Available | Yes | -| [Google Directory](sources/google-directory.md) | Alpha | Yes | -| [Google Search Console](sources/google-search-console.md) | Generally Available | Yes | -| [Google Sheets](sources/google-sheets.md) | Generally Available | Yes | -| [Google Webfonts](sources/google-webfonts.md) | Alpha | Yes | -| [Google Workspace Admin Reports](sources/google-workspace-admin-reports.md) | Alpha | Yes | -| [Greenhouse](sources/greenhouse.md) | Beta | Yes | -| [Gridly](sources/gridly.md) | Alpha | No | -| [Gutendex](sources/gutendex.md) | Alpha | No | -| [Harness](sources/harness.md) | Alpha | No | -| [Harvest](sources/harvest.md) | Generally Available | Yes | -| [http-request](sources/http-request.md) | Alpha | No | -| [HubSpot](sources/hubspot.md) | Generally Available | Yes | -| [Insightly](sources/insightly.md) | Alpha | Yes | -| [Instagram](sources/instagram.md) | Generally Available | Yes | -| [Intercom](sources/intercom.md) | Generally Available | Yes | -| [Iterable](sources/iterable.md) | Generally Available | Yes | -| [Jenkins](sources/jenkins.md) | Alpha | No | -| [Jira](sources/jira.md) | Alpha | No | -| [Kafka](sources/kafka.md) | Alpha | No | -| [Klaviyo](sources/klaviyo.md) | Generally Available | Yes | -| [Kustomer](sources/kustomer.md) | Alpha | Yes | -| [Kyriba](sources/kyriba.md) | Alpha | No | -| [Lemlist](sources/lemlist.md) | Alpha | Yes | -| [Lever](sources/lever-hiring.md) | Alpha | No | -| [LinkedIn Ads](sources/linkedin-ads.md) | Generally Available | Yes | -| [LinkedIn Pages](sources/linkedin-pages.md) | Alpha | No | -| [Linnworks](sources/linnworks.md) | Alpha | Yes | -| [Lokalise](sources/lokalise.md) | Alpha | Yes | -| [Looker](sources/looker.md) | Alpha | Yes | -| [Magento](sources/magento.md) | Alpha | No | -| [Mailchimp](sources/mailchimp.md) | Generally Available | Yes | -| [Mailjet SMS](sources/mailjet-sms.md) | Alpha | No | -| [Mailjet Mail](sources/mailjet-mail.md) | Alpha | No | -| [Mailerlite](sources/mailerlite.md) | Alpha | No | -| [Mailjet Mail](sources/mailjet-mail.md) | Alpha | No | -| [Marketo](sources/marketo.md) | Generally Available | Yes | -| [Metabase](sources/metabase.md) | Alpha | Yes | -| [Microsoft Dynamics AX](sources/microsoft-dynamics-ax.md) | Alpha | No | -| [Microsoft Dynamics Customer Engagement](sources/microsoft-dynamics-customer-engagement.md) | Alpha | No | -| [Microsoft Dynamics GP](sources/microsoft-dynamics-gp.md) | Alpha | No | -| [Microsoft Dynamics NAV](sources/microsoft-dynamics-nav.md) | Alpha | No | -| [Microsoft SQL Server (MSSQL)](sources/mssql.md) | Alpha | Yes | -| [Microsoft Teams](sources/microsoft-teams.md) | Alpha | Yes | -| [Mixpanel](sources/mixpanel.md) | Generally Available | Yes | -| [Monday](sources/monday.md) | Alpha | Yes | -| [Mongo DB](sources/mongodb-v2.md) | Alpha | Yes | -| [My Hours](sources/my-hours.md) | Alpha | Yes | -| [MySQL](sources/mysql.md) | Beta | Yes | -| [NASA](sources/nasa.md) | Alpha | Yes | -| [Notion](sources/notion.md) | Generally Available | Yes | -| [Okta](sources/okta.md) | Alpha | Yes | -| [Omnisend](sources/omnisend.md) | Alpha | No | -| [OneSignal](sources/onesignal.md) | Alpha | No | -| [OpenWeather](sources/openweather.md) | Alpha | No | -| [Oracle DB](sources/oracle.md) | Alpha | Yes | -| [Oracle Netsuite](sources/netsuite.md) | Alpha | Yes | -| [Oracle PeopleSoft](sources/oracle-peoplesoft.md) | Alpha | No | -| [Oracle Siebel CRM](sources/oracle-siebel-crm.md) | Alpha | No | -| [Orb](sources/orb.md) | Alpha | Yes | -| [Orbit](sources/orbit.md) | Alpha | Yes | -| [Outreach](./sources/outreach.md) | Alpha | No | -| [PagerDuty](sources/pagerduty.md) | Alpha | No | -| [PayPal Transaction](sources/paypal-transaction.md) | Generally Available | Yes | -| [Paystack](sources/paystack.md) | Alpha | No | -| [PersistIq](sources/persistiq.md) | Alpha | Yes | -| [Pinterest](sources/pinterest.md) | Generally Available | Yes | -| [Pipedrive](sources/pipedrive.md) | Alpha | No | -| [Pivotal Tracker](sources/pivotal-tracker.md) | Alpha | No | -| [Plaid](sources/plaid.md) | Alpha | No | -| [PokéAPI](sources/pokeapi.md) | Alpha | Yes | -| [Postgres](sources/postgres.md) | Generally Available | Yes | -| [PostHog](sources/posthog.md) | Alpha | Yes | -| [PrestaShop](sources/presta-shop.md) | Alpha | Yes | -| [Public APIs](sources/public-apis.md) | Alpha | Yes | -| [Qualaroo](sources/qualaroo.md) | Alpha | Yes | -| [QuickBooks](sources/quickbooks.md) | Alpha | No | -| [RD Station Marketing](sources/rd-station-marketing.md) | Alpha | No | -| [Recharge](sources/recharge.md) | Generally Available | Yes | -| [Recurly](sources/recurly.md) | Alpha | Yes | -| [Redshift](sources/redshift.md) | Alpha | Yes | -| [Retently](sources/retently.md) | Alpha | Yes | -| [S3](sources/s3.md) | Generally Available | Yes | -| [Salesforce](sources/salesforce.md) | Generally Available | Yes | -| [Salesloft](sources/salesloft.md) | Alpha | No | -| [SAP Business One](sources/sap-business-one.md) | Alpha | No | -| [SearchMetrics](./sources/search-metrics.md) | Alpha | No | -| [Sendgrid](sources/sendgrid.md) | Beta | Yes | -| [Sentry](sources/sentry.md) | Generally Available | Yes | -| [SFTP Bulk](sources/sftp-bulk.md) | Alpha | Yes | -| [SFTP](sources/sftp.md) | Alpha | Yes | -| [Shopify](sources/shopify.md) | Alpha | No | -| [Short.io](sources/shortio.md) | Alpha | Yes | -| [Slack](sources/slack.md) | Generally Available | Yes | -| [Smartsheets](sources/smartsheets.md) | Beta | Yes | -| [Snapchat Marketing](sources/snapchat-marketing.md) | Generally Available | Yes | -| [Snowflake](sources/snowflake.md) | Alpha | Yes | -| [Sonar Cloud](sources/sonar-cloud.md) | Alpha | Yes | -| [Spree Commerce](sources/spree-commerce.md) | Alpha | No | -| [Square](sources/square.md) | Alpha | Yes | -| [Strava](sources/strava.md) | Alpha | No | -| [Stripe](sources/stripe.md) | Generally Available | Yes | -| [Sugar CRM](sources/sugar-crm.md) | Alpha | No | -| [SurveyMonkey](sources/surveymonkey.md) | Generally Available | Yes | -| [Tempo](sources/tempo.md) | Alpha | Yes | -| [TiDB](sources/tidb.md) | Alpha | No | -| [TikTok Marketing](./sources/tiktok-marketing.md) | Generally Available | Yes | -| [Trello](sources/trello.md) | Alpha | No | -| [Twilio](sources/twilio.md) | Generally Available | Yes | -| [Typeform](sources/typeform.md) | Alpha | Yes | -| [US Census](sources/us-census.md) | Alpha | Yes | -| [VictorOps](sources/victorops.md) | Alpha | No | -| [Waiteraid](sources/waiteraid.md) | Alpha | Yes | -| [Webflow](sources/webflow.md ) | Alpha | Yes | -| [Whisky Hunter](sources/whisky-hunter.md ) | Alpha | No | -| [WooCommerce](sources/woocommerce.md) | Alpha | No | -| [Wordpress](sources/wordpress.md) | Alpha | No | -| [Workable](sources/workable.md) | Alpha | No | -| [Wrike](sources/wrike.md) | Alpha | No | -| [YouTube Analytics](sources/youtube-analytics.md) | Beta | Yes | -| [Xkcd](sources/xkcd.md) | Alpha | No | -| [Zencart](sources/zencart.md) | Alpha | No | -| [Zendesk Chat](sources/zendesk-chat.md) | Generally Available | Yes | -| [Zendesk Sunshine](sources/zendesk-sunshine.md) | Alpha | Yes | -| [Zendesk Support](sources/zendesk-support.md) | Generally Available | Yes | -| [Zendesk Talk](sources/zendesk-talk.md) | Generally Available | Yes | -| [Zenloop](sources/zenloop.md) | Alpha | Yes | -| [Zoho CRM](sources/zoho-crm.md) | Alpha | No | -| [Zoom](sources/zoom.md) | Alpha | No | -| [Zuora](sources/zuora.md) | Alpha | Yes | + ## Destinations -| Connector | Product Release Stage| Available in Cloud? | -|:-----------------------------------------------------------| :------------------- | :------------------ | -| [Amazon SQS](destinations/amazon-sqs.md) | Alpha | No | -| [Amazon Datalake](destinations/aws-datalake.md) | Alpha | No | -| [AzureBlobStorage](destinations/azureblobstorage.md) | Alpha | Yes | -| [BigQuery](destinations/bigquery.md) | Generally Available | Yes | -| [Cassandra](destinations/cassandra.md) | Alpha | No | -| [Chargify (Keen)](destinations/chargify.md) | Alpha | Yes | -| [ClickHouse](destinations/clickhouse.md) | Alpha | Yes | -| [Databricks](destinations/databricks.md) | Alpha | No | -| [DynamoDB](destinations/dynamodb.md) | Alpha | No | -| [Elasticsearch](destinations/elasticsearch.md) | Alpha | No | -| [End-to-End Testing](destinations/e2e-test.md) | Alpha | Yes | -| [Firebolt](destinations/firebolt.md) | Alpha | Yes | -| [Google Cloud Storage (GCS)](destinations/gcs.md) | Beta | Yes | -| [Google Pubsub](destinations/pubsub.md) | Alpha | Yes | -| [Google Sheets](destinations/google-sheets.md) | Alpha | Yes | -| [Heap Analytics](destinations/heap-analytics.md) | Alpha | No | -| [Kafka](destinations/kafka.md) | Alpha | No | -| [Keen](destinations/keen.md) | Alpha | No | -| [Kinesis](destinations/kinesis.md) | Alpha | No | -| [Local CSV](destinations/local-csv.md) | Alpha | No | -| [Local JSON](destinations/local-json.md) | Alpha | No | -| [MariaDB ColumnStore](destinations/mariadb-columnstore.md) | Alpha | No | -| [MeiliSearch](destinations/meilisearch.md) | Alpha | No | -| [MongoDB](destinations/mongodb.md) | Alpha | No | -| [MQTT](destinations/mqtt.md) | Alpha | No | -| [MS SQL Server](destinations/mssql.md) | Alpha | Yes | -| [MySQL](destinations/mysql.md) | Alpha | Yes | -| [Oracle](destinations/oracle.md) | Alpha | Yes | -| [Postgres](destinations/postgres.md) | Alpha | Yes | -| [Pulsar](destinations/pulsar.md) | Alpha | No | -| [R2](destinations/r2.md) | Alpha | No | -| [RabbitMQ](destinations/rabbitmq.md) | Alpha | No | -| [Redis](destinations/redis.md) | Alpha | No | -| [Redshift](destinations/redshift.md) | Beta | Yes | -| [Rockset](destinations/rockset.md) | Alpha | No | -| [S3](destinations/s3.md) | Generally Available | Yes | -| [Scylla](destinations/scylla.md) | Alpha | No | -| [SFTP JSON](destinations/sftp-json.md) | Alpha | Yes | -| [Snowflake](destinations/snowflake.md) | Generally Available | Yes | -| [SQLite](destinations/sqlite.md) | Alpha | No | -| [Streamr](destinations/streamr.md) | Alpha | No | -| [TiDB](destinations/tidb.md) | Alpha | No | -| [Typesense](destinations/typesense.md) | Alpha | No | -| [Yugabytedb](destinations/yugabytedb.md) | Alpha | No | + \ No newline at end of file From 7693a3079af56ae417b52fc0eb16e7986b671903 Mon Sep 17 00:00:00 2001 From: Zaza Javakhishvili Date: Thu, 3 Nov 2022 11:19:10 -0400 Subject: [PATCH 06/73] Source Amazon Seller Partner - add new reports and bump version (#18283) * add new amazon seller partner reports and bump version * amazon seller partner new reports review based changes * Amazon seller partner new reports review based changes 2 * amazon seller partner ./gradlew format * amazon seller partner - add aditional 2 report types * Amazon seller partner some stream fix * amazon seller partner - ledger detailed view report data type fix * amazon seller repport fix xml orders parse * remove deprecated inventory helth report * Amazon seller partner review based change 3 * Update acceptance-test-config.yml * fix: generate source definitions for 0.2.28 version Co-authored-by: Juozas V Co-authored-by: sajarin --- .../resources/seed/source_definitions.yaml | 2 +- .../src/main/resources/seed/source_specs.yaml | 2 +- .../source-amazon-seller-partner/Dockerfile | 2 +- .../acceptance-test-config.yml | 50 ++++- ...g_get_fba_estimated_fba_fees_txt_data.json | 70 +++++++ ...ba_fulfillment_current_inventory_data.json | 28 +++ ...ment_customer_shipment_promotion_data.json | 29 +++ ...ulfillment_inventory_adjustments_data.json | 31 +++ ...a_fulfillment_inventory_receipts_data.json | 27 +++ ...ba_fulfillment_inventory_summary_data.json | 28 +++ ...ba_fulfillment_monthly_inventory_data.json | 29 +++ ...talog_get_fba_inventory_planning_data.json | 85 ++++++++ ...t_fba_myi_unsuppressed_inventory_data.json | 41 ++++ ...red_catalog_get_fba_sns_forecast_data.json | 40 ++++ ..._catalog_get_fba_sns_performance_data.json | 44 ++++ ...le_archived_orders_data_by_order_date.json | 51 +++++ ...flat_file_returns_data_by_return_date.json | 52 +++++ ...d_catalog_get_ledger_detail_view_data.json | 34 ++++ ..._catalog_get_ledger_summary_view_data.json | 41 ++++ ..._get_merchant_cancelled_listings_data.json | 62 ++++++ ...ed_catalog_get_merchant_listings_data.json | 67 ++++++ ...et_merchant_listings_data_back_compat.json | 66 ++++++ ...g_get_merchant_listings_inactive_data.json | 48 +++++ ...log_get_merchants_listings_fyp_report.json | 28 +++ ...atalog_get_stranded_inventory_ui_data.json | 38 ++++ ...all_orders_data_by_order_date_general.json | 74 +++++++ .../integration_tests/sample_state.json | 66 ++++++ ...AZON_FULFILLED_SHIPMENTS_DATA_GENERAL.json | 192 +++++------------- .../GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA.json | 48 +++++ ...BA_FULFILLMENT_CURRENT_INVENTORY_DATA.json | 16 ++ ...MENT_CUSTOMER_SHIPMENT_PROMOTION_DATA.json | 17 ++ ...ULFILLMENT_INVENTORY_ADJUSTMENTS_DATA.json | 19 ++ ...A_FULFILLMENT_INVENTORY_RECEIPTS_DATA.json | 15 ++ ...BA_FULFILLMENT_INVENTORY_SUMMARY_DATA.json | 16 ++ ...BA_FULFILLMENT_MONTHLY_INVENTORY_DATA.json | 17 ++ .../GET_FBA_INVENTORY_PLANNING_DATA.json | 73 +++++++ ...T_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA.json | 29 +++ .../schemas/GET_FBA_SNS_FORECAST_DATA.json | 26 +++ .../schemas/GET_FBA_SNS_PERFORMANCE_DATA.json | 32 +++ ...LE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE.json | 39 ++++ ...FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE.json | 40 ++++ .../schemas/GET_LEDGER_DETAIL_VIEW_DATA.json | 22 ++ .../schemas/GET_LEDGER_SUMMARY_VIEW_DATA.json | 29 +++ .../GET_MERCHANTS_LISTINGS_FYP_REPORT.json | 16 ++ .../GET_MERCHANT_CANCELLED_LISTINGS_DATA.json | 50 +++++ .../schemas/GET_MERCHANT_LISTINGS_DATA.json | 55 +++++ ...ET_MERCHANT_LISTINGS_DATA_BACK_COMPAT.json | 54 +++++ .../GET_MERCHANT_LISTINGS_INACTIVE_DATA.json | 36 ++++ .../GET_STRANDED_INVENTORY_UI_DATA.json | 26 +++ ...ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL.json | 62 ++++++ .../source_amazon_seller_partner/source.py | 44 ++++ .../source_amazon_seller_partner/streams.py | 165 ++++++++++++++- .../sources/amazon-seller-partner.md | 23 +++ 53 files changed, 2143 insertions(+), 153 deletions(-) create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_estimated_fba_fees_txt_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_current_inventory_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_customer_shipment_promotion_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_adjustments_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_receipts_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_summary_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_monthly_inventory_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_inventory_planning_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_myi_unsuppressed_inventory_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_sns_forecast_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_sns_performance_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_flat_file_archived_orders_data_by_order_date.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_flat_file_returns_data_by_return_date.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_ledger_detail_view_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_ledger_summary_view_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_cancelled_listings_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_data_back_compat.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_inactive_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchants_listings_fyp_report.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_stranded_inventory_ui_data.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_xml_all_orders_data_by_order_date_general.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_CURRENT_INVENTORY_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_SUMMARY_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_MONTHLY_INVENTORY_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_INVENTORY_PLANNING_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_SNS_FORECAST_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_SNS_PERFORMANCE_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_LEDGER_DETAIL_VIEW_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_LEDGER_SUMMARY_VIEW_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANTS_LISTINGS_FYP_REPORT.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_CANCELLED_LISTINGS_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_DATA_BACK_COMPAT.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_INACTIVE_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_STRANDED_INVENTORY_UI_DATA.json create mode 100644 airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL.json diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index 2b53633ed09f..2f15b5bec0a3 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -55,7 +55,7 @@ - name: Amazon Seller Partner sourceDefinitionId: e55879a8-0ef8-4557-abcf-ab34c53ec460 dockerRepository: airbyte/source-amazon-seller-partner - dockerImageTag: 0.2.27 + dockerImageTag: 0.2.28 sourceType: api documentationUrl: https://docs.airbyte.com/integrations/sources/amazon-seller-partner icon: amazonsellerpartner.svg diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 7edad5248d6d..b4caf4cc9ec7 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -863,7 +863,7 @@ type: "string" path_in_connector_config: - "client_secret" -- dockerImage: "airbyte/source-amazon-seller-partner:0.2.27" +- dockerImage: "airbyte/source-amazon-seller-partner:0.2.28" spec: documentationUrl: "https://docs.airbyte.com/integrations/sources/amazon-seller-partner" changelogUrl: "https://docs.airbyte.com/integrations/sources/amazon-seller-partner" diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/Dockerfile b/airbyte-integrations/connectors/source-amazon-seller-partner/Dockerfile index e7b4197565c6..1f02d51d84eb 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/Dockerfile +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/Dockerfile @@ -12,5 +12,5 @@ RUN pip install . ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.2.27 +LABEL io.airbyte.version=0.2.28 LABEL io.airbyte.name=airbyte/source-amazon-seller-partner diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/acceptance-test-config.yml b/airbyte-integrations/connectors/source-amazon-seller-partner/acceptance-test-config.yml index 13530f0ade72..135f5de1a6b4 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/acceptance-test-config.yml +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/acceptance-test-config.yml @@ -2,8 +2,6 @@ connector_image: airbyte/source-amazon-seller-partner:dev tests: spec: - spec_path: "integration_tests/spec.json" - backward_compatibility_tests_config: - disable_for_version: "0.2.26" connection: # - config_path: "secrets/config.json" # status: "succeed" @@ -13,8 +11,6 @@ tests: timeout_seconds: 60 discovery: - config_path: "secrets/config.json" - backward_compatibility_tests_config: - disable_for_version: "0.2.26" # TODO: uncomment when at least one record exist # basic_read: # - config_path: "secrets/config.json" @@ -30,7 +26,7 @@ tests: # "GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA", # "GET_FBA_FULFILLMENT_REMOVAL_SHIPMENT_DETAIL_DATA", # "GET_VENDOR_INVENTORY_HEALTH_AND_PLANNING_REPORT", -# "VendorDirectFulfillmentShipping", +# "VendorDirectFulfillmentShipping" # ] # - config_path: "secrets/config.json" # configured_catalog_path: "integration_tests/configured_catalog_brand_analytics_alternate_purchase.json" @@ -48,6 +44,50 @@ tests: # configured_catalog_path: "integration_tests/configured_catalog_browse_tree_data.json" # - config_path: "secrets/config.json" # configured_catalog_path: "integration_tests/configured_catalog_restock_inventory.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_estimated_fba_fees_txt_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_fulfillment_current_inventory_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_fulfillment_customer_shipment_promotion_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_fulfillment_inventory_adjustments_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_fulfillment_inventory_receipts_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_fulfillment_inventory_summary_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_fulfillment_monthly_inventory_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_myi_unsuppressed_inventory_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_sns_forecast_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_sns_performance_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_flat_file_archived_orders_data_by_order_date.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_flat_file_returns_data_by_return_date.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_merchant_cancelled_listings_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_merchant_listings_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_merchant_listings_data_back_compat.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_merchants_listings_fyp_report.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_merchant_listings_inactive_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_stranded_inventory_ui_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_xml_all_orders_data_by_order_date_general.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_ledger_detail_view_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_fba_inventory_planning_data.json" +# - config_path: "secrets/config.json" +# configured_catalog_path: "integration_tests/configured_catalog_get_ledger_summary_view_data.json" # TODO: uncomment when Orders (or any other incremental) stream is filled with data # incremental: # - config_path: "secrets/config.json" diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_estimated_fba_fees_txt_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_estimated_fba_fees_txt_data.json new file mode 100644 index 000000000000..9759ed3af1e2 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_estimated_fba_fees_txt_data.json @@ -0,0 +1,70 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA", + "json_schema": { + "title": "FBA Fee Preview Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "product-group": { "type": ["null", "string"] }, + "brand": { "type": ["null", "string"] }, + "fulfilled-by": { "type": ["null", "string"] }, + "your-price": { "type": ["null", "string"] }, + "sales-price": { "type": ["null", "string"] }, + "longest-side": { "type": ["null", "string"] }, + "median-side": { "type": ["null", "string"] }, + "shortest-side": { "type": ["null", "string"] }, + "length-and-girth": { "type": ["null", "string"] }, + "unit-of-dimension": { "type": ["null", "string"] }, + "item-package-weight": { "type": ["null", "string"] }, + "unit-of-weight": { "type": ["null", "string"] }, + "product-size-tier": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "estimated-fee-total": { "type": ["null", "string"] }, + "estimated-referral-fee-per-unit": { "type": ["null", "string"] }, + "estimated-variable-closing-fee": { "type": ["null", "string"] }, + "estimated-order-handling-fee-per-order": { + "type": ["null", "string"] + }, + "estimated-pick-pack-fee-per-unit": { "type": ["null", "string"] }, + "estimated-weight-handling-fee-per-unit": { + "type": ["null", "string"] + }, + "expected-fulfillment-fee-per-unit": { "type": ["null", "string"] }, + "estimated-future-fee (Current Selling on Amazon + Future Fulfillment fees)": { + "type": ["null", "string"] + }, + "estimated-future-order-handling-fee-per-order": { + "type": ["null", "string"] + }, + "estimated-future-pick-pack-fee-per-unit": { + "type": ["null", "string"] + }, + "estimated-future-weight-handling-fee-per-unit": { + "type": ["null", "string"] + }, + "expected-future-fulfillment-fee-per-unit": { + "type": ["null", "string"] + }, + "estimated-future-referral-fee-per-unit": { + "type": ["null", "string"] + }, + "current-fee-category": { "type": ["null", "string"] }, + "future-fee-category": { "type": ["null", "string"] }, + "future-fee-category-effective-date": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_current_inventory_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_current_inventory_data.json new file mode 100644 index 000000000000..376c90214355 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_current_inventory_data.json @@ -0,0 +1,28 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_FULFILLMENT_CURRENT_INVENTORY_DATA", + "json_schema": { + "title": "FBA Daily Inventory History Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "snapshot-date": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] }, + "detailed-disposition": { "type": ["null", "string"] }, + "country": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_customer_shipment_promotion_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_customer_shipment_promotion_data.json new file mode 100644 index 000000000000..4d641e80e1fe --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_customer_shipment_promotion_data.json @@ -0,0 +1,29 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA", + "json_schema": { + "title": "FBA Promotions Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "shipment-date": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "item-promotion-discount": { "type": ["null", "string"] }, + "item-promotion-id": { "type": ["null", "string"] }, + "description": { "type": ["null", "string"] }, + "promotion-rule-value": { "type": ["null", "string"] }, + "amazon-order-id": { "type": ["null", "string"] }, + "shipment-id": { "type": ["null", "string"] }, + "shipment-item-id": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_adjustments_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_adjustments_data.json new file mode 100644 index 000000000000..eb241d9e7e3e --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_adjustments_data.json @@ -0,0 +1,31 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA", + "json_schema": { + "title": "FBA Inventory Adjustments Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "adjusted-date": { "type": ["null", "string"] }, + "transaction-item-id": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "reason": { "type": ["null", "string"] }, + "disposition": { "type": ["null", "string"] }, + "reconciled": { "type": ["null", "string"] }, + "unreconciled": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_receipts_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_receipts_data.json new file mode 100644 index 000000000000..92575cfb052e --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_receipts_data.json @@ -0,0 +1,27 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA", + "json_schema": { + "title": "FBA Received Inventory Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "received-date": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "fba-shipment-id": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_summary_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_summary_data.json new file mode 100644 index 000000000000..b38e9b2849ef --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_inventory_summary_data.json @@ -0,0 +1,28 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_FULFILLMENT_INVENTORY_SUMMARY_DATA", + "json_schema": { + "title": "FBA Inventory Event Detail Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "snapshot-date": { "type": ["null", "string"] }, + "transaction-type": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "disposition": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_monthly_inventory_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_monthly_inventory_data.json new file mode 100644 index 000000000000..c695f887c910 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_fulfillment_monthly_inventory_data.json @@ -0,0 +1,29 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_FULFILLMENT_MONTHLY_INVENTORY_DATA", + "json_schema": { + "title": "FBA Monthly Inventory History Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "month": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "average-quantity": { "type": ["null", "string"] }, + "end-quantity": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] }, + "detailed-disposition": { "type": ["null", "string"] }, + "country": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_inventory_planning_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_inventory_planning_data.json new file mode 100644 index 000000000000..c1f82a2c7b7f --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_inventory_planning_data.json @@ -0,0 +1,85 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_INVENTORY_PLANNING_DATA", + "json_schema": { + "title": "FBA Manage Inventory Health Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "snapshot-date": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "condition": { "type": ["null", "string"] }, + "available": { "type": ["null", "string"] }, + "pending-removal-quantity": { "type": ["null", "string"] }, + "inv-age-0-to-90-days": { "type": ["null", "string"] }, + "inv-age-91-to-180-days": { "type": ["null", "string"] }, + "inv-age-181-to-270-days": { "type": ["null", "string"] }, + "inv-age-271-to-365-days": { "type": ["null", "string"] }, + "inv-age-365-plus-days": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "qty-to-be-charged-ltsf-9-mo": { "type": ["null", "string"] }, + "projected-ltsf-9-mo": { "type": ["null", "string"] }, + "qty-to-be-charged-ltsf-12-mo": { "type": ["null", "string"] }, + "estimated-ltsf-next-charge": { "type": ["null", "string"] }, + "units-shipped-t7": { "type": ["null", "string"] }, + "units-shipped-t30": { "type": ["null", "string"] }, + "units-shipped-t60": { "type": ["null", "string"] }, + "units-shipped-t90": { "type": ["null", "string"] }, + "alert": { "type": ["null", "string"] }, + "your-price": { "type": ["null", "string"] }, + "sales-price": { "type": ["null", "string"] }, + "lowest-price-new-plus-shipping": { "type": ["null", "string"] }, + "lowest-price-used": { "type": ["null", "string"] }, + "recommended-action": { "type": ["null", "string"] }, + "healthy-inventory-level": { "type": ["null", "string"] }, + "recommended-sales-price": { "type": ["null", "string"] }, + "recommended-sale-duration-days": { "type": ["null", "string"] }, + "recommended-removal-quantity": { "type": ["null", "string"] }, + "estimated-cost-savings-of-recommended-actions": { + "type": ["null", "string"] + }, + "sell-through": { "type": ["null", "string"] }, + "item-volume": { "type": ["null", "string"] }, + "volume-unit-measurement": { "type": ["null", "string"] }, + "storage-type": { "type": ["null", "string"] }, + "storage-volume": { "type": ["null", "string"] }, + "marketplace": { "type": ["null", "string"] }, + "product-group": { "type": ["null", "string"] }, + "sales-rank": { "type": ["null", "string"] }, + "days-of-supply": { "type": ["null", "string"] }, + "estimated-excess-quantity": { "type": ["null", "string"] }, + "weeks-of-cover-t30": { "type": ["null", "string"] }, + "weeks-of-cover-t90": { "type": ["null", "string"] }, + "featuredoffer-price": { "type": ["null", "string"] }, + "sales-shipped-last-7-days": { "type": ["null", "string"] }, + "sales-shipped-last-30-days": { "type": ["null", "string"] }, + "sales-shipped-last-60-days": { "type": ["null", "string"] }, + "sales-shipped-last-90-days": { "type": ["null", "string"] }, + "inv-age-0-to-30-days": { "type": ["null", "string"] }, + "inv-age-31-to-60-days": { "type": ["null", "string"] }, + "inv-age-61-to-90-days": { "type": ["null", "string"] }, + "inv-age-181-to-330-days": { "type": ["null", "string"] }, + "inv-age-331-to-365-days": { "type": ["null", "string"] }, + "estimated-storage-cost-next-month": { "type": ["null", "string"] }, + "inbound-quantity": { "type": ["null", "string"] }, + "inbound-working": { "type": ["null", "string"] }, + "inbound-shipped": { "type": ["null", "string"] }, + "inbound-received": { "type": ["null", "string"] }, + "no-sale-last-6-months": { "type": ["null", "string"] }, + "reserved-quantity": { "type": ["null", "string"] }, + "unfulfillable-quantity": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_myi_unsuppressed_inventory_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_myi_unsuppressed_inventory_data.json new file mode 100644 index 000000000000..ec3bb01ef5b4 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_myi_unsuppressed_inventory_data.json @@ -0,0 +1,41 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA", + "json_schema": { + "title": "FBA Manage Inventory", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "condition": { "type": ["null", "string"] }, + "your-price": { "type": ["null", "string"] }, + "mfn-listing-exists": { "type": ["null", "string"] }, + "mfn-fulfillable-quantity": { "type": ["null", "string"] }, + "afn-listing-exists": { "type": ["null", "string"] }, + "afn-warehouse-quantity": { "type": ["null", "string"] }, + "afn-fulfillable-quantity": { "type": ["null", "string"] }, + "afn-unsellable-quantity": { "type": ["null", "string"] }, + "afn-reserved-quantity": { "type": ["null", "string"] }, + "afn-total-quantity": { "type": ["null", "string"] }, + "per-unit-volume": { "type": ["null", "string"] }, + "afn-inbound-working-quantity": { "type": ["null", "string"] }, + "afn-inbound-shipped-quantity": { "type": ["null", "string"] }, + "afn-inbound-receiving-quantity": { "type": ["null", "string"] }, + "afn-researching-quantity": { "type": ["null", "string"] }, + "afn-reserved-future-supply": { "type": ["null", "string"] }, + "afn-future-supply-buyable": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_sns_forecast_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_sns_forecast_data.json new file mode 100644 index 000000000000..4a447e44ae41 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_sns_forecast_data.json @@ -0,0 +1,40 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_SNS_FORECAST_DATA", + "json_schema": { + "title": "Subscribe and Save Forecast Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "offer-state": { "type": ["null", "string"] }, + "snapshot-date": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "estimated-avg-sns-discount-next-8-weeks": { + "type": ["null", "string"] + }, + "product-name": { "type": ["null", "string"] }, + "country": { "type": ["null", "string"] }, + "active-subscriptions": { "type": ["null", "string"] }, + "week-1-start-date": { "type": ["null", "string"] }, + "scheduled-sns-units-week-1": { "type": ["null", "string"] }, + "scheduled-sns-units-week-2": { "type": ["null", "string"] }, + "scheduled-sns-units-week-3": { "type": ["null", "string"] }, + "scheduled-sns-units-week-4": { "type": ["null", "string"] }, + "scheduled-sns-units-week-5": { "type": ["null", "string"] }, + "scheduled-sns-units-week-6": { "type": ["null", "string"] }, + "scheduled-sns-units-week-7": { "type": ["null", "string"] }, + "scheduled-sns-units-week-8": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_sns_performance_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_sns_performance_data.json new file mode 100644 index 000000000000..42072661c95a --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_fba_sns_performance_data.json @@ -0,0 +1,44 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FBA_SNS_PERFORMANCE_DATA", + "json_schema": { + "title": "Subscribe and Save Performance Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "offer-state": { "type": ["null", "string"] }, + "snapshot-date": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "country": { "type": ["null", "string"] }, + "week-1-start-date": { "type": ["null", "string"] }, + "sns-units-shipped-week-1": { "type": ["null", "string"] }, + "oos-rate-week-1": { "type": ["null", "string"] }, + "sns-sale-price-week-1": { "type": ["null", "string"] }, + "sns-discount-week-1": { "type": ["null", "string"] }, + "sns-units-shipped-week-2": { "type": ["null", "string"] }, + "oos-rate-week-2": { "type": ["null", "string"] }, + "sns-sale-price-week-2": { "type": ["null", "string"] }, + "sns-discount-week-2": { "type": ["null", "string"] }, + "sns-units-shipped-week-3": { "type": ["null", "string"] }, + "oos-rate-week-3": { "type": ["null", "string"] }, + "sns-sale-price-week-3": { "type": ["null", "string"] }, + "sns-discount-week-3": { "type": ["null", "string"] }, + "sns-units-shipped-week-4": { "type": ["null", "string"] }, + "oos-rate-week-4": { "type": ["null", "string"] }, + "sns-sale-price-week-4": { "type": ["null", "string"] }, + "sns-discount-week-4": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_flat_file_archived_orders_data_by_order_date.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_flat_file_archived_orders_data_by_order_date.json new file mode 100644 index 000000000000..a1e6825b8fc6 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_flat_file_archived_orders_data_by_order_date.json @@ -0,0 +1,51 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE", + "json_schema": { + "title": "Flat File Archived Orders Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "amazon-order-id": { "type": ["null", "string"] }, + "merchant-order-id": { "type": ["null", "string"] }, + "purchase-date": { "type": ["null", "string"] }, + "last-updated-date": { "type": ["null", "string"] }, + "order-status": { "type": ["null", "string"] }, + "fulfillment-channel": { "type": ["null", "string"] }, + "sales-channel": { "type": ["null", "string"] }, + "order-channel": { "type": ["null", "string"] }, + "url": { "type": ["null", "string"] }, + "ship-service-level": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "item-status": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "item-price": { "type": ["null", "string"] }, + "item-tax": { "type": ["null", "string"] }, + "shipping-price": { "type": ["null", "string"] }, + "shipping-tax": { "type": ["null", "string"] }, + "gift-wrap-price": { "type": ["null", "string"] }, + "gift-wrap-tax": { "type": ["null", "string"] }, + "item-promotion-discount": { "type": ["null", "string"] }, + "ship-promotion-discount": { "type": ["null", "string"] }, + "ship-country": { "type": ["null", "string"] }, + "ship-promotion-id": { "type": ["null", "string"] }, + "promotion-ids": { "type": ["null", "string"] }, + "is-business-order": { "type": ["null", "string"] }, + "purchase-order-number": { "type": ["null", "string"] }, + "price-designation": { "type": ["null", "string"] }, + "is-replacement-order": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_flat_file_returns_data_by_return_date.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_flat_file_returns_data_by_return_date.json new file mode 100644 index 000000000000..d9a25080a0a9 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_flat_file_returns_data_by_return_date.json @@ -0,0 +1,52 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE", + "json_schema": { + "title": "Flat File Returns Report by Return Date", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "Order ID": { "type": ["null", "string"] }, + "Order date": { "type": ["null", "string"] }, + "Return request date": { "type": ["null", "string"] }, + "Return request status": { "type": ["null", "string"] }, + "Amazon RMA ID": { "type": ["null", "string"] }, + "Merchant RMA ID": { "type": ["null", "string"] }, + "Label type": { "type": ["null", "string"] }, + "Label cost": { "type": ["null", "string"] }, + "Currency code": { "type": ["null", "string"] }, + "Return carrier": { "type": ["null", "string"] }, + "Tracking ID": { "type": ["null", "string"] }, + "Label to be paid by": { "type": ["null", "string"] }, + "A-to-Z Claim": { "type": ["null", "string"] }, + "Is prime": { "type": ["null", "string"] }, + "ASIN": { "type": ["null", "string"] }, + "Merchant SKU": { "type": ["null", "string"] }, + "Item Name": { "type": ["null", "string"] }, + "Return quantity": { "type": ["null", "string"] }, + "Return Reason": { "type": ["null", "string"] }, + "In policy": { "type": ["null", "string"] }, + "Return type": { "type": ["null", "string"] }, + "Resolution": { "type": ["null", "string"] }, + "Invoice number": { "type": ["null", "string"] }, + "Return delivery date": { "type": ["null", "string"] }, + "Order Amount": { "type": ["null", "string"] }, + "Order quantity": { "type": ["null", "string"] }, + "SafeT Action reason": { "type": ["null", "string"] }, + "SafeT claim id": { "type": ["null", "string"] }, + "SafeT claim state": { "type": ["null", "string"] }, + "SafeT claim creation time": { "type": ["null", "string"] }, + "SafeT claim reimbursement amount": { "type": ["null", "string"] }, + "Refunded Amount": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_ledger_detail_view_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_ledger_detail_view_data.json new file mode 100644 index 000000000000..deb52a3a1bca --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_ledger_detail_view_data.json @@ -0,0 +1,34 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_LEDGER_DETAIL_VIEW_DATA", + "json_schema": { + "title": "Inventory Ledger Report - Detailed View", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "Date": { "type": ["null", "string"], "format": "date" }, + "FNSKU": { "type": ["null", "string"] }, + "ASIN": { "type": ["null", "string"] }, + "MSKU": { "type": ["null", "string"] }, + "Title": { "type": ["null", "string"] }, + "Event Type": { "type": ["null", "string"] }, + "Reference ID": { "type": ["null", "string"] }, + "Quantity": { "type": ["null", "string"] }, + "Fulfillment Center": { "type": ["null", "string"] }, + "Disposition": { "type": ["null", "string"] }, + "Reason": { "type": ["null", "string"] }, + "Country": { "type": ["null", "string"] }, + "Reconciled Quantity": { "type": ["null", "string"] }, + "Unreconciled Quantity": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_ledger_summary_view_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_ledger_summary_view_data.json new file mode 100644 index 000000000000..7b398f5a1562 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_ledger_summary_view_data.json @@ -0,0 +1,41 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_LEDGER_SUMMARY_VIEW_DATA", + "json_schema": { + "title": "Inventory Ledger Report - Summary View", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "Date": { "type": ["null", "string"] }, + "FNSKU": { "type": ["null", "string"] }, + "ASIN": { "type": ["null", "string"] }, + "MSKU": { "type": ["null", "string"] }, + "Title": { "type": ["null", "string"] }, + "Disposition": { "type": ["null", "string"] }, + "Starting Warehouse Balance": { "type": ["null", "string"] }, + "In Transit Between Warehouses": { "type": ["null", "string"] }, + "Receipts": { "type": ["null", "string"] }, + "Customer Shipments": { "type": ["null", "string"] }, + "Customer Returns": { "type": ["null", "string"] }, + "Vendor Returns": { "type": ["null", "string"] }, + "Warehouse Transfer In/Out": { "type": ["null", "string"] }, + "Found": { "type": ["null", "string"] }, + "Lost": { "type": ["null", "string"] }, + "Damaged": { "type": ["null", "string"] }, + "Disposed": { "type": ["null", "string"] }, + "Other Events": { "type": ["null", "string"] }, + "Ending Warehouse Balance": { "type": ["null", "string"] }, + "Unknown Events": { "type": ["null", "string"] }, + "Location": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_cancelled_listings_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_cancelled_listings_data.json new file mode 100644 index 000000000000..43cbf999744d --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_cancelled_listings_data.json @@ -0,0 +1,62 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_MERCHANT_CANCELLED_LISTINGS_DATA", + "json_schema": { + "title": "Canceled Listings Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "item-name": { "type": ["null", "string"] }, + "item-description": { "type": ["null", "string"] }, + "seller-sku": { "type": ["null", "string"] }, + "price": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "image-url": { "type": ["null", "string"] }, + "item-is-marketplace": { "type": ["null", "string"] }, + "product-id-type": { "type": ["null", "string"] }, + "zshop-shipping-fee": { "type": ["null", "string"] }, + "item-note": { "type": ["null", "string"] }, + "item-condition": { "type": ["null", "string"] }, + "zshop-category1": { "type": ["null", "string"] }, + "zshop-browse-path": { "type": ["null", "string"] }, + "zshop-storefront-feature": { "type": ["null", "string"] }, + "asin1": { "type": ["null", "string"] }, + "asin2": { "type": ["null", "string"] }, + "asin3": { "type": ["null", "string"] }, + "will-ship-internationally": { "type": ["null", "string"] }, + "expedited-shipping": { "type": ["null", "string"] }, + "zshop-boldface": { "type": ["null", "string"] }, + "product-id": { "type": ["null", "string"] }, + "add-delete": { "type": ["null", "string"] }, + "Business Price": { "type": ["null", "string"] }, + "Quantity Price Type": { "type": ["null", "string"] }, + "Quantity Lower Bound 1": { "type": ["null", "string"] }, + "Quantity Price 1": { "type": ["null", "string"] }, + "Quantity Lower Bound 2": { "type": ["null", "string"] }, + "Quantity Price 2": { "type": ["null", "string"] }, + "Quantity Lower Bound 3": { "type": ["null", "string"] }, + "Quantity Price 3": { "type": ["null", "string"] }, + "Quantity Lower Bound 4": { "type": ["null", "string"] }, + "Quantity Price 4": { "type": ["null", "string"] }, + "Quantity Lower Bound 5": { "type": ["null", "string"] }, + "Quantity Price 5": { "type": ["null", "string"] }, + "merchant-shipping-group": { "type": ["null", "string"] }, + "Progressive Price Type": { "type": ["null", "string"] }, + "Progressive Lower Bound 1": { "type": ["null", "string"] }, + "Progressive Price 1": { "type": ["null", "string"] }, + "Progressive Lower Bound 2": { "type": ["null", "string"] }, + "Progressive Price 2": { "type": ["null", "string"] }, + "Progressive Lower Bound 3": { "type": ["null", "string"] }, + "Progressive Price 3": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_data.json new file mode 100644 index 000000000000..51425d42aaa7 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_data.json @@ -0,0 +1,67 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_MERCHANT_LISTINGS_DATA", + "json_schema": { + "title": "Active Listings Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "item-name": { "type": ["null", "string"] }, + "item-description": { "type": ["null", "string"] }, + "listing-id": { "type": ["null", "string"] }, + "seller-sku": { "type": ["null", "string"] }, + "price": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "open-date": { "type": ["null", "string"] }, + "image-url": { "type": ["null", "string"] }, + "item-is-marketplace": { "type": ["null", "string"] }, + "product-id-type": { "type": ["null", "string"] }, + "zshop-shipping-fee": { "type": ["null", "string"] }, + "item-note": { "type": ["null", "string"] }, + "item-condition": { "type": ["null", "string"] }, + "zshop-category1": { "type": ["null", "string"] }, + "zshop-browse-path": { "type": ["null", "string"] }, + "zshop-storefront-feature": { "type": ["null", "string"] }, + "asin1": { "type": ["null", "string"] }, + "asin2": { "type": ["null", "string"] }, + "asin3": { "type": ["null", "string"] }, + "will-ship-internationally": { "type": ["null", "string"] }, + "expedited-shipping": { "type": ["null", "string"] }, + "zshop-boldface": { "type": ["null", "string"] }, + "product-id": { "type": ["null", "string"] }, + "bid-for-featured-placement": { "type": ["null", "string"] }, + "add-delete": { "type": ["null", "string"] }, + "pending-quantity": { "type": ["null", "string"] }, + "fulfillment-channel": { "type": ["null", "string"] }, + "Business Price": { "type": ["null", "string"] }, + "Quantity Price Type": { "type": ["null", "string"] }, + "Quantity Lower Bound 1": { "type": ["null", "string"] }, + "Quantity Price 1": { "type": ["null", "string"] }, + "Quantity Lower Bound 2": { "type": ["null", "string"] }, + "Quantity Price 2": { "type": ["null", "string"] }, + "Quantity Lower Bound 3": { "type": ["null", "string"] }, + "Quantity Price 3": { "type": ["null", "string"] }, + "Quantity Lower Bound 4": { "type": ["null", "string"] }, + "Quantity Price 4": { "type": ["null", "string"] }, + "Quantity Lower Bound 5": { "type": ["null", "string"] }, + "Quantity Price 5": { "type": ["null", "string"] }, + "merchant-shipping-group": { "type": ["null", "string"] }, + "Progressive Price Type": { "type": ["null", "string"] }, + "Progressive Lower Bound 1": { "type": ["null", "string"] }, + "Progressive Price 1": { "type": ["null", "string"] }, + "Progressive Lower Bound 2": { "type": ["null", "string"] }, + "Progressive Price 2": { "type": ["null", "string"] }, + "Progressive Lower Bound 3": { "type": ["null", "string"] }, + "Progressive Price 3": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_data_back_compat.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_data_back_compat.json new file mode 100644 index 000000000000..cc2501e6e348 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_data_back_compat.json @@ -0,0 +1,66 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_MERCHANT_LISTINGS_DATA_BACK_COMPAT", + "json_schema": { + "title": "Open Listings Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "item-name": { "type": ["null", "string"] }, + "item-description": { "type": ["null", "string"] }, + "listing-id": { "type": ["null", "string"] }, + "seller-sku": { "type": ["null", "string"] }, + "price": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "open-date": { "type": ["null", "string"] }, + "image-url": { "type": ["null", "string"] }, + "item-is-marketplace": { "type": ["null", "string"] }, + "product-id-type": { "type": ["null", "string"] }, + "zshop-shipping-fee": { "type": ["null", "string"] }, + "item-note": { "type": ["null", "string"] }, + "item-condition": { "type": ["null", "string"] }, + "zshop-category1": { "type": ["null", "string"] }, + "zshop-browse-path": { "type": ["null", "string"] }, + "zshop-storefront-feature": { "type": ["null", "string"] }, + "asin1": { "type": ["null", "string"] }, + "asin2": { "type": ["null", "string"] }, + "asin3": { "type": ["null", "string"] }, + "will-ship-internationally": { "type": ["null", "string"] }, + "expedited-shipping": { "type": ["null", "string"] }, + "zshop-boldface": { "type": ["null", "string"] }, + "product-id": { "type": ["null", "string"] }, + "bid-for-featured-placement": { "type": ["null", "string"] }, + "add-delete": { "type": ["null", "string"] }, + "pending-quantity": { "type": ["null", "string"] }, + "Business Price": { "type": ["null", "string"] }, + "Quantity Price Type": { "type": ["null", "string"] }, + "Quantity Lower Bound 1": { "type": ["null", "string"] }, + "Quantity Price 1": { "type": ["null", "string"] }, + "Quantity Lower Bound 2": { "type": ["null", "string"] }, + "Quantity Price 2": { "type": ["null", "string"] }, + "Quantity Lower Bound 3": { "type": ["null", "string"] }, + "Quantity Price 3": { "type": ["null", "string"] }, + "Quantity Lower Bound 4": { "type": ["null", "string"] }, + "Quantity Price 4": { "type": ["null", "string"] }, + "Quantity Lower Bound 5": { "type": ["null", "string"] }, + "Quantity Price 5": { "type": ["null", "string"] }, + "merchant-shipping-group": { "type": ["null", "string"] }, + "Progressive Price Type": { "type": ["null", "string"] }, + "Progressive Lower Bound 1": { "type": ["null", "string"] }, + "Progressive Price 1": { "type": ["null", "string"] }, + "Progressive Lower Bound 2": { "type": ["null", "string"] }, + "Progressive Price 2": { "type": ["null", "string"] }, + "Progressive Lower Bound 3": { "type": ["null", "string"] }, + "Progressive Price 3": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_inactive_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_inactive_data.json new file mode 100644 index 000000000000..4b6d2285408b --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchant_listings_inactive_data.json @@ -0,0 +1,48 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_MERCHANT_LISTINGS_INACTIVE_DATA", + "json_schema": { + "title": "Inactive Listings Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "item-name": { "type": ["null", "string"] }, + "item-description": { "type": ["null", "string"] }, + "listing-id": { "type": ["null", "string"] }, + "seller-sku": { "type": ["null", "string"] }, + "price": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "open-date": { "type": ["null", "string"] }, + "image-url": { "type": ["null", "string"] }, + "item-is-marketplace": { "type": ["null", "string"] }, + "product-id-type": { "type": ["null", "string"] }, + "zshop-shipping-fee": { "type": ["null", "string"] }, + "item-note": { "type": ["null", "string"] }, + "item-condition": { "type": ["null", "string"] }, + "zshop-category1": { "type": ["null", "string"] }, + "zshop-browse-path": { "type": ["null", "string"] }, + "zshop-storefront-feature": { "type": ["null", "string"] }, + "asin1": { "type": ["null", "string"] }, + "asin2": { "type": ["null", "string"] }, + "asin3": { "type": ["null", "string"] }, + "will-ship-internationally": { "type": ["null", "string"] }, + "expedited-shipping": { "type": ["null", "string"] }, + "zshop-boldface": { "type": ["null", "string"] }, + "product-id": { "type": ["null", "string"] }, + "bid-for-featured-placement": { "type": ["null", "string"] }, + "add-delete": { "type": ["null", "string"] }, + "pending-quantity": { "type": ["null", "string"] }, + "fulfillment-channel": { "type": ["null", "string"] }, + "merchant-shipping-group": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchants_listings_fyp_report.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchants_listings_fyp_report.json new file mode 100644 index 000000000000..499bb0acbe4f --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_merchants_listings_fyp_report.json @@ -0,0 +1,28 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_MERCHANTS_LISTINGS_FYP_REPORT", + "json_schema": { + "title": "Suppressed Listings Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "Status": { "type": ["null", "string"] }, + "Reason": { "type": ["null", "string"] }, + "SKU": { "type": ["null", "string"] }, + "ASIN": { "type": ["null", "string"] }, + "Product name": { "type": ["null", "string"] }, + "Condition": { "type": ["null", "string"] }, + "Status Change Date": { "type": ["null", "string"] }, + "Issue Description": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_stranded_inventory_ui_data.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_stranded_inventory_ui_data.json new file mode 100644 index 000000000000..30862e161d20 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_stranded_inventory_ui_data.json @@ -0,0 +1,38 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_STRANDED_INVENTORY_UI_DATA", + "json_schema": { + "title": "FBA Stranded Inventory Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "primary-action": { "type": ["null", "string"] }, + "date-stranded": { "type": ["null", "string"] }, + "Date-to-take-auto-removal": { "type": ["null", "string"] }, + "status-primary": { "type": ["null", "string"] }, + "status-secondary": { "type": ["null", "string"] }, + "error-message": { "type": ["null", "string"] }, + "stranded-reason": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "condition": { "type": ["null", "string"] }, + "fulfilled-by": { "type": ["null", "string"] }, + "fulfillable-qty": { "type": ["null", "string"] }, + "your-price": { "type": ["null", "string"] }, + "unfulfillable-qty": { "type": ["null", "string"] }, + "reserved-quantity": { "type": ["null", "string"] }, + "inbound-shipped-qty": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_xml_all_orders_data_by_order_date_general.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_xml_all_orders_data_by_order_date_general.json new file mode 100644 index 000000000000..b4c29300ab4e --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/configured_catalog_get_xml_all_orders_data_by_order_date_general.json @@ -0,0 +1,74 @@ +{ + "streams": [ + { + "stream": { + "name": "GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL", + "json_schema": { + "title": "XML Orders By Order Date Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "LastUpdatedDate": { "type": ["null", "string"] }, + "SalesChannel": { "type": ["null", "string"] }, + "OrderStatus": { "type": ["null", "string"] }, + "AmazonOrderID": { "type": ["null", "string"] }, + "PurchaseDate": { "type": ["null", "string"] }, + "OrderItem": { + "type": ["array"], + "items": { "type": ["null", "object"] }, + "properties": { + "ItemStatus": { "type": ["null", "string"] }, + "ProductName": { "type": ["null", "string"] }, + "ItemPrice": { + "type": ["null", "object"], + "properties": { + "Component": { + "type": ["array"], + "items": { "type": ["null", "object"] }, + "properties": { + "Type": { "type": ["null", "string"] }, + "Amount": { + "type": ["null", "object"], + "properties": { + "currency": { "type": ["null", "string"] }, + "value": { "type": ["null", "string"] } + } + } + } + } + } + }, + "ASIN": { "type": ["null", "string"] }, + "Quantity": { "type": ["null", "string"] }, + "AmazonOrderItemCode": { "type": ["null", "string"] }, + "SKU": { "type": ["null", "string"] } + } + }, + "FulfillmentData": { + "type": ["null", "object"], + "properties": { + "Address": { + "type": ["null", "object"], + "properties": { + "State": { "type": ["null", "string"] }, + "PostalCode": { "type": ["null", "string"] }, + "Country": { "type": ["null", "string"] }, + "City": { "type": ["null", "string"] } + } + }, + "ShipServiceLevel": { "type": ["null", "string"] }, + "FulfillmentChannel": { "type": ["null", "string"] } + } + }, + "IsBusinessOrder": { "type": ["null", "string"] }, + "MerchantOrderID": { "type": ["null", "string"] } + } + }, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/sample_state.json b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/sample_state.json index ede2a81ac078..bebd0fa00a49 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/sample_state.json +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/integration_tests/sample_state.json @@ -37,5 +37,71 @@ }, "GET_XML_BROWSE_TREE_DATA": { "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_FULFILLMENT_CURRENT_INVENTORY_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_FULFILLMENT_INVENTORY_SUMMARY_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_FULFILLMENT_MONTHLY_INVENTORY_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_SNS_FORECAST_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_SNS_PERFORMANCE_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_MERCHANT_CANCELLED_LISTINGS_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_MERCHANT_LISTINGS_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_MERCHANT_LISTINGS_DATA_BACK_COMPAT": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_MERCHANTS_LISTINGS_FYP_REPORT": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_MERCHANT_LISTINGS_INACTIVE_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_STRANDED_INVENTORY_UI_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_LEDGER_DETAIL_VIEW_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_FBA_INVENTORY_PLANNING_DATA": { + "createdTime": "2021-07-01T00:00:00Z" + }, + "GET_LEDGER_SUMMARY_VIEW_DATA": { + "createdTime": "2021-07-01T00:00:00Z" } } diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL.json index 214ac2b7c020..d2e8b0e3c036 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL.json +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL.json @@ -4,149 +4,53 @@ "type": "object", "$schema": "http://json-schema.org/draft-07/schema#", "properties": { - "amazon-order-id": { - "type": ["null", "string"] - }, - "merchant-order-id": { - "type": ["null", "string"] - }, - "shipment-id": { - "type": ["null", "string"] - }, - "shipment-item-id": { - "type": ["null", "string"] - }, - "amazon-order-item-id": { - "type": ["null", "string"] - }, - "merchant-order-item-id": { - "type": ["null", "string"] - }, - "purchase-date": { - "type": ["null", "string"] - }, - "payments-date": { - "type": ["null", "string"] - }, - "shipment-date": { - "type": ["null", "string"] - }, - "reporting-date": { - "type": ["null", "string"] - }, - "buyer-email": { - "type": ["null", "string"] - }, - "buyer-name": { - "type": ["null", "string"] - }, - "buyer-phone-number": { - "type": ["null", "string"] - }, - "sku": { - "type": ["null", "string"] - }, - "product-name": { - "type": ["null", "string"] - }, - "quantity-shipped": { - "type": ["null", "string"] - }, - "currency": { - "type": ["null", "string"] - }, - "item-price": { - "type": ["null", "string"] - }, - "item-tax": { - "type": ["null", "string"] - }, - "shipping-price": { - "type": ["null", "string"] - }, - "shipping-tax": { - "type": ["null", "string"] - }, - "gift-wrap-price": { - "type": ["null", "string"] - }, - "gift-wrap-tax": { - "type": ["null", "string"] - }, - "ship-service-level": { - "type": ["null", "string"] - }, - "recipient-name": { - "type": ["null", "string"] - }, - "ship-address-1": { - "type": ["null", "string"] - }, - "ship-address-2": { - "type": ["null", "string"] - }, - "ship-address-3": { - "type": ["null", "string"] - }, - "ship-city": { - "type": ["null", "string"] - }, - "ship-state": { - "type": ["null", "string"] - }, - "ship-postal-code": { - "type": ["null", "string"] - }, - "ship-country": { - "type": ["null", "string"] - }, - "ship-phone-number": { - "type": ["null", "string"] - }, - "bill-address-1": { - "type": ["null", "string"] - }, - "bill-address-2": { - "type": ["null", "string"] - }, - "bill-address-3": { - "type": ["null", "string"] - }, - "bill-city": { - "type": ["null", "string"] - }, - "bill-state": { - "type": ["null", "string"] - }, - "bill-postal-code": { - "type": ["null", "string"] - }, - "bill-country": { - "type": ["null", "string"] - }, - "item-promotion-discount": { - "type": ["null", "string"] - }, - "ship-promotion-discount": { - "type": ["null", "string"] - }, - "carrier": { - "type": ["null", "string"] - }, - "tracking-number": { - "type": ["null", "string"] - }, - "estimated-arrival-date": { - "type": ["null", "string"] - }, - "fulfillment-center-id": { - "type": ["null", "string"] - }, - "fulfillment-channel": { - "type": ["null", "string"] - }, - "sales-channel": { - "type": ["null", "string"] - } + "amazon-order-id": { "type": ["null", "string"] }, + "merchant-order-id": { "type": ["null", "string"] }, + "shipment-id": { "type": ["null", "string"] }, + "shipment-item-id": { "type": ["null", "string"] }, + "amazon-order-item-id": { "type": ["null", "string"] }, + "merchant-order-item-id": { "type": ["null", "string"] }, + "purchase-date": { "type": ["null", "string"] }, + "payments-date": { "type": ["null", "string"] }, + "shipment-date": { "type": ["null", "string"] }, + "reporting-date": { "type": ["null", "string"] }, + "buyer-email": { "type": ["null", "string"] }, + "buyer-name": { "type": ["null", "string"] }, + "buyer-phone-number": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "quantity-shipped": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "item-price": { "type": ["null", "string"] }, + "item-tax": { "type": ["null", "string"] }, + "shipping-price": { "type": ["null", "string"] }, + "shipping-tax": { "type": ["null", "string"] }, + "gift-wrap-price": { "type": ["null", "string"] }, + "gift-wrap-tax": { "type": ["null", "string"] }, + "ship-service-level": { "type": ["null", "string"] }, + "recipient-name": { "type": ["null", "string"] }, + "ship-address-1": { "type": ["null", "string"] }, + "ship-address-2": { "type": ["null", "string"] }, + "ship-address-3": { "type": ["null", "string"] }, + "ship-city": { "type": ["null", "string"] }, + "ship-state": { "type": ["null", "string"] }, + "ship-postal-code": { "type": ["null", "string"] }, + "ship-country": { "type": ["null", "string"] }, + "ship-phone-number": { "type": ["null", "string"] }, + "bill-address-1": { "type": ["null", "string"] }, + "bill-address-2": { "type": ["null", "string"] }, + "bill-address-3": { "type": ["null", "string"] }, + "bill-city": { "type": ["null", "string"] }, + "bill-state": { "type": ["null", "string"] }, + "bill-postal-code": { "type": ["null", "string"] }, + "bill-country": { "type": ["null", "string"] }, + "item-promotion-discount": { "type": ["null", "string"] }, + "ship-promotion-discount": { "type": ["null", "string"] }, + "carrier": { "type": ["null", "string"] }, + "tracking-number": { "type": ["null", "string"] }, + "estimated-arrival-date": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] }, + "fulfillment-channel": { "type": ["null", "string"] }, + "sales-channel": { "type": ["null", "string"] } } } diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA.json new file mode 100644 index 000000000000..af433395dc9f --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA.json @@ -0,0 +1,48 @@ +{ + "title": "FBA Fee Preview Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "product-group": { "type": ["null", "string"] }, + "brand": { "type": ["null", "string"] }, + "fulfilled-by": { "type": ["null", "string"] }, + "your-price": { "type": ["null", "string"] }, + "sales-price": { "type": ["null", "string"] }, + "longest-side": { "type": ["null", "string"] }, + "median-side": { "type": ["null", "string"] }, + "shortest-side": { "type": ["null", "string"] }, + "length-and-girth": { "type": ["null", "string"] }, + "unit-of-dimension": { "type": ["null", "string"] }, + "item-package-weight": { "type": ["null", "string"] }, + "unit-of-weight": { "type": ["null", "string"] }, + "product-size-tier": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "estimated-fee-total": { "type": ["null", "string"] }, + "estimated-referral-fee-per-unit": { "type": ["null", "string"] }, + "estimated-variable-closing-fee": { "type": ["null", "string"] }, + "estimated-order-handling-fee-per-order": { "type": ["null", "string"] }, + "estimated-pick-pack-fee-per-unit": { "type": ["null", "string"] }, + "estimated-weight-handling-fee-per-unit": { "type": ["null", "string"] }, + "expected-fulfillment-fee-per-unit": { "type": ["null", "string"] }, + "estimated-future-fee (Current Selling on Amazon + Future Fulfillment fees)": { + "type": ["null", "string"] + }, + "estimated-future-order-handling-fee-per-order": { + "type": ["null", "string"] + }, + "estimated-future-pick-pack-fee-per-unit": { "type": ["null", "string"] }, + "estimated-future-weight-handling-fee-per-unit": { + "type": ["null", "string"] + }, + "expected-future-fulfillment-fee-per-unit": { "type": ["null", "string"] }, + "estimated-future-referral-fee-per-unit": { "type": ["null", "string"] }, + "current-fee-category": { "type": ["null", "string"] }, + "future-fee-category": { "type": ["null", "string"] }, + "future-fee-category-effective-date": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_CURRENT_INVENTORY_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_CURRENT_INVENTORY_DATA.json new file mode 100644 index 000000000000..401cbf484380 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_CURRENT_INVENTORY_DATA.json @@ -0,0 +1,16 @@ +{ + "title": "FBA Daily Inventory History Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "snapshot-date": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] }, + "detailed-disposition": { "type": ["null", "string"] }, + "country": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA.json new file mode 100644 index 000000000000..610e71ce9ac6 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA.json @@ -0,0 +1,17 @@ +{ + "title": "FBA Promotions Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "shipment-date": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "item-promotion-discount": { "type": ["null", "string"] }, + "item-promotion-id": { "type": ["null", "string"] }, + "description": { "type": ["null", "string"] }, + "promotion-rule-value": { "type": ["null", "string"] }, + "amazon-order-id": { "type": ["null", "string"] }, + "shipment-id": { "type": ["null", "string"] }, + "shipment-item-id": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA.json new file mode 100644 index 000000000000..916f932cc057 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA.json @@ -0,0 +1,19 @@ +{ + "title": "FBA Inventory Adjustments Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "adjusted-date": { "type": ["null", "string"] }, + "transaction-item-id": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "reason": { "type": ["null", "string"] }, + "disposition": { "type": ["null", "string"] }, + "reconciled": { "type": ["null", "string"] }, + "unreconciled": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA.json new file mode 100644 index 000000000000..3d23369d51e1 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA.json @@ -0,0 +1,15 @@ +{ + "title": "FBA Received Inventory Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "received-date": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "fba-shipment-id": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_SUMMARY_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_SUMMARY_DATA.json new file mode 100644 index 000000000000..1ddf4fceca59 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_INVENTORY_SUMMARY_DATA.json @@ -0,0 +1,16 @@ +{ + "title": "FBA Inventory Event Detail Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "snapshot-date": { "type": ["null", "string"] }, + "transaction-type": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "disposition": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_MONTHLY_INVENTORY_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_MONTHLY_INVENTORY_DATA.json new file mode 100644 index 000000000000..796985c5210e --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_FULFILLMENT_MONTHLY_INVENTORY_DATA.json @@ -0,0 +1,17 @@ +{ + "title": "FBA Monthly Inventory History Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "month": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "average-quantity": { "type": ["null", "string"] }, + "end-quantity": { "type": ["null", "string"] }, + "fulfillment-center-id": { "type": ["null", "string"] }, + "detailed-disposition": { "type": ["null", "string"] }, + "country": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_INVENTORY_PLANNING_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_INVENTORY_PLANNING_DATA.json new file mode 100644 index 000000000000..30ead73eab60 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_INVENTORY_PLANNING_DATA.json @@ -0,0 +1,73 @@ +{ + "title": "FBA Manage Inventory Health Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "snapshot-date": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "condition": { "type": ["null", "string"] }, + "available": { "type": ["null", "string"] }, + "pending-removal-quantity": { "type": ["null", "string"] }, + "inv-age-0-to-90-days": { "type": ["null", "string"] }, + "inv-age-91-to-180-days": { "type": ["null", "string"] }, + "inv-age-181-to-270-days": { "type": ["null", "string"] }, + "inv-age-271-to-365-days": { "type": ["null", "string"] }, + "inv-age-365-plus-days": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "qty-to-be-charged-ltsf-9-mo": { "type": ["null", "string"] }, + "projected-ltsf-9-mo": { "type": ["null", "string"] }, + "qty-to-be-charged-ltsf-12-mo": { "type": ["null", "string"] }, + "estimated-ltsf-next-charge": { "type": ["null", "string"] }, + "units-shipped-t7": { "type": ["null", "string"] }, + "units-shipped-t30": { "type": ["null", "string"] }, + "units-shipped-t60": { "type": ["null", "string"] }, + "units-shipped-t90": { "type": ["null", "string"] }, + "alert": { "type": ["null", "string"] }, + "your-price": { "type": ["null", "string"] }, + "sales-price": { "type": ["null", "string"] }, + "lowest-price-new-plus-shipping": { "type": ["null", "string"] }, + "lowest-price-used": { "type": ["null", "string"] }, + "recommended-action": { "type": ["null", "string"] }, + "healthy-inventory-level": { "type": ["null", "string"] }, + "recommended-sales-price": { "type": ["null", "string"] }, + "recommended-sale-duration-days": { "type": ["null", "string"] }, + "recommended-removal-quantity": { "type": ["null", "string"] }, + "estimated-cost-savings-of-recommended-actions": { + "type": ["null", "string"] + }, + "sell-through": { "type": ["null", "string"] }, + "item-volume": { "type": ["null", "string"] }, + "volume-unit-measurement": { "type": ["null", "string"] }, + "storage-type": { "type": ["null", "string"] }, + "storage-volume": { "type": ["null", "string"] }, + "marketplace": { "type": ["null", "string"] }, + "product-group": { "type": ["null", "string"] }, + "sales-rank": { "type": ["null", "string"] }, + "days-of-supply": { "type": ["null", "string"] }, + "estimated-excess-quantity": { "type": ["null", "string"] }, + "weeks-of-cover-t30": { "type": ["null", "string"] }, + "weeks-of-cover-t90": { "type": ["null", "string"] }, + "featuredoffer-price": { "type": ["null", "string"] }, + "sales-shipped-last-7-days": { "type": ["null", "string"] }, + "sales-shipped-last-30-days": { "type": ["null", "string"] }, + "sales-shipped-last-60-days": { "type": ["null", "string"] }, + "sales-shipped-last-90-days": { "type": ["null", "string"] }, + "inv-age-0-to-30-days": { "type": ["null", "string"] }, + "inv-age-31-to-60-days": { "type": ["null", "string"] }, + "inv-age-61-to-90-days": { "type": ["null", "string"] }, + "inv-age-181-to-330-days": { "type": ["null", "string"] }, + "inv-age-331-to-365-days": { "type": ["null", "string"] }, + "estimated-storage-cost-next-month": { "type": ["null", "string"] }, + "inbound-quantity": { "type": ["null", "string"] }, + "inbound-working": { "type": ["null", "string"] }, + "inbound-shipped": { "type": ["null", "string"] }, + "inbound-received": { "type": ["null", "string"] }, + "no-sale-last-6-months": { "type": ["null", "string"] }, + "reserved-quantity": { "type": ["null", "string"] }, + "unfulfillable-quantity": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA.json new file mode 100644 index 000000000000..77d1c2d6c9f0 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA.json @@ -0,0 +1,29 @@ +{ + "title": "FBA Manage Inventory", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "condition": { "type": ["null", "string"] }, + "your-price": { "type": ["null", "string"] }, + "mfn-listing-exists": { "type": ["null", "string"] }, + "mfn-fulfillable-quantity": { "type": ["null", "string"] }, + "afn-listing-exists": { "type": ["null", "string"] }, + "afn-warehouse-quantity": { "type": ["null", "string"] }, + "afn-fulfillable-quantity": { "type": ["null", "string"] }, + "afn-unsellable-quantity": { "type": ["null", "string"] }, + "afn-reserved-quantity": { "type": ["null", "string"] }, + "afn-total-quantity": { "type": ["null", "string"] }, + "per-unit-volume": { "type": ["null", "string"] }, + "afn-inbound-working-quantity": { "type": ["null", "string"] }, + "afn-inbound-shipped-quantity": { "type": ["null", "string"] }, + "afn-inbound-receiving-quantity": { "type": ["null", "string"] }, + "afn-researching-quantity": { "type": ["null", "string"] }, + "afn-reserved-future-supply": { "type": ["null", "string"] }, + "afn-future-supply-buyable": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_SNS_FORECAST_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_SNS_FORECAST_DATA.json new file mode 100644 index 000000000000..d47ec26a178e --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_SNS_FORECAST_DATA.json @@ -0,0 +1,26 @@ +{ + "title": "Subscribe and Save Forecast Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "offer-state": { "type": ["null", "string"] }, + "snapshot-date": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "estimated-avg-sns-discount-next-8-weeks": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "country": { "type": ["null", "string"] }, + "active-subscriptions": { "type": ["null", "string"] }, + "week-1-start-date": { "type": ["null", "string"] }, + "scheduled-sns-units-week-1": { "type": ["null", "string"] }, + "scheduled-sns-units-week-2": { "type": ["null", "string"] }, + "scheduled-sns-units-week-3": { "type": ["null", "string"] }, + "scheduled-sns-units-week-4": { "type": ["null", "string"] }, + "scheduled-sns-units-week-5": { "type": ["null", "string"] }, + "scheduled-sns-units-week-6": { "type": ["null", "string"] }, + "scheduled-sns-units-week-7": { "type": ["null", "string"] }, + "scheduled-sns-units-week-8": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_SNS_PERFORMANCE_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_SNS_PERFORMANCE_DATA.json new file mode 100644 index 000000000000..16e1010a9387 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FBA_SNS_PERFORMANCE_DATA.json @@ -0,0 +1,32 @@ +{ + "title": "Subscribe and Save Performance Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "offer-state": { "type": ["null", "string"] }, + "snapshot-date": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "country": { "type": ["null", "string"] }, + "week-1-start-date": { "type": ["null", "string"] }, + "sns-units-shipped-week-1": { "type": ["null", "string"] }, + "oos-rate-week-1": { "type": ["null", "string"] }, + "sns-sale-price-week-1": { "type": ["null", "string"] }, + "sns-discount-week-1": { "type": ["null", "string"] }, + "sns-units-shipped-week-2": { "type": ["null", "string"] }, + "oos-rate-week-2": { "type": ["null", "string"] }, + "sns-sale-price-week-2": { "type": ["null", "string"] }, + "sns-discount-week-2": { "type": ["null", "string"] }, + "sns-units-shipped-week-3": { "type": ["null", "string"] }, + "oos-rate-week-3": { "type": ["null", "string"] }, + "sns-sale-price-week-3": { "type": ["null", "string"] }, + "sns-discount-week-3": { "type": ["null", "string"] }, + "sns-units-shipped-week-4": { "type": ["null", "string"] }, + "oos-rate-week-4": { "type": ["null", "string"] }, + "sns-sale-price-week-4": { "type": ["null", "string"] }, + "sns-discount-week-4": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE.json new file mode 100644 index 000000000000..a2635187c16b --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE.json @@ -0,0 +1,39 @@ +{ + "title": "Flat File Archived Orders Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "amazon-order-id": { "type": ["null", "string"] }, + "merchant-order-id": { "type": ["null", "string"] }, + "purchase-date": { "type": ["null", "string"] }, + "last-updated-date": { "type": ["null", "string"] }, + "order-status": { "type": ["null", "string"] }, + "fulfillment-channel": { "type": ["null", "string"] }, + "sales-channel": { "type": ["null", "string"] }, + "order-channel": { "type": ["null", "string"] }, + "url": { "type": ["null", "string"] }, + "ship-service-level": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "item-status": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "item-price": { "type": ["null", "string"] }, + "item-tax": { "type": ["null", "string"] }, + "shipping-price": { "type": ["null", "string"] }, + "shipping-tax": { "type": ["null", "string"] }, + "gift-wrap-price": { "type": ["null", "string"] }, + "gift-wrap-tax": { "type": ["null", "string"] }, + "item-promotion-discount": { "type": ["null", "string"] }, + "ship-promotion-discount": { "type": ["null", "string"] }, + "ship-country": { "type": ["null", "string"] }, + "ship-promotion-id": { "type": ["null", "string"] }, + "promotion-ids": { "type": ["null", "string"] }, + "is-business-order": { "type": ["null", "string"] }, + "purchase-order-number": { "type": ["null", "string"] }, + "price-designation": { "type": ["null", "string"] }, + "is-replacement-order": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE.json new file mode 100644 index 000000000000..f2db5fb0b0a9 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE.json @@ -0,0 +1,40 @@ +{ + "title": "Flat File Returns Report by Return Date", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "Order ID": { "type": ["null", "string"] }, + "Order date": { "type": ["null", "string"] }, + "Return request date": { "type": ["null", "string"] }, + "Return request status": { "type": ["null", "string"] }, + "Amazon RMA ID": { "type": ["null", "string"] }, + "Merchant RMA ID": { "type": ["null", "string"] }, + "Label type": { "type": ["null", "string"] }, + "Label cost": { "type": ["null", "string"] }, + "Currency code": { "type": ["null", "string"] }, + "Return carrier": { "type": ["null", "string"] }, + "Tracking ID": { "type": ["null", "string"] }, + "Label to be paid by": { "type": ["null", "string"] }, + "A-to-Z Claim": { "type": ["null", "string"] }, + "Is prime": { "type": ["null", "string"] }, + "ASIN": { "type": ["null", "string"] }, + "Merchant SKU": { "type": ["null", "string"] }, + "Item Name": { "type": ["null", "string"] }, + "Return quantity": { "type": ["null", "string"] }, + "Return Reason": { "type": ["null", "string"] }, + "In policy": { "type": ["null", "string"] }, + "Return type": { "type": ["null", "string"] }, + "Resolution": { "type": ["null", "string"] }, + "Invoice number": { "type": ["null", "string"] }, + "Return delivery date": { "type": ["null", "string"] }, + "Order Amount": { "type": ["null", "string"] }, + "Order quantity": { "type": ["null", "string"] }, + "SafeT Action reason": { "type": ["null", "string"] }, + "SafeT claim id": { "type": ["null", "string"] }, + "SafeT claim state": { "type": ["null", "string"] }, + "SafeT claim creation time": { "type": ["null", "string"] }, + "SafeT claim reimbursement amount": { "type": ["null", "string"] }, + "Refunded Amount": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_LEDGER_DETAIL_VIEW_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_LEDGER_DETAIL_VIEW_DATA.json new file mode 100644 index 000000000000..1c3509889cf0 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_LEDGER_DETAIL_VIEW_DATA.json @@ -0,0 +1,22 @@ +{ + "title": "Inventory Ledger Report - Detailed View", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "Date": { "type": ["null", "string"], "format": "date" }, + "FNSKU": { "type": ["null", "string"] }, + "ASIN": { "type": ["null", "string"] }, + "MSKU": { "type": ["null", "string"] }, + "Title": { "type": ["null", "string"] }, + "Event Type": { "type": ["null", "string"] }, + "Reference ID": { "type": ["null", "string"] }, + "Quantity": { "type": ["null", "string"] }, + "Fulfillment Center": { "type": ["null", "string"] }, + "Disposition": { "type": ["null", "string"] }, + "Reason": { "type": ["null", "string"] }, + "Country": { "type": ["null", "string"] }, + "Reconciled Quantity": { "type": ["null", "string"] }, + "Unreconciled Quantity": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_LEDGER_SUMMARY_VIEW_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_LEDGER_SUMMARY_VIEW_DATA.json new file mode 100644 index 000000000000..288c4928a8a1 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_LEDGER_SUMMARY_VIEW_DATA.json @@ -0,0 +1,29 @@ +{ + "title": "Inventory Ledger Report - Summary View", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "Date": { "type": ["null", "string"] }, + "FNSKU": { "type": ["null", "string"] }, + "ASIN": { "type": ["null", "string"] }, + "MSKU": { "type": ["null", "string"] }, + "Title": { "type": ["null", "string"] }, + "Disposition": { "type": ["null", "string"] }, + "Starting Warehouse Balance": { "type": ["null", "string"] }, + "In Transit Between Warehouses": { "type": ["null", "string"] }, + "Receipts": { "type": ["null", "string"] }, + "Customer Shipments": { "type": ["null", "string"] }, + "Customer Returns": { "type": ["null", "string"] }, + "Vendor Returns": { "type": ["null", "string"] }, + "Warehouse Transfer In/Out": { "type": ["null", "string"] }, + "Found": { "type": ["null", "string"] }, + "Lost": { "type": ["null", "string"] }, + "Damaged": { "type": ["null", "string"] }, + "Disposed": { "type": ["null", "string"] }, + "Other Events": { "type": ["null", "string"] }, + "Ending Warehouse Balance": { "type": ["null", "string"] }, + "Unknown Events": { "type": ["null", "string"] }, + "Location": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANTS_LISTINGS_FYP_REPORT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANTS_LISTINGS_FYP_REPORT.json new file mode 100644 index 000000000000..f2f56e7d53b1 --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANTS_LISTINGS_FYP_REPORT.json @@ -0,0 +1,16 @@ +{ + "title": "Suppressed Listings Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "Status": { "type": ["null", "string"] }, + "Reason": { "type": ["null", "string"] }, + "SKU": { "type": ["null", "string"] }, + "ASIN": { "type": ["null", "string"] }, + "Product name": { "type": ["null", "string"] }, + "Condition": { "type": ["null", "string"] }, + "Status Change Date": { "type": ["null", "string"] }, + "Issue Description": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_CANCELLED_LISTINGS_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_CANCELLED_LISTINGS_DATA.json new file mode 100644 index 000000000000..35c5cd32d74e --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_CANCELLED_LISTINGS_DATA.json @@ -0,0 +1,50 @@ +{ + "title": "Canceled Listings Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "item-name": { "type": ["null", "string"] }, + "item-description": { "type": ["null", "string"] }, + "seller-sku": { "type": ["null", "string"] }, + "price": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "image-url": { "type": ["null", "string"] }, + "item-is-marketplace": { "type": ["null", "string"] }, + "product-id-type": { "type": ["null", "string"] }, + "zshop-shipping-fee": { "type": ["null", "string"] }, + "item-note": { "type": ["null", "string"] }, + "item-condition": { "type": ["null", "string"] }, + "zshop-category1": { "type": ["null", "string"] }, + "zshop-browse-path": { "type": ["null", "string"] }, + "zshop-storefront-feature": { "type": ["null", "string"] }, + "asin1": { "type": ["null", "string"] }, + "asin2": { "type": ["null", "string"] }, + "asin3": { "type": ["null", "string"] }, + "will-ship-internationally": { "type": ["null", "string"] }, + "expedited-shipping": { "type": ["null", "string"] }, + "zshop-boldface": { "type": ["null", "string"] }, + "product-id": { "type": ["null", "string"] }, + "add-delete": { "type": ["null", "string"] }, + "Business Price": { "type": ["null", "string"] }, + "Quantity Price Type": { "type": ["null", "string"] }, + "Quantity Lower Bound 1": { "type": ["null", "string"] }, + "Quantity Price 1": { "type": ["null", "string"] }, + "Quantity Lower Bound 2": { "type": ["null", "string"] }, + "Quantity Price 2": { "type": ["null", "string"] }, + "Quantity Lower Bound 3": { "type": ["null", "string"] }, + "Quantity Price 3": { "type": ["null", "string"] }, + "Quantity Lower Bound 4": { "type": ["null", "string"] }, + "Quantity Price 4": { "type": ["null", "string"] }, + "Quantity Lower Bound 5": { "type": ["null", "string"] }, + "Quantity Price 5": { "type": ["null", "string"] }, + "merchant-shipping-group": { "type": ["null", "string"] }, + "Progressive Price Type": { "type": ["null", "string"] }, + "Progressive Lower Bound 1": { "type": ["null", "string"] }, + "Progressive Price 1": { "type": ["null", "string"] }, + "Progressive Lower Bound 2": { "type": ["null", "string"] }, + "Progressive Price 2": { "type": ["null", "string"] }, + "Progressive Lower Bound 3": { "type": ["null", "string"] }, + "Progressive Price 3": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_DATA.json new file mode 100644 index 000000000000..f4c243481e5d --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_DATA.json @@ -0,0 +1,55 @@ +{ + "title": "Active Listings Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "item-name": { "type": ["null", "string"] }, + "item-description": { "type": ["null", "string"] }, + "listing-id": { "type": ["null", "string"] }, + "seller-sku": { "type": ["null", "string"] }, + "price": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "open-date": { "type": ["null", "string"] }, + "image-url": { "type": ["null", "string"] }, + "item-is-marketplace": { "type": ["null", "string"] }, + "product-id-type": { "type": ["null", "string"] }, + "zshop-shipping-fee": { "type": ["null", "string"] }, + "item-note": { "type": ["null", "string"] }, + "item-condition": { "type": ["null", "string"] }, + "zshop-category1": { "type": ["null", "string"] }, + "zshop-browse-path": { "type": ["null", "string"] }, + "zshop-storefront-feature": { "type": ["null", "string"] }, + "asin1": { "type": ["null", "string"] }, + "asin2": { "type": ["null", "string"] }, + "asin3": { "type": ["null", "string"] }, + "will-ship-internationally": { "type": ["null", "string"] }, + "expedited-shipping": { "type": ["null", "string"] }, + "zshop-boldface": { "type": ["null", "string"] }, + "product-id": { "type": ["null", "string"] }, + "bid-for-featured-placement": { "type": ["null", "string"] }, + "add-delete": { "type": ["null", "string"] }, + "pending-quantity": { "type": ["null", "string"] }, + "fulfillment-channel": { "type": ["null", "string"] }, + "Business Price": { "type": ["null", "string"] }, + "Quantity Price Type": { "type": ["null", "string"] }, + "Quantity Lower Bound 1": { "type": ["null", "string"] }, + "Quantity Price 1": { "type": ["null", "string"] }, + "Quantity Lower Bound 2": { "type": ["null", "string"] }, + "Quantity Price 2": { "type": ["null", "string"] }, + "Quantity Lower Bound 3": { "type": ["null", "string"] }, + "Quantity Price 3": { "type": ["null", "string"] }, + "Quantity Lower Bound 4": { "type": ["null", "string"] }, + "Quantity Price 4": { "type": ["null", "string"] }, + "Quantity Lower Bound 5": { "type": ["null", "string"] }, + "Quantity Price 5": { "type": ["null", "string"] }, + "merchant-shipping-group": { "type": ["null", "string"] }, + "Progressive Price Type": { "type": ["null", "string"] }, + "Progressive Lower Bound 1": { "type": ["null", "string"] }, + "Progressive Price 1": { "type": ["null", "string"] }, + "Progressive Lower Bound 2": { "type": ["null", "string"] }, + "Progressive Price 2": { "type": ["null", "string"] }, + "Progressive Lower Bound 3": { "type": ["null", "string"] }, + "Progressive Price 3": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_DATA_BACK_COMPAT.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_DATA_BACK_COMPAT.json new file mode 100644 index 000000000000..af4b8c76d21e --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_DATA_BACK_COMPAT.json @@ -0,0 +1,54 @@ +{ + "title": "Open Listings Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "item-name": { "type": ["null", "string"] }, + "item-description": { "type": ["null", "string"] }, + "listing-id": { "type": ["null", "string"] }, + "seller-sku": { "type": ["null", "string"] }, + "price": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "open-date": { "type": ["null", "string"] }, + "image-url": { "type": ["null", "string"] }, + "item-is-marketplace": { "type": ["null", "string"] }, + "product-id-type": { "type": ["null", "string"] }, + "zshop-shipping-fee": { "type": ["null", "string"] }, + "item-note": { "type": ["null", "string"] }, + "item-condition": { "type": ["null", "string"] }, + "zshop-category1": { "type": ["null", "string"] }, + "zshop-browse-path": { "type": ["null", "string"] }, + "zshop-storefront-feature": { "type": ["null", "string"] }, + "asin1": { "type": ["null", "string"] }, + "asin2": { "type": ["null", "string"] }, + "asin3": { "type": ["null", "string"] }, + "will-ship-internationally": { "type": ["null", "string"] }, + "expedited-shipping": { "type": ["null", "string"] }, + "zshop-boldface": { "type": ["null", "string"] }, + "product-id": { "type": ["null", "string"] }, + "bid-for-featured-placement": { "type": ["null", "string"] }, + "add-delete": { "type": ["null", "string"] }, + "pending-quantity": { "type": ["null", "string"] }, + "Business Price": { "type": ["null", "string"] }, + "Quantity Price Type": { "type": ["null", "string"] }, + "Quantity Lower Bound 1": { "type": ["null", "string"] }, + "Quantity Price 1": { "type": ["null", "string"] }, + "Quantity Lower Bound 2": { "type": ["null", "string"] }, + "Quantity Price 2": { "type": ["null", "string"] }, + "Quantity Lower Bound 3": { "type": ["null", "string"] }, + "Quantity Price 3": { "type": ["null", "string"] }, + "Quantity Lower Bound 4": { "type": ["null", "string"] }, + "Quantity Price 4": { "type": ["null", "string"] }, + "Quantity Lower Bound 5": { "type": ["null", "string"] }, + "Quantity Price 5": { "type": ["null", "string"] }, + "merchant-shipping-group": { "type": ["null", "string"] }, + "Progressive Price Type": { "type": ["null", "string"] }, + "Progressive Lower Bound 1": { "type": ["null", "string"] }, + "Progressive Price 1": { "type": ["null", "string"] }, + "Progressive Lower Bound 2": { "type": ["null", "string"] }, + "Progressive Price 2": { "type": ["null", "string"] }, + "Progressive Lower Bound 3": { "type": ["null", "string"] }, + "Progressive Price 3": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_INACTIVE_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_INACTIVE_DATA.json new file mode 100644 index 000000000000..900d02802e1f --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_MERCHANT_LISTINGS_INACTIVE_DATA.json @@ -0,0 +1,36 @@ +{ + "title": "Inactive Listings Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "item-name": { "type": ["null", "string"] }, + "item-description": { "type": ["null", "string"] }, + "listing-id": { "type": ["null", "string"] }, + "seller-sku": { "type": ["null", "string"] }, + "price": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "string"] }, + "open-date": { "type": ["null", "string"] }, + "image-url": { "type": ["null", "string"] }, + "item-is-marketplace": { "type": ["null", "string"] }, + "product-id-type": { "type": ["null", "string"] }, + "zshop-shipping-fee": { "type": ["null", "string"] }, + "item-note": { "type": ["null", "string"] }, + "item-condition": { "type": ["null", "string"] }, + "zshop-category1": { "type": ["null", "string"] }, + "zshop-browse-path": { "type": ["null", "string"] }, + "zshop-storefront-feature": { "type": ["null", "string"] }, + "asin1": { "type": ["null", "string"] }, + "asin2": { "type": ["null", "string"] }, + "asin3": { "type": ["null", "string"] }, + "will-ship-internationally": { "type": ["null", "string"] }, + "expedited-shipping": { "type": ["null", "string"] }, + "zshop-boldface": { "type": ["null", "string"] }, + "product-id": { "type": ["null", "string"] }, + "bid-for-featured-placement": { "type": ["null", "string"] }, + "add-delete": { "type": ["null", "string"] }, + "pending-quantity": { "type": ["null", "string"] }, + "fulfillment-channel": { "type": ["null", "string"] }, + "merchant-shipping-group": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_STRANDED_INVENTORY_UI_DATA.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_STRANDED_INVENTORY_UI_DATA.json new file mode 100644 index 000000000000..3ebcb0d0db8b --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_STRANDED_INVENTORY_UI_DATA.json @@ -0,0 +1,26 @@ +{ + "title": "FBA Stranded Inventory Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "primary-action": { "type": ["null", "string"] }, + "date-stranded": { "type": ["null", "string"] }, + "Date-to-take-auto-removal": { "type": ["null", "string"] }, + "status-primary": { "type": ["null", "string"] }, + "status-secondary": { "type": ["null", "string"] }, + "error-message": { "type": ["null", "string"] }, + "stranded-reason": { "type": ["null", "string"] }, + "asin": { "type": ["null", "string"] }, + "sku": { "type": ["null", "string"] }, + "fnsku": { "type": ["null", "string"] }, + "product-name": { "type": ["null", "string"] }, + "condition": { "type": ["null", "string"] }, + "fulfilled-by": { "type": ["null", "string"] }, + "fulfillable-qty": { "type": ["null", "string"] }, + "your-price": { "type": ["null", "string"] }, + "unfulfillable-qty": { "type": ["null", "string"] }, + "reserved-quantity": { "type": ["null", "string"] }, + "inbound-shipped-qty": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL.json b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL.json new file mode 100644 index 000000000000..e06c2dda083c --- /dev/null +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/schemas/GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL.json @@ -0,0 +1,62 @@ +{ + "title": "XML Orders By Order Date Report", + "description": "", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "LastUpdatedDate": { "type": ["null", "string"] }, + "SalesChannel": { "type": ["null", "string"] }, + "OrderStatus": { "type": ["null", "string"] }, + "AmazonOrderID": { "type": ["null", "string"] }, + "PurchaseDate": { "type": ["null", "string"] }, + "OrderItem": { + "type": ["array"], + "items": { "type": ["null", "object"] }, + "properties": { + "ItemStatus": { "type": ["null", "string"] }, + "ProductName": { "type": ["null", "string"] }, + "ItemPrice": { + "type": ["null", "object"], + "properties": { + "Component": { + "type": ["array"], + "items": { "type": ["null", "object"] }, + "properties": { + "Type": { "type": ["null", "string"] }, + "Amount": { + "type": ["null", "object"], + "properties": { + "currency": { "type": ["null", "string"] }, + "value": { "type": ["null", "string"] } + } + } + } + } + } + }, + "ASIN": { "type": ["null", "string"] }, + "Quantity": { "type": ["null", "string"] }, + "AmazonOrderItemCode": { "type": ["null", "string"] }, + "SKU": { "type": ["null", "string"] } + } + }, + "FulfillmentData": { + "type": ["null", "object"], + "properties": { + "Address": { + "type": ["null", "object"], + "properties": { + "State": { "type": ["null", "string"] }, + "PostalCode": { "type": ["null", "string"] }, + "Country": { "type": ["null", "string"] }, + "City": { "type": ["null", "string"] } + } + }, + "ShipServiceLevel": { "type": ["null", "string"] }, + "FulfillmentChannel": { "type": ["null", "string"] } + } + }, + "IsBusinessOrder": { "type": ["null", "string"] }, + "MerchantOrderID": { "type": ["null", "string"] } + } +} diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/source.py b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/source.py index 0c13cdcb8f59..a9ead15029ce 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/source.py +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/source.py @@ -21,28 +21,50 @@ FbaAfnInventoryByCountryReports, FbaAfnInventoryReports, FbaCustomerReturnsReports, + FbaEstimatedFbaFeesTxtReport, + FbaFulfillmentCurrentInventoryReport, + FbaFulfillmentCustomerShipmentPromotionReport, + FbaFulfillmentInventoryAdjustReport, + FbaFulfillmentInventoryReceiptsReport, + FbaFulfillmentInventorySummaryReport, + FbaFulfillmentMonthlyInventoryReport, + FbaInventoryPlaningReport, FbaInventoryReports, + FbaMyiUnsuppressedInventoryReport, FbaOrdersReports, FbaReplacementsReports, FbaShipmentsReports, + FbaSnsForecastReport, + FbaSnsPerformanceReport, FbaStorageFeesReports, + FlatFileArchivedOrdersDataByOrderDate, FlatFileOpenListingsReports, FlatFileOrdersReports, FlatFileOrdersReportsByLastUpdate, + FlatFileReturnsDataByReturnDate, FlatFileSettlementV2Reports, FulfilledShipmentsReports, GetXmlBrowseTreeData, + LedgerDetailedViewReports, + LedgerSummaryViewReport, ListFinancialEventGroups, ListFinancialEvents, + MerchantCancelledListingsReport, + MerchantListingsFypReport, + MerchantListingsInactiveData, + MerchantListingsReport, + MerchantListingsReportBackCompat, MerchantListingsReports, Orders, RestockInventoryReports, SellerAnalyticsSalesAndTrafficReports, SellerFeedbackReports, + StrandedInventoryUiReport, VendorDirectFulfillmentShipping, VendorInventoryHealthReports, VendorInventoryReports, VendorSalesReports, + XmlAllOrdersDataByOrderDataGeneral, ) @@ -166,6 +188,28 @@ def streams(self, config: Mapping[str, Any]) -> List[Stream]: GetXmlBrowseTreeData(**stream_kwargs), ListFinancialEventGroups(**stream_kwargs), ListFinancialEvents(**stream_kwargs), + LedgerDetailedViewReports(**stream_kwargs), + FbaEstimatedFbaFeesTxtReport(**stream_kwargs), + FbaFulfillmentCurrentInventoryReport(**stream_kwargs), + FbaFulfillmentCustomerShipmentPromotionReport(**stream_kwargs), + FbaFulfillmentInventoryAdjustReport(**stream_kwargs), + FbaFulfillmentInventoryReceiptsReport(**stream_kwargs), + FbaFulfillmentInventorySummaryReport(**stream_kwargs), + FbaMyiUnsuppressedInventoryReport(**stream_kwargs), + MerchantCancelledListingsReport(**stream_kwargs), + MerchantListingsReport(**stream_kwargs), + MerchantListingsReportBackCompat(**stream_kwargs), + MerchantListingsInactiveData(**stream_kwargs), + StrandedInventoryUiReport(**stream_kwargs), + XmlAllOrdersDataByOrderDataGeneral(**stream_kwargs), + FbaFulfillmentMonthlyInventoryReport(**stream_kwargs), + MerchantListingsFypReport(**stream_kwargs), + FbaSnsForecastReport(**stream_kwargs), + FbaSnsPerformanceReport(**stream_kwargs), + FlatFileArchivedOrdersDataByOrderDate(**stream_kwargs), + FlatFileReturnsDataByReturnDate(**stream_kwargs), + FbaInventoryPlaningReport(**stream_kwargs), + LedgerSummaryViewReport(**stream_kwargs), ] def spec(self, *args, **kwargs) -> ConnectorSpecification: diff --git a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/streams.py b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/streams.py index 21644dff0530..f2bf81f42368 100644 --- a/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/streams.py +++ b/airbyte-integrations/connectors/source-amazon-seller-partner/source_amazon_seller_partner/streams.py @@ -152,6 +152,8 @@ class ReportsAmazonSPStream(Stream, ABC): - yield the report document (if report processing status is `DONE`) """ + replication_start_date_limit_in_days = 90 + primary_key = None path_prefix = f"reports/{REPORTS_API_VERSION}" sleep_seconds = 30 @@ -239,7 +241,9 @@ def _report_data( stream_slice: Mapping[str, Any] = None, stream_state: Mapping[str, Any] = None, ) -> Mapping[str, Any]: - replication_start_date = max(pendulum.parse(self._replication_start_date), pendulum.now("utc").subtract(days=90)) + replication_start_date = max( + pendulum.parse(self._replication_start_date), pendulum.now("utc").subtract(days=self.replication_start_date_limit_in_days) + ) params = { "reportType": self.name, @@ -282,6 +286,7 @@ def _retrieve_report(self, report_id: str) -> Mapping[str, Any]: ) retrieve_report_response = self._send_request(retrieve_report_request) report_payload = retrieve_report_response.json() + return report_payload def decompress_report_document(self, url, payload): @@ -412,6 +417,8 @@ class FulfilledShipmentsReports(ReportsAmazonSPStream): name = "GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL" + replication_start_date_limit_in_days = 30 + class FlatFileOpenListingsReports(ReportsAmazonSPStream): name = "GET_FLAT_FILE_OPEN_LISTINGS_DATA" @@ -463,6 +470,139 @@ def parse_document(self, document): name = "GET_XML_BROWSE_TREE_DATA" +class FbaEstimatedFbaFeesTxtReport(ReportsAmazonSPStream): + name = "GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA" + + +class FbaFulfillmentCurrentInventoryReport(ReportsAmazonSPStream): + name = "GET_FBA_FULFILLMENT_CURRENT_INVENTORY_DATA" + + +class FbaFulfillmentCustomerShipmentPromotionReport(ReportsAmazonSPStream): + name = "GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_PROMOTION_DATA" + + +class FbaFulfillmentInventoryAdjustReport(ReportsAmazonSPStream): + name = "GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA" + + +class FbaFulfillmentInventoryReceiptsReport(ReportsAmazonSPStream): + name = "GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA" + + +class FbaFulfillmentInventorySummaryReport(ReportsAmazonSPStream): + name = "GET_FBA_FULFILLMENT_INVENTORY_SUMMARY_DATA" + + +class FbaMyiUnsuppressedInventoryReport(ReportsAmazonSPStream): + name = "GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA" + + +class MerchantListingsReport(ReportsAmazonSPStream): + name = "GET_MERCHANT_LISTINGS_DATA" + + +class MerchantListingsInactiveData(ReportsAmazonSPStream): + name = "GET_MERCHANT_LISTINGS_INACTIVE_DATA" + + +class StrandedInventoryUiReport(ReportsAmazonSPStream): + name = "GET_STRANDED_INVENTORY_UI_DATA" + + +class XmlAllOrdersDataByOrderDataGeneral(ReportsAmazonSPStream): + def parse_document(self, document): + parsed = xmltodict.parse(document, attr_prefix="", cdata_key="value", force_list={"Message", "OrderItem"}) + orders = parsed.get("AmazonEnvelope", {}).get("Message", []) + result = [] + if isinstance(orders, list): + for order in orders: + result.append(order.get("Order", {})) + + return result + + name = "GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_GENERAL" + + +class MerchantListingsReportBackCompat(ReportsAmazonSPStream): + def _report_data( + self, + sync_mode: SyncMode, + cursor_field: List[str] = None, + stream_slice: Mapping[str, Any] = None, + stream_state: Mapping[str, Any] = None, + ) -> Mapping[str, Any]: + params = super()._report_data(sync_mode, cursor_field, stream_slice, stream_state) + options = self.report_options() + if options is not None: + params.update({"reportOptions": options}) + return params + + name = "GET_MERCHANT_LISTINGS_DATA_BACK_COMPAT" + + +class MerchantCancelledListingsReport(ReportsAmazonSPStream): + def _report_data( + self, + sync_mode: SyncMode, + cursor_field: List[str] = None, + stream_slice: Mapping[str, Any] = None, + stream_state: Mapping[str, Any] = None, + ) -> Mapping[str, Any]: + params = super()._report_data(sync_mode, cursor_field, stream_slice, stream_state) + options = self.report_options() + if options is not None: + params.update({"reportOptions": options}) + return params + + name = "GET_MERCHANT_CANCELLED_LISTINGS_DATA" + + +class FbaFulfillmentMonthlyInventoryReport(ReportsAmazonSPStream): + name = "GET_FBA_FULFILLMENT_MONTHLY_INVENTORY_DATA" + + +class MerchantListingsFypReport(ReportsAmazonSPStream): + name = "GET_MERCHANTS_LISTINGS_FYP_REPORT" + + +class FbaSnsForecastReport(ReportsAmazonSPStream): + name = "GET_FBA_SNS_FORECAST_DATA" + + +class FbaSnsPerformanceReport(ReportsAmazonSPStream): + name = "GET_FBA_SNS_PERFORMANCE_DATA" + + +class FlatFileArchivedOrdersDataByOrderDate(ReportsAmazonSPStream): + name = "GET_FLAT_FILE_ARCHIVED_ORDERS_DATA_BY_ORDER_DATE" + + +class FlatFileReturnsDataByReturnDate(ReportsAmazonSPStream): + name = "GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE" + + +class FbaInventoryPlaningReport(ReportsAmazonSPStream): + name = "GET_FBA_INVENTORY_PLANNING_DATA" + + +class LedgerSummaryViewReport(ReportsAmazonSPStream): + def _report_data( + self, + sync_mode: SyncMode, + cursor_field: List[str] = None, + stream_slice: Mapping[str, Any] = None, + stream_state: Mapping[str, Any] = None, + ) -> Mapping[str, Any]: + params = super()._report_data(sync_mode, cursor_field, stream_slice, stream_state) + options = self.report_options() + if options is not None: + params.update({"reportOptions": options}) + return params + + name = "GET_LEDGER_SUMMARY_VIEW_DATA" + + class AnalyticsStream(ReportsAmazonSPStream): def parse_document(self, document): parsed = json_lib.loads(document) @@ -737,6 +877,29 @@ def backoff_time(self, response: requests.Response) -> Optional[float]: return self.default_backoff_time +class LedgerDetailedViewReports(IncrementalReportsAmazonSPStream): + """ + API docs: https://developer-docs.amazon.com/sp-api/docs/report-type-values + """ + + name = "GET_LEDGER_DETAIL_VIEW_DATA" + cursor_field = "Date" + transformer: TypeTransformer = TypeTransformer(TransformConfig.DefaultSchemaNormalization | TransformConfig.CustomSchemaNormalization) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.transformer.registerCustomTransform(self.get_transform_function()) + + def get_transform_function(self): + def transform_function(original_value: Any, field_schema: Dict[str, Any]) -> Any: + if original_value and field_schema.get("format") == "date": + transformed_value = pendulum.from_format(original_value, "MM/DD/YYYY").to_date_string() + return transformed_value + return original_value + + return transform_function + + class IncrementalAnalyticsStream(AnalyticsStream): fixed_period_in_days = 0 diff --git a/docs/integrations/sources/amazon-seller-partner.md b/docs/integrations/sources/amazon-seller-partner.md index 5034aa33bab5..fab319ca0b06 100644 --- a/docs/integrations/sources/amazon-seller-partner.md +++ b/docs/integrations/sources/amazon-seller-partner.md @@ -83,6 +83,28 @@ This source is capable of syncing the following tables and their data: - [Browse tree report](https://github.com/amzn/selling-partner-api-docs/blob/main/references/reports-api/reporttype-values.md#browse-tree-report) - [Financial Event Groups](https://developer-docs.amazon.com/sp-api/docs/finances-api-reference#get-financesv0financialeventgroups) - [Financial Events](https://developer-docs.amazon.com/sp-api/docs/finances-api-reference#get-financesv0financialevents) +- [FBA Fee Preview Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [FBA Daily Inventory History Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [FBA Promotions Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [FBA Inventory Adjustments Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [FBA Received Inventory Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [FBA Inventory Event Detail Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [FBA Monthly Inventory History Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [FBA Manage Inventory](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Subscribe and Save Forecast Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Subscribe and Save Performance Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Flat File Archived Orders Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Flat File Returns Report by Return Date](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Canceled Listings Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Active Listings Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Open Listings Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Suppressed Listings Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Inactive Listings Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [FBA Stranded Inventory Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [XML Orders By Order Date Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Inventory Ledger Report - Detailed View](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [FBA Manage Inventory Health Report](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) +- [Inventory Ledger Report - Summary View](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) ## Report options @@ -104,6 +126,7 @@ Make sure to configure the [required parameters](https://developer-docs.amazon.c | Version | Date | Pull Request | Subject | |:---------|:-----------|:-----------------------------------------------------------|:-----------------------------------------------------------------------| +| `0.2.28` | 2022-10-20 | [\#18283](https://github.com/airbytehq/airbyte/pull/18283) | Added multiple (22) report types | | `0.2.26` | 2022-09-24 | [\#16629](https://github.com/airbytehq/airbyte/pull/16629) | Report API version to 2021-06-30, added multiple (5) report types | | `0.2.25` | 2022-07-27 | [\#15063](https://github.com/airbytehq/airbyte/pull/15063) | Add Restock Inventory Report | | `0.2.24` | 2022-07-12 | [\#14625](https://github.com/airbytehq/airbyte/pull/14625) | Add FBA Storage Fees Report | From fcf47584e8be7a3e5e345e342110f78d57970e7c Mon Sep 17 00:00:00 2001 From: Jonathan Pearlin Date: Thu, 3 Nov 2022 11:50:17 -0400 Subject: [PATCH 07/73] Filter DestroyWorkflowThreadError from trace (#18907) --- .../tracing/TemporalSdkInterceptor.java | 23 ++++- .../tracing/TemporalSdkInterceptorTest.java | 89 +++++++++++++------ 2 files changed, 84 insertions(+), 28 deletions(-) diff --git a/airbyte-workers/src/main/java/io/airbyte/workers/tracing/TemporalSdkInterceptor.java b/airbyte-workers/src/main/java/io/airbyte/workers/tracing/TemporalSdkInterceptor.java index 64486137d866..8ec652f10da8 100644 --- a/airbyte-workers/src/main/java/io/airbyte/workers/tracing/TemporalSdkInterceptor.java +++ b/airbyte-workers/src/main/java/io/airbyte/workers/tracing/TemporalSdkInterceptor.java @@ -21,6 +21,11 @@ @Slf4j public class TemporalSdkInterceptor implements TraceInterceptor { + /** + * Trace resource name used to scope the filtering performed by this interceptor. + */ + static final String CONNECTION_MANAGER_WORKFLOW_IMPL_RESOURCE_NAME = "ConnectionManagerWorkflowImpl.run"; + /** * Error message tag key name that contains the Temporal exit error message. */ @@ -73,7 +78,23 @@ boolean isExitTrace(final MutableSpan trace) { return trace.isError() && EXIT_ERROR_MESSAGE.equalsIgnoreCase(trace.getTags().getOrDefault(ERROR_MESSAGE_TAG_KEY, "").toString()) && - WORKFLOW_TRACE_OPERATION_NAME.equalsIgnoreCase(trace.getOperationName().toString()); + (safeEquals(trace.getOperationName(), WORKFLOW_TRACE_OPERATION_NAME) + || safeEquals(trace.getResourceName(), CONNECTION_MANAGER_WORKFLOW_IMPL_RESOURCE_NAME)); + } + + /** + * Safely test if the provided {@link CharSequence} equals the provided expected string value. + * + * @param actual The {@link CharSequence} to test. + * @param expected The expected string value to be contained in the {@link CharSequence}. + * @return {@code true} if the strings are equal (ignoring case) or {@code false} otherwise. + */ + private boolean safeEquals(final CharSequence actual, final String expected) { + if (actual != null) { + return expected.equalsIgnoreCase(actual.toString()); + } else { + return false; + } } } diff --git a/airbyte-workers/src/test/java/io/airbyte/workers/tracing/TemporalSdkInterceptorTest.java b/airbyte-workers/src/test/java/io/airbyte/workers/tracing/TemporalSdkInterceptorTest.java index 5565d63b31e5..811fef3bdd39 100644 --- a/airbyte-workers/src/test/java/io/airbyte/workers/tracing/TemporalSdkInterceptorTest.java +++ b/airbyte-workers/src/test/java/io/airbyte/workers/tracing/TemporalSdkInterceptorTest.java @@ -5,6 +5,7 @@ package io.airbyte.workers.tracing; import static io.airbyte.metrics.lib.ApmTraceConstants.WORKFLOW_TRACE_OPERATION_NAME; +import static io.airbyte.workers.tracing.TemporalSdkInterceptor.CONNECTION_MANAGER_WORKFLOW_IMPL_RESOURCE_NAME; import static io.airbyte.workers.tracing.TemporalSdkInterceptor.ERROR_MESSAGE_TAG_KEY; import static io.airbyte.workers.tracing.TemporalSdkInterceptor.EXIT_ERROR_MESSAGE; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -33,18 +34,29 @@ void testOnTraceComplete() { otherError.setOperationName(WORKFLOW_TRACE_OPERATION_NAME); otherError.setTag("error.message", "some other error"); - final var temporalExitMsgError = new DummySpan(); - temporalExitMsgError.setError(true); - temporalExitMsgError.setOperationName(WORKFLOW_TRACE_OPERATION_NAME); - temporalExitMsgError.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); + final var temporalExitMsgOperationNameError = new DummySpan(); + temporalExitMsgOperationNameError.setError(true); + temporalExitMsgOperationNameError.setOperationName(WORKFLOW_TRACE_OPERATION_NAME); + temporalExitMsgOperationNameError.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); + + final var temporalExitMsgResourceNameError = new DummySpan(); + temporalExitMsgResourceNameError.setError(true); + temporalExitMsgResourceNameError.setResourceName(CONNECTION_MANAGER_WORKFLOW_IMPL_RESOURCE_NAME); + temporalExitMsgResourceNameError.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); + + final var temporalExitMsgOtherOperationError = new DummySpan(); + temporalExitMsgOtherOperationError.setError(true); + temporalExitMsgOtherOperationError.setOperationName("OtherOperation"); + temporalExitMsgOtherOperationError.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); final var temporalExitMsgOtherResourceError = new DummySpan(); temporalExitMsgOtherResourceError.setError(true); - temporalExitMsgOtherResourceError.setOperationName("OtherOperation"); + temporalExitMsgOtherResourceError.setResourceName("OtherResource"); temporalExitMsgOtherResourceError.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); final var spans = List.of( - simple, noError, otherError, temporalExitMsgError, temporalExitMsgOtherResourceError); + simple, noError, otherError, temporalExitMsgOperationNameError, temporalExitMsgResourceNameError, temporalExitMsgOtherOperationError, + temporalExitMsgOtherResourceError); final var interceptor = new TemporalSdkInterceptor(); final var actual = interceptor.onTraceComplete(spans); @@ -53,7 +65,9 @@ void testOnTraceComplete() { assertFalse(simple.isError()); assertFalse(noError.isError()); assertTrue(otherError.isError()); - assertFalse(temporalExitMsgError.isError()); + assertFalse(temporalExitMsgOperationNameError.isError()); + assertFalse(temporalExitMsgResourceNameError.isError()); + assertTrue(temporalExitMsgOtherOperationError.isError()); assertTrue(temporalExitMsgOtherResourceError.isError()); } @@ -64,26 +78,47 @@ void testIsExitTrace() { assertEquals(false, interceptor.isExitTrace(null)); assertEquals(false, interceptor.isExitTrace(new DummySpan())); - final var temporalTrace = new DummySpan(); - temporalTrace.setOperationName(WORKFLOW_TRACE_OPERATION_NAME); - assertEquals(false, interceptor.isExitTrace(temporalTrace)); - - final var temporalTraceWithError = new DummySpan(); - temporalTraceWithError.setError(true); - temporalTraceWithError.setOperationName(WORKFLOW_TRACE_OPERATION_NAME); - assertEquals(false, interceptor.isExitTrace(temporalTraceWithError)); - - final var temporalTraceWithExitError = new DummySpan(); - temporalTraceWithExitError.setError(true); - temporalTraceWithExitError.setOperationName(WORKFLOW_TRACE_OPERATION_NAME); - temporalTraceWithExitError.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); - assertEquals(true, interceptor.isExitTrace(temporalTraceWithExitError)); - - final var otherTemporalTraceWithExitError = new DummySpan(); - otherTemporalTraceWithExitError.setError(true); - otherTemporalTraceWithExitError.setOperationName("OtherOperation"); - otherTemporalTraceWithExitError.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); - assertEquals(false, interceptor.isExitTrace(otherTemporalTraceWithExitError)); + final var temporalTraceWithOperationName = new DummySpan(); + temporalTraceWithOperationName.setOperationName(WORKFLOW_TRACE_OPERATION_NAME); + assertEquals(false, interceptor.isExitTrace(temporalTraceWithOperationName)); + + final var temporalTraceWithResourceName = new DummySpan(); + temporalTraceWithResourceName.setResourceName(CONNECTION_MANAGER_WORKFLOW_IMPL_RESOURCE_NAME); + assertEquals(false, interceptor.isExitTrace(temporalTraceWithResourceName)); + + final var temporalTraceWithErrorAndOperationName = new DummySpan(); + temporalTraceWithErrorAndOperationName.setError(true); + temporalTraceWithErrorAndOperationName.setOperationName(WORKFLOW_TRACE_OPERATION_NAME); + assertEquals(false, interceptor.isExitTrace(temporalTraceWithErrorAndOperationName)); + + final var temporalTraceWithErrorAndResourceName = new DummySpan(); + temporalTraceWithErrorAndResourceName.setError(true); + temporalTraceWithErrorAndResourceName.setResourceName(CONNECTION_MANAGER_WORKFLOW_IMPL_RESOURCE_NAME); + assertEquals(false, interceptor.isExitTrace(temporalTraceWithErrorAndResourceName)); + + final var temporalTraceWithExitErrorAndOperationName = new DummySpan(); + temporalTraceWithExitErrorAndOperationName.setError(true); + temporalTraceWithExitErrorAndOperationName.setOperationName(WORKFLOW_TRACE_OPERATION_NAME); + temporalTraceWithExitErrorAndOperationName.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); + assertEquals(true, interceptor.isExitTrace(temporalTraceWithExitErrorAndOperationName)); + + final var temporalTraceWithExitErrorAndResourceName = new DummySpan(); + temporalTraceWithExitErrorAndResourceName.setError(true); + temporalTraceWithExitErrorAndResourceName.setResourceName(CONNECTION_MANAGER_WORKFLOW_IMPL_RESOURCE_NAME); + temporalTraceWithExitErrorAndResourceName.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); + assertEquals(true, interceptor.isExitTrace(temporalTraceWithExitErrorAndResourceName)); + + final var otherTemporalTraceWithExitErrorAndOtherOperationName = new DummySpan(); + otherTemporalTraceWithExitErrorAndOtherOperationName.setError(true); + otherTemporalTraceWithExitErrorAndOtherOperationName.setOperationName("OtherOperation"); + otherTemporalTraceWithExitErrorAndOtherOperationName.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); + assertEquals(false, interceptor.isExitTrace(otherTemporalTraceWithExitErrorAndOtherOperationName)); + + final var otherTemporalTraceWithExitErrorAndOtherResourceName = new DummySpan(); + otherTemporalTraceWithExitErrorAndOtherResourceName.setError(true); + otherTemporalTraceWithExitErrorAndOtherResourceName.setResourceName("OtherResource"); + otherTemporalTraceWithExitErrorAndOtherResourceName.setTag(ERROR_MESSAGE_TAG_KEY, EXIT_ERROR_MESSAGE); + assertEquals(false, interceptor.isExitTrace(otherTemporalTraceWithExitErrorAndOtherResourceName)); } @Test From fad7ff2fdb2afd1d0ed03d0fc74e9fa33bcf4dde Mon Sep 17 00:00:00 2001 From: Jonathan Pearlin Date: Thu, 3 Nov 2022 12:02:04 -0400 Subject: [PATCH 08/73] Record replication stats as part of trace (#18909) * Record replication stats as part of trace * PR feedback --- .../metrics/lib/ApmTraceConstants.java | 17 ++++++++++ .../metrics/lib/OssMetricsRegistry.java | 8 ++++- .../sync/ReplicationActivityImpl.java | 32 ++++++++++++++++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/airbyte-metrics/metrics-lib/src/main/java/io/airbyte/metrics/lib/ApmTraceConstants.java b/airbyte-metrics/metrics-lib/src/main/java/io/airbyte/metrics/lib/ApmTraceConstants.java index 4fa0cf52e6f6..ae0cd6bd2c5b 100644 --- a/airbyte-metrics/metrics-lib/src/main/java/io/airbyte/metrics/lib/ApmTraceConstants.java +++ b/airbyte-metrics/metrics-lib/src/main/java/io/airbyte/metrics/lib/ApmTraceConstants.java @@ -73,6 +73,23 @@ public static final class Tags { */ public static final String PROCESS_EXIT_VALUE_KEY = "process.exit_value"; + /** + * Name of the APM trace tag that holds the replication bytes synced value associated with the + * trace. + */ + public static final String REPLICATION_BYTES_SYNCED_KEY = "replication.bytes_synced"; + + /** + * Name of the APM trace tag that holds the replication records synced value associated with the + * trace. + */ + public static final String REPLICATION_RECORDS_SYNCED_KEY = "replication.records_synced"; + + /** + * Name of the APM trace tag that holds the replication status value associated with the trace. + */ + public static final String REPLICATION_STATUS_KEY = "replication.status"; + /** * Name of the APM trace tag that holds the source Docker image value associated with the trace. */ diff --git a/airbyte-metrics/metrics-lib/src/main/java/io/airbyte/metrics/lib/OssMetricsRegistry.java b/airbyte-metrics/metrics-lib/src/main/java/io/airbyte/metrics/lib/OssMetricsRegistry.java index 6962b7c56c01..8ce51860395e 100644 --- a/airbyte-metrics/metrics-lib/src/main/java/io/airbyte/metrics/lib/OssMetricsRegistry.java +++ b/airbyte-metrics/metrics-lib/src/main/java/io/airbyte/metrics/lib/OssMetricsRegistry.java @@ -128,7 +128,13 @@ public enum OssMetricsRegistry implements MetricsRegistry { "count of the number of successful workflow syncs."), TEMPORAL_WORKFLOW_FAILURE(MetricEmittingApps.WORKER, "temporal_workflow_failure", - "count of the number of workflow failures"); + "count of the number of workflow failures"), + REPLICATION_BYTES_SYNCED(MetricEmittingApps.WORKER, + "replication_bytes_synced", + "number of bytes synced during replication"), + REPLICATION_RECORDS_SYNCED(MetricEmittingApps.WORKER, + "replication_records_synced", + "number of records synced during replication"); private final MetricEmittingApp application; private final String metricName; diff --git a/airbyte-workers/src/main/java/io/airbyte/workers/temporal/sync/ReplicationActivityImpl.java b/airbyte-workers/src/main/java/io/airbyte/workers/temporal/sync/ReplicationActivityImpl.java index 7aaed5e278b7..2c7369b4d858 100644 --- a/airbyte-workers/src/main/java/io/airbyte/workers/temporal/sync/ReplicationActivityImpl.java +++ b/airbyte-workers/src/main/java/io/airbyte/workers/temporal/sync/ReplicationActivityImpl.java @@ -7,6 +7,9 @@ import static io.airbyte.metrics.lib.ApmTraceConstants.ACTIVITY_TRACE_OPERATION_NAME; import static io.airbyte.metrics.lib.ApmTraceConstants.Tags.DESTINATION_DOCKER_IMAGE_KEY; import static io.airbyte.metrics.lib.ApmTraceConstants.Tags.JOB_ID_KEY; +import static io.airbyte.metrics.lib.ApmTraceConstants.Tags.REPLICATION_BYTES_SYNCED_KEY; +import static io.airbyte.metrics.lib.ApmTraceConstants.Tags.REPLICATION_RECORDS_SYNCED_KEY; +import static io.airbyte.metrics.lib.ApmTraceConstants.Tags.REPLICATION_STATUS_KEY; import static io.airbyte.metrics.lib.ApmTraceConstants.Tags.SOURCE_DOCKER_IMAGE_KEY; import datadog.trace.api.Trace; @@ -36,6 +39,7 @@ import io.airbyte.metrics.lib.MetricClient; import io.airbyte.metrics.lib.MetricClientFactory; import io.airbyte.metrics.lib.MetricEmittingApps; +import io.airbyte.metrics.lib.OssMetricsRegistry; import io.airbyte.persistence.job.models.IntegrationLauncherConfig; import io.airbyte.persistence.job.models.JobRunConfig; import io.airbyte.workers.ContainerOrchestratorConfig; @@ -59,11 +63,13 @@ import io.airbyte.workers.sync.ReplicationLauncherWorker; import io.airbyte.workers.temporal.TemporalAttemptExecution; import io.micronaut.context.annotation.Value; +import io.micronaut.core.util.CollectionUtils; import io.temporal.activity.Activity; import io.temporal.activity.ActivityExecutionContext; import jakarta.inject.Named; import jakarta.inject.Singleton; import java.nio.file.Path; +import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -185,7 +191,7 @@ public StandardSyncOutput replicate(final JobRunConfig jobRunConfig, final String standardSyncOutputString = standardSyncOutput.toString(); LOGGER.info("sync summary: {}", standardSyncOutputString); if (standardSyncOutputString.length() > MAX_TEMPORAL_MESSAGE_SIZE) { - LOGGER.error("Sync ouput exceeds the max temporal message size of {}, actual is {}.", MAX_TEMPORAL_MESSAGE_SIZE, + LOGGER.error("Sync output exceeds the max temporal message size of {}, actual is {}.", MAX_TEMPORAL_MESSAGE_SIZE, standardSyncOutputString.length()); } else { LOGGER.info("Sync summary length: {}", standardSyncOutputString.length()); @@ -201,6 +207,8 @@ private static StandardSyncOutput reduceReplicationOutput(final ReplicationOutpu final StandardSyncSummary syncSummary = new StandardSyncSummary(); final ReplicationAttemptSummary replicationSummary = output.getReplicationAttemptSummary(); + traceReplicationSummary(replicationSummary); + syncSummary.setBytesSynced(replicationSummary.getBytesSynced()); syncSummary.setRecordsSynced(replicationSummary.getRecordsSynced()); syncSummary.setStartTime(replicationSummary.getStartTime()); @@ -217,6 +225,28 @@ private static StandardSyncOutput reduceReplicationOutput(final ReplicationOutpu return standardSyncOutput; } + private static void traceReplicationSummary(final ReplicationAttemptSummary replicationSummary) { + if (replicationSummary == null) { + return; + } + + final Map tags = new HashMap<>(); + if (replicationSummary.getBytesSynced() != null) { + tags.put(REPLICATION_BYTES_SYNCED_KEY, replicationSummary.getBytesSynced()); + MetricClientFactory.getMetricClient().count(OssMetricsRegistry.REPLICATION_BYTES_SYNCED, replicationSummary.getBytesSynced()); + } + if (replicationSummary.getRecordsSynced() != null) { + tags.put(REPLICATION_RECORDS_SYNCED_KEY, replicationSummary.getRecordsSynced()); + MetricClientFactory.getMetricClient().count(OssMetricsRegistry.REPLICATION_RECORDS_SYNCED, replicationSummary.getRecordsSynced()); + } + if (replicationSummary.getStatus() != null) { + tags.put(REPLICATION_STATUS_KEY, replicationSummary.getStatus().value()); + } + if (!tags.isEmpty()) { + ApmTraceUtils.addTagsToTrace(tags); + } + } + private CheckedSupplier, Exception> getLegacyWorkerFactory(final IntegrationLauncherConfig sourceLauncherConfig, final IntegrationLauncherConfig destinationLauncherConfig, final JobRunConfig jobRunConfig, From 2dec2691a9cda1b6964593635a10a988a6359516 Mon Sep 17 00:00:00 2001 From: Jonathan Pearlin Date: Thu, 3 Nov 2022 12:03:22 -0400 Subject: [PATCH 09/73] Record replication stats as part of trace (#18909) * Record replication stats as part of trace * PR feedback From 97777977e38a0d6b8694e30abf6db7ffb07339f0 Mon Sep 17 00:00:00 2001 From: Jonathan Pearlin Date: Thu, 3 Nov 2022 12:03:57 -0400 Subject: [PATCH 10/73] Record replication stats as part of trace (#18909) * Record replication stats as part of trace * PR feedback From dd7184dbca3e756e53dc27c37f50c95470b11a6f Mon Sep 17 00:00:00 2001 From: Brian Lai <51336873+brianjlai@users.noreply.github.com> Date: Thu, 3 Nov 2022 12:05:04 -0400 Subject: [PATCH 11/73] [low-code cdk] Allow for read command to be run on low code connector streams w/o a schema file (#18532) * use mockschemaloader as the default and rename JsonSchema to JsonFileSchemaLoader * rename mock to EmptySchemaLoader * retain existing JsonSchema while hacktoberfest is still in progress * bump version and changelog --- airbyte-cdk/python/CHANGELOG.md | 3 ++ .../sources/declarative/declarative_stream.py | 4 +-- .../parsers/class_types_registry.py | 7 ++-- .../default_implementation_registry.py | 4 +-- .../sources/declarative/schema/__init__.py | 5 +-- .../declarative/schema/empty_schema_loader.py | 36 +++++++++++++++++++ ...n_schema.py => json_file_schema_loader.py} | 2 +- airbyte-cdk/python/setup.py | 2 +- .../declarative/schema/test_json_schema.py | 4 +-- .../sources/declarative/test_factory.py | 11 +++--- .../test_yaml_declarative_source.py | 3 +- .../source_courier/courier.yaml | 2 +- .../source_gocardless/gocardless.yaml | 2 +- .../source_greenhouse/greenhouse.yaml | 1 + .../source_sendgrid/sendgrid.yaml | 2 +- .../source-sentry/source_sentry/sentry.yaml | 2 +- 16 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/empty_schema_loader.py rename airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/{json_schema.py => json_file_schema_loader.py} (98%) diff --git a/airbyte-cdk/python/CHANGELOG.md b/airbyte-cdk/python/CHANGELOG.md index 75eeccc8cdad..0d6c5ec08cb4 100644 --- a/airbyte-cdk/python/CHANGELOG.md +++ b/airbyte-cdk/python/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 0.5.2 +Low-code: Allow for read even when schemas are not defined for a connector yet + ## 0.4.2 Low-code: Fix off by one error with the stream slicers diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/declarative_stream.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/declarative_stream.py index f29069f92b25..c998ee98342f 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/declarative_stream.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/declarative_stream.py @@ -7,7 +7,7 @@ from airbyte_cdk.models import SyncMode from airbyte_cdk.sources.declarative.retrievers.retriever import Retriever -from airbyte_cdk.sources.declarative.schema.json_schema import JsonSchema +from airbyte_cdk.sources.declarative.schema import EmptySchemaLoader from airbyte_cdk.sources.declarative.schema.schema_loader import SchemaLoader from airbyte_cdk.sources.declarative.transformations import RecordTransformation from airbyte_cdk.sources.declarative.types import Config, StreamSlice @@ -48,7 +48,7 @@ class DeclarativeStream(Stream, JsonSchemaMixin): def __post_init__(self, options: Mapping[str, Any]): self.stream_cursor_field = self.stream_cursor_field or [] self.transformations = self.transformations or [] - self._schema_loader = self.schema_loader if self.schema_loader else JsonSchema(config=self.config, options=options) + self._schema_loader = self.schema_loader if self.schema_loader else EmptySchemaLoader(config=self.config, options=options) @property def primary_key(self) -> Optional[Union[str, List[str], List[List[str]]]]: diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/class_types_registry.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/class_types_registry.py index 2419443089aa..2478c4d998a3 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/class_types_registry.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/class_types_registry.py @@ -32,7 +32,8 @@ from airbyte_cdk.sources.declarative.requesters.paginators.strategies.offset_increment import OffsetIncrement from airbyte_cdk.sources.declarative.requesters.paginators.strategies.page_increment import PageIncrement from airbyte_cdk.sources.declarative.retrievers.simple_retriever import SimpleRetriever -from airbyte_cdk.sources.declarative.schema.json_schema import JsonSchema +from airbyte_cdk.sources.declarative.schema import EmptySchemaLoader +from airbyte_cdk.sources.declarative.schema.json_file_schema_loader import JsonFileSchemaLoader from airbyte_cdk.sources.declarative.stream_slicers.cartesian_product_stream_slicer import CartesianProductStreamSlicer from airbyte_cdk.sources.declarative.stream_slicers.datetime_stream_slicer import DatetimeStreamSlicer from airbyte_cdk.sources.declarative.stream_slicers.list_stream_slicer import ListStreamSlicer @@ -58,11 +59,13 @@ "DefaultErrorHandler": DefaultErrorHandler, "DefaultPaginator": DefaultPaginator, "DpathExtractor": DpathExtractor, + "EmptySchemaLoader": EmptySchemaLoader, "ExponentialBackoffStrategy": ExponentialBackoffStrategy, "HttpRequester": HttpRequester, "InterpolatedBoolean": InterpolatedBoolean, "InterpolatedString": InterpolatedString, - "JsonSchema": JsonSchema, + "JsonSchema": JsonFileSchemaLoader, # todo remove after hacktoberfest and update connectors to use JsonFileSchemaLoader + "JsonFileSchemaLoader": JsonFileSchemaLoader, "ListStreamSlicer": ListStreamSlicer, "MinMaxDatetime": MinMaxDatetime, "NoAuth": NoAuth, diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py index e86a3f6462fb..84e1f3631c05 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py @@ -30,7 +30,7 @@ from airbyte_cdk.sources.declarative.requesters.requester import Requester from airbyte_cdk.sources.declarative.retrievers.retriever import Retriever from airbyte_cdk.sources.declarative.retrievers.simple_retriever import SimpleRetriever -from airbyte_cdk.sources.declarative.schema.json_schema import JsonSchema +from airbyte_cdk.sources.declarative.schema import EmptySchemaLoader from airbyte_cdk.sources.declarative.schema.schema_loader import SchemaLoader from airbyte_cdk.sources.declarative.stream_slicers.single_slice import SingleSlice from airbyte_cdk.sources.declarative.stream_slicers.stream_slicer import StreamSlicer @@ -58,7 +58,7 @@ RequestOptionsProvider: InterpolatedRequestOptionsProvider, Requester: HttpRequester, Retriever: SimpleRetriever, - SchemaLoader: JsonSchema, + SchemaLoader: EmptySchemaLoader, Stream: DeclarativeStream, StreamSlicer: SingleSlice, } diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/__init__.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/__init__.py index cbef6eb1d268..85de3cc4f2f6 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/__init__.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/__init__.py @@ -2,7 +2,8 @@ # Copyright (c) 2022 Airbyte, Inc., all rights reserved. # -from airbyte_cdk.sources.declarative.schema.json_schema import JsonSchema +from airbyte_cdk.sources.declarative.schema.empty_schema_loader import EmptySchemaLoader +from airbyte_cdk.sources.declarative.schema.json_file_schema_loader import JsonFileSchemaLoader from airbyte_cdk.sources.declarative.schema.schema_loader import SchemaLoader -__all__ = ["JsonSchema", "SchemaLoader"] +__all__ = ["JsonFileSchemaLoader", "EmptySchemaLoader", "SchemaLoader"] diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/empty_schema_loader.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/empty_schema_loader.py new file mode 100644 index 000000000000..2c189793bf27 --- /dev/null +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/empty_schema_loader.py @@ -0,0 +1,36 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from dataclasses import InitVar, dataclass +from typing import Any, Mapping + +from airbyte_cdk.sources.declarative.schema.schema_loader import SchemaLoader +from airbyte_cdk.sources.declarative.types import Config +from dataclasses_jsonschema import JsonSchemaMixin + + +@dataclass +class EmptySchemaLoader(SchemaLoader, JsonSchemaMixin): + """ + Loads an empty schema for streams that have not defined their schema file yet. + + Attributes: + config (Config): The user-provided configuration as specified by the source's spec + options (Mapping[str, Any]): Additional arguments to pass to the string interpolation if needed + """ + + config: Config + options: InitVar[Mapping[str, Any]] + + def __post_init__(self, options: Mapping[str, Any]): + pass + + def get_json_schema(self) -> Mapping[str, Any]: + """ + Returns by default the empty schema. + + :return: The empty schema + """ + + return {} diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/json_schema.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/json_file_schema_loader.py similarity index 98% rename from airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/json_schema.py rename to airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/json_file_schema_loader.py index a76371757965..de3fb380d1bc 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/json_schema.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/json_file_schema_loader.py @@ -27,7 +27,7 @@ def _default_file_path() -> str: @dataclass -class JsonSchema(SchemaLoader, JsonSchemaMixin): +class JsonFileSchemaLoader(SchemaLoader, JsonSchemaMixin): """ Loads the schema from a json file diff --git a/airbyte-cdk/python/setup.py b/airbyte-cdk/python/setup.py index adfc9b1c6d43..b9db9aa0088f 100644 --- a/airbyte-cdk/python/setup.py +++ b/airbyte-cdk/python/setup.py @@ -15,7 +15,7 @@ setup( name="airbyte-cdk", - version="0.4.2", + version="0.5.2", description="A framework for writing Airbyte Connectors.", long_description=README, long_description_content_type="text/markdown", diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/schema/test_json_schema.py b/airbyte-cdk/python/unit_tests/sources/declarative/schema/test_json_schema.py index 4dc237dc3086..5f95c2fa093c 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/schema/test_json_schema.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/schema/test_json_schema.py @@ -3,7 +3,7 @@ # import pytest -from airbyte_cdk.sources.declarative.schema import JsonSchema +from airbyte_cdk.sources.declarative.schema import JsonFileSchemaLoader @pytest.mark.parametrize( @@ -19,7 +19,7 @@ ], ) def test_extract_resource_and_schema_path(test_name, input_path, expected_resource, expected_path): - json_schema = JsonSchema(input_path, {}, {}) + json_schema = JsonFileSchemaLoader({}, {}, input_path) actual_resource, actual_path = json_schema.extract_resource_and_schema_path(input_path) assert actual_resource == expected_resource diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py b/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py index cbf436b15d5c..fde611268a42 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py @@ -34,7 +34,8 @@ ) from airbyte_cdk.sources.declarative.requesters.requester import HttpMethod from airbyte_cdk.sources.declarative.retrievers.simple_retriever import SimpleRetriever -from airbyte_cdk.sources.declarative.schema.json_schema import JsonSchema +from airbyte_cdk.sources.declarative.schema import EmptySchemaLoader +from airbyte_cdk.sources.declarative.schema.json_file_schema_loader import JsonFileSchemaLoader from airbyte_cdk.sources.declarative.stream_slicers.datetime_stream_slicer import DatetimeStreamSlicer from airbyte_cdk.sources.declarative.stream_slicers.list_stream_slicer import ListStreamSlicer from airbyte_cdk.sources.declarative.transformations import AddFields, RemoveFields @@ -318,7 +319,7 @@ def test_full_config(): partial_stream: class_name: "airbyte_cdk.sources.declarative.declarative_stream.DeclarativeStream" schema_loader: - class_name: airbyte_cdk.sources.declarative.schema.json_schema.JsonSchema + class_name: airbyte_cdk.sources.declarative.schema.json_file_schema_loader.JsonFileSchemaLoader file_path: "./source_sendgrid/schemas/{{ options.name }}.json" cursor_field: [ ] list_stream: @@ -358,7 +359,7 @@ def test_full_config(): assert type(stream) == DeclarativeStream assert stream.primary_key == "id" assert stream.name == "lists" - assert type(stream.schema_loader) == JsonSchema + assert type(stream.schema_loader) == JsonFileSchemaLoader assert type(stream.retriever) == SimpleRetriever assert stream.retriever.requester.http_method == HttpMethod.GET assert stream.retriever.requester.authenticator._token.eval(input_config) == "verysecrettoken" @@ -558,13 +559,13 @@ def test_config_with_defaults(): assert type(stream) == DeclarativeStream assert stream.primary_key == "id" assert stream.name == "lists" - assert type(stream.schema_loader) == JsonSchema + assert type(stream.schema_loader) == EmptySchemaLoader assert type(stream.retriever) == SimpleRetriever assert stream.retriever.requester.http_method == HttpMethod.GET assert stream.retriever.requester.authenticator._token.eval(input_config) == "verysecrettoken" assert [fp.eval(input_config) for fp in stream.retriever.record_selector.extractor.field_pointer] == ["result"] - assert stream.schema_loader._get_json_filepath() == "./source_sendgrid/schemas/lists.yaml" + assert stream.schema_loader.get_json_schema() == {} assert isinstance(stream.retriever.paginator, DefaultPaginator) assert stream.retriever.paginator.url_base.string == "https://api.sendgrid.com" diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/test_yaml_declarative_source.py b/airbyte-cdk/python/unit_tests/sources/declarative/test_yaml_declarative_source.py index e1195244740d..5eb99ddd78d1 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/test_yaml_declarative_source.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/test_yaml_declarative_source.py @@ -268,7 +268,8 @@ def test_generate_schema(): declarative_stream = schema["definitions"]["DeclarativeStream"] assert {"retriever", "config"}.issubset(declarative_stream["required"]) - assert declarative_stream["properties"]["schema_loader"]["$ref"] == "#/definitions/JsonSchema" + assert {"$ref": "#/definitions/EmptySchemaLoader"} in declarative_stream["properties"]["schema_loader"]["anyOf"] + assert {"$ref": "#/definitions/JsonFileSchemaLoader"} in declarative_stream["properties"]["schema_loader"]["anyOf"] assert declarative_stream["properties"]["retriever"]["$ref"] == "#/definitions/SimpleRetriever" assert declarative_stream["properties"]["name"]["type"] == "string" assert {"type": "array", "items": {"type": "string"}} in declarative_stream["properties"]["primary_key"]["anyOf"] diff --git a/airbyte-integrations/connectors/source-courier/source_courier/courier.yaml b/airbyte-integrations/connectors/source-courier/source_courier/courier.yaml index 32fd7da08afe..61364352f844 100644 --- a/airbyte-integrations/connectors/source-courier/source_courier/courier.yaml +++ b/airbyte-integrations/connectors/source-courier/source_courier/courier.yaml @@ -2,7 +2,7 @@ version: "0.1.0" definitions: schema_loader: - type: JsonSchema + type: JsonFileSchemaLoader file_path: "./source_courier/schemas/{{ options['name'] }}.json" root_selector: diff --git a/airbyte-integrations/connectors/source-gocardless/source_gocardless/gocardless.yaml b/airbyte-integrations/connectors/source-gocardless/source_gocardless/gocardless.yaml index 4953d02f4ee8..51aa8edf150a 100644 --- a/airbyte-integrations/connectors/source-gocardless/source_gocardless/gocardless.yaml +++ b/airbyte-integrations/connectors/source-gocardless/source_gocardless/gocardless.yaml @@ -2,7 +2,7 @@ version: "0.1.0" definitions: schema_loader: - type: JsonSchema + type: JsonFileSchemaLoader file_path: "./source_gocardless/schemas/{{ options['name'] }}.json" selector: type: RecordSelector diff --git a/airbyte-integrations/connectors/source-greenhouse/source_greenhouse/greenhouse.yaml b/airbyte-integrations/connectors/source-greenhouse/source_greenhouse/greenhouse.yaml index 6b54022a5d2c..695efefb045d 100644 --- a/airbyte-integrations/connectors/source-greenhouse/source_greenhouse/greenhouse.yaml +++ b/airbyte-integrations/connectors/source-greenhouse/source_greenhouse/greenhouse.yaml @@ -2,6 +2,7 @@ version: "0.1.0" definitions: schema_loader: + type: JsonFileSchemaLoader file_path: "./source_greenhouse/schemas/{{ options['name'] }}.json" selector: type: RecordSelector diff --git a/airbyte-integrations/connectors/source-sendgrid/source_sendgrid/sendgrid.yaml b/airbyte-integrations/connectors/source-sendgrid/source_sendgrid/sendgrid.yaml index a7fa390cbd4a..d964a1724f4e 100644 --- a/airbyte-integrations/connectors/source-sendgrid/source_sendgrid/sendgrid.yaml +++ b/airbyte-integrations/connectors/source-sendgrid/source_sendgrid/sendgrid.yaml @@ -4,7 +4,7 @@ definitions: step: "30d" schema_loader: - type: JsonSchema + type: JsonFileSchemaLoader file_path: "./source_sendgrid/schemas/{{ options.name }}.json" requester: diff --git a/airbyte-integrations/connectors/source-sentry/source_sentry/sentry.yaml b/airbyte-integrations/connectors/source-sentry/source_sentry/sentry.yaml index 8ebc766387b0..36e1de113259 100644 --- a/airbyte-integrations/connectors/source-sentry/source_sentry/sentry.yaml +++ b/airbyte-integrations/connectors/source-sentry/source_sentry/sentry.yaml @@ -2,7 +2,7 @@ version: "0.1.0" definitions: page_size: 50 schema_loader: - type: JsonSchema + type: JsonFileSchemaLoader file_path: "./source_sentry/schemas/{{ options.name }}.json" selector: type: RecordSelector From cf2f23df9a8a98bef4d23b08adf5c72aef4507ff Mon Sep 17 00:00:00 2001 From: Brian Lai <51336873+brianjlai@users.noreply.github.com> Date: Thu, 3 Nov 2022 12:05:30 -0400 Subject: [PATCH 12/73] [low-code cdk] Allow for read command to be run on low code connector streams w/o a schema file (#18532) * use mockschemaloader as the default and rename JsonSchema to JsonFileSchemaLoader * rename mock to EmptySchemaLoader * retain existing JsonSchema while hacktoberfest is still in progress * bump version and changelog From f4e3b605c940e61bf7a2755ce6166b9253b5ab97 Mon Sep 17 00:00:00 2001 From: "Sherif A. Nada" Date: Thu, 3 Nov 2022 09:18:37 -0700 Subject: [PATCH 13/73] fix typo in lowcode tutorial (#18916) --- .../config-based/tutorial/5-incremental-reads.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/connector-development/config-based/tutorial/5-incremental-reads.md b/docs/connector-development/config-based/tutorial/5-incremental-reads.md index a8068c63eaf4..18acb3de45e0 100644 --- a/docs/connector-development/config-based/tutorial/5-incremental-reads.md +++ b/docs/connector-development/config-based/tutorial/5-incremental-reads.md @@ -110,7 +110,7 @@ definitions: and refer to it in the stream's retriever. This will generate slices from the start time until the end time, where each slice is exactly one day. -The start time is defined in the config file, while the end time is defined by the `now_local()` macro, which will evaluate to the current date in the current timezone at runtime. See the section on [string interpolation](../advanced-topics.md#string-interpolation) for more details. +The start time is defined in the config file, while the end time is defined by the `now_utc()` macro, which will evaluate to the current date in the current timezone at runtime. See the section on [string interpolation](../advanced-topics.md#string-interpolation) for more details. Note that we're also setting the `stream_cursor_field` in the stream's `$options` so it can be accessed by the `StreamSlicer`: From 418d0ca7c811faea113ce78de50d5a856cb66d90 Mon Sep 17 00:00:00 2001 From: Jonathan Pearlin Date: Thu, 3 Nov 2022 12:25:33 -0400 Subject: [PATCH 14/73] Update ReplicationActivityImpl.java (#18919) --- .../airbyte/workers/temporal/sync/ReplicationActivityImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/airbyte-workers/src/main/java/io/airbyte/workers/temporal/sync/ReplicationActivityImpl.java b/airbyte-workers/src/main/java/io/airbyte/workers/temporal/sync/ReplicationActivityImpl.java index 2c7369b4d858..54bc24a4aa6f 100644 --- a/airbyte-workers/src/main/java/io/airbyte/workers/temporal/sync/ReplicationActivityImpl.java +++ b/airbyte-workers/src/main/java/io/airbyte/workers/temporal/sync/ReplicationActivityImpl.java @@ -63,7 +63,6 @@ import io.airbyte.workers.sync.ReplicationLauncherWorker; import io.airbyte.workers.temporal.TemporalAttemptExecution; import io.micronaut.context.annotation.Value; -import io.micronaut.core.util.CollectionUtils; import io.temporal.activity.Activity; import io.temporal.activity.ActivityExecutionContext; import jakarta.inject.Named; From a5f72d2a6dcab21498322173459a186c9df79612 Mon Sep 17 00:00:00 2001 From: Liren Tu Date: Thu, 3 Nov 2022 09:31:34 -0700 Subject: [PATCH 15/73] Remove deprecated connector dependency report (#18889) * Update action and template * Bump version for testing * Revert change to test comment update * Update action * Update action * Add comment * Test change again * Update comment * Revert change for testing * Add comment * Fix typos --- .../connector_dependency_template.md | 10 +++++++++- .github/workflows/report-connectors-dependency.yml | 14 +++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/comment_templates/connector_dependency_template.md b/.github/comment_templates/connector_dependency_template.md index b14b73b86e77..6482be6cf525 100644 --- a/.github/comment_templates/connector_dependency_template.md +++ b/.github/comment_templates/connector_dependency_template.md @@ -1,5 +1,7 @@ +## Affected Connector Report + NOTE ⚠️ Changes in this PR affect the following connectors. Make sure to do the following as needed: - Run integration tests - Bump connector version @@ -17,6 +19,8 @@ NOTE ⚠️ Changes in this PR affect the following connectors. Make sure to do | --- | :---: | :---: | :---: | {source_rows} +* See "Actionable Items" below for how to resolve warnings and errors. +

@@ -30,6 +34,8 @@ NOTE ⚠️ Changes in this PR affect the following connectors. Make sure to do | --- | :---: | :---: | :---: | {destination_rows} +* See "Actionable Items" below for how to resolve warnings and errors. +
{others} @@ -38,7 +44,9 @@ NOTE ⚠️ Changes in this PR affect the following connectors. Make sure to do -### Notes +### Actionable Items + +(click to expand) diff --git a/.github/workflows/report-connectors-dependency.yml b/.github/workflows/report-connectors-dependency.yml index 046bb3685c2f..e8461cb15d91 100644 --- a/.github/workflows/report-connectors-dependency.yml +++ b/.github/workflows/report-connectors-dependency.yml @@ -25,7 +25,8 @@ jobs: echo "comment=true" >> $GITHUB_OUTPUT fi - name: Find existing comment for connector dependencies - if: steps.dependency_report.outputs.comment == 'true' + # Always run this step because the action may need to + # remove a comment created from a previous commit. uses: peter-evans/find-comment@v2 id: find_comment with: @@ -40,3 +41,14 @@ jobs: comment-id: ${{ steps.find_comment.outputs.comment-id }} edit-mode: "replace" body-file: "comment_body.md" + - name: Remove deprecated report in PR + if: steps.dependency_report.outputs.comment != 'true' && steps.find_comment.outputs.comment-id != '' + uses: peter-evans/create-or-update-comment@v2 + with: + issue-number: ${{ github.event.pull_request.number }} + comment-id: ${{ steps.find_comment.outputs.comment-id }} + edit-mode: "replace" + body: | + + ## Affected Connector Report + The latest commit has removed all connector-related changes. There are no more dependent connectors for this PR. From f4880813662e2a79ddc39e175ac5f1ed4f903025 Mon Sep 17 00:00:00 2001 From: Volodymyr Pochtar Date: Thu, 3 Nov 2022 19:27:52 +0200 Subject: [PATCH 16/73] ci: bring old set-output to build branch and artifact tags (#18923) --- .github/actions/build-branch/action.yml | 6 ++++++ .github/workflows/publish-oss-for-cloud.yml | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/.github/actions/build-branch/action.yml b/.github/actions/build-branch/action.yml index 04d15c4998c8..c2eca92897dc 100644 --- a/.github/actions/build-branch/action.yml +++ b/.github/actions/build-branch/action.yml @@ -19,6 +19,12 @@ runs: # [[ "${{ inputs.branch_version_tag }}" != '' ]] && echo "branch_version_tag=${{ inputs.branch_version_tag }}" >> $GITHUB_OUTPUT \ || { short_hash=$(git rev-parse --short HEAD); echo "branch_version_tag=dev-$short_hash" >> $GITHUB_OUTPUT ; } + cat $GITHUB_OUTPUT || true # for the sake of investigation + + # if the *branch_version_tag* input param is not specified, then generate it as 'dev-` + # + [[ "${{ inputs.branch_version_tag }}" != '' ]] && echo "::set-output name=branch_version_tag::${{ inputs.branch_version_tag }}" \ + || { short_hash=$(git rev-parse --short HEAD); echo "::set-output name=branch_version_tag::dev-$short_hash"; } - uses: actions/setup-java@v1 with: diff --git a/.github/workflows/publish-oss-for-cloud.yml b/.github/workflows/publish-oss-for-cloud.yml index 8ee97b1ef1ec..11ffd9d98c39 100644 --- a/.github/workflows/publish-oss-for-cloud.yml +++ b/.github/workflows/publish-oss-for-cloud.yml @@ -72,6 +72,15 @@ jobs: if $(git merge-base --is-ancestor "${commit_sha}" master); then echo "master_tag=${commit_sha}" >> $GITHUB_OUTPUT fi + cat $GITHUB_OUTPUT || true # for the sake of investigation + + # set dev_tag + # AirbyteVersion.java allows versions that have a prefix of 'dev' + echo "::set-output name=dev_tag::dev-${commit_sha}" + + if $(git merge-base --is-ancestor "${commit_sha}" master); then + echo "::set-output name=master_tag::${commit_sha}" + fi oss-branch-build: name: "Gradle Build and Publish" From 9231e3ea35761ce4dffb7c52cfb11f34f6c21265 Mon Sep 17 00:00:00 2001 From: Cole Snodgrass Date: Thu, 3 Nov 2022 10:32:08 -0700 Subject: [PATCH 17/73] removed unused code (#18788) * removed unused code * reformat with proper line length --- .../concurrency/GracefulShutdownHandler.java | 39 -- .../concurrency/LifecycledCallable.java | 110 ------ .../airbyte/commons/functional/Consumers.java | 27 -- .../commons/functional/ListConsumer.java | 35 -- .../java/io/airbyte/commons/io/Archives.java | 82 ----- .../io/airbyte/commons/io/FileTtlManager.java | 82 ----- .../io/airbyte/commons/json/JsonSchemas.java | 30 +- .../commons/lang/CloseableShutdownHook.java | 12 +- .../io/airbyte/commons/lang/Exceptions.java | 17 +- .../java/io/airbyte/commons/lang/Queues.java | 39 -- .../io/airbyte/commons/logging/MdcScope.java | 2 +- .../java/io/airbyte/commons/set/MoreSets.java | 22 -- .../io/airbyte/commons/time/Instants.java | 13 - .../java/io/airbyte/commons/type/Types.java | 23 -- .../io/airbyte/commons/util/MoreLists.java | 41 --- .../GracefulShutdownHandlerTest.java | 26 -- .../concurrency/LifecycledCallableTest.java | 78 ---- .../commons/io/FileTtlManagerTest.java | 58 --- .../io/airbyte/commons/set/MoreSetsTest.java | 27 -- .../io/airbyte/commons/time/InstantsTest.java | 20 - .../airbyte/commons/util/MoreListsTest.java | 30 -- .../DestinationAcceptanceTest.java | 342 ++++++++++++------ .../source/relationaldb/AbstractDbSource.java | 326 ++++++++++------- .../protocol/models/CatalogHelpers.java | 164 ++++++--- 24 files changed, 552 insertions(+), 1093 deletions(-) delete mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/concurrency/GracefulShutdownHandler.java delete mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/concurrency/LifecycledCallable.java delete mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/functional/Consumers.java delete mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/functional/ListConsumer.java delete mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/io/Archives.java delete mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/io/FileTtlManager.java delete mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/lang/Queues.java delete mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/set/MoreSets.java delete mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/time/Instants.java delete mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/type/Types.java delete mode 100644 airbyte-commons/src/test/java/io/airbyte/commons/concurrency/GracefulShutdownHandlerTest.java delete mode 100644 airbyte-commons/src/test/java/io/airbyte/commons/concurrency/LifecycledCallableTest.java delete mode 100644 airbyte-commons/src/test/java/io/airbyte/commons/io/FileTtlManagerTest.java delete mode 100644 airbyte-commons/src/test/java/io/airbyte/commons/set/MoreSetsTest.java delete mode 100644 airbyte-commons/src/test/java/io/airbyte/commons/time/InstantsTest.java diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/concurrency/GracefulShutdownHandler.java b/airbyte-commons/src/main/java/io/airbyte/commons/concurrency/GracefulShutdownHandler.java deleted file mode 100644 index 809ecf22d00d..000000000000 --- a/airbyte-commons/src/main/java/io/airbyte/commons/concurrency/GracefulShutdownHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.commons.concurrency; - -import java.time.Duration; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class GracefulShutdownHandler extends Thread { - - private static final Logger LOGGER = LoggerFactory.getLogger(GracefulShutdownHandler.class); - private final Duration terminateWaitDuration; - private final ExecutorService[] threadPools; - - public GracefulShutdownHandler(final Duration terminateWaitDuration, final ExecutorService... threadPools) { - this.terminateWaitDuration = terminateWaitDuration; - this.threadPools = threadPools.clone(); - } - - @Override - public void run() { - for (final ExecutorService threadPool : threadPools) { - threadPool.shutdown(); - - try { - if (!threadPool.awaitTermination(terminateWaitDuration.getSeconds(), TimeUnit.SECONDS)) { - LOGGER.error("Unable to kill threads by shutdown timeout."); - } - } catch (final InterruptedException e) { - LOGGER.error("Wait for graceful thread shutdown interrupted.", e); - } - } - } - -} diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/concurrency/LifecycledCallable.java b/airbyte-commons/src/main/java/io/airbyte/commons/concurrency/LifecycledCallable.java deleted file mode 100644 index e556cfa99f99..000000000000 --- a/airbyte-commons/src/main/java/io/airbyte/commons/concurrency/LifecycledCallable.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.commons.concurrency; - -import io.airbyte.commons.functional.CheckedConsumer; -import java.util.concurrent.Callable; - -public class LifecycledCallable implements Callable { - - public static class Builder { - - private final Callable callable; - - private VoidCallable onStart; - private CheckedConsumer onSuccess; - private CheckedConsumer onException; - private VoidCallable onFinish; - - public Builder(final Callable callable) { - this.callable = callable; - - this.onStart = () -> {}; - this.onSuccess = noop -> {}; - this.onException = noop -> {}; - this.onFinish = () -> {}; - } - - public Builder setOnStart(final VoidCallable onStart) { - this.onStart = onStart; - return this; - } - - public Builder setOnSuccess(final CheckedConsumer onSuccess) { - this.onSuccess = onSuccess; - return this; - } - - public Builder setOnException(final CheckedConsumer onException) { - this.onException = onException; - return this; - } - - public Builder setOnFinish(final VoidCallable onFinish) { - this.onFinish = onFinish; - return this; - } - - public LifecycledCallable build() { - return new LifecycledCallable<>(onStart, callable, onSuccess, onException, onFinish); - } - - } - - private final VoidCallable onStart; - private final Callable decoratedCallable; - private final CheckedConsumer onSuccess; - private final CheckedConsumer onException; - private final VoidCallable onFinish; - - private LifecycledCallable(final VoidCallable onStart, - final Callable decoratedCallable, - final CheckedConsumer onSuccess, - final CheckedConsumer onException, - final VoidCallable onFinish) { - this.onStart = onStart; - this.decoratedCallable = decoratedCallable; - this.onSuccess = onSuccess; - this.onException = onException; - this.onFinish = onFinish; - } - - @Override - public T call() throws Exception { - try { - onStart(); - final T result = execute(); - onSuccess(result); - return result; - } catch (final Exception e) { - onException(e); - throw e; - } finally { - onFinish(); - } - } - - private void onStart() throws Exception { - this.onStart.call(); - } - - private T execute() throws Exception { - return this.decoratedCallable.call(); - - } - - private void onSuccess(final T value) throws Exception { - this.onSuccess.accept(value); - } - - private void onException(final Exception e) throws Exception { - this.onException.accept(e); - } - - private void onFinish() throws Exception { - this.onFinish.call(); - } - -} diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/functional/Consumers.java b/airbyte-commons/src/main/java/io/airbyte/commons/functional/Consumers.java deleted file mode 100644 index 9738a4cd7130..000000000000 --- a/airbyte-commons/src/main/java/io/airbyte/commons/functional/Consumers.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.commons.functional; - -import java.util.function.Consumer; -import java.util.function.Function; - -public class Consumers { - - /** - * Adds a function in front of a consumer. The return of the function will be consumed by the - * original consumer. - * - * @param beforeFunction function that will be execute on an item intended for a consumer. - * @param consumer the consumer that is being preempted. - * @param type of the consumer. - * @return consumer that will run the function and then the original consumer on accept. - */ - public static Consumer wrapConsumer(final Function beforeFunction, final Consumer consumer) { - return (json) -> { - consumer.accept(beforeFunction.apply(json)); - }; - } - -} diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/functional/ListConsumer.java b/airbyte-commons/src/main/java/io/airbyte/commons/functional/ListConsumer.java deleted file mode 100644 index e63fb5f69ebb..000000000000 --- a/airbyte-commons/src/main/java/io/airbyte/commons/functional/ListConsumer.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.commons.functional; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - -/** - * Consumes elements and saves them into a list. This list can be accessed at anytime. Because this - * class stores everything it consumes in memory, it must be used carefully (the original use case - * is for testing interfaces that operate on consumers) - * - * @param type of the consumed elements - */ -public class ListConsumer implements Consumer { - - private final List consumed; - - public ListConsumer() { - this.consumed = new ArrayList<>(); - } - - @Override - public void accept(final T t) { - consumed.add(t); - } - - public List getConsumed() { - return new ArrayList<>(consumed); - } - -} diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/io/Archives.java b/airbyte-commons/src/main/java/io/airbyte/commons/io/Archives.java deleted file mode 100644 index 0e81c1d6adf3..000000000000 --- a/airbyte-commons/src/main/java/io/airbyte/commons/io/Archives.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.commons.io; - -import io.airbyte.commons.lang.Exceptions; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.zip.GZIPOutputStream; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.tar.TarArchiveEntry; -import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; -import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; -import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; - -public class Archives { - - /** - * Compress a @param sourceFolder into a Gzip Tarball @param archiveFile - */ - public static void createArchive(final Path sourceFolder, final Path archiveFile) throws IOException { - final TarArchiveOutputStream archive = - new TarArchiveOutputStream(new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream(archiveFile.toFile())))); - Files.walk(sourceFolder) - .filter(Files::isRegularFile) - .forEach(file -> { - final Path targetFile = sourceFolder.relativize(file); - Exceptions.toRuntime(() -> compressFile(file, targetFile, archive)); - }); - archive.close(); - } - - private static void compressFile(final Path file, final Path filename, final TarArchiveOutputStream archive) throws IOException { - final TarArchiveEntry tarEntry = new TarArchiveEntry(file.toFile(), filename.toString()); - archive.putArchiveEntry(tarEntry); - Files.copy(file, archive); - archive.closeArchiveEntry(); - } - - /** - * Uncompress a Gzip Tarball @param archiveFile into the @param destinationFolder - */ - public static void extractArchive(final Path archiveFile, final Path destinationFolder) throws IOException { - final TarArchiveInputStream archive = - new TarArchiveInputStream(new GzipCompressorInputStream(new BufferedInputStream(Files.newInputStream(archiveFile)))); - ArchiveEntry entry = archive.getNextEntry(); - while (entry != null) { - final Path newPath = zipSlipProtect(entry, destinationFolder); - if (entry.isDirectory()) { - Files.createDirectories(newPath); - } else { - final Path parent = newPath.getParent(); - if (parent != null) { - if (Files.notExists(parent)) { - Files.createDirectories(parent); - } - } - Files.copy(archive, newPath, StandardCopyOption.REPLACE_EXISTING); - } - entry = archive.getNextEntry(); - } - } - - private static Path zipSlipProtect(final ArchiveEntry entry, final Path destinationFolder) - throws IOException { - final Path targetDirResolved = destinationFolder.resolve(entry.getName()); - // make sure normalized file still has destinationFolder as its prefix, - // else throws exception, see: https://snyk.io/research/zip-slip-vulnerability - final Path normalizePath = targetDirResolved.normalize(); - if (!normalizePath.startsWith(destinationFolder)) { - throw new IOException("Bad entry: " + entry.getName()); - } - return normalizePath; - } - -} diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/io/FileTtlManager.java b/airbyte-commons/src/main/java/io/airbyte/commons/io/FileTtlManager.java deleted file mode 100644 index 7ab4ad7134d0..000000000000 --- a/airbyte-commons/src/main/java/io/airbyte/commons/io/FileTtlManager.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.commons.io; - -import com.google.common.base.Preconditions; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalNotification; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.Duration; -import java.time.Instant; -import java.util.concurrent.TimeUnit; -import org.apache.commons.io.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The goal of this class is to remove files given a ttl. It does so WITHOUT adding any background - * threads. The tradeoff it makes is that it only removes files that have reached their TTL (or if - * the cache is full) whenever a new file is added to the manager. This is a good choice when trying - * to avoid file size growing monotonically over long stretches of time. - */ -public class FileTtlManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(FileTtlManager.class); - - private final Cache cache; - private final long expirationDuration; - private final TimeUnit expirationTimeUnit; - - public FileTtlManager(final long expirationDuration, final TimeUnit expirationTimeUnit, final long maxSize) { - this.expirationDuration = expirationDuration; - this.expirationTimeUnit = expirationTimeUnit; - cache = CacheBuilder.newBuilder() - .expireAfterWrite(expirationDuration, expirationTimeUnit) - .maximumSize(maxSize) - .removalListener((RemovalNotification removalNotification) -> { - try { - Files.deleteIfExists(removalNotification.getKey()); - } catch (final IOException e) { - throw new RuntimeException("Failed to delete file at end of ttl: " + removalNotification.getKey(), e); - } - }) - .build(); - } - - public void register(final Path path) { - Preconditions.checkNotNull(path); - Preconditions.checkArgument(path.toFile().isFile()); // only accept files. - - // add to cache so that it will be deleted when expiration time is reached. - cache.put(path, Instant.now()); - // also add schedule deletion when jvm ends (in case jvm ends before expiration is reached). - path.toFile().deleteOnExit(); - reportCacheStatus(); - } - - private void reportCacheStatus() { - final Instant now = Instant.now(); - final StringBuilder sb = new StringBuilder(String.format("Files with ttls (total files: %s):\n", cache.size())); - - cache.asMap().forEach((path, registeredAt) -> { - try { - final Duration timeElapsed = Duration.between(registeredAt, now); - final Duration diffBetweenTotalLifeTimeAndTimeElapsed = Duration.of(expirationDuration, expirationTimeUnit.toChronoUnit()).minus(timeElapsed); - final long minutesRemaining = Math.max(diffBetweenTotalLifeTimeAndTimeElapsed.toMinutes(), 0L); - - sb.append(String.format("File name: %s, Size (MB) %s, TTL %s\n", path, FileUtils.byteCountToDisplaySize(Files.size(path)), minutesRemaining)); - } catch (final IOException e) { - throw new RuntimeException(e); - } - }); - sb.append("---\n"); - final String toLog = sb.toString(); - LOGGER.info(toLog); - } - -} diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/json/JsonSchemas.java b/airbyte-commons/src/main/java/io/airbyte/commons/json/JsonSchemas.java index 7f692042b6ec..492003a2df72 100644 --- a/airbyte-commons/src/main/java/io/airbyte/commons/json/JsonSchemas.java +++ b/airbyte-commons/src/main/java/io/airbyte/commons/json/JsonSchemas.java @@ -10,7 +10,6 @@ import io.airbyte.commons.io.IOs; import io.airbyte.commons.resources.MoreResources; import io.airbyte.commons.util.MoreIterators; -import io.airbyte.commons.util.MoreLists; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -48,7 +47,8 @@ public class JsonSchemas { private static final String ALL_OF_TYPE = "allOf"; private static final String ANY_OF_TYPE = "anyOf"; - private static final Set COMPOSITE_KEYWORDS = Set.of(ONE_OF_TYPE, ALL_OF_TYPE, ANY_OF_TYPE); + private static final Set COMPOSITE_KEYWORDS = Set.of(ONE_OF_TYPE, ALL_OF_TYPE, + ANY_OF_TYPE); /** * JsonSchema supports to ways of declaring type. `type: "string"` and `type: ["null", "string"]`. @@ -114,11 +114,11 @@ public static void traverseJsonSchema(final JsonNode jsonSchema, final BiConsume * Collection } because there is no order or uniqueness guarantee so neither List nor Set * make sense. */ - public static List traverseJsonSchemaWithCollector(final JsonNode jsonSchema, - final BiFunction, T> mapper) { + public static List traverseJsonSchemaWithCollector(final JsonNode jsonSchema, final BiFunction, T> mapper) { // for the sake of code reuse, use the filtered collector method but makes sure the filter always // returns true. - return traverseJsonSchemaWithFilteredCollector(jsonSchema, (node, path) -> Optional.ofNullable(mapper.apply(node, path))); + return traverseJsonSchemaWithFilteredCollector(jsonSchema, + (node, path) -> Optional.ofNullable(mapper.apply(node, path))); } /** @@ -135,7 +135,8 @@ public static List traverseJsonSchemaWithCollector(final JsonNode jsonSch public static List traverseJsonSchemaWithFilteredCollector(final JsonNode jsonSchema, final BiFunction, Optional> mapper) { final List collector = new ArrayList<>(); - traverseJsonSchema(jsonSchema, (node, path) -> mapper.apply(node, path).ifPresent(collector::add)); + traverseJsonSchema(jsonSchema, + (node, path) -> mapper.apply(node, path).ifPresent(collector::add)); return collector.stream().toList(); // make list unmodifiable } @@ -166,14 +167,14 @@ public static List> collectPathsThatMeetCondition(final Js * @param jsonSchemaNode - jsonschema object to traverse. * @param consumer - consumer to be called at each node. it accepts the current node and the path to * the node from the root of the object passed at the root level invocation - * */ @SuppressWarnings("PMD.ForLoopCanBeForeach") private static void traverseJsonSchemaInternal(final JsonNode jsonSchemaNode, final List path, final BiConsumer> consumer) { if (!jsonSchemaNode.isObject()) { - throw new IllegalArgumentException(String.format("json schema nodes should always be object nodes. path: %s actual: %s", path, jsonSchemaNode)); + throw new IllegalArgumentException( + String.format("json schema nodes should always be object nodes. path: %s actual: %s", path, jsonSchemaNode)); } consumer.accept(jsonSchemaNode, path); // if type is missing assume object. not official JsonSchema, but it seems to be a common @@ -184,7 +185,8 @@ private static void traverseJsonSchemaInternal(final JsonNode jsonSchemaNode, switch (nodeType) { // case BOOLEAN_TYPE, NUMBER_TYPE, STRING_TYPE, NULL_TYPE -> do nothing after consumer.accept above. case ARRAY_TYPE -> { - final List newPath = MoreLists.add(path, FieldNameOrList.list()); + final List newPath = new ArrayList<>(List.copyOf(path)); + newPath.add(FieldNameOrList.list()); if (jsonSchemaNode.has(JSON_SCHEMA_ITEMS_KEY)) { // hit every node. traverseJsonSchemaInternal(jsonSchemaNode.get(JSON_SCHEMA_ITEMS_KEY), newPath, consumer); @@ -195,9 +197,11 @@ private static void traverseJsonSchemaInternal(final JsonNode jsonSchemaNode, case OBJECT_TYPE -> { final Optional comboKeyWordOptional = getKeywordIfComposite(jsonSchemaNode); if (jsonSchemaNode.has(JSON_SCHEMA_PROPERTIES_KEY)) { - for (final Iterator> it = jsonSchemaNode.get(JSON_SCHEMA_PROPERTIES_KEY).fields(); it.hasNext();) { + for (final Iterator> it = jsonSchemaNode.get( + JSON_SCHEMA_PROPERTIES_KEY).fields(); it.hasNext();) { final Entry child = it.next(); - final List newPath = MoreLists.add(path, FieldNameOrList.fieldName(child.getKey())); + final List newPath = new ArrayList<>(List.copyOf(path)); + newPath.add(FieldNameOrList.fieldName(child.getKey())); traverseJsonSchemaInternal(child.getValue(), newPath, consumer); } } else if (comboKeyWordOptional.isPresent()) { @@ -272,11 +276,11 @@ public static List getType(final JsonNode jsonSchema) { /** * Provides a basic scheme for describing the path into a JSON object. Each element in the path is * either a field name or a list. - * + *

* This class is helpful in the case where fields can be any UTF-8 string, so the only simple way to * keep track of the different parts of a path without going crazy with escape characters is to keep * it in a list with list set aside as a special case. - * + *

* We prefer using this scheme instead of JSONPath in the tree traversal because, it is easier to * decompose a path in this scheme than it is in JSONPath. Some callers of the traversal logic want * to isolate parts of the path easily without the need for complex regex (that would be required if diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/lang/CloseableShutdownHook.java b/airbyte-commons/src/main/java/io/airbyte/commons/lang/CloseableShutdownHook.java index be36a4aef325..34b63df03ccd 100644 --- a/airbyte-commons/src/main/java/io/airbyte/commons/lang/CloseableShutdownHook.java +++ b/airbyte-commons/src/main/java/io/airbyte/commons/lang/CloseableShutdownHook.java @@ -7,7 +7,6 @@ import com.google.common.annotations.VisibleForTesting; import java.io.Closeable; import java.util.Collection; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,14 +14,14 @@ /** * Registers a shutdown hook that calls the close method of the provided objects. If an object does * not support either the {@link AutoCloseable} or {@link Closeable} interface, it will be ignored. - * + *

* This is a temporary class that is being provided to ensure that resources created by each * application are properly closed on shutdown. This logic will no longer be necessary once an * application framework is introduced to the project that can provide object lifecycle management. */ public class CloseableShutdownHook { - private static final Logger LOGGER = LoggerFactory.getLogger(CloseableShutdownHook.class); + private static final Logger log = LoggerFactory.getLogger(CloseableShutdownHook.class); /** * Registers a runtime shutdown hook with the application for each provided closeable object. @@ -42,10 +41,9 @@ public static void registerRuntimeShutdownHook(final Object... objects) { @VisibleForTesting static Thread buildShutdownHookThread(final Object... objects) { final Collection autoCloseables = Stream.of(objects) - .filter(o -> o != null) .filter(o -> o instanceof AutoCloseable) - .map(o -> AutoCloseable.class.cast(o)) - .collect(Collectors.toList()); + .map(AutoCloseable.class::cast) + .toList(); return new Thread(() -> { autoCloseables.forEach(CloseableShutdownHook::close); @@ -56,7 +54,7 @@ private static void close(final AutoCloseable autoCloseable) { try { autoCloseable.close(); } catch (final Exception e) { - LOGGER.error("Unable to close object {}.", autoCloseable.getClass().getName(), e); + log.error("Unable to close object {}.", autoCloseable.getClass().getName(), e); } } diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/lang/Exceptions.java b/airbyte-commons/src/main/java/io/airbyte/commons/lang/Exceptions.java index 92110cdcb614..18adda592fe2 100644 --- a/airbyte-commons/src/main/java/io/airbyte/commons/lang/Exceptions.java +++ b/airbyte-commons/src/main/java/io/airbyte/commons/lang/Exceptions.java @@ -4,16 +4,15 @@ package io.airbyte.commons.lang; +import java.lang.invoke.MethodHandles; import java.util.concurrent.Callable; import java.util.function.Function; -import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@Slf4j public class Exceptions { - private static final Logger LOGGER = LoggerFactory.getLogger(Exceptions.class); + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); /** * Catch a checked exception and rethrow as a {@link RuntimeException} @@ -41,14 +40,6 @@ public static void toRuntime(final Procedure voidCallable) { castCheckedToRuntime(voidCallable, RuntimeException::new); } - public static void toIllegalState(final Procedure voidCallable) { - castCheckedToRuntime(voidCallable, IllegalStateException::new); - } - - public static void toIllegalArgument(final Procedure voidCallable) { - castCheckedToRuntime(voidCallable, IllegalArgumentException::new); - } - private static void castCheckedToRuntime(final Procedure voidCallable, final Function exceptionFactory) { try { voidCallable.call(); @@ -63,7 +54,7 @@ public static void swallow(final Procedure procedure) { try { procedure.call(); } catch (final Exception e) { - LOGGER.error("Swallowed error.", e); + log.error("Swallowed error.", e); } } @@ -76,7 +67,7 @@ public interface Procedure { public static T swallowWithDefault(final Callable procedure, final T defaultValue) { try { return procedure.call(); - } catch (Exception e) { + } catch (final Exception e) { return defaultValue; } } diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/lang/Queues.java b/airbyte-commons/src/main/java/io/airbyte/commons/lang/Queues.java deleted file mode 100644 index 79fbf35a62d4..000000000000 --- a/airbyte-commons/src/main/java/io/airbyte/commons/lang/Queues.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.commons.lang; - -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.function.Consumer; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -public class Queues { - - /** - * Exposes the contents a {@link CloseableQueue} as a {@link Stream}. Consuming or closing the - * stream does NOT close the queue. - * - * @param queue queue whose content will be exposed as a stream. - * @param type provided by the queue - * @return stream interface on top of the queue. - */ - public static Stream toStream(final CloseableQueue queue) { - return StreamSupport.stream(new Spliterators.AbstractSpliterator<>(Long.MAX_VALUE, Spliterator.ORDERED) { - - @Override - public boolean tryAdvance(final Consumer action) { - final T record = queue.poll(); - if (record == null) { - return false; - } - action.accept(record); - return true; - } - - }, false); - } - -} diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/logging/MdcScope.java b/airbyte-commons/src/main/java/io/airbyte/commons/logging/MdcScope.java index 2b8b2da210f7..34b36adefb5f 100644 --- a/airbyte-commons/src/main/java/io/airbyte/commons/logging/MdcScope.java +++ b/airbyte-commons/src/main/java/io/airbyte/commons/logging/MdcScope.java @@ -12,7 +12,7 @@ /** * This class is an autoClosable class that will add some specific values into the log MDC. When - * being close, it will restore the orginal MDC. It is advise to use it like that: + * being close, it will restore the original MDC. It is advised to use it like that: * *

  *   
diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/set/MoreSets.java b/airbyte-commons/src/main/java/io/airbyte/commons/set/MoreSets.java
deleted file mode 100644
index b51fd27d7ebd..000000000000
--- a/airbyte-commons/src/main/java/io/airbyte/commons/set/MoreSets.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2022 Airbyte, Inc., all rights reserved.
- */
-
-package io.airbyte.commons.set;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
-import java.util.Set;
-
-public class MoreSets {
-
-  public static  void assertEqualsVerbose(final Set set1, final Set set2) {
-    Preconditions.checkNotNull(set1);
-    Preconditions.checkNotNull(set2);
-
-    Preconditions.checkArgument(set1.equals(set2), String.format(
-        "Sets are not the same. Elements in set 1 and not in set 2: %s.  Elements in set 2 and not in set 1: %s",
-        Sets.difference(set1, set2), Sets.difference(set2, set1)));
-  }
-
-}
diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/time/Instants.java b/airbyte-commons/src/main/java/io/airbyte/commons/time/Instants.java
deleted file mode 100644
index 7927af8d1923..000000000000
--- a/airbyte-commons/src/main/java/io/airbyte/commons/time/Instants.java
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright (c) 2022 Airbyte, Inc., all rights reserved.
- */
-
-package io.airbyte.commons.time;
-
-public class Instants {
-
-  public static long toSeconds(final long millis) {
-    return millis / 1000;
-  }
-
-}
diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/type/Types.java b/airbyte-commons/src/main/java/io/airbyte/commons/type/Types.java
deleted file mode 100644
index b74ef7bd0930..000000000000
--- a/airbyte-commons/src/main/java/io/airbyte/commons/type/Types.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 2022 Airbyte, Inc., all rights reserved.
- */
-
-package io.airbyte.commons.type;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-public class Types {
-
-  /**
-   * Convenience method converting a list to a list of lists of the same type. Each item in the
-   * original list is inserted into its own list.
-   */
-  public static  List> boxToListofList(final List list) {
-    final var nonNullEntries = list.stream().filter(Objects::nonNull);
-    return nonNullEntries.map(Collections::singletonList).collect(Collectors.toList());
-  }
-
-}
diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/util/MoreLists.java b/airbyte-commons/src/main/java/io/airbyte/commons/util/MoreLists.java
index fa6779f0d64d..3ede6f63f835 100644
--- a/airbyte-commons/src/main/java/io/airbyte/commons/util/MoreLists.java
+++ b/airbyte-commons/src/main/java/io/airbyte/commons/util/MoreLists.java
@@ -4,38 +4,11 @@
 
 package io.airbyte.commons.util;
 
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
-import java.util.Optional;
 import java.util.stream.Stream;
 
 public class MoreLists {
 
-  /**
-   * @return returns empty optional if the list is empty or if the last element in the list is null.
-   */
-  public static  Optional last(final List list) {
-    if (list.isEmpty()) {
-      return Optional.empty();
-    }
-    return Optional.ofNullable(list.get(list.size() - 1));
-  }
-
-  /**
-   * Reverses a list by creating a new list with the same elements of the input list and then
-   * reversing it. The input list will not be altered.
-   *
-   * @param list to reverse
-   * @param  type
-   * @return new list with elements of original reversed.
-   */
-  public static  List reversed(final List list) {
-    final ArrayList reversed = new ArrayList<>(list);
-    Collections.reverse(reversed);
-    return reversed;
-  }
-
   /**
    * Concatenate multiple lists into one list.
    *
@@ -48,18 +21,4 @@ public static  List concat(final List... lists) {
     return Stream.of(lists).flatMap(List::stream).toList();
   }
 
-  /**
-   * Copies provided list and adds the new item to the copy.
-   *
-   * @param list list to copy and add to
-   * @param toAdd item to add
-   * @param  type of list
-   * @return new list with contents of provided list and the added item
-   */
-  public static  List add(final List list, final T toAdd) {
-    final ArrayList newList = new ArrayList<>(list);
-    newList.add(toAdd);
-    return newList;
-  }
-
 }
diff --git a/airbyte-commons/src/test/java/io/airbyte/commons/concurrency/GracefulShutdownHandlerTest.java b/airbyte-commons/src/test/java/io/airbyte/commons/concurrency/GracefulShutdownHandlerTest.java
deleted file mode 100644
index dad814168d17..000000000000
--- a/airbyte-commons/src/test/java/io/airbyte/commons/concurrency/GracefulShutdownHandlerTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2022 Airbyte, Inc., all rights reserved.
- */
-
-package io.airbyte.commons.concurrency;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import java.time.Duration;
-import java.util.concurrent.ExecutorService;
-import org.junit.jupiter.api.Test;
-
-class GracefulShutdownHandlerTest {
-
-  @Test
-  void testRun() throws InterruptedException {
-    final ExecutorService executorService = mock(ExecutorService.class);
-    final GracefulShutdownHandler gracefulShutdownHandler = new GracefulShutdownHandler(Duration.ofSeconds(30), executorService);
-    gracefulShutdownHandler.start();
-    gracefulShutdownHandler.join();
-
-    verify(executorService).shutdown();
-  }
-
-}
diff --git a/airbyte-commons/src/test/java/io/airbyte/commons/concurrency/LifecycledCallableTest.java b/airbyte-commons/src/test/java/io/airbyte/commons/concurrency/LifecycledCallableTest.java
deleted file mode 100644
index 3206a0205e8a..000000000000
--- a/airbyte-commons/src/test/java/io/airbyte/commons/concurrency/LifecycledCallableTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2022 Airbyte, Inc., all rights reserved.
- */
-
-package io.airbyte.commons.concurrency;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import io.airbyte.commons.functional.CheckedConsumer;
-import java.util.concurrent.Callable;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.InOrder;
-
-class LifecycledCallableTest {
-
-  private Callable callable;
-  private VoidCallable onStart;
-  private CheckedConsumer onException;
-  private CheckedConsumer onSuccess;
-  private VoidCallable onFinish;
-
-  @SuppressWarnings("unchecked")
-  @BeforeEach
-  void setUp() {
-    callable = mock(Callable.class);
-    onStart = mock(VoidCallable.class);
-    onException = mock(CheckedConsumer.class);
-    onSuccess = mock(CheckedConsumer.class);
-    onFinish = mock(VoidCallable.class);
-  }
-
-  @Test
-  void testSuccess() throws Exception {
-    final LifecycledCallable lc = new LifecycledCallable.Builder<>(callable)
-        .setOnStart(onStart)
-        .setOnException(onException)
-        .setOnSuccess(onSuccess)
-        .setOnFinish(onFinish)
-        .build();
-
-    when(callable.call()).thenReturn(1);
-
-    assertEquals(1, lc.call());
-
-    final InOrder inOrder = inOrder(callable, onStart, onException, onSuccess, onFinish);
-    inOrder.verify(onStart).call();
-    inOrder.verify(callable).call();
-    inOrder.verify(onSuccess).accept(1);
-    inOrder.verify(onFinish).call();
-  }
-
-  @Test
-  void testException() throws Exception {
-    final LifecycledCallable lc = new LifecycledCallable.Builder<>(callable)
-        .setOnStart(onStart)
-        .setOnException(onException)
-        .setOnSuccess(onSuccess)
-        .setOnFinish(onFinish)
-        .build();
-
-    final RuntimeException re = new RuntimeException();
-    when(callable.call()).thenThrow(re);
-
-    assertThrows(RuntimeException.class, lc::call);
-
-    final InOrder inOrder = inOrder(callable, onStart, onException, onSuccess, onFinish);
-    inOrder.verify(onStart).call();
-    inOrder.verify(callable).call();
-    inOrder.verify(onException).accept(re);
-    inOrder.verify(onFinish).call();
-  }
-
-}
diff --git a/airbyte-commons/src/test/java/io/airbyte/commons/io/FileTtlManagerTest.java b/airbyte-commons/src/test/java/io/airbyte/commons/io/FileTtlManagerTest.java
deleted file mode 100644
index bb3476175acf..000000000000
--- a/airbyte-commons/src/test/java/io/airbyte/commons/io/FileTtlManagerTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2022 Airbyte, Inc., all rights reserved.
- */
-
-package io.airbyte.commons.io;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.concurrent.TimeUnit;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-class FileTtlManagerTest {
-
-  private Path file1;
-  private Path file2;
-  private Path file3;
-
-  @BeforeEach
-
-  void setup() throws IOException {
-    final Path testRoot = Files.createTempDirectory(Path.of("/tmp"), "ttl_test");
-    file1 = Files.createFile(testRoot.resolve("file1"));
-    file2 = Files.createFile(testRoot.resolve("file2"));
-    file3 = Files.createFile(testRoot.resolve("file3"));
-  }
-
-  @Test
-  void testExpiresAfterTime() throws InterruptedException {
-    final FileTtlManager fileTtlManager = new FileTtlManager(1, TimeUnit.SECONDS, 10);
-
-    assertTrue(Files.exists(file1));
-    fileTtlManager.register(file1);
-    fileTtlManager.register(file2);
-    assertTrue(Files.exists(file1));
-    Thread.sleep(10001L);
-    fileTtlManager.register(file3);
-    assertFalse(Files.exists(file1));
-  }
-
-  @Test
-  void testExpiresAfterSizeLimit() {
-    final FileTtlManager fileTtlManager = new FileTtlManager(1, TimeUnit.HOURS, 2);
-
-    assertTrue(Files.exists(file1));
-    fileTtlManager.register(file1);
-    assertTrue(Files.exists(file1));
-    fileTtlManager.register(file2);
-    assertTrue(Files.exists(file1));
-    fileTtlManager.register(file3);
-    assertFalse(Files.exists(file1));
-  }
-
-}
diff --git a/airbyte-commons/src/test/java/io/airbyte/commons/set/MoreSetsTest.java b/airbyte-commons/src/test/java/io/airbyte/commons/set/MoreSetsTest.java
deleted file mode 100644
index 209cdd3f7b3a..000000000000
--- a/airbyte-commons/src/test/java/io/airbyte/commons/set/MoreSetsTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2022 Airbyte, Inc., all rights reserved.
- */
-
-package io.airbyte.commons.set;
-
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-import com.google.common.collect.ImmutableSet;
-import java.util.Set;
-import org.junit.jupiter.api.Test;
-
-class MoreSetsTest {
-
-  @Test
-  void testAssertEqualsVerbose() {
-    final Set set1 = ImmutableSet.of(1, 2, 3);
-    final Set set2 = ImmutableSet.of(1, 2, 3);
-    final Set set3 = ImmutableSet.of(1, 2);
-
-    assertDoesNotThrow(() -> MoreSets.assertEqualsVerbose(set1, set1));
-    assertDoesNotThrow(() -> MoreSets.assertEqualsVerbose(set1, set2));
-    assertThrows(IllegalArgumentException.class, () -> MoreSets.assertEqualsVerbose(set1, set3));
-  }
-
-}
diff --git a/airbyte-commons/src/test/java/io/airbyte/commons/time/InstantsTest.java b/airbyte-commons/src/test/java/io/airbyte/commons/time/InstantsTest.java
deleted file mode 100644
index 75012c362ac3..000000000000
--- a/airbyte-commons/src/test/java/io/airbyte/commons/time/InstantsTest.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2022 Airbyte, Inc., all rights reserved.
- */
-
-package io.airbyte.commons.time;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.time.Instant;
-import org.junit.jupiter.api.Test;
-
-class InstantsTest {
-
-  @Test
-  void testMillisToSeconds() {
-    final Instant now = Instant.now();
-    assertEquals(now.getEpochSecond(), Instants.toSeconds(now.toEpochMilli()));
-  }
-
-}
diff --git a/airbyte-commons/src/test/java/io/airbyte/commons/util/MoreListsTest.java b/airbyte-commons/src/test/java/io/airbyte/commons/util/MoreListsTest.java
index 3243f370bc57..542e0ee75a49 100644
--- a/airbyte-commons/src/test/java/io/airbyte/commons/util/MoreListsTest.java
+++ b/airbyte-commons/src/test/java/io/airbyte/commons/util/MoreListsTest.java
@@ -6,32 +6,11 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Optional;
 import org.junit.jupiter.api.Test;
 
 class MoreListsTest {
 
-  @Test
-  void testLast() {
-    assertEquals(Optional.of(3), MoreLists.last(List.of(1, 2, 3)));
-    assertEquals(Optional.empty(), MoreLists.last(List.of()));
-
-    final List ints = new ArrayList<>();
-    ints.add(1);
-    ints.add(2);
-    ints.add(null);
-    assertEquals(Optional.empty(), MoreLists.last(ints));
-  }
-
-  @Test
-  void testReverse() {
-    final List originalList = List.of(1, 2, 3);
-    assertEquals(List.of(3, 2, 1), MoreLists.reversed(originalList));
-    assertEquals(List.of(1, 2, 3), originalList);
-  }
-
   @Test
   void testConcat() {
     final List> lists = List.of(List.of(1, 2, 3), List.of(4, 5, 6), List.of(7, 8, 9));
@@ -40,13 +19,4 @@ void testConcat() {
     assertEquals(expected, actual);
   }
 
-  @Test
-  void testAdd() {
-    final List originalList = List.of(1, 2, 3);
-
-    assertEquals(List.of(1, 2, 3, 4), MoreLists.add(originalList, 4));
-    // verify original list was not mutated.
-    assertEquals(List.of(1, 2, 3), originalList);
-  }
-
 }
diff --git a/airbyte-integrations/bases/standard-destination-test/src/main/java/io/airbyte/integrations/standardtest/destination/DestinationAcceptanceTest.java b/airbyte-integrations/bases/standard-destination-test/src/main/java/io/airbyte/integrations/standardtest/destination/DestinationAcceptanceTest.java
index c503edd6e323..f73f96140200 100644
--- a/airbyte-integrations/bases/standard-destination-test/src/main/java/io/airbyte/integrations/standardtest/destination/DestinationAcceptanceTest.java
+++ b/airbyte-integrations/bases/standard-destination-test/src/main/java/io/airbyte/integrations/standardtest/destination/DestinationAcceptanceTest.java
@@ -19,7 +19,6 @@
 import io.airbyte.commons.lang.Exceptions;
 import io.airbyte.commons.resources.MoreResources;
 import io.airbyte.commons.util.MoreIterators;
-import io.airbyte.commons.util.MoreLists;
 import io.airbyte.config.EnvConfigs;
 import io.airbyte.config.JobGetSpecConfig;
 import io.airbyte.config.OperatorDbt;
@@ -156,7 +155,7 @@ protected abstract List retrieveRecords(TestDestinationEnv testEnv,
    * the configuration's 'schema' field, as this is how most of our destinations implement this.
    * Destinations are free to appropriately override this. The return value is used to assert
    * correctness.
-   *
+   * 

* If not applicable, Destinations are free to ignore this. * * @param config - integration-specific configuration returned by {@link #getConfig()}. @@ -279,7 +278,9 @@ protected boolean implementsRecordSizeLimitChecks() { * @return All of the records in the destination at the time this method is invoked. * @throws Exception - can throw any exception, test framework will handle. */ - protected List retrieveNormalizedRecords(final TestDestinationEnv testEnv, final String streamName, final String namespace) + protected List retrieveNormalizedRecords(final TestDestinationEnv testEnv, + final String streamName, + final String namespace) throws Exception { throw new IllegalStateException("Not implemented"); } @@ -326,7 +327,8 @@ void setUpInternal() throws Exception { setup(testEnv); - processFactory = new DockerProcessFactory(workerConfigs, workspaceRoot, workspaceRoot.toString(), localRoot.toString(), "host"); + processFactory = new DockerProcessFactory(workerConfigs, workspaceRoot, + workspaceRoot.toString(), localRoot.toString(), "host"); } @AfterEach @@ -366,11 +368,15 @@ public void testCheckConnectionInvalidCredentials() throws Exception { */ @ParameterizedTest @ArgumentsSource(DataArgumentsProvider.class) - public void testSync(final String messagesFilename, final String catalogFilename) throws Exception { - final AirbyteCatalog catalog = Jsons.deserialize(MoreResources.readResource(catalogFilename), AirbyteCatalog.class); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); + public void testSync(final String messagesFilename, final String catalogFilename) + throws Exception { + final AirbyteCatalog catalog = Jsons.deserialize(MoreResources.readResource(catalogFilename), + AirbyteCatalog.class); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); final List messages = MoreResources.readResource(messagesFilename).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); final JsonNode config = getConfig(); final String defaultSchema = getDefaultSchema(config); @@ -384,11 +390,16 @@ public void testSync(final String messagesFilename, final String catalogFilename */ @ParameterizedTest @ArgumentsSource(DataArgumentsProvider.class) - public void testSyncWithLargeRecordBatch(final String messagesFilename, final String catalogFilename) throws Exception { - final AirbyteCatalog catalog = Jsons.deserialize(MoreResources.readResource(catalogFilename), AirbyteCatalog.class); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); + public void testSyncWithLargeRecordBatch(final String messagesFilename, + final String catalogFilename) + throws Exception { + final AirbyteCatalog catalog = Jsons.deserialize(MoreResources.readResource(catalogFilename), + AirbyteCatalog.class); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); final List messages = MoreResources.readResource(messagesFilename).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); final List largeNumberRecords = Collections .nCopies(400, messages) @@ -397,7 +408,9 @@ public void testSyncWithLargeRecordBatch(final String messagesFilename, final St // regroup messages per stream .sorted(Comparator .comparing(AirbyteMessage::getType) - .thenComparing(message -> message.getType().equals(Type.RECORD) ? message.getRecord().getStream() : message.toString())) + .thenComparing( + message -> message.getType().equals(Type.RECORD) ? message.getRecord().getStream() + : message.toString())) .collect(Collectors.toList()); final JsonNode config = getConfig(); @@ -415,11 +428,16 @@ public void testSecondSync() throws Exception { } final AirbyteCatalog catalog = - Jsons.deserialize(MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), AirbyteCatalog.class); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); - - final List firstSyncMessages = MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + Jsons.deserialize( + MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), + AirbyteCatalog.class); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); + + final List firstSyncMessages = MoreResources.readResource( + DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); final JsonNode config = getConfig(); runSyncAndVerifyStateOutput(config, firstSyncMessages, configuredCatalog, false); @@ -427,9 +445,12 @@ public void testSecondSync() throws Exception { // affected\deleted\overridden by our activities during first, second or any future sync. // So let's create a dummy data that will be checked after all sync. It should remain the same final AirbyteCatalog dummyCatalog = - Jsons.deserialize(MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), AirbyteCatalog.class); + Jsons.deserialize( + MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), + AirbyteCatalog.class); dummyCatalog.getStreams().get(0).setName(DUMMY_CATALOG_NAME); - final ConfiguredAirbyteCatalog configuredDummyCatalog = CatalogHelpers.toDefaultConfiguredCatalog(dummyCatalog); + final ConfiguredAirbyteCatalog configuredDummyCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + dummyCatalog); // update messages to set new dummy stream name firstSyncMessages.stream().filter(message -> message.getRecord() != null) .forEach(message -> message.getRecord().setStream(DUMMY_CATALOG_NAME)); @@ -454,7 +475,8 @@ public void testSecondSync() throws Exception { .build()))), new AirbyteMessage() .withType(Type.STATE) - .withState(new AirbyteStateMessage().withData(Jsons.jsonNode(ImmutableMap.of("checkpoint", 2))))); + .withState(new AirbyteStateMessage().withData( + Jsons.jsonNode(ImmutableMap.of("checkpoint", 2))))); runSyncAndVerifyStateOutput(config, secondSyncMessages, configuredCatalog, false); final String defaultSchema = getDefaultSchema(config); @@ -472,8 +494,11 @@ public void testSecondSync() throws Exception { @Test public void testLineBreakCharacters() throws Exception { final AirbyteCatalog catalog = - Jsons.deserialize(MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), AirbyteCatalog.class); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); + Jsons.deserialize( + MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), + AirbyteCatalog.class); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); final JsonNode config = getConfig(); final List secondSyncMessages = Lists.newArrayList( @@ -493,7 +518,8 @@ public void testLineBreakCharacters() throws Exception { .build()))), new AirbyteMessage() .withType(Type.STATE) - .withState(new AirbyteStateMessage().withData(Jsons.jsonNode(ImmutableMap.of("checkpoint", 2))))); + .withState(new AirbyteStateMessage().withData( + Jsons.jsonNode(ImmutableMap.of("checkpoint", 2))))); runSyncAndVerifyStateOutput(config, secondSyncMessages, configuredCatalog, false); final String defaultSchema = getDefaultSchema(config); @@ -533,15 +559,20 @@ public void testIncrementalSync() throws Exception { } final AirbyteCatalog catalog = - Jsons.deserialize(MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), AirbyteCatalog.class); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); + Jsons.deserialize( + MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), + AirbyteCatalog.class); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); configuredCatalog.getStreams().forEach(s -> { s.withSyncMode(SyncMode.INCREMENTAL); s.withDestinationSyncMode(DestinationSyncMode.APPEND); }); - final List firstSyncMessages = MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + final List firstSyncMessages = MoreResources.readResource( + DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); final JsonNode config = getConfig(); runSyncAndVerifyStateOutput(config, firstSyncMessages, configuredCatalog, false); final List secondSyncMessages = Lists.newArrayList( @@ -561,7 +592,8 @@ public void testIncrementalSync() throws Exception { .build()))), new AirbyteMessage() .withType(Type.STATE) - .withState(new AirbyteStateMessage().withData(Jsons.jsonNode(ImmutableMap.of("checkpoint", 2))))); + .withState(new AirbyteStateMessage().withData( + Jsons.jsonNode(ImmutableMap.of("checkpoint", 2))))); runSyncAndVerifyStateOutput(config, secondSyncMessages, configuredCatalog, false); final List expectedMessagesAfterSecondSync = new ArrayList<>(); @@ -569,7 +601,8 @@ public void testIncrementalSync() throws Exception { expectedMessagesAfterSecondSync.addAll(secondSyncMessages); final String defaultSchema = getDefaultSchema(config); - retrieveRawRecordsAndAssertSameMessages(catalog, expectedMessagesAfterSecondSync, defaultSchema); + retrieveRawRecordsAndAssertSameMessages(catalog, expectedMessagesAfterSecondSync, + defaultSchema); } /** @@ -578,51 +611,63 @@ public void testIncrementalSync() throws Exception { */ @ParameterizedTest @ArgumentsSource(DataArgumentsProvider.class) - public void testSyncWithNormalization(final String messagesFilename, final String catalogFilename) throws Exception { + public void testSyncWithNormalization(final String messagesFilename, final String catalogFilename) + throws Exception { if (!normalizationFromSpec()) { return; } - final AirbyteCatalog catalog = Jsons.deserialize(MoreResources.readResource(catalogFilename), AirbyteCatalog.class); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); + final AirbyteCatalog catalog = Jsons.deserialize(MoreResources.readResource(catalogFilename), + AirbyteCatalog.class); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); final List messages = MoreResources.readResource(messagesFilename).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); final JsonNode config = getConfig(); runSyncAndVerifyStateOutput(config, messages, configuredCatalog, true); final String defaultSchema = getDefaultSchema(config); - final List actualMessages = retrieveNormalizedRecords(catalog, defaultSchema); + final List actualMessages = retrieveNormalizedRecords(catalog, + defaultSchema); assertSameMessages(messages, actualMessages, true); } /** * Verify that the integration successfully writes records successfully both raw and normalized and * run dedupe transformations. - * + *

* Although this test assumes append-dedup requires normalization, and almost all our Destinations * do so, this is not necessarily true. This explains {@link #implementsAppendDedup()}. */ @Test public void testIncrementalDedupeSync() throws Exception { if (!implementsAppendDedup()) { - LOGGER.info("Destination's spec.json does not include 'append_dedupe' in its '\"supportedDestinationSyncModes\"'"); + LOGGER.info( + "Destination's spec.json does not include 'append_dedupe' in its '\"supportedDestinationSyncModes\"'"); return; } final AirbyteCatalog catalog = - Jsons.deserialize(MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), AirbyteCatalog.class); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); + Jsons.deserialize( + MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), + AirbyteCatalog.class); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); configuredCatalog.getStreams().forEach(s -> { s.withSyncMode(SyncMode.INCREMENTAL); s.withDestinationSyncMode(DestinationSyncMode.APPEND_DEDUP); s.withCursorField(Collections.emptyList()); // use composite primary key of various types (string, float) - s.withPrimaryKey(List.of(List.of("id"), List.of("currency"), List.of("date"), List.of("NZD"))); + s.withPrimaryKey( + List.of(List.of("id"), List.of("currency"), List.of("date"), List.of("NZD"))); }); - final List firstSyncMessages = MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + final List firstSyncMessages = MoreResources.readResource( + DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); final JsonNode config = getConfig(); runSyncAndVerifyStateOutput(config, firstSyncMessages, configuredCatalog, true); @@ -653,7 +698,8 @@ public void testIncrementalDedupeSync() throws Exception { .build()))), new AirbyteMessage() .withType(Type.STATE) - .withState(new AirbyteStateMessage().withData(Jsons.jsonNode(ImmutableMap.of("checkpoint", 2))))); + .withState(new AirbyteStateMessage().withData( + Jsons.jsonNode(ImmutableMap.of("checkpoint", 2))))); runSyncAndVerifyStateOutput(config, secondSyncMessages, configuredCatalog, true); final List expectedMessagesAfterSecondSync = new ArrayList<>(); @@ -680,12 +726,15 @@ public void testIncrementalDedupeSync() throws Exception { message.getRecord().getData().get("currency").asText() + message.getRecord().getData().get("date").asText() + message.getRecord().getData().get("NZD").asText(); - return message.getRecord().getEmittedAt().equals(latestMessagesOnly.get(key).getRecord().getEmittedAt()); + return message.getRecord().getEmittedAt() + .equals(latestMessagesOnly.get(key).getRecord().getEmittedAt()); }).collect(Collectors.toList()); final String defaultSchema = getDefaultSchema(config); - retrieveRawRecordsAndAssertSameMessages(catalog, expectedMessagesAfterSecondSync, defaultSchema); - final List actualMessages = retrieveNormalizedRecords(catalog, defaultSchema); + retrieveRawRecordsAndAssertSameMessages(catalog, expectedMessagesAfterSecondSync, + defaultSchema); + final List actualMessages = retrieveNormalizedRecords(catalog, + defaultSchema); assertSameMessages(expectedMessages, actualMessages, true); } @@ -693,7 +742,7 @@ public void testIncrementalDedupeSync() throws Exception { * This test is running a sync using the exchange rate catalog and messages. However it also * generates and adds two extra messages with big records (near the destination limit as defined by * getMaxValueLengthLimit() - * + *

* The first big message should be small enough to fit into the destination while the second message * would be too big and fails to replicate. */ @@ -704,10 +753,15 @@ void testSyncVeryBigRecords() throws Exception { } final AirbyteCatalog catalog = - Jsons.deserialize(MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), AirbyteCatalog.class); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); - final List messages = MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + Jsons.deserialize( + MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), + AirbyteCatalog.class); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); + final List messages = MoreResources.readResource( + DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); // Add a big message that barely fits into the limits of the destination messages.add(new AirbyteMessage() .withType(Type.RECORD) @@ -781,10 +835,11 @@ public void testCustomDbtTransformations() throws Exception { // this test successfully and that we are able to convert a destination 'config.json' into a dbt // 'profiles.yml' // (we don't actually rely on normalization running anything else here though) - final DbtTransformationRunner runner = new DbtTransformationRunner(processFactory, NormalizationRunnerFactory.create( - getImageName(), - processFactory, - NORMALIZATION_VERSION)); + final DbtTransformationRunner runner = new DbtTransformationRunner(processFactory, + NormalizationRunnerFactory.create( + getImageName(), + processFactory, + NORMALIZATION_VERSION)); runner.start(); final Path transformationRoot = Files.createDirectories(jobRoot.resolve("transform")); final OperatorDbt dbtConfig = new OperatorDbt() @@ -797,7 +852,9 @@ public void testCustomDbtTransformations() throws Exception { // TODO once we're on DBT 1.x, switch this back to using the main branch .withGitRepoUrl("https://github.com/airbytehq/jaffle_shop.git") .withGitRepoBranch("pre_dbt_upgrade") - .withDockerImage(NormalizationRunnerFactory.getNormalizationInfoForConnector(getImageName()).getLeft() + ":" + NORMALIZATION_VERSION); + .withDockerImage( + NormalizationRunnerFactory.getNormalizationInfoForConnector(getImageName()).getLeft() + + ":" + NORMALIZATION_VERSION); // // jaffle_shop is a fictional ecommerce store maintained by fishtownanalytics/dbt. // @@ -856,10 +913,11 @@ void testCustomDbtTransformationsFailure() throws Exception { final JsonNode config = getConfig(); - final DbtTransformationRunner runner = new DbtTransformationRunner(processFactory, NormalizationRunnerFactory.create( - getImageName(), - processFactory, - NORMALIZATION_VERSION)); + final DbtTransformationRunner runner = new DbtTransformationRunner(processFactory, + NormalizationRunnerFactory.create( + getImageName(), + processFactory, + NORMALIZATION_VERSION)); runner.start(); final Path transformationRoot = Files.createDirectories(jobRoot.resolve("transform")); final OperatorDbt dbtConfig = new OperatorDbt() @@ -887,14 +945,20 @@ void testSyncUsesAirbyteStreamNamespaceIfNotNull() throws Exception { // TODO(davin): make these tests part of the catalog file. final AirbyteCatalog catalog = - Jsons.deserialize(MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), AirbyteCatalog.class); + Jsons.deserialize( + MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), + AirbyteCatalog.class); final String namespace = "sourcenamespace"; catalog.getStreams().forEach(stream -> stream.setNamespace(namespace)); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); - final List messages = MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); - final List messagesWithNewNamespace = getRecordMessagesWithNewNamespace(messages, namespace); + final List messages = MoreResources.readResource( + DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); + final List messagesWithNewNamespace = getRecordMessagesWithNewNamespace( + messages, namespace); final JsonNode config = getConfig(); final String defaultSchema = getDefaultSchema(config); @@ -913,7 +977,9 @@ void testSyncWriteSameTableNameDifferentNamespace() throws Exception { // TODO(davin): make these tests part of the catalog file. final var catalog = - Jsons.deserialize(MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), AirbyteCatalog.class); + Jsons.deserialize( + MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), + AirbyteCatalog.class); final var namespace1 = "sourcenamespace"; catalog.getStreams().forEach(stream -> stream.setNamespace(namespace1)); @@ -921,7 +987,8 @@ void testSyncWriteSameTableNameDifferentNamespace() throws Exception { final var namespace2 = "diff_source_namespace"; final var mapper = MoreMappers.initMapper(); for (final AirbyteStream stream : catalog.getStreams()) { - final var clonedStream = mapper.readValue(mapper.writeValueAsString(stream), AirbyteStream.class); + final var clonedStream = mapper.readValue(mapper.writeValueAsString(stream), + AirbyteStream.class); clonedStream.setNamespace(namespace2); diffNamespaceStreams.add(clonedStream); } @@ -929,11 +996,15 @@ void testSyncWriteSameTableNameDifferentNamespace() throws Exception { final var configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); - final var ns1Messages = MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + final var ns1Messages = MoreResources.readResource( + DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); final var ns1MessagesAtNamespace1 = getRecordMessagesWithNewNamespace(ns1Messages, namespace1); - final var ns2Messages = MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + final var ns2Messages = MoreResources.readResource( + DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); final var ns2MessagesAtNamespace2 = getRecordMessagesWithNewNamespace(ns2Messages, namespace2); final var allMessages = new ArrayList<>(ns1MessagesAtNamespace1); @@ -948,7 +1019,8 @@ void testSyncWriteSameTableNameDifferentNamespace() throws Exception { public static class NamespaceTestCaseProvider implements ArgumentsProvider { @Override - public Stream provideArguments(final ExtensionContext context) throws Exception { + public Stream provideArguments(final ExtensionContext context) + throws Exception { final JsonNode testCases = Jsons.deserialize(MoreResources.readResource("namespace_test_cases.json")); return MoreIterators.toList(testCases.elements()).stream() @@ -963,23 +1035,32 @@ public Stream provideArguments(final ExtensionContext conte @ParameterizedTest @ArgumentsSource(NamespaceTestCaseProvider.class) - public void testNamespaces(final String testCaseId, final String namespace, final String normalizedNamespace) throws Exception { + public void testNamespaces(final String testCaseId, + final String namespace, + final String normalizedNamespace) + throws Exception { final Optional nameTransformer = getNameTransformer(); - nameTransformer.ifPresent(namingConventionTransformer -> assertNamespaceNormalization(testCaseId, normalizedNamespace, - namingConventionTransformer.getNamespace(namespace))); + nameTransformer.ifPresent( + namingConventionTransformer -> assertNamespaceNormalization(testCaseId, normalizedNamespace, + namingConventionTransformer.getNamespace(namespace))); if (!implementsNamespaces() || !supportNamespaceTest()) { return; } final AirbyteCatalog catalog = Jsons.deserialize( - MoreResources.readResource(DataArgumentsProvider.NAMESPACE_CONFIG.catalogFile), AirbyteCatalog.class); + MoreResources.readResource(DataArgumentsProvider.NAMESPACE_CONFIG.catalogFile), + AirbyteCatalog.class); catalog.getStreams().forEach(stream -> stream.setNamespace(namespace)); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); - final List messages = MoreResources.readResource(DataArgumentsProvider.NAMESPACE_CONFIG.messageFile).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); - final List messagesWithNewNamespace = getRecordMessagesWithNewNamespace(messages, namespace); + final List messages = MoreResources.readResource( + DataArgumentsProvider.NAMESPACE_CONFIG.messageFile).lines() + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); + final List messagesWithNewNamespace = getRecordMessagesWithNewNamespace( + messages, namespace); final JsonNode config = getConfig(); try { @@ -1023,11 +1104,16 @@ public void testSyncNotFailsWithNewFields() throws Exception { } final AirbyteCatalog catalog = - Jsons.deserialize(MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), AirbyteCatalog.class); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); - - final List firstSyncMessages = MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + Jsons.deserialize( + MoreResources.readResource(DataArgumentsProvider.EXCHANGE_RATE_CONFIG.catalogFile), + AirbyteCatalog.class); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); + + final List firstSyncMessages = MoreResources.readResource( + DataArgumentsProvider.EXCHANGE_RATE_CONFIG.messageFile).lines() + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); final JsonNode config = getConfig(); runSyncAndVerifyStateOutput(config, firstSyncMessages, configuredCatalog, false); final var stream = catalog.getStreams().get(0); @@ -1050,13 +1136,16 @@ public void testSyncNotFailsWithNewFields() throws Exception { .build()))), new AirbyteMessage() .withType(Type.STATE) - .withState(new AirbyteStateMessage().withData(Jsons.jsonNode(ImmutableMap.of("checkpoint", 2))))); + .withState(new AirbyteStateMessage().withData( + Jsons.jsonNode(ImmutableMap.of("checkpoint", 2))))); // Run sync and verify that all message were written without failing runSyncAndVerifyStateOutput(config, secondSyncMessagesWithNewFields, configuredCatalog, false); - final var destinationOutput = retrieveRecords(testEnv, stream.getName(), getDefaultSchema(config), stream.getJsonSchema()); + final var destinationOutput = retrieveRecords(testEnv, stream.getName(), + getDefaultSchema(config), stream.getJsonSchema()); // Remove state message - secondSyncMessagesWithNewFields.removeIf(airbyteMessage -> airbyteMessage.getType().equals(Type.STATE)); + secondSyncMessagesWithNewFields.removeIf( + airbyteMessage -> airbyteMessage.getType().equals(Type.STATE)); assertEquals(secondSyncMessagesWithNewFields.size(), destinationOutput.size()); } @@ -1083,7 +1172,9 @@ protected void assertNamespaceNormalization(final String testCaseId, final String expectedNormalizedNamespace, final String actualNormalizedNamespace) { assertEquals(expectedNormalizedNamespace, actualNormalizedNamespace, - String.format("Test case %s failed; if this is expected, please override assertNamespaceNormalization", testCaseId)); + String.format( + "Test case %s failed; if this is expected, please override assertNamespaceNormalization", + testCaseId)); } private ConnectorSpecification runSpec() throws WorkerException { @@ -1095,14 +1186,17 @@ private ConnectorSpecification runSpec() throws WorkerException { protected StandardCheckConnectionOutput runCheck(final JsonNode config) throws WorkerException { return new DefaultCheckConnectionWorker( new AirbyteIntegrationLauncher(JOB_ID, JOB_ATTEMPT, getImageName(), processFactory, null)) - .run(new StandardCheckConnectionInput().withConnectionConfiguration(config), jobRoot).getCheckConnection(); + .run(new StandardCheckConnectionInput().withConnectionConfiguration(config), jobRoot) + .getCheckConnection(); } - protected StandardCheckConnectionOutput.Status runCheckWithCatchedException(final JsonNode config) { + protected StandardCheckConnectionOutput.Status runCheckWithCatchedException( + final JsonNode config) { try { final StandardCheckConnectionOutput standardCheckConnectionOutput = new DefaultCheckConnectionWorker( new AirbyteIntegrationLauncher(JOB_ID, JOB_ATTEMPT, getImageName(), processFactory, null)) - .run(new StandardCheckConnectionInput().withConnectionConfiguration(config), jobRoot).getCheckConnection(); + .run(new StandardCheckConnectionInput().withConnectionConfiguration(config), jobRoot) + .getCheckConnection(); return standardCheckConnectionOutput.getStatus(); } catch (final Exception e) { LOGGER.error("Failed to check connection:" + e.getMessage()); @@ -1120,14 +1214,19 @@ protected void runSyncAndVerifyStateOutput(final JsonNode config, final ConfiguredAirbyteCatalog catalog, final boolean runNormalization) throws Exception { - final List destinationOutput = runSync(config, messages, catalog, runNormalization); - final AirbyteMessage expectedStateMessage = MoreLists.reversed(messages) + final List destinationOutput = runSync(config, messages, catalog, + runNormalization); + + Collections.reverse(messages); + final AirbyteMessage expectedStateMessage = messages .stream() .filter(m -> m.getType() == Type.STATE) .findFirst() - .orElseThrow(() -> new IllegalArgumentException("All message sets used for testing should include a state record")); + .orElseThrow(() -> new IllegalArgumentException( + "All message sets used for testing should include a state record")); - final AirbyteMessage actualStateMessage = MoreLists.reversed(destinationOutput) + Collections.reverse(destinationOutput); + final AirbyteMessage actualStateMessage = destinationOutput .stream() .filter(m -> m.getType() == Type.STATE) .findFirst() @@ -1174,7 +1273,8 @@ private List runSync( NORMALIZATION_VERSION); runner.start(); final Path normalizationRoot = Files.createDirectories(jobRoot.resolve("normalize")); - if (!runner.normalize(JOB_ID, JOB_ATTEMPT, normalizationRoot, destinationConfig.getDestinationConnectionConfiguration(), + if (!runner.normalize(JOB_ID, JOB_ATTEMPT, normalizationRoot, + destinationConfig.getDestinationConnectionConfiguration(), destinationConfig.getCatalog(), null)) { throw new WorkerException("Normalization Failed."); } @@ -1190,9 +1290,12 @@ protected void retrieveRawRecordsAndAssertSameMessages(final AirbyteCatalog cata for (final AirbyteStream stream : catalog.getStreams()) { final String streamName = stream.getName(); final String schema = stream.getNamespace() != null ? stream.getNamespace() : defaultSchema; - final List msgList = retrieveRecords(testEnv, streamName, schema, stream.getJsonSchema()) - .stream() - .map(data -> new AirbyteRecordMessage().withStream(streamName).withNamespace(schema).withData(data)).toList(); + final List msgList = retrieveRecords(testEnv, streamName, schema, + stream.getJsonSchema()) + .stream() + .map(data -> new AirbyteRecordMessage().withStream(streamName).withNamespace(schema) + .withData(data)) + .toList(); actualMessages.addAll(msgList); } @@ -1219,15 +1322,18 @@ protected void assertSameMessages(final List expected, testDataComparator.assertSameData(expectedProcessed, actualProcessed); } - protected List retrieveNormalizedRecords(final AirbyteCatalog catalog, final String defaultSchema) throws Exception { + protected List retrieveNormalizedRecords(final AirbyteCatalog catalog, + final String defaultSchema) + throws Exception { final List actualMessages = new ArrayList<>(); for (final AirbyteStream stream : catalog.getStreams()) { final String streamName = stream.getName(); - final List msgList = retrieveNormalizedRecords(testEnv, streamName, defaultSchema) - .stream() - .map(data -> new AirbyteRecordMessage().withStream(streamName).withData(data)).toList(); + final List msgList = retrieveNormalizedRecords(testEnv, streamName, + defaultSchema) + .stream() + .map(data -> new AirbyteRecordMessage().withStream(streamName).withData(data)).toList(); actualMessages.addAll(msgList); } return actualMessages; @@ -1278,7 +1384,8 @@ private void pruneMutate(final JsonNode json) { "HASHID", "unique_key", "UNIQUE_KEY"); - if (airbyteInternalFields.stream().anyMatch(internalField -> key.toLowerCase().contains(internalField.toLowerCase())) + if (airbyteInternalFields.stream() + .anyMatch(internalField -> key.toLowerCase().contains(internalField.toLowerCase())) || json.get(key).isNull()) { ((ObjectNode) json).remove(key); } @@ -1443,8 +1550,10 @@ protected boolean supportObjectDataTypeTest() { return false; } - private boolean checkTestCompatibility(final DataTypeTestArgumentProvider.TestCompatibility testCompatibility) { - return testCompatibility.isTestCompatible(supportBasicDataTypeTest(), supportArrayDataTypeTest(), supportObjectDataTypeTest()); + private boolean checkTestCompatibility( + final DataTypeTestArgumentProvider.TestCompatibility testCompatibility) { + return testCompatibility.isTestCompatible(supportBasicDataTypeTest(), + supportArrayDataTypeTest(), supportObjectDataTypeTest()); } @ParameterizedTest @@ -1453,11 +1562,13 @@ public void testDataTypeTestWithNormalization(final String messagesFilename, final String catalogFilename, final DataTypeTestArgumentProvider.TestCompatibility testCompatibility) throws Exception { - if (!checkTestCompatibility(testCompatibility)) + if (!checkTestCompatibility(testCompatibility)) { return; + } final AirbyteCatalog catalog = readCatalogFromFile(catalogFilename); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog(catalog); + final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers.toDefaultConfiguredCatalog( + catalog); final List messages = readMessagesFromFile(messagesFilename); if (supportsNormalization()) { @@ -1473,9 +1584,11 @@ private AirbyteCatalog readCatalogFromFile(final String catalogFilename) throws return Jsons.deserialize(MoreResources.readResource(catalogFilename), AirbyteCatalog.class); } - private List readMessagesFromFile(final String messagesFilename) throws IOException { + private List readMessagesFromFile(final String messagesFilename) + throws IOException { return MoreResources.readResource(messagesFilename).lines() - .map(record -> Jsons.deserialize(record, AirbyteMessage.class)).collect(Collectors.toList()); + .map(record -> Jsons.deserialize(record, AirbyteMessage.class)) + .collect(Collectors.toList()); } private void runAndCheckWithNormalization(final List messages, @@ -1485,7 +1598,8 @@ private void runAndCheckWithNormalization(final List messages, final JsonNode config = getConfig(); runSyncAndVerifyStateOutput(config, messages, configuredCatalog, true); - final List actualMessages = retrieveNormalizedRecords(catalog, getDefaultSchema(config)); + final List actualMessages = retrieveNormalizedRecords(catalog, + getDefaultSchema(config)); assertSameMessages(messages, actualMessages, true); } @@ -1501,7 +1615,9 @@ private void runAndCheckWithoutNormalization(final List messages /** * Mutate the input airbyte record message namespace. */ - private static List getRecordMessagesWithNewNamespace(final List airbyteMessages, final String namespace) { + private static List getRecordMessagesWithNewNamespace( + final List airbyteMessages, + final String namespace) { airbyteMessages.forEach(message -> { if (message.getRecord() != null) { message.getRecord().setNamespace(namespace); diff --git a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java index eed23df04b81..f6a0d225b7fb 100644 --- a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java +++ b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java @@ -15,7 +15,6 @@ import io.airbyte.commons.functional.CheckedConsumer; import io.airbyte.commons.json.Jsons; import io.airbyte.commons.lang.Exceptions; -import io.airbyte.commons.type.Types; import io.airbyte.commons.util.AutoCloseableIterator; import io.airbyte.commons.util.AutoCloseableIterators; import io.airbyte.config.StateWrapper; @@ -87,7 +86,8 @@ public AirbyteConnectionStatus check(final JsonNode config) throws Exception { return new AirbyteConnectionStatus().withStatus(Status.SUCCEEDED); } catch (final ConnectionErrorException ex) { - final String message = getErrorMessage(ex.getStateCode(), ex.getErrorCode(), ex.getExceptionMessage(), ex); + final String message = getErrorMessage(ex.getStateCode(), ex.getErrorCode(), + ex.getExceptionMessage(), ex); AirbyteTraceMessageUtility.emitConfigErrorTrace(ex, message); return new AirbyteConnectionStatus() .withStatus(Status.FAILED) @@ -107,13 +107,21 @@ public AirbyteCatalog discover(final JsonNode config) throws Exception { try { final Database database = createDatabaseInternal(config); final List streams = getTables(database).stream() - .map(tableInfo -> CatalogHelpers - .createAirbyteStream(tableInfo.getName(), tableInfo.getNameSpace(), - tableInfo.getFields()) - .withSupportedSyncModes( - tableInfo.getCursorFields() != null && tableInfo.getCursorFields().isEmpty() ? Lists.newArrayList(SyncMode.FULL_REFRESH) - : Lists.newArrayList(SyncMode.FULL_REFRESH, SyncMode.INCREMENTAL)) - .withSourceDefinedPrimaryKey(Types.boxToListofList(tableInfo.getPrimaryKeys()))) + .map(tableInfo -> { + final var primaryKeys = tableInfo.getPrimaryKeys().stream() + .filter(Objects::nonNull) + .map(Collections::singletonList) + .collect(Collectors.toList()); + + return CatalogHelpers + .createAirbyteStream(tableInfo.getName(), tableInfo.getNameSpace(), + tableInfo.getFields()) + .withSupportedSyncModes( + tableInfo.getCursorFields() != null && tableInfo.getCursorFields().isEmpty() + ? Lists.newArrayList(SyncMode.FULL_REFRESH) + : Lists.newArrayList(SyncMode.FULL_REFRESH, SyncMode.INCREMENTAL)) + .withSourceDefinedPrimaryKey(primaryKeys); + }) .collect(Collectors.toList()); return new AirbyteCatalog().withStreams(streams); } finally { @@ -122,23 +130,25 @@ public AirbyteCatalog discover(final JsonNode config) throws Exception { } /** - * Creates a list of AirbyteMessageIterators with all the streams selected in a configured catalog + * Creates a list of AirbyteMessageIterators with all the streams selected in a configured + * catalog * - * @param config - integration-specific configuration object as json. e.g. { "username": "airbyte", - * "password": "super secure" } + * @param config - integration-specific configuration object as json. e.g. { "username": + * "airbyte", "password": "super secure" } * @param catalog - schema of the incoming messages. - * @param state - state of the incoming messages. + * @param state - state of the incoming messages. * @return AirbyteMessageIterator with all the streams that are to be synced * @throws Exception */ @Override public AutoCloseableIterator read(final JsonNode config, - final ConfiguredAirbyteCatalog catalog, - final JsonNode state) + final ConfiguredAirbyteCatalog catalog, + final JsonNode state) throws Exception { try { final StateManager stateManager = - StateManagerFactory.createStateManager(getSupportedStateType(config), deserializeInitialState(state, config), catalog); + StateManagerFactory.createStateManager(getSupportedStateType(config), + deserializeInitialState(state, config), catalog); final Instant emittedAt = Instant.now(); final Database database = createDatabaseInternal(config); @@ -146,15 +156,18 @@ public AutoCloseableIterator read(final JsonNode config, final Map>> fullyQualifiedTableNameToInfo = discoverWithoutSystemTables(database) .stream() - .collect(Collectors.toMap(t -> String.format("%s.%s", t.getNameSpace(), t.getName()), Function - .identity())); + .collect(Collectors.toMap(t -> String.format("%s.%s", t.getNameSpace(), t.getName()), + Function + .identity())); validateCursorFieldForIncrementalTables(fullyQualifiedTableNameToInfo, catalog); final List> incrementalIterators = - getIncrementalIterators(database, catalog, fullyQualifiedTableNameToInfo, stateManager, emittedAt); + getIncrementalIterators(database, catalog, fullyQualifiedTableNameToInfo, stateManager, + emittedAt); final List> fullRefreshIterators = - getFullRefreshIterators(database, catalog, fullyQualifiedTableNameToInfo, stateManager, emittedAt); + getFullRefreshIterators(database, catalog, fullyQualifiedTableNameToInfo, stateManager, + emittedAt); final List> iteratorList = Stream .of(incrementalIterators, fullRefreshIterators) .flatMap(Collection::stream) @@ -181,16 +194,19 @@ private boolean isConfigError(final Exception exception) { return exception instanceof InvalidCursorException; } - private void validateCursorFieldForIncrementalTables(final Map>> tableNameToTable, - final ConfiguredAirbyteCatalog catalog) { + private void validateCursorFieldForIncrementalTables( + final Map>> tableNameToTable, + final ConfiguredAirbyteCatalog catalog) { final List tablesWithInvalidCursor = new ArrayList<>(); for (final ConfiguredAirbyteStream airbyteStream : catalog.getStreams()) { final AirbyteStream stream = airbyteStream.getStream(); final String fullyQualifiedTableName = getFullyQualifiedTableName(stream.getNamespace(), stream.getName()); final boolean hasSourceDefinedCursor = - !Objects.isNull(airbyteStream.getStream().getSourceDefinedCursor()) && airbyteStream.getStream().getSourceDefinedCursor(); - if (!tableNameToTable.containsKey(fullyQualifiedTableName) || airbyteStream.getSyncMode() != SyncMode.INCREMENTAL || hasSourceDefinedCursor) { + !Objects.isNull(airbyteStream.getStream().getSourceDefinedCursor()) + && airbyteStream.getStream().getSourceDefinedCursor(); + if (!tableNameToTable.containsKey(fullyQualifiedTableName) + || airbyteStream.getSyncMode() != SyncMode.INCREMENTAL || hasSourceDefinedCursor) { continue; } @@ -207,7 +223,9 @@ private void validateCursorFieldForIncrementalTables(final Map>> discoverWithoutSystemTables(final Database database) throws Exception { + protected List>> discoverWithoutSystemTables( + final Database database) throws Exception { final Set systemNameSpaces = getExcludedInternalNameSpaces(); final List>> discoveredTables = discoverInternal(database); return (systemNameSpaces == null || systemNameSpaces.isEmpty() ? discoveredTables - : discoveredTables.stream().filter(table -> !systemNameSpaces.contains(table.getNameSpace())).collect( - Collectors.toList())); + : discoveredTables.stream() + .filter(table -> !systemNameSpaces.contains(table.getNameSpace())).collect( + Collectors.toList())); } - protected List> getFullRefreshIterators(final Database database, - final ConfiguredAirbyteCatalog catalog, - final Map>> tableNameToTable, - final StateManager stateManager, - final Instant emittedAt) { + protected List> getFullRefreshIterators( + final Database database, + final ConfiguredAirbyteCatalog catalog, + final Map>> tableNameToTable, + final StateManager stateManager, + final Instant emittedAt) { return getSelectedIterators( database, catalog, @@ -238,11 +259,12 @@ protected List> getFullRefreshIterators(fi configuredStream -> configuredStream.getSyncMode().equals(SyncMode.FULL_REFRESH)); } - protected List> getIncrementalIterators(final Database database, - final ConfiguredAirbyteCatalog catalog, - final Map>> tableNameToTable, - final StateManager stateManager, - final Instant emittedAt) { + protected List> getIncrementalIterators( + final Database database, + final ConfiguredAirbyteCatalog catalog, + final Map>> tableNameToTable, + final StateManager stateManager, + final Instant emittedAt) { return getSelectedIterators( database, catalog, @@ -255,20 +277,23 @@ protected List> getIncrementalIterators(fi /** * Creates a list of read iterators for each stream within an ConfiguredAirbyteCatalog * - * @param database Source Database - * @param catalog List of streams (e.g. database tables or API endpoints) with settings on sync mode + * @param database Source Database + * @param catalog List of streams (e.g. database tables or API endpoints) with settings + * on sync mode * @param tableNameToTable Mapping of table name to table - * @param stateManager Manager used to track the state of data synced by the connector - * @param emittedAt Time when data was emitted from the Source database - * @param selector essentially a boolean that verifies if configuredStream has selected a sync mode + * @param stateManager Manager used to track the state of data synced by the connector + * @param emittedAt Time when data was emitted from the Source database + * @param selector essentially a boolean that verifies if configuredStream has selected a + * sync mode * @return List of AirbyteMessageIterators containing all iterators for a catalog */ - protected List> getSelectedIterators(final Database database, - final ConfiguredAirbyteCatalog catalog, - final Map>> tableNameToTable, - final StateManager stateManager, - final Instant emittedAt, - final Predicate selector) { + protected List> getSelectedIterators( + final Database database, + final ConfiguredAirbyteCatalog catalog, + final Map>> tableNameToTable, + final StateManager stateManager, + final Instant emittedAt, + final Predicate selector) { final List> iteratorList = new ArrayList<>(); for (final ConfiguredAirbyteStream airbyteStream : catalog.getStreams()) { if (selector.test(airbyteStream)) { @@ -299,21 +324,22 @@ protected List> getSelectedIterators(final /** * ReadIterator is used to retrieve records from a source connector * - * @param database Source Database + * @param database Source Database * @param airbyteStream represents an ingestion source (e.g. API endpoint or database table) - * @param table information in tabular format - * @param stateManager Manager used to track the state of data synced by the connector - * @param emittedAt Time when data was emitted from the Source database + * @param table information in tabular format + * @param stateManager Manager used to track the state of data synced by the connector + * @param emittedAt Time when data was emitted from the Source database * @return */ protected AutoCloseableIterator createReadIterator(final Database database, - final ConfiguredAirbyteStream airbyteStream, - final TableInfo> table, - final StateManager stateManager, - final Instant emittedAt) { + final ConfiguredAirbyteStream airbyteStream, + final TableInfo> table, + final StateManager stateManager, + final Instant emittedAt) { final String streamName = airbyteStream.getStream().getName(); final String namespace = airbyteStream.getStream().getNamespace(); - final AirbyteStreamNameNamespacePair pair = new AirbyteStreamNameNamespacePair(streamName, namespace); + final AirbyteStreamNameNamespacePair pair = new AirbyteStreamNameNamespacePair(streamName, + namespace); final Set selectedFieldsInCatalog = CatalogHelpers.getTopLevelFieldNames(airbyteStream); final List selectedDatabaseFields = table.getFields() .stream() @@ -339,26 +365,33 @@ protected AutoCloseableIterator createReadIterator(final Databas emittedAt); } else { // if no cursor is present then this is the first read for is the same as doing a full refresh read. - airbyteMessageIterator = getFullRefreshStream(database, streamName, namespace, selectedDatabaseFields, table, emittedAt); + airbyteMessageIterator = getFullRefreshStream(database, streamName, namespace, + selectedDatabaseFields, table, emittedAt); } - final JsonSchemaPrimitive cursorType = IncrementalUtils.getCursorType(airbyteStream, cursorField); - - iterator = AutoCloseableIterators.transform(autoCloseableIterator -> new StateDecoratingIterator( - autoCloseableIterator, - stateManager, - pair, - cursorField, - cursorInfo.map(CursorInfo::getCursor).orElse(null), - cursorType, - getStateEmissionFrequency()), + final JsonSchemaPrimitive cursorType = IncrementalUtils.getCursorType(airbyteStream, + cursorField); + + iterator = AutoCloseableIterators.transform( + autoCloseableIterator -> new StateDecoratingIterator( + autoCloseableIterator, + stateManager, + pair, + cursorField, + cursorInfo.map(CursorInfo::getCursor).orElse(null), + cursorType, + getStateEmissionFrequency()), airbyteMessageIterator); } else if (airbyteStream.getSyncMode() == SyncMode.FULL_REFRESH) { - iterator = getFullRefreshStream(database, streamName, namespace, selectedDatabaseFields, table, emittedAt); + iterator = getFullRefreshStream(database, streamName, namespace, selectedDatabaseFields, + table, emittedAt); } else if (airbyteStream.getSyncMode() == null) { - throw new IllegalArgumentException(String.format("%s requires a source sync mode", this.getClass())); + throw new IllegalArgumentException( + String.format("%s requires a source sync mode", this.getClass())); } else { - throw new IllegalArgumentException(String.format("%s does not support sync mode: %s.", this.getClass(), airbyteStream.getSyncMode())); + throw new IllegalArgumentException( + String.format("%s does not support sync mode: %s.", this.getClass(), + airbyteStream.getSyncMode())); } final AtomicLong recordCount = new AtomicLong(); @@ -372,20 +405,21 @@ protected AutoCloseableIterator createReadIterator(final Databas } /** - * @param database Source Database - * @param airbyteStream represents an ingestion source (e.g. API endpoint or database table) + * @param database Source Database + * @param airbyteStream represents an ingestion source (e.g. API endpoint or database + * table) * @param selectedDatabaseFields subset of database fields selected for replication - * @param table information in tabular format - * @param cursorInfo state of where to start the sync from - * @param emittedAt Time when data was emitted from the Source database + * @param table information in tabular format + * @param cursorInfo state of where to start the sync from + * @param emittedAt Time when data was emitted from the Source database * @return AirbyteMessage Iterator that */ protected AutoCloseableIterator getIncrementalStream(final Database database, - final ConfiguredAirbyteStream airbyteStream, - final List selectedDatabaseFields, - final TableInfo> table, - final CursorInfo cursorInfo, - final Instant emittedAt) { + final ConfiguredAirbyteStream airbyteStream, + final List selectedDatabaseFields, + final TableInfo> table, + final CursorInfo cursorInfo, + final Instant emittedAt) { final String streamName = airbyteStream.getStream().getName(); final String namespace = airbyteStream.getStream().getNamespace(); final String cursorField = IncrementalUtils.getCursorField(airbyteStream); @@ -395,7 +429,8 @@ protected AutoCloseableIterator getIncrementalStream(final Datab .findFirst() .orElseThrow(); - Preconditions.checkState(table.getFields().stream().anyMatch(f -> f.getName().equals(cursorField)), + Preconditions.checkState( + table.getFields().stream().anyMatch(f -> f.getName().equals(cursorField)), String.format("Could not find cursor field %s in table %s", cursorField, table.getName())); final AutoCloseableIterator queryIterator = queryTableIncremental( @@ -412,23 +447,24 @@ protected AutoCloseableIterator getIncrementalStream(final Datab /** * Creates a AirbyteMessageIterator that contains all records for a database source connection * - * @param database Source Database - * @param streamName name of an individual stream in which a stream represents a source (e.g. API - * endpoint or database table) - * @param namespace Namespace of the database (e.g. public) + * @param database Source Database + * @param streamName name of an individual stream in which a stream represents a + * source (e.g. API endpoint or database table) + * @param namespace Namespace of the database (e.g. public) * @param selectedDatabaseFields List of all interested database column names - * @param table information in tabular format - * @param emittedAt Time when data was emitted from the Source database + * @param table information in tabular format + * @param emittedAt Time when data was emitted from the Source database * @return AirbyteMessageIterator with all records for a database source */ protected AutoCloseableIterator getFullRefreshStream(final Database database, - final String streamName, - final String namespace, - final List selectedDatabaseFields, - final TableInfo> table, - final Instant emittedAt) { + final String streamName, + final String namespace, + final List selectedDatabaseFields, + final TableInfo> table, + final Instant emittedAt) { final AutoCloseableIterator queryStream = - queryTableFullRefresh(database, selectedDatabaseFields, table.getNameSpace(), table.getName()); + queryTableFullRefresh(database, selectedDatabaseFields, table.getNameSpace(), + table.getName()); return getMessageIterator(queryStream, streamName, namespace, emittedAt.toEpochMilli()); } @@ -436,10 +472,11 @@ protected String getFullyQualifiedTableName(final String nameSpace, final String return nameSpace != null ? nameSpace + "." + tableName : tableName; } - public AutoCloseableIterator getMessageIterator(final AutoCloseableIterator recordIterator, - final String streamName, - final String namespace, - final long emittedAt) { + public AutoCloseableIterator getMessageIterator( + final AutoCloseableIterator recordIterator, + final String streamName, + final String namespace, + final long emittedAt) { return AutoCloseableIterators.transform(recordIterator, r -> new AirbyteMessage() .withType(Type.RECORD) .withRecord(new AirbyteRecordMessage() @@ -458,7 +495,8 @@ public AutoCloseableIterator getMessageIterator(final AutoClosea */ protected List> getTables(final Database database) throws Exception { final List>> tableInfos = discoverWithoutSystemTables(database); - final Map> fullyQualifiedTableNameToPrimaryKeys = discoverPrimaryKeys(database, tableInfos); + final Map> fullyQualifiedTableNameToPrimaryKeys = discoverPrimaryKeys( + database, tableInfos); return tableInfos.stream() .map(t -> { @@ -471,10 +509,13 @@ protected List> getTables(final Database database) throws Excep .map(this::toField) .distinct() .collect(Collectors.toList()); - final String fullyQualifiedTableName = getFullyQualifiedTableName(t.getNameSpace(), t.getName()); - final List primaryKeys = fullyQualifiedTableNameToPrimaryKeys.getOrDefault(fullyQualifiedTableName, Collections - .emptyList()); - return TableInfo.builder().nameSpace(t.getNameSpace()).name(t.getName()).fields(fields).primaryKeys(primaryKeys) + final String fullyQualifiedTableName = getFullyQualifiedTableName(t.getNameSpace(), + t.getName()); + final List primaryKeys = fullyQualifiedTableNameToPrimaryKeys.getOrDefault( + fullyQualifiedTableName, Collections + .emptyList()); + return TableInfo.builder().nameSpace(t.getNameSpace()).name(t.getName()) + .fields(fields).primaryKeys(primaryKeys) .cursorFields(t.getCursorFields()) .build(); }) @@ -482,7 +523,8 @@ protected List> getTables(final Database database) throws Excep } protected Field toField(final CommonField field) { - if (getType(field.getType()) == JsonSchemaType.OBJECT && field.getProperties() != null && !field.getProperties().isEmpty()) { + if (getType(field.getType()) == JsonSchemaType.OBJECT && field.getProperties() != null + && !field.getProperties().isEmpty()) { final var properties = field.getProperties().stream().map(this::toField).toList(); return Field.of(field.getName(), getType(field.getType()), properties); } else { @@ -490,7 +532,8 @@ protected Field toField(final CommonField field) { } } - protected void assertColumnsWithSameNameAreSame(final String nameSpace, final String tableName, final List> columns) { + protected void assertColumnsWithSameNameAreSame(final String nameSpace, final String tableName, + final List> columns) { columns.stream() .collect(Collectors.groupingBy(CommonField::getName)) .values() @@ -499,7 +542,8 @@ protected void assertColumnsWithSameNameAreSame(final String nameSpace, final St columnsWithSameName.forEach(column -> { if (!column.equals(comparisonColumn)) { throw new RuntimeException( - String.format("Found multiple columns with same name: %s in table: %s.%s but the columns are not the same. columns: %s", + String.format( + "Found multiple columns with same name: %s in table: %s.%s but the columns are not the same. columns: %s", comparisonColumn.getName(), nameSpace, tableName, columns)); } }); @@ -508,19 +552,19 @@ protected void assertColumnsWithSameNameAreSame(final String nameSpace, final St /** * @param database - The database where from privileges for tables will be consumed - * @param schema - The schema where from privileges for tables will be consumed - * @return Set with privileges for tables for current DB-session user The method is responsible for - * SELECT-ing the table with privileges. In some cases such SELECT doesn't require (e.g. in - * Oracle DB - the schema is the user, you cannot REVOKE a privilege on a table from its - * owner). + * @param schema - The schema where from privileges for tables will be consumed + * @return Set with privileges for tables for current DB-session user The method is responsible + * for SELECT-ing the table with privileges. In some cases such SELECT doesn't require (e.g. in + * Oracle DB - the schema is the user, you cannot REVOKE a privilege on a table from its owner). */ - public Set getPrivilegesTableForCurrentUser(final JdbcDatabase database, final String schema) throws SQLException { + public Set getPrivilegesTableForCurrentUser(final JdbcDatabase database, + final String schema) throws SQLException { return Collections.emptySet(); } /** - * Map a database implementation-specific configuration to json object that adheres to the database - * config spec. See resources/spec.json. + * Map a database implementation-specific configuration to json object that adheres to the + * database config spec. See resources/spec.json. * * @param config database implementation-specific configuration. * @return database spec config @@ -567,30 +611,31 @@ public abstract List> getCheckOperations(Js * @throws Exception access to the database might lead to an exceptions. */ protected abstract List>> discoverInternal( - final Database database) + final Database database) throws Exception; /** * Discovers all available tables within a schema in the source database. * * @param database - source database - * @param schema - source schema + * @param schema - source schema * @return list of source tables * @throws Exception - access to the database might lead to exceptions. */ - protected abstract List>> discoverInternal(final Database database, String schema) + protected abstract List>> discoverInternal( + final Database database, String schema) throws Exception; /** * Discover Primary keys for each table and @return a map of namespace.table name to their * associated list of primary key fields. * - * @param database source database + * @param database source database * @param tableInfos list of tables * @return map of namespace.table and primary key fields. */ protected abstract Map> discoverPrimaryKeys(Database database, - List>> tableInfos); + List>> tableInfos); /** * Returns quote symbol of the database @@ -602,16 +647,16 @@ protected abstract Map> discoverPrimaryKeys(Database databa /** * Read all data from a table. * - * @param database source database + * @param database source database * @param columnNames interested column names - * @param schemaName table namespace - * @param tableName target table + * @param schemaName table namespace + * @param tableName target table * @return iterator with read data */ public abstract AutoCloseableIterator queryTableFullRefresh(final Database database, - final List columnNames, - final String schemaName, - final String tableName); + final List columnNames, + final String schemaName, + final String tableName); /** * Read incremental data from a table. Incremental read should return only records where cursor @@ -622,23 +667,22 @@ public abstract AutoCloseableIterator queryTableFullRefresh(final Data * @return iterator with read data */ public abstract AutoCloseableIterator queryTableIncremental(Database database, - List columnNames, - String schemaName, - String tableName, - CursorInfo cursorInfo, - DataType cursorFieldType); + List columnNames, + String schemaName, + String tableName, + CursorInfo cursorInfo, + DataType cursorFieldType); /** * When larger than 0, the incremental iterator will emit intermediate state for every N records. - * Please note that if intermediate state emission is enabled, the incremental query must be ordered - * by the cursor field. + * Please note that if intermediate state emission is enabled, the incremental query must be + * ordered by the cursor field. */ protected int getStateEmissionFrequency() { return 0; } /** - * * @return list of fields that could be used as cursors */ public abstract boolean isCursorType(DataType type); @@ -654,11 +698,13 @@ private Database createDatabaseInternal(final JsonNode sourceConfig) throws Exce * Deserializes the state represented as JSON into an object representation. * * @param initialStateJson The state as JSON. - * @param config The connector configuration. + * @param config The connector configuration. * @return The deserialized object representation of the state. */ - protected List deserializeInitialState(final JsonNode initialStateJson, final JsonNode config) { - final Optional typedState = StateMessageHelper.getTypedState(initialStateJson, featureFlags.useStreamCapableState()); + protected List deserializeInitialState(final JsonNode initialStateJson, + final JsonNode config) { + final Optional typedState = StateMessageHelper.getTypedState(initialStateJson, + featureFlags.useStreamCapableState()); return typedState.map((state) -> { switch (state.getStateType()) { case GLOBAL: @@ -667,7 +713,8 @@ protected List deserializeInitialState(final JsonNode initi return state.getStateMessages(); case LEGACY: default: - return List.of(new AirbyteStateMessage().withType(AirbyteStateType.LEGACY).withData(state.getLegacyState())); + return List.of(new AirbyteStateMessage().withType(AirbyteStateType.LEGACY) + .withData(state.getLegacyState())); } }).orElse(generateEmptyInitialState(config)); } @@ -680,7 +727,8 @@ protected List deserializeInitialState(final JsonNode initi */ protected List generateEmptyInitialState(final JsonNode config) { // For backwards compatibility with existing connectors - return List.of(new AirbyteStateMessage().withType(AirbyteStateType.LEGACY).withData(Jsons.jsonNode(new DbState()))); + return List.of(new AirbyteStateMessage().withType(AirbyteStateType.LEGACY) + .withData(Jsons.jsonNode(new DbState()))); } /** diff --git a/airbyte-protocol/protocol-models/src/main/java/io/airbyte/protocol/models/CatalogHelpers.java b/airbyte-protocol/protocol-models/src/main/java/io/airbyte/protocol/models/CatalogHelpers.java index de776f3b129c..5f3ce6e419fc 100644 --- a/airbyte-protocol/protocol-models/src/main/java/io/airbyte/protocol/models/CatalogHelpers.java +++ b/airbyte-protocol/protocol-models/src/main/java/io/airbyte/protocol/models/CatalogHelpers.java @@ -12,7 +12,6 @@ import io.airbyte.commons.json.JsonSchemas; import io.airbyte.commons.json.Jsons; import io.airbyte.commons.util.MoreIterators; -import io.airbyte.commons.util.MoreLists; import io.airbyte.protocol.models.transform_models.FieldTransform; import io.airbyte.protocol.models.transform_models.StreamTransform; import io.airbyte.protocol.models.transform_models.UpdateFieldSchemaTransform; @@ -36,8 +35,10 @@ public class CatalogHelpers { private static final String ITEMS_KEY = "items"; - public static AirbyteCatalog createAirbyteCatalog(final String streamName, final Field... fields) { - return new AirbyteCatalog().withStreams(Lists.newArrayList(createAirbyteStream(streamName, fields))); + public static AirbyteCatalog createAirbyteCatalog(final String streamName, + final Field... fields) { + return new AirbyteCatalog().withStreams( + Lists.newArrayList(createAirbyteStream(streamName, fields))); } public static AirbyteStream createAirbyteStream(final String streamName, final Field... fields) { @@ -45,30 +46,46 @@ public static AirbyteStream createAirbyteStream(final String streamName, final F return createAirbyteStream(streamName, null, Arrays.asList(fields)); } - public static AirbyteStream createAirbyteStream(final String streamName, final String namespace, final Field... fields) { + public static AirbyteStream createAirbyteStream(final String streamName, + final String namespace, + final Field... fields) { return createAirbyteStream(streamName, namespace, Arrays.asList(fields)); } - public static AirbyteStream createAirbyteStream(final String streamName, final String namespace, final List fields) { - return new AirbyteStream().withName(streamName).withNamespace(namespace).withJsonSchema(fieldsToJsonSchema(fields)) + public static AirbyteStream createAirbyteStream(final String streamName, + final String namespace, + final List fields) { + return new AirbyteStream().withName(streamName).withNamespace(namespace) + .withJsonSchema(fieldsToJsonSchema(fields)) .withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH)); } - public static ConfiguredAirbyteCatalog createConfiguredAirbyteCatalog(final String streamName, final String namespace, final Field... fields) { - return new ConfiguredAirbyteCatalog().withStreams(Lists.newArrayList(createConfiguredAirbyteStream(streamName, namespace, fields))); + public static ConfiguredAirbyteCatalog createConfiguredAirbyteCatalog(final String streamName, + final String namespace, + final Field... fields) { + return new ConfiguredAirbyteCatalog().withStreams( + Lists.newArrayList(createConfiguredAirbyteStream(streamName, namespace, fields))); } - public static ConfiguredAirbyteCatalog createConfiguredAirbyteCatalog(final String streamName, final String namespace, final List fields) { - return new ConfiguredAirbyteCatalog().withStreams(Lists.newArrayList(createConfiguredAirbyteStream(streamName, namespace, fields))); + public static ConfiguredAirbyteCatalog createConfiguredAirbyteCatalog(final String streamName, + final String namespace, + final List fields) { + return new ConfiguredAirbyteCatalog().withStreams( + Lists.newArrayList(createConfiguredAirbyteStream(streamName, namespace, fields))); } - public static ConfiguredAirbyteStream createConfiguredAirbyteStream(final String streamName, final String namespace, final Field... fields) { + public static ConfiguredAirbyteStream createConfiguredAirbyteStream(final String streamName, + final String namespace, + final Field... fields) { return createConfiguredAirbyteStream(streamName, namespace, Arrays.asList(fields)); } - public static ConfiguredAirbyteStream createConfiguredAirbyteStream(final String streamName, final String namespace, final List fields) { + public static ConfiguredAirbyteStream createConfiguredAirbyteStream(final String streamName, + final String namespace, + final List fields) { return new ConfiguredAirbyteStream() - .withStream(new AirbyteStream().withName(streamName).withNamespace(namespace).withJsonSchema(fieldsToJsonSchema(fields)) + .withStream(new AirbyteStream().withName(streamName).withNamespace(namespace) + .withJsonSchema(fieldsToJsonSchema(fields)) .withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH))) .withSyncMode(SyncMode.FULL_REFRESH).withDestinationSyncMode(DestinationSyncMode.OVERWRITE); } @@ -80,7 +97,8 @@ public static ConfiguredAirbyteStream createConfiguredAirbyteStream(final String * @param configuredCatalog - catalog to convert * @return - airbyte catalog */ - public static AirbyteCatalog configuredCatalogToCatalog(final ConfiguredAirbyteCatalog configuredCatalog) { + public static AirbyteCatalog configuredCatalogToCatalog( + final ConfiguredAirbyteCatalog configuredCatalog) { return new AirbyteCatalog().withStreams( configuredCatalog.getStreams() .stream() @@ -105,7 +123,8 @@ public static StreamDescriptor extractDescriptor(final ConfiguredAirbyteStream a * @return stream descriptor */ public static StreamDescriptor extractDescriptor(final AirbyteStream airbyteStream) { - return new StreamDescriptor().withName(airbyteStream.getName()).withNamespace(airbyteStream.getNamespace()); + return new StreamDescriptor().withName(airbyteStream.getName()) + .withNamespace(airbyteStream.getNamespace()); } /** @@ -114,7 +133,8 @@ public static StreamDescriptor extractDescriptor(final AirbyteStream airbyteStre * @param configuredCatalog catalog * @return list of stream descriptors */ - public static List extractStreamDescriptors(final ConfiguredAirbyteCatalog configuredCatalog) { + public static List extractStreamDescriptors( + final ConfiguredAirbyteCatalog configuredCatalog) { return extractStreamDescriptors(configuredCatalogToCatalog(configuredCatalog)); } @@ -125,7 +145,8 @@ public static List extractStreamDescriptors(final ConfiguredAi * @param configuredCatalog catalog * @return list of stream descriptors */ - public static List extractIncrementalStreamDescriptors(final ConfiguredAirbyteCatalog configuredCatalog) { + public static List extractIncrementalStreamDescriptors( + final ConfiguredAirbyteCatalog configuredCatalog) { return configuredCatalog.getStreams() .stream() .filter(configuredStream -> configuredStream.getSyncMode() == SyncMode.INCREMENTAL) @@ -207,7 +228,8 @@ public static JsonNode fieldsToJsonSchema(final List fields) { @SuppressWarnings("unchecked") public static Set getTopLevelFieldNames(final ConfiguredAirbyteStream stream) { // it is json, so the key has to be a string. - final Map object = Jsons.object(stream.getStream().getJsonSchema().get("properties"), Map.class); + final Map object = Jsons.object( + stream.getStream().getJsonSchema().get("properties"), Map.class); return object.keySet(); } @@ -221,11 +243,21 @@ protected static Set getAllFieldNames(final JsonNode jsonSchema) { .stream() .map(Pair::getLeft) // only need field name, not fully qualified name - .map(MoreLists::last) + .map(CatalogHelpers::last) .flatMap(Optional::stream) .collect(Collectors.toSet()); } + /** + * @return returns empty optional if the list is empty or if the last element in the list is null. + */ + private static Optional last(final List list) { + if (list.isEmpty()) { + return Optional.empty(); + } + return Optional.ofNullable(list.get(list.size() - 1)); + } + /** * Extracts all fields and their schemas from a JSONSchema. This method returns values in * depth-first search preorder. It short circuits at oneOfs--in other words, child fields of a oneOf @@ -236,19 +268,23 @@ protected static Set getAllFieldNames(final JsonNode jsonSchema) { * preorder. */ @VisibleForTesting - protected static List, JsonNode>> getFullyQualifiedFieldNamesWithTypes(final JsonNode jsonSchema) { + protected static List, JsonNode>> getFullyQualifiedFieldNamesWithTypes( + final JsonNode jsonSchema) { // if this were ever a performance issue, it could be replaced with a trie. this seems unlikely // however. final Set> fieldNamesThatAreOneOfs = new HashSet<>(); return JsonSchemas.traverseJsonSchemaWithCollector(jsonSchema, (node, basicPath) -> { - final List fieldName = basicPath.stream().map(fieldOrList -> fieldOrList.isList() ? ITEMS_KEY : fieldOrList.getFieldName()).toList(); + final List fieldName = basicPath.stream() + .map(fieldOrList -> fieldOrList.isList() ? ITEMS_KEY : fieldOrList.getFieldName()) + .toList(); return Pair.of(fieldName, node); }) .stream() // first node is the original object. .skip(1) - .filter(fieldWithSchema -> filterChildrenOfFoneOneOf(fieldWithSchema.getLeft(), fieldWithSchema.getRight(), fieldNamesThatAreOneOfs)) + .filter(fieldWithSchema -> filterChildrenOfFoneOneOf(fieldWithSchema.getLeft(), + fieldWithSchema.getRight(), fieldNamesThatAreOneOfs)) .toList(); } @@ -291,14 +327,17 @@ private static boolean isOneOfField(final JsonNode schema) { } private static boolean isObjectWithSubFields(final Field field) { - return field.getType().equals(JsonSchemaType.OBJECT) && field.getSubFields() != null && !field.getSubFields().isEmpty(); + return field.getType().equals(JsonSchemaType.OBJECT) && field.getSubFields() != null + && !field.getSubFields().isEmpty(); } public static StreamDescriptor extractStreamDescriptor(final AirbyteStream airbyteStream) { - return new StreamDescriptor().withName(airbyteStream.getName()).withNamespace(airbyteStream.getNamespace()); + return new StreamDescriptor().withName(airbyteStream.getName()) + .withNamespace(airbyteStream.getNamespace()); } - private static Map streamDescriptorToMap(final AirbyteCatalog catalog) { + private static Map streamDescriptorToMap( + final AirbyteCatalog catalog) { return catalog.getStreams() .stream() .collect(Collectors.toMap(CatalogHelpers::extractStreamDescriptor, s -> s)); @@ -316,13 +355,17 @@ public static Set getCatalogDiff(final AirbyteCatalog oldCatalo final ConfiguredAirbyteCatalog configuredCatalog) { final Set streamTransforms = new HashSet<>(); - final Map descriptorToStreamOld = streamDescriptorToMap(oldCatalog); - final Map descriptorToStreamNew = streamDescriptorToMap(newCatalog); + final Map descriptorToStreamOld = streamDescriptorToMap( + oldCatalog); + final Map descriptorToStreamNew = streamDescriptorToMap( + newCatalog); Sets.difference(descriptorToStreamOld.keySet(), descriptorToStreamNew.keySet()) - .forEach(descriptor -> streamTransforms.add(StreamTransform.createRemoveStreamTransform(descriptor))); + .forEach(descriptor -> streamTransforms.add( + StreamTransform.createRemoveStreamTransform(descriptor))); Sets.difference(descriptorToStreamNew.keySet(), descriptorToStreamOld.keySet()) - .forEach(descriptor -> streamTransforms.add(StreamTransform.createAddStreamTransform(descriptor))); + .forEach(descriptor -> streamTransforms.add( + StreamTransform.createAddStreamTransform(descriptor))); Sets.intersection(descriptorToStreamOld.keySet(), descriptorToStreamNew.keySet()) .forEach(descriptor -> { final AirbyteStream streamOld = descriptorToStreamOld.get(descriptor); @@ -334,7 +377,8 @@ public static Set getCatalogDiff(final AirbyteCatalog oldCatalo .findFirst(); if (!streamOld.equals(streamNew)) { - streamTransforms.add(StreamTransform.createUpdateStreamTransform(descriptor, getStreamDiff(streamOld, streamNew, stream))); + streamTransforms.add(StreamTransform.createUpdateStreamTransform(descriptor, + getStreamDiff(streamOld, streamNew, stream))); } }); @@ -345,34 +389,40 @@ private static UpdateStreamTransform getStreamDiff(final AirbyteStream streamOld final AirbyteStream streamNew, final Optional configuredStream) { final Set fieldTransforms = new HashSet<>(); - final Map, JsonNode> fieldNameToTypeOld = getFullyQualifiedFieldNamesWithTypes(streamOld.getJsonSchema()) - .stream() - .collect( - HashMap::new, - CatalogHelpers::collectInHashMap, - CatalogHelpers::combineAccumulator); - final Map, JsonNode> fieldNameToTypeNew = getFullyQualifiedFieldNamesWithTypes(streamNew.getJsonSchema()) - .stream() - .collect( - HashMap::new, - CatalogHelpers::collectInHashMap, - CatalogHelpers::combineAccumulator); + final Map, JsonNode> fieldNameToTypeOld = getFullyQualifiedFieldNamesWithTypes( + streamOld.getJsonSchema()) + .stream() + .collect( + HashMap::new, + CatalogHelpers::collectInHashMap, + CatalogHelpers::combineAccumulator); + final Map, JsonNode> fieldNameToTypeNew = getFullyQualifiedFieldNamesWithTypes( + streamNew.getJsonSchema()) + .stream() + .collect( + HashMap::new, + CatalogHelpers::collectInHashMap, + CatalogHelpers::combineAccumulator); Sets.difference(fieldNameToTypeOld.keySet(), fieldNameToTypeNew.keySet()) .forEach(fieldName -> { - fieldTransforms.add(FieldTransform.createRemoveFieldTransform(fieldName, fieldNameToTypeOld.get(fieldName), + fieldTransforms.add(FieldTransform.createRemoveFieldTransform(fieldName, + fieldNameToTypeOld.get(fieldName), transformBreaksConnection(configuredStream, fieldName))); }); Sets.difference(fieldNameToTypeNew.keySet(), fieldNameToTypeOld.keySet()) - .forEach(fieldName -> fieldTransforms.add(FieldTransform.createAddFieldTransform(fieldName, fieldNameToTypeNew.get(fieldName)))); - Sets.intersection(fieldNameToTypeOld.keySet(), fieldNameToTypeNew.keySet()).forEach(fieldName -> { - final JsonNode oldType = fieldNameToTypeOld.get(fieldName); - final JsonNode newType = fieldNameToTypeNew.get(fieldName); + .forEach(fieldName -> fieldTransforms.add( + FieldTransform.createAddFieldTransform(fieldName, fieldNameToTypeNew.get(fieldName)))); + Sets.intersection(fieldNameToTypeOld.keySet(), fieldNameToTypeNew.keySet()) + .forEach(fieldName -> { + final JsonNode oldType = fieldNameToTypeOld.get(fieldName); + final JsonNode newType = fieldNameToTypeNew.get(fieldName); - if (!oldType.equals(newType)) { - fieldTransforms.add(FieldTransform.createUpdateFieldTransform(fieldName, new UpdateFieldSchemaTransform(oldType, newType))); - } - }); + if (!oldType.equals(newType)) { + fieldTransforms.add(FieldTransform.createUpdateFieldTransform(fieldName, + new UpdateFieldSchemaTransform(oldType, newType))); + } + }); return new UpdateStreamTransform(fieldTransforms); } @@ -381,7 +431,8 @@ private static UpdateStreamTransform getStreamDiff(final AirbyteStream streamOld static final JsonNode DUPLICATED_SCHEMA = Jsons.jsonNode("Duplicated Schema"); @VisibleForTesting - static void collectInHashMap(final Map, JsonNode> accumulator, final Pair, JsonNode> value) { + static void collectInHashMap(final Map, JsonNode> accumulator, + final Pair, JsonNode> value) { if (accumulator.containsKey(value.getKey())) { accumulator.put(value.getKey(), DUPLICATED_SCHEMA); } else { @@ -390,7 +441,8 @@ static void collectInHashMap(final Map, JsonNode> accumulator, fina } @VisibleForTesting - static void combineAccumulator(final Map, JsonNode> accumulatorLeft, final Map, JsonNode> accumulatorRight) { + static void combineAccumulator(final Map, JsonNode> accumulatorLeft, + final Map, JsonNode> accumulatorRight) { accumulatorRight.forEach((key, value) -> { if (accumulatorLeft.containsKey(key)) { accumulatorLeft.put(key, DUPLICATED_SCHEMA); @@ -400,7 +452,8 @@ static void combineAccumulator(final Map, JsonNode> accumulatorLeft }); } - static boolean transformBreaksConnection(final Optional configuredStream, final List fieldName) { + static boolean transformBreaksConnection(final Optional configuredStream, + final List fieldName) { if (configuredStream.isEmpty()) { return false; } @@ -413,7 +466,8 @@ static boolean transformBreaksConnection(final Optional } final DestinationSyncMode destinationSyncMode = streamConfig.getDestinationSyncMode(); - if (DestinationSyncMode.APPEND_DEDUP == destinationSyncMode && streamConfig.getPrimaryKey().contains(fieldName)) { + if (DestinationSyncMode.APPEND_DEDUP == destinationSyncMode && streamConfig.getPrimaryKey() + .contains(fieldName)) { return true; } return false; From 8bb97010f39ef1823b0deae91d4d5347ee610311 Mon Sep 17 00:00:00 2001 From: VitaliiMaltsev <39538064+VitaliiMaltsev@users.noreply.github.com> Date: Thu, 3 Nov 2022 19:40:20 +0200 Subject: [PATCH 18/73] MySQL Source: fixed unencrypted CDC connections (#18851) * MySQL Source: fixed unencrypted CDC connections * updated changelog * bump version * auto-bump connector version Co-authored-by: Octavia Squidington III --- .../resources/seed/source_definitions.yaml | 2 +- .../src/main/resources/seed/source_specs.yaml | 2 +- .../source-mysql-strict-encrypt/Dockerfile | 2 +- .../connectors/source-mysql/Dockerfile | 2 +- .../source/mysql/MySqlCdcProperties.java | 2 +- ...cMySqlSslRequiredSourceAcceptanceTest.java | 198 ++++++++++++++++++ docs/integrations/sources/mysql.md | 1 + 7 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 airbyte-integrations/connectors/source-mysql/src/test-integration/java/io/airbyte/integrations/io/airbyte/integration_tests/sources/CdcMySqlSslRequiredSourceAcceptanceTest.java diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index 2f15b5bec0a3..90c091333e32 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -813,7 +813,7 @@ - name: MySQL sourceDefinitionId: 435bb9a5-7887-4809-aa58-28c27df0d7ad dockerRepository: airbyte/source-mysql - dockerImageTag: 1.0.10 + dockerImageTag: 1.0.11 documentationUrl: https://docs.airbyte.com/integrations/sources/mysql icon: mysql.svg sourceType: database diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index b4caf4cc9ec7..82a4f6b86628 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -7727,7 +7727,7 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] -- dockerImage: "airbyte/source-mysql:1.0.10" +- dockerImage: "airbyte/source-mysql:1.0.11" spec: documentationUrl: "https://docs.airbyte.com/integrations/sources/mysql" connectionSpecification: diff --git a/airbyte-integrations/connectors/source-mysql-strict-encrypt/Dockerfile b/airbyte-integrations/connectors/source-mysql-strict-encrypt/Dockerfile index 9baa9badbdb4..86a16ad9c7f9 100644 --- a/airbyte-integrations/connectors/source-mysql-strict-encrypt/Dockerfile +++ b/airbyte-integrations/connectors/source-mysql-strict-encrypt/Dockerfile @@ -16,6 +16,6 @@ ENV APPLICATION source-mysql-strict-encrypt COPY --from=build /airbyte /airbyte -LABEL io.airbyte.version=1.0.10 +LABEL io.airbyte.version=1.0.11 LABEL io.airbyte.name=airbyte/source-mysql-strict-encrypt diff --git a/airbyte-integrations/connectors/source-mysql/Dockerfile b/airbyte-integrations/connectors/source-mysql/Dockerfile index 8be6326053cb..b8186ad82952 100644 --- a/airbyte-integrations/connectors/source-mysql/Dockerfile +++ b/airbyte-integrations/connectors/source-mysql/Dockerfile @@ -16,6 +16,6 @@ ENV APPLICATION source-mysql COPY --from=build /airbyte /airbyte -LABEL io.airbyte.version=1.0.10 +LABEL io.airbyte.version=1.0.11 LABEL io.airbyte.name=airbyte/source-mysql diff --git a/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/MySqlCdcProperties.java b/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/MySqlCdcProperties.java index 3c57cf3f2d55..5c8cd0c74b93 100644 --- a/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/MySqlCdcProperties.java +++ b/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/MySqlCdcProperties.java @@ -67,7 +67,7 @@ private static Properties commonProperties(final JdbcDatabase database) { // https://debezium.io/documentation/reference/stable/connectors/mysql.html#mysql-property-database-ssl-mode if (!sourceConfig.has(JdbcUtils.SSL_KEY) || sourceConfig.get(JdbcUtils.SSL_KEY).asBoolean()) { if (dbConfig.has(SSL_MODE) && !dbConfig.get(SSL_MODE).asText().isEmpty()) { - props.setProperty("database.sslmode", MySqlSource.toSslJdbcParamInternal(SslMode.valueOf(dbConfig.get(SSL_MODE).asText()))); + props.setProperty("database.ssl.mode", MySqlSource.toSslJdbcParamInternal(SslMode.valueOf(dbConfig.get(SSL_MODE).asText()))); props.setProperty("database.history.producer.security.protocol", "SSL"); props.setProperty("database.history.consumer.security.protocol", "SSL"); diff --git a/airbyte-integrations/connectors/source-mysql/src/test-integration/java/io/airbyte/integrations/io/airbyte/integration_tests/sources/CdcMySqlSslRequiredSourceAcceptanceTest.java b/airbyte-integrations/connectors/source-mysql/src/test-integration/java/io/airbyte/integrations/io/airbyte/integration_tests/sources/CdcMySqlSslRequiredSourceAcceptanceTest.java new file mode 100644 index 000000000000..02a8dc39fbc8 --- /dev/null +++ b/airbyte-integrations/connectors/source-mysql/src/test-integration/java/io/airbyte/integrations/io/airbyte/integration_tests/sources/CdcMySqlSslRequiredSourceAcceptanceTest.java @@ -0,0 +1,198 @@ +package io.airbyte.integrations.io.airbyte.integration_tests.sources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import io.airbyte.commons.json.Jsons; +import io.airbyte.db.Database; +import io.airbyte.db.factory.DSLContextFactory; +import io.airbyte.db.factory.DatabaseDriver; +import io.airbyte.db.jdbc.JdbcUtils; +import io.airbyte.integrations.base.ssh.SshHelpers; +import io.airbyte.integrations.standardtest.source.SourceAcceptanceTest; +import io.airbyte.integrations.standardtest.source.TestDestinationEnv; +import io.airbyte.protocol.models.AirbyteMessage; +import io.airbyte.protocol.models.AirbyteRecordMessage; +import io.airbyte.protocol.models.AirbyteStateMessage; +import io.airbyte.protocol.models.CatalogHelpers; +import io.airbyte.protocol.models.ConfiguredAirbyteCatalog; +import io.airbyte.protocol.models.ConfiguredAirbyteStream; +import io.airbyte.protocol.models.ConnectorSpecification; +import io.airbyte.protocol.models.DestinationSyncMode; +import io.airbyte.protocol.models.Field; +import io.airbyte.protocol.models.JsonSchemaType; +import io.airbyte.protocol.models.SyncMode; +import org.jooq.DSLContext; +import org.jooq.SQLDialect; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MySQLContainer; + +import java.util.List; +import java.util.stream.Collectors; + +import static io.airbyte.integrations.io.airbyte.integration_tests.sources.utils.TestConstants.INITIAL_CDC_WAITING_SECONDS; +import static io.airbyte.protocol.models.SyncMode.INCREMENTAL; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +public class CdcMySqlSslRequiredSourceAcceptanceTest extends SourceAcceptanceTest { + private static final String STREAM_NAME = "id_and_name"; + private static final String STREAM_NAME2 = "starships"; + private MySQLContainer container; + private JsonNode config; + + @Override + protected String getImageName() { + return "airbyte/source-mysql:dev"; + } + + @Override + protected ConnectorSpecification getSpec() throws Exception { + return SshHelpers.getSpecAndInjectSsh(); + } + + @Override + protected JsonNode getConfig() { + return config; + } + + @Override + protected ConfiguredAirbyteCatalog getConfiguredCatalog() { + return new ConfiguredAirbyteCatalog().withStreams(Lists.newArrayList( + new ConfiguredAirbyteStream() + .withSyncMode(INCREMENTAL) + .withDestinationSyncMode(DestinationSyncMode.APPEND) + .withStream(CatalogHelpers.createAirbyteStream( + String.format("%s", STREAM_NAME), + String.format("%s", config.get(JdbcUtils.DATABASE_KEY).asText()), + Field.of("id", JsonSchemaType.NUMBER), + Field.of("name", JsonSchemaType.STRING)) + .withSourceDefinedCursor(true) + .withSourceDefinedPrimaryKey(List.of(List.of("id"))) + .withSupportedSyncModes( + Lists.newArrayList(SyncMode.FULL_REFRESH, INCREMENTAL))), + new ConfiguredAirbyteStream() + .withSyncMode(INCREMENTAL) + .withDestinationSyncMode(DestinationSyncMode.APPEND) + .withStream(CatalogHelpers.createAirbyteStream( + String.format("%s", STREAM_NAME2), + String.format("%s", config.get(JdbcUtils.DATABASE_KEY).asText()), + Field.of("id", JsonSchemaType.NUMBER), + Field.of("name", JsonSchemaType.STRING)) + .withSourceDefinedCursor(true) + .withSourceDefinedPrimaryKey(List.of(List.of("id"))) + .withSupportedSyncModes( + Lists.newArrayList(SyncMode.FULL_REFRESH, INCREMENTAL))))); + } + + @Override + protected JsonNode getState() { + return null; + } + + @Override + protected void setupEnvironment(final TestDestinationEnv environment) throws Exception { + container = new MySQLContainer<>("mysql:8.0"); + container.start(); + + final var sslMode = ImmutableMap.builder() + .put(JdbcUtils.MODE_KEY, "required") + .build(); + final JsonNode replicationMethod = Jsons.jsonNode(ImmutableMap.builder() + .put("method", "CDC") + .put("initial_waiting_seconds", INITIAL_CDC_WAITING_SECONDS) + .build()); + + config = Jsons.jsonNode(ImmutableMap.builder() + .put(JdbcUtils.HOST_KEY, container.getHost()) + .put(JdbcUtils.PORT_KEY, container.getFirstMappedPort()) + .put(JdbcUtils.DATABASE_KEY, container.getDatabaseName()) + .put(JdbcUtils.USERNAME_KEY, container.getUsername()) + .put(JdbcUtils.PASSWORD_KEY, container.getPassword()) + .put(JdbcUtils.SSL_KEY, true) + .put(JdbcUtils.SSL_MODE_KEY, sslMode) + .put("replication_method", replicationMethod) + .put("is_test", true) + .build()); + + revokeAllPermissions(); + grantCorrectPermissions(); + alterUserRequireSsl(); + createAndPopulateTables(); + } + + private void alterUserRequireSsl() { + executeQuery("ALTER USER " + container.getUsername() + " REQUIRE SSL;"); + } + + private void createAndPopulateTables() { + executeQuery("CREATE TABLE id_and_name(id INTEGER PRIMARY KEY, name VARCHAR(200));"); + executeQuery( + "INSERT INTO id_and_name (id, name) VALUES (1,'picard'), (2, 'crusher'), (3, 'vash');"); + executeQuery("CREATE TABLE starships(id INTEGER PRIMARY KEY, name VARCHAR(200));"); + executeQuery( + "INSERT INTO starships (id, name) VALUES (1,'enterprise-d'), (2, 'defiant'), (3, 'yamato');"); + } + + private void revokeAllPermissions() { + executeQuery("REVOKE ALL PRIVILEGES, GRANT OPTION FROM " + container.getUsername() + "@'%';"); + } + + private void grantCorrectPermissions() { + executeQuery( + "GRANT SELECT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO " + + container.getUsername() + "@'%';"); + } + + private void executeQuery(final String query) { + try (final DSLContext dslContext = DSLContextFactory.create( + "root", + "test", + DatabaseDriver.MYSQL.getDriverClassName(), + String.format(DatabaseDriver.MYSQL.getUrlFormatString(), + container.getHost(), + container.getFirstMappedPort(), + container.getDatabaseName()), + SQLDialect.MYSQL)) { + final Database database = new Database(dslContext); + database.query( + ctx -> ctx + .execute(query)); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void tearDown(final TestDestinationEnv testEnv) { + container.close(); + } + + @Test + public void testIncrementalSyncShouldNotFailIfBinlogIsDeleted() throws Exception { + final ConfiguredAirbyteCatalog configuredCatalog = withSourceDefinedCursors(getConfiguredCatalog()); + // only sync incremental streams + configuredCatalog.setStreams( + configuredCatalog.getStreams().stream().filter(s -> s.getSyncMode() == INCREMENTAL).collect(Collectors.toList())); + + final List airbyteMessages = runRead(configuredCatalog, getState()); + final List recordMessages = filterRecords(airbyteMessages); + final List stateMessages = airbyteMessages + .stream() + .filter(m -> m.getType() == AirbyteMessage.Type.STATE) + .map(AirbyteMessage::getState) + .collect(Collectors.toList()); + assertFalse(recordMessages.isEmpty(), "Expected the first incremental sync to produce records"); + assertFalse(stateMessages.isEmpty(), "Expected incremental sync to produce STATE messages"); + + // when we run incremental sync again there should be no new records. Run a sync with the latest + // state message and assert no records were emitted. + final JsonNode latestState = Jsons.jsonNode(supportsPerStream() ? stateMessages : List.of(Iterables.getLast(stateMessages))); + // RESET MASTER removes all binary log files that are listed in the index file, + // leaving only a single, empty binary log file with a numeric suffix of .000001 + executeQuery("RESET MASTER;"); + + assertEquals(6, filterRecords(runRead(configuredCatalog, latestState)).size()); + } +} diff --git a/docs/integrations/sources/mysql.md b/docs/integrations/sources/mysql.md index 5dcc873df3a0..b2a78ecf2869 100644 --- a/docs/integrations/sources/mysql.md +++ b/docs/integrations/sources/mysql.md @@ -252,6 +252,7 @@ WHERE actor_definition_id ='435bb9a5-7887-4809-aa58-28c27df0d7ad' AND (configura ## Changelog | Version | Date | Pull Request | Subject | |:--------|:-----------|:-----------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------| +| 1.0.11 | 2022-11-03 | [18851](https://github.com/airbytehq/airbyte/pull/18851) | Fix bug with unencrypted CDC connections | | 1.0.10 | 2022-11-02 | [18619](https://github.com/airbytehq/airbyte/pull/18619) | Fix bug with handling Tinyint(1) Unsigned values as boolean | | 1.0.9 | 2022-10-31 | [18538](https://github.com/airbytehq/airbyte/pull/18538) | Encode database name | | 1.0.8 | 2022-10-25 | [18383](https://github.com/airbytehq/airbyte/pull/18383) | Better SSH error handling + messages | From c01b81bddbd0b9a55ff1a8cc966087dccb37ca5d Mon Sep 17 00:00:00 2001 From: Serhii Chvaliuk Date: Thu, 3 Nov 2022 19:46:06 +0200 Subject: [PATCH 19/73] Source Mixpanel: "export" stream make line parsing more robust (#18846) Signed-off-by: Sergey Chvalyuk --- .../resources/seed/source_definitions.yaml | 2 +- .../src/main/resources/seed/source_specs.yaml | 4 +-- .../connectors/source-mixpanel/Dockerfile | 2 +- .../connectors/source-mixpanel/setup.py | 2 +- .../source_mixpanel/streams/export.py | 32 ++++++++++++++++--- .../unit_tests/test_streams.py | 12 +++++++ docs/integrations/sources/mixpanel.md | 3 +- 7 files changed, 46 insertions(+), 11 deletions(-) diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index 90c091333e32..f541db1ad9f8 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -781,7 +781,7 @@ - name: Mixpanel sourceDefinitionId: 12928b32-bf0a-4f1e-964f-07e12e37153a dockerRepository: airbyte/source-mixpanel - dockerImageTag: 0.1.28 + dockerImageTag: 0.1.29 documentationUrl: https://docs.airbyte.com/integrations/sources/mixpanel icon: mixpanel.svg sourceType: api diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 82a4f6b86628..3666b2fb13cf 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -7322,7 +7322,7 @@ path_in_connector_config: - "credentials" - "client_secret" -- dockerImage: "airbyte/source-mixpanel:0.1.28" +- dockerImage: "airbyte/source-mixpanel:0.1.29" spec: documentationUrl: "https://docs.airbyte.com/integrations/sources/mixpanel" connectionSpecification: @@ -7331,7 +7331,7 @@ type: "object" properties: credentials: - title: "Authentication" + title: "Authentication *" description: "Choose how to authenticate to Mixpanel" type: "object" order: 0 diff --git a/airbyte-integrations/connectors/source-mixpanel/Dockerfile b/airbyte-integrations/connectors/source-mixpanel/Dockerfile index 3d23ac5d7499..cd44abfc08fe 100644 --- a/airbyte-integrations/connectors/source-mixpanel/Dockerfile +++ b/airbyte-integrations/connectors/source-mixpanel/Dockerfile @@ -13,5 +13,5 @@ ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.28 +LABEL io.airbyte.version=0.1.29 LABEL io.airbyte.name=airbyte/source-mixpanel diff --git a/airbyte-integrations/connectors/source-mixpanel/setup.py b/airbyte-integrations/connectors/source-mixpanel/setup.py index 2e8c999f12f7..8853942e605d 100644 --- a/airbyte-integrations/connectors/source-mixpanel/setup.py +++ b/airbyte-integrations/connectors/source-mixpanel/setup.py @@ -6,7 +6,7 @@ from setuptools import find_packages, setup MAIN_REQUIREMENTS = [ - "airbyte-cdk~=0.1", + "airbyte-cdk~=0.2", ] TEST_REQUIREMENTS = ["pytest~=6.1", "source-acceptance-test", "pytest-mock~=3.6", "requests_mock~=1.8"] diff --git a/airbyte-integrations/connectors/source-mixpanel/source_mixpanel/streams/export.py b/airbyte-integrations/connectors/source-mixpanel/source_mixpanel/streams/export.py index 50bccb9f5946..abef69db1e9f 100644 --- a/airbyte-integrations/connectors/source-mixpanel/source_mixpanel/streams/export.py +++ b/airbyte-integrations/connectors/source-mixpanel/source_mixpanel/streams/export.py @@ -85,6 +85,32 @@ def url_base(self): def path(self, **kwargs) -> str: return "export" + def iter_dicts(self, lines): + """ + The incoming stream has to be JSON lines format. + From time to time for some reason, the one record can be split into multiple lines. + We try to combine such split parts into one record only if parts go nearby. + """ + parts = [] + for record_line in lines: + if record_line == "terminated early": + self.logger.warning(f"Couldn't fetch data from Export API. Response: {record_line}") + return + try: + yield json.loads(record_line) + except ValueError: + parts.append(record_line) + else: + parts = [] + + if len(parts) > 1: + try: + yield json.loads("".join(parts)) + except ValueError: + pass + else: + parts = [] + def process_response(self, response: requests.Response, **kwargs) -> Iterable[Mapping]: """Export API return response in JSONL format but each line is a valid JSON object Raw item example: @@ -106,11 +132,7 @@ def process_response(self, response: requests.Response, **kwargs) -> Iterable[Ma """ # We prefer response.iter_lines() to response.text.split_lines() as the later can missparse text properties embeding linebreaks - for record_line in response.iter_lines(decode_unicode=True): - if record_line == "terminated early": - self.logger.warning(f"Couldn't fetch data from Export API. Response: {record_line}") - break - record = json.loads(record_line) + for record in self.iter_dicts(response.iter_lines(decode_unicode=True)): # transform record into flat dict structure item = {"event": record["event"]} properties = record["properties"] diff --git a/airbyte-integrations/connectors/source-mixpanel/unit_tests/test_streams.py b/airbyte-integrations/connectors/source-mixpanel/unit_tests/test_streams.py index 0f5c365aa9bb..cab84ff7f652 100644 --- a/airbyte-integrations/connectors/source-mixpanel/unit_tests/test_streams.py +++ b/airbyte-integrations/connectors/source-mixpanel/unit_tests/test_streams.py @@ -2,6 +2,7 @@ # Copyright (c) 2022 Airbyte, Inc., all rights reserved. # +import json from datetime import timedelta from unittest.mock import MagicMock @@ -456,3 +457,14 @@ def test_export_terminated_early(requests_mock, config): stream = Export(authenticator=MagicMock(), **config) requests_mock.register_uri("GET", get_url_to_mock(stream), text="terminated early\n") assert list(read_full_refresh(stream)) == [] + + +def test_export_iter_dicts(config): + stream = Export(authenticator=MagicMock(), **config) + record = {"key1": "value1", "key2": "value2"} + record_string = json.dumps(record) + assert list(stream.iter_dicts([record_string, record_string])) == [record, record] + # combine record from 2 standing nearby parts + assert list(stream.iter_dicts([record_string, record_string[:2], record_string[2:], record_string])) == [record, record, record] + # drop record parts because they are not standing nearby + assert list(stream.iter_dicts([record_string, record_string[:2], record_string, record_string[2:]])) == [record, record] diff --git a/docs/integrations/sources/mixpanel.md b/docs/integrations/sources/mixpanel.md index fed97ee1ff0f..df8be46d181e 100644 --- a/docs/integrations/sources/mixpanel.md +++ b/docs/integrations/sources/mixpanel.md @@ -50,7 +50,8 @@ Syncing huge date windows may take longer due to Mixpanel's low API rate-limits | Version | Date | Pull Request | Subject | | :------ | :--------- | :------------------------------------------------------- | :--------------------------------------------------------------------------------------------------- | -| 0.1.28 | 2022-10-06 | [17699](https://github.com/airbytehq/airbyte/pull/17699) | Fix discover step issue cursor field None | +| 0.1.29 | 2022-11-02 | [18846](https://github.com/airbytehq/airbyte/pull/18846) | For "export" stream make line parsing more robust | +| 0.1.28 | 2022-10-06 | [17699](https://github.com/airbytehq/airbyte/pull/17699) | Fix discover step issue cursor field None | | 0.1.27 | 2022-09-29 | [17415](https://github.com/airbytehq/airbyte/pull/17415) | Disable stream "cohort_members" on discover if not access | | 0.1.26 | 2022-09-28 | [17304](https://github.com/airbytehq/airbyte/pull/17304) | Migrate to per-stream states. | | 0.1.25 | 2022-09-27 | [17145](https://github.com/airbytehq/airbyte/pull/17145) | Disable streams "export", "engage" on discover if not access | From b92c961499c0452a8724099e4eb6426a75dacf71 Mon Sep 17 00:00:00 2001 From: Benoit Moriceau Date: Thu, 3 Nov 2022 12:01:38 -0700 Subject: [PATCH 20/73] Disable flaky test (#18932) --- .../java/io/airbyte/test/acceptance/BasicAcceptanceTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/airbyte-tests/src/acceptanceTests/java/io/airbyte/test/acceptance/BasicAcceptanceTests.java b/airbyte-tests/src/acceptanceTests/java/io/airbyte/test/acceptance/BasicAcceptanceTests.java index 4f9baa0bc91b..af778f649cbe 100644 --- a/airbyte-tests/src/acceptanceTests/java/io/airbyte/test/acceptance/BasicAcceptanceTests.java +++ b/airbyte-tests/src/acceptanceTests/java/io/airbyte/test/acceptance/BasicAcceptanceTests.java @@ -658,6 +658,7 @@ void testIncrementalSync() throws Exception { } + @Disabled @Test @Order(14) void testDeleteConnection() throws Exception { From c40f1b6b7f73bd542eb876f26b55bdda8ca63e74 Mon Sep 17 00:00:00 2001 From: JJ Nilbodee Date: Thu, 3 Nov 2022 19:46:48 +0000 Subject: [PATCH 21/73] =?UTF-8?q?=F0=9F=8E=89=20New=20Source:=20SurveySpar?= =?UTF-8?q?row=20(#18395)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * generated from template * initial commit * add sample_config * add docs * apply comments * minor changes * try using ListSlicer * use ListStreamSlicer * fix base url * update cdk version in requirements * add surveysparrow to source def * add schemaloader * auto-bump connector version Co-authored-by: marcosmarxm Co-authored-by: Octavia Squidington III --- .../resources/seed/source_definitions.yaml | 7 ++ .../src/main/resources/seed/source_specs.yaml | 22 ++++ .../source-survey-sparrow/.dockerignore | 6 + .../source-survey-sparrow/Dockerfile | 38 ++++++ .../source-survey-sparrow/README.md | 79 ++++++++++++ .../source-survey-sparrow/__init__.py | 3 + .../acceptance-test-config.yml | 26 ++++ .../acceptance-test-docker.sh | 16 +++ .../source-survey-sparrow/build.gradle | 9 ++ .../integration_tests/__init__.py | 3 + .../integration_tests/abnormal_state.json | 5 + .../integration_tests/acceptance.py | 16 +++ .../integration_tests/configured_catalog.json | 76 +++++++++++ .../integration_tests/invalid_config.json | 3 + .../integration_tests/sample_config.json | 4 + .../integration_tests/sample_state.json | 5 + .../connectors/source-survey-sparrow/main.py | 13 ++ .../source-survey-sparrow/requirements.txt | 2 + .../connectors/source-survey-sparrow/setup.py | 29 +++++ .../source_survey_sparrow/__init__.py | 8 ++ .../schemas/contact_lists.json | 19 +++ .../schemas/contacts.json | 36 ++++++ .../schemas/questions.json | 61 +++++++++ .../schemas/responses.json | 44 +++++++ .../source_survey_sparrow/schemas/roles.json | 33 +++++ .../schemas/survey_folders.json | 25 ++++ .../schemas/surveys.json | 22 ++++ .../source_survey_sparrow/schemas/users.json | 37 ++++++ .../source_survey_sparrow/source.py | 18 +++ .../source_survey_sparrow/spec.yaml | 20 +++ .../source_survey_sparrow/survey_sparrow.yaml | 118 ++++++++++++++++++ docs/integrations/sources/surveysparrow.md | 48 +++++++ 32 files changed, 851 insertions(+) create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/.dockerignore create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/Dockerfile create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/README.md create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/__init__.py create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/acceptance-test-config.yml create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/acceptance-test-docker.sh create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/build.gradle create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/integration_tests/__init__.py create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/integration_tests/abnormal_state.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/integration_tests/acceptance.py create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/integration_tests/configured_catalog.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/integration_tests/invalid_config.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/integration_tests/sample_config.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/integration_tests/sample_state.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/main.py create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/requirements.txt create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/setup.py create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/__init__.py create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/contact_lists.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/contacts.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/questions.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/responses.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/roles.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/survey_folders.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/surveys.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/users.json create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/source.py create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/spec.yaml create mode 100644 airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/survey_sparrow.yaml create mode 100644 docs/integrations/sources/surveysparrow.md diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index f541db1ad9f8..c0e7479070af 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -1216,6 +1216,13 @@ icon: surveymonkey.svg sourceType: api releaseStage: generally_available +- name: SurveySparrow + sourceDefinitionId: 4a4d887b-0f2d-4b33-ab7f-9b01b9072804 + dockerRepository: airbyte/source-survey-sparrow + dockerImageTag: 0.1.0 + documentationUrl: https://docs.airbyte.com/integrations/sources/survey-sparrow + sourceType: api + releaseStage: alpha - name: TalkDesk Explore sourceDefinitionId: f00d2cf4-3c28-499a-ba93-b50b6f26359e dockerRepository: airbyte/source-talkdesk-explore diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 3666b2fb13cf..759f2e1c7cf1 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -12123,6 +12123,28 @@ oauthFlowInitParameters: [] oauthFlowOutputParameters: - - "access_token" +- dockerImage: "airbyte/source-survey-sparrow:0.1.0" + spec: + documentationUrl: "https://docs.airbyte.com/integrations/sources/surveysparrow" + connectionSpecification: + $schema: "http://json-schema.org/draft-07/schema#" + title: "Survey Sparrow Spec" + type: "object" + required: + - "access_token" + additionalProperties: true + properties: + access_token: + type: "string" + description: "Your access token. See here. The key is case sensitive." + airbyte_secret: true + survey_id: + type: "array" + description: "A List of your survey ids for survey-specific stream" + supportsNormalization: false + supportsDBT: false + supported_destination_sync_modes: [] - dockerImage: "airbyte/source-talkdesk-explore:0.1.0" spec: documentationUrl: "https://docsurl.com" diff --git a/airbyte-integrations/connectors/source-survey-sparrow/.dockerignore b/airbyte-integrations/connectors/source-survey-sparrow/.dockerignore new file mode 100644 index 000000000000..dcd6eb4cb049 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/.dockerignore @@ -0,0 +1,6 @@ +* +!Dockerfile +!main.py +!source_survey_sparrow +!setup.py +!secrets diff --git a/airbyte-integrations/connectors/source-survey-sparrow/Dockerfile b/airbyte-integrations/connectors/source-survey-sparrow/Dockerfile new file mode 100644 index 000000000000..e1cf9ba43b97 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/Dockerfile @@ -0,0 +1,38 @@ +FROM python:3.9.11-alpine3.15 as base + +# build and load all requirements +FROM base as builder +WORKDIR /airbyte/integration_code + +# upgrade pip to the latest version +RUN apk --no-cache upgrade \ + && pip install --upgrade pip \ + && apk --no-cache add tzdata build-base + + +COPY setup.py ./ +# install necessary packages to a temporary folder +RUN pip install --prefix=/install . + +# build a clean environment +FROM base +WORKDIR /airbyte/integration_code + +# copy all loaded and built libraries to a pure basic image +COPY --from=builder /install /usr/local +# add default timezone settings +COPY --from=builder /usr/share/zoneinfo/Etc/UTC /etc/localtime +RUN echo "Etc/UTC" > /etc/timezone + +# bash is installed for more convenient debugging. +RUN apk --no-cache add bash + +# copy payload code only +COPY main.py ./ +COPY source_survey_sparrow ./source_survey_sparrow + +ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" +ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] + +LABEL io.airbyte.version=0.1.0 +LABEL io.airbyte.name=airbyte/source-survey-sparrow diff --git a/airbyte-integrations/connectors/source-survey-sparrow/README.md b/airbyte-integrations/connectors/source-survey-sparrow/README.md new file mode 100644 index 000000000000..847d9d62d3f9 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/README.md @@ -0,0 +1,79 @@ +# Survey Sparrow Source + +This is the repository for the Survey Sparrow configuration based source connector. +For information about how to use this connector within Airbyte, see [the documentation](https://docs.airbyte.io/integrations/sources/survey-sparrow). + +## Local development + +#### Building via Gradle +You can also build the connector in Gradle. This is typically used in CI and not needed for your development workflow. + +To build using Gradle, from the Airbyte repository root, run: +``` +./gradlew :airbyte-integrations:connectors:source-survey-sparrow:build +``` + +#### Create credentials +**If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.io/integrations/sources/survey-sparrow) +to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `source_survey_sparrow/spec.yaml` file. +Note that any directory named `secrets` is gitignored across the entire Airbyte repo, so there is no danger of accidentally checking in sensitive information. +See `integration_tests/sample_config.json` for a sample config file. + +**If you are an Airbyte core member**, copy the credentials in Lastpass under the secret name `source survey-sparrow test creds` +and place them into `secrets/config.json`. + +### Locally running the connector docker image + +#### Build +First, make sure you build the latest Docker image: +``` +docker build . -t airbyte/source-survey-sparrow:dev +``` + +You can also build the connector image via Gradle: +``` +./gradlew :airbyte-integrations:connectors:source-survey-sparrow:airbyteDocker +``` +When building via Gradle, the docker image name and tag, respectively, are the values of the `io.airbyte.name` and `io.airbyte.version` `LABEL`s in +the Dockerfile. + +#### Run +Then run any of the connector commands as follows: +``` +docker run --rm airbyte/source-survey-sparrow:dev spec +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-survey-sparrow:dev check --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-survey-sparrow:dev discover --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/source-survey-sparrow:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json +``` +## Testing + +#### Acceptance Tests +Customize `acceptance-test-config.yml` file to configure tests. See [Source Acceptance Tests](https://docs.airbyte.io/connector-development/testing-connectors/source-acceptance-tests-reference) for more information. +If your connector requires to create or destroy resources for use during acceptance tests create fixtures for it and place them inside integration_tests/acceptance.py. + +To run your integration tests with docker + +### Using gradle to run tests +All commands should be run from airbyte project root. +To run unit tests: +``` +./gradlew :airbyte-integrations:connectors:source-survey-sparrow:unitTest +``` +To run acceptance and custom integration tests: +``` +./gradlew :airbyte-integrations:connectors:source-survey-sparrow:integrationTest +``` + +## Dependency Management +All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development. +We split dependencies between two groups, dependencies that are: +* required for your connector to work need to go to `MAIN_REQUIREMENTS` list. +* required for the testing need to go to `TEST_REQUIREMENTS` list + +### Publishing a new version of the connector +You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what? +1. Make sure your changes are passing unit and integration tests. +1. Bump the connector version in `Dockerfile` -- just increment the value of the `LABEL io.airbyte.version` appropriately (we use [SemVer](https://semver.org/)). +1. Create a Pull Request. +1. Pat yourself on the back for being an awesome contributor. +1. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master. diff --git a/airbyte-integrations/connectors/source-survey-sparrow/__init__.py b/airbyte-integrations/connectors/source-survey-sparrow/__init__.py new file mode 100644 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-survey-sparrow/acceptance-test-config.yml b/airbyte-integrations/connectors/source-survey-sparrow/acceptance-test-config.yml new file mode 100644 index 000000000000..1a7dc9c87a81 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/acceptance-test-config.yml @@ -0,0 +1,26 @@ +# See [Source Acceptance Tests](https://docs.airbyte.com/connector-development/testing-connectors/source-acceptance-tests-reference) +# for more information about how to configure these tests +connector_image: airbyte/source-survey-sparrow:dev +tests: + spec: + - spec_path: "source_survey_sparrow/spec.yaml" + connection: + - config_path: "secrets/config.json" + status: "succeed" + - config_path: "integration_tests/invalid_config.json" + status: "failed" + discovery: + - config_path: "secrets/config.json" + basic_read: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" + empty_streams: ["contact_lists", "responses", "surveys"] + # TODO uncomment this block to specify that the tests should assert the connector outputs the records provided in the input file a file + # expect_records: + # path: "integration_tests/expected_records.txt" + # extra_fields: no + # exact_order: no + # extra_records: yes + full_refresh: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" diff --git a/airbyte-integrations/connectors/source-survey-sparrow/acceptance-test-docker.sh b/airbyte-integrations/connectors/source-survey-sparrow/acceptance-test-docker.sh new file mode 100644 index 000000000000..c51577d10690 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/acceptance-test-docker.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +# Build latest connector image +docker build . -t $(cat acceptance-test-config.yml | grep "connector_image" | head -n 1 | cut -d: -f2-) + +# Pull latest acctest image +docker pull airbyte/source-acceptance-test:latest + +# Run +docker run --rm -it \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /tmp:/tmp \ + -v $(pwd):/test_input \ + airbyte/source-acceptance-test \ + --acceptance-test-config /test_input + diff --git a/airbyte-integrations/connectors/source-survey-sparrow/build.gradle b/airbyte-integrations/connectors/source-survey-sparrow/build.gradle new file mode 100644 index 000000000000..e6542b6054ff --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/build.gradle @@ -0,0 +1,9 @@ +plugins { + id 'airbyte-python' + id 'airbyte-docker' + id 'airbyte-source-acceptance-test' +} + +airbytePython { + moduleDirectory 'source_survey_sparrow' +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/__init__.py b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/__init__.py new file mode 100644 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/abnormal_state.json b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/abnormal_state.json new file mode 100644 index 000000000000..52b0f2c2118f --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/abnormal_state.json @@ -0,0 +1,5 @@ +{ + "todo-stream-name": { + "todo-field-name": "todo-abnormal-value" + } +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/acceptance.py b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/acceptance.py new file mode 100644 index 000000000000..1302b2f57e10 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/acceptance.py @@ -0,0 +1,16 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import pytest + +pytest_plugins = ("source_acceptance_test.plugin",) + + +@pytest.fixture(scope="session", autouse=True) +def connector_setup(): + """This fixture is a placeholder for external resources that acceptance test might require.""" + # TODO: setup test dependencies if needed. otherwise remove the TODO comments + yield + # TODO: clean up test dependencies diff --git a/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/configured_catalog.json b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/configured_catalog.json new file mode 100644 index 000000000000..72598e0516ad --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/configured_catalog.json @@ -0,0 +1,76 @@ +{ + "streams": [ + { + "stream": { + "name": "contacts", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "contact_lists", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "questions", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "responses", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "roles", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "surveys", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "survey_folders", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "users", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/invalid_config.json b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/invalid_config.json new file mode 100644 index 000000000000..5a47240008a0 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/invalid_config.json @@ -0,0 +1,3 @@ +{ + "access_token": "" +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/sample_config.json b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/sample_config.json new file mode 100644 index 000000000000..b4f98424e822 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/sample_config.json @@ -0,0 +1,4 @@ +{ + "access_token": "", + "survey_id": [1234, 5678] +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/sample_state.json b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/sample_state.json new file mode 100644 index 000000000000..3587e579822d --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/integration_tests/sample_state.json @@ -0,0 +1,5 @@ +{ + "todo-stream-name": { + "todo-field-name": "value" + } +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/main.py b/airbyte-integrations/connectors/source-survey-sparrow/main.py new file mode 100644 index 000000000000..748298d3e8be --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/main.py @@ -0,0 +1,13 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import sys + +from airbyte_cdk.entrypoint import launch +from source_survey_sparrow import SourceSurveySparrow + +if __name__ == "__main__": + source = SourceSurveySparrow() + launch(source, sys.argv[1:]) diff --git a/airbyte-integrations/connectors/source-survey-sparrow/requirements.txt b/airbyte-integrations/connectors/source-survey-sparrow/requirements.txt new file mode 100644 index 000000000000..0411042aa091 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/requirements.txt @@ -0,0 +1,2 @@ +-e ../../bases/source-acceptance-test +-e . diff --git a/airbyte-integrations/connectors/source-survey-sparrow/setup.py b/airbyte-integrations/connectors/source-survey-sparrow/setup.py new file mode 100644 index 000000000000..dbdaa0025b4e --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/setup.py @@ -0,0 +1,29 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from setuptools import find_packages, setup + +MAIN_REQUIREMENTS = [ + "airbyte-cdk~=0.5", +] + +TEST_REQUIREMENTS = [ + "pytest~=6.1", + "pytest-mock~=3.6.1", + "source-acceptance-test", +] + +setup( + name="source_survey_sparrow", + description="Source implementation for Survey Sparrow.", + author="Airbyte", + author_email="contact@airbyte.io", + packages=find_packages(), + install_requires=MAIN_REQUIREMENTS, + package_data={"": ["*.json", "*.yaml", "schemas/*.json", "schemas/shared/*.json"]}, + extras_require={ + "tests": TEST_REQUIREMENTS, + }, +) diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/__init__.py b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/__init__.py new file mode 100644 index 000000000000..1e16c729b1e3 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/__init__.py @@ -0,0 +1,8 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from .source import SourceSurveySparrow + +__all__ = ["SourceSurveySparrow"] diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/contact_lists.json b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/contact_lists.json new file mode 100644 index 000000000000..b5852ccdff26 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/contact_lists.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": { + "type": ["null", "integer"] + }, + "name": { + "type": ["null", "string"] + }, + "description": { + "type": ["null", "string"] + }, + "created_at": { + "type": ["null", "string"], + "format": "date-time" + } + } +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/contacts.json b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/contacts.json new file mode 100644 index 000000000000..b0316769f39b --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/contacts.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": { + "type": ["null", "integer"] + }, + "email": { + "type": ["null", "string"] + }, + "mobile": { + "type": ["null", "string"] + }, + "job_title": { + "type": ["null", "string"] + }, + "active": { + "type": ["null", "boolean"] + }, + "unsubscribed": { + "type": ["null", "boolean"] + }, + "name": { + "type": ["null", "string"] + }, + "last_name": { + "type": ["null", "string"] + }, + "first_name": { + "type": ["null", "string"] + }, + "createddate": { + "type": ["null", "string"] + } + } +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/questions.json b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/questions.json new file mode 100644 index 000000000000..3f0ebc8ff700 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/questions.json @@ -0,0 +1,61 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": { + "type": ["null", "integer"] + }, + "rtxt": { + "type": ["null", "string"] + }, + "type": { + "type": ["null", "string"] + }, + "multiple_answers": { + "type": ["null", "boolean"] + }, + "is_required": { + "type": ["null", "boolean"] + }, + "properties": { + "type": ["null", "object"], + "properties": { + "data": { + "type": ["null", "object"] + }, + "clone": { + "type": ["null", "object"] + } + } + }, + "parent_question_id": { + "type": ["null", "integer"] + }, + "position": { + "type": ["null", "string"] + }, + "created_at": { + "type": ["null", "string"], + "format": "date-time" + }, + "updated_at": { + "type": ["null", "string"], + "format": "date-time" + }, + "section": { + "type": ["null", "object"] + }, + "tags": { + "type": ["null", "array"] + }, + "annotations": { + "type": ["null", "array"] + }, + "scale_points": { + "type": ["null", "array"] + }, + "choices": { + "type": ["null", "array"] + } + } +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/responses.json b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/responses.json new file mode 100644 index 000000000000..78bce1fd286a --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/responses.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": { + "type": ["null", "integer"] + }, + "completed_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "survey_id": { + "type": ["null", "integer"] + }, + "state": { + "type": ["null", "string"] + }, + "channel_id": { + "type": ["null", "integer"] + }, + "language": { + "type": ["null", "string"] + }, + "start_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "contact": { + "type": ["null", "string"] + }, + "channel": { + "type": ["null", "object"] + }, + "answers": { + "type": ["null", "array"] + }, + "variables": { + "type": ["null", "array"] + }, + "expressions": { + "type": ["null", "array"] + } + } +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/roles.json b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/roles.json new file mode 100644 index 000000000000..665def537a7f --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/roles.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": { + "type": ["null", "integer"] + }, + "name": { + "type": ["null", "string"] + }, + "label": { + "type": ["null", "string"] + }, + "description": { + "type": ["null", "string"] + }, + "created_at": { + "type": ["null", "string"], + "format": "date-time" + }, + "updated_at": { + "type": ["null", "string"], + "format": "date-time" + }, + "deleted_at": { + "type": ["null", "string"], + "format": "date-time" + }, + "account_id": { + "type": ["null", "integer"] + } + } +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/survey_folders.json b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/survey_folders.json new file mode 100644 index 000000000000..1890356de05b --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/survey_folders.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": { + "type": ["null", "integer"] + }, + "name": { + "type": ["null", "string"] + }, + "description": { + "type": ["null", "string"] + }, + "auto_created": { + "type": ["null", "boolean"] + }, + "visibility": { + "type": ["null", "string"] + }, + "created_at": { + "type": ["null", "string"], + "format": "date-time" + } + } +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/surveys.json b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/surveys.json new file mode 100644 index 000000000000..0d1035b55370 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/surveys.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": { + "type": ["null", "integer"] + }, + "name": { + "type": ["null", "string"] + }, + "archived": { + "type": ["null", "boolean"] + }, + "survey_type": { + "type": ["null", "string"] + }, + "created_at": { + "type": ["null", "string"], + "format": "date-time" + } + } +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/users.json b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/users.json new file mode 100644 index 000000000000..d8ba88646f67 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/schemas/users.json @@ -0,0 +1,37 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": { + "type": ["null", "integer"] + }, + "name": { + "type": ["null", "string"] + }, + "email": { + "type": ["null", "string"] + }, + "phone": { + "type": ["null", "string"] + }, + "admin": { + "type": ["null", "boolean"] + }, + "owner": { + "type": ["null", "boolean"] + }, + "agency_owner": { + "type": ["null", "boolean"] + }, + "verified": { + "type": ["null", "boolean"] + }, + "role_id": { + "type": ["null", "integer"] + }, + "created_at": { + "type": ["null", "string"], + "format": "date-time" + } + } +} diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/source.py b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/source.py new file mode 100644 index 000000000000..c61cdd97176f --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/source.py @@ -0,0 +1,18 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from airbyte_cdk.sources.declarative.yaml_declarative_source import YamlDeclarativeSource + +""" +This file provides the necessary constructs to interpret a provided declarative YAML configuration file into +source connector. + +WARNING: Do not modify this file. +""" + + +# Declarative Source +class SourceSurveySparrow(YamlDeclarativeSource): + def __init__(self): + super().__init__(**{"path_to_yaml": "survey_sparrow.yaml"}) diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/spec.yaml b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/spec.yaml new file mode 100644 index 000000000000..5eba7bce4b6c --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/spec.yaml @@ -0,0 +1,20 @@ +documentationUrl: https://docs.airbyte.com/integrations/sources/surveysparrow +connectionSpecification: + $schema: http://json-schema.org/draft-07/schema# + title: Survey Sparrow Spec + type: object + required: + - access_token + additionalProperties: true + properties: + # 'TODO: This schema defines the configuration required for the source. This usually involves metadata such as database and/or authentication information.': + access_token: + type: string + description: >- + Your access token. See here. The key is + case sensitive. + airbyte_secret: true + survey_id: + type: array + description: A List of your survey ids for survey-specific stream diff --git a/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/survey_sparrow.yaml b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/survey_sparrow.yaml new file mode 100644 index 000000000000..edb0da25ddd1 --- /dev/null +++ b/airbyte-integrations/connectors/source-survey-sparrow/source_survey_sparrow/survey_sparrow.yaml @@ -0,0 +1,118 @@ +version: "0.1.0" + +definitions: + page_size: 50 + selector: + extractor: + field_pointer: ["data"] + requester: + url_base: "https://api.surveysparrow.com/v3" + http_method: "GET" + authenticator: + type: BearerAuthenticator + api_token: "{{ config['access_token'] }}" + retriever: + record_selector: + $ref: "*ref(definitions.selector)" + paginator: + type: "DefaultPaginator" + page_size_option: + inject_into: "request_parameter" + field_name: "limit" + pagination_strategy: + type: "PageIncrement" + page_size: "*ref(definitions.page_size)" + page_token_option: + inject_into: "request_parameter" + field_name: "page" + url_base: "*ref(definitions.requester.url_base)" + requester: + $ref: "*ref(definitions.requester)" + base_stream: + schema_loader: + type: JsonSchema + file_path: "./source_survey_sparrow/schemas/{{ options['name'] }}.json" + retriever: + $ref: "*ref(definitions.retriever)" + contacts_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "contacts" + primary_key: "id" + path: "/contacts" + contact_lists_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "contact_lists" + primary_key: "id" + path: "/contact_lists" + paginator: + type: "NoPagination" + questions_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "questions" + primary_key: "id" + path: "/questions" + retriever: + $ref: "*ref(definitions.base_stream.retriever)" + stream_slicer: + type: "ListStreamSlicer" + slice_values: "{{ config.get('survey_id') }}" + cursor_field: "survey_id" + request_option: + field_name: "survey_id" + inject_into: "request_parameter" + responses_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "responses" + primary_key: "id" + path: "/responses" + retriever: + $ref: "*ref(definitions.base_stream.retriever)" + stream_slicer: + type: "ListStreamSlicer" + slice_values: "{{ config.get('survey_id') }}" + cursor_field: "survey_id" + request_option: + field_name: "survey_id" + inject_into: "request_parameter" + roles_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "roles" + primary_key: "id" + path: "/roles" + surveys_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "surveys" + primary_key: "id" + path: "/surveys" + survey_folders_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "survey_folders" + primary_key: "id" + path: "/survey_folders" + users_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "users" + primary_key: "id" + path: "/users" + +streams: + - "*ref(definitions.contacts_stream)" + - "*ref(definitions.contact_lists_stream)" + - "*ref(definitions.questions_stream)" + - "*ref(definitions.responses_stream)" + - "*ref(definitions.roles_stream)" + - "*ref(definitions.surveys_stream)" + - "*ref(definitions.survey_folders_stream)" + - "*ref(definitions.users_stream)" + +check: + stream_names: + - "roles" diff --git a/docs/integrations/sources/surveysparrow.md b/docs/integrations/sources/surveysparrow.md new file mode 100644 index 000000000000..33f99664ff63 --- /dev/null +++ b/docs/integrations/sources/surveysparrow.md @@ -0,0 +1,48 @@ +# SurveySparrow + +This page guides you through the process of setting up the SurveySparrow source connector. + +## Prerequisites + +### For Airbyte Open Source: +* Access Token + +## Setup guide +### Step 1: Set up SurveySparrow +Please read this [docs](https://developers.surveysparrow.com/rest-apis). + +In order to get access token, follow these steps: + +1. Login to your surveysparrow account and go to Settings → Apps & Integrations +2. Create a Private App +3. Enter Name, Description, select scope and generate the access token +4. Copy and keep the access token in a safe place (Access token will be displayed only once and you may need to re-generate if you misplaced) +5. Save your app and you are good to start developing your private app + +## Step 2: Set up the source connector in Airbyte + +**For Airbyte Open Source:** + +1. Go to local Airbyte page. +2. In the left navigation bar, click **Sources**. In the top-right corner, click **+ new source**. +3. On the source setup page, select **SurveySparrow** from the Source type dropdown and enter a name for this connector. +4. Add **Access Token** +5. Add Survey ID (optional) +6. Click `Set up source`. + +## Supported streams and sync modes + +* [Contacts](https://developers.surveysparrow.com/rest-apis/contacts#getV3Contacts) +* [ContactLists](https://developers.surveysparrow.com/rest-apis/contact_lists#getV3Contact_lists) +* [Questions](https://developers.surveysparrow.com/rest-apis/questions#getV3Questions) +* [Responses](https://developers.surveysparrow.com/rest-apis/response#getV3Responses) +* [Roles](https://developers.surveysparrow.com/rest-apis/roles#getV3Roles) +* [Surveys](https://developers.surveysparrow.com/rest-apis/survey#getV3Surveys) +* [SurveyFolders](https://developers.surveysparrow.com/rest-apis/survey_folder#getV3Survey_folders) +* [Users](https://developers.surveysparrow.com/rest-apis/users#getV3Users) + +## Changelog + +| Version | Date | Pull Request | Subject | +| :------ | :--------- | :------------------------------------------------------- | :--------------------------------------------------------------------- | +| 0.1.0 | | [18395](https://github.com/airbytehq/airbyte/pull/18395) | Initial Release | From afde9c6c9416d04d19eba8cfe8f8e4cc0f2744da Mon Sep 17 00:00:00 2001 From: Volodymyr Pochtar Date: Thu, 3 Nov 2022 21:50:19 +0200 Subject: [PATCH 22/73] ci: return 7 symbols short git hash on branch build (#18934) --- .github/actions/build-branch/action.yml | 8 +------- .github/workflows/publish-oss-for-cloud.yml | 10 +--------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/.github/actions/build-branch/action.yml b/.github/actions/build-branch/action.yml index c2eca92897dc..e1df48d97e2d 100644 --- a/.github/actions/build-branch/action.yml +++ b/.github/actions/build-branch/action.yml @@ -18,13 +18,7 @@ runs: # if the *branch_version_tag* input param is not specified, then generate it as 'dev-` # [[ "${{ inputs.branch_version_tag }}" != '' ]] && echo "branch_version_tag=${{ inputs.branch_version_tag }}" >> $GITHUB_OUTPUT \ - || { short_hash=$(git rev-parse --short HEAD); echo "branch_version_tag=dev-$short_hash" >> $GITHUB_OUTPUT ; } - cat $GITHUB_OUTPUT || true # for the sake of investigation - - # if the *branch_version_tag* input param is not specified, then generate it as 'dev-` - # - [[ "${{ inputs.branch_version_tag }}" != '' ]] && echo "::set-output name=branch_version_tag::${{ inputs.branch_version_tag }}" \ - || { short_hash=$(git rev-parse --short HEAD); echo "::set-output name=branch_version_tag::dev-$short_hash"; } + || { short_hash=$(git rev-parse --short=7 HEAD); echo "branch_version_tag=dev-$short_hash" >> $GITHUB_OUTPUT ; } - uses: actions/setup-java@v1 with: diff --git a/.github/workflows/publish-oss-for-cloud.yml b/.github/workflows/publish-oss-for-cloud.yml index 11ffd9d98c39..f3a5937f1577 100644 --- a/.github/workflows/publish-oss-for-cloud.yml +++ b/.github/workflows/publish-oss-for-cloud.yml @@ -62,7 +62,7 @@ jobs: run: |- set -x - commit_sha=$(git rev-parse --short HEAD) + commit_sha=$(git rev-parse --short=7 HEAD) # set dev_tag # AirbyteVersion.java allows versions that have a prefix of 'dev' @@ -74,14 +74,6 @@ jobs: fi cat $GITHUB_OUTPUT || true # for the sake of investigation - # set dev_tag - # AirbyteVersion.java allows versions that have a prefix of 'dev' - echo "::set-output name=dev_tag::dev-${commit_sha}" - - if $(git merge-base --is-ancestor "${commit_sha}" master); then - echo "::set-output name=master_tag::${commit_sha}" - fi - oss-branch-build: name: "Gradle Build and Publish" needs: From d405bc9c5fdb2d1a68f9212478c661144d446062 Mon Sep 17 00:00:00 2001 From: Jimmy Ma Date: Thu, 3 Nov 2022 13:01:45 -0700 Subject: [PATCH 23/73] Extract StandardSyncPersistence from ConfigRepository (#18930) --- .../config/persistence/ConfigRepository.java | 24 +- .../DatabaseConfigPersistence.java | 201 +---------------- .../persistence/PersistenceHelpers.java | 30 +++ .../persistence/StandardSyncPersistence.java | 209 ++++++++++++++++++ .../BaseDatabaseConfigPersistenceTest.java | 1 + .../ConfigRepositoryE2EReadWriteTest.java | 3 +- .../persistence/ConfigRepositoryTest.java | 11 +- ...baseConfigPersistenceE2EReadWriteTest.java | 33 ++- .../persistence/StatePersistenceTest.java | 3 +- 9 files changed, 299 insertions(+), 216 deletions(-) create mode 100644 airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/StandardSyncPersistence.java diff --git a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigRepository.java b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigRepository.java index 24f2090cf866..e800f0779304 100644 --- a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigRepository.java +++ b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigRepository.java @@ -92,16 +92,22 @@ public class ConfigRepository { private final ConfigPersistence persistence; private final ExceptionWrappingDatabase database; private final ActorDefinitionMigrator actorDefinitionMigrator; + private final StandardSyncPersistence standardSyncPersistence; public ConfigRepository(final Database database) { - this(DatabaseConfigPersistence.createWithValidation(database), database, new ActorDefinitionMigrator(new ExceptionWrappingDatabase(database))); + this(DatabaseConfigPersistence.createWithValidation(database), database, new ActorDefinitionMigrator(new ExceptionWrappingDatabase(database)), + new StandardSyncPersistence(database)); } @VisibleForTesting - ConfigRepository(final ConfigPersistence persistence, final Database database, final ActorDefinitionMigrator actorDefinitionMigrator) { + ConfigRepository(final ConfigPersistence persistence, + final Database database, + final ActorDefinitionMigrator actorDefinitionMigrator, + final StandardSyncPersistence standardSyncPersistence) { this.persistence = persistence; this.database = new ExceptionWrappingDatabase(database); this.actorDefinitionMigrator = actorDefinitionMigrator; + this.standardSyncPersistence = standardSyncPersistence; } /** @@ -408,11 +414,7 @@ public void deleteStandardDestinationDefinition(final UUID destDefId) throws IOE } public void deleteStandardSyncDefinition(final UUID syncDefId) throws IOException { - try { - persistence.deleteConfig(ConfigSchema.STANDARD_SYNC, syncDefId.toString()); - } catch (final ConfigNotFoundException e) { - LOGGER.info("Attempted to delete destination definition with id: {}, but it does not exist", syncDefId); - } + standardSyncPersistence.deleteStandardSync(syncDefId); } public void deleteDestinationDefinitionAndAssociations(final UUID destinationDefinitionId) @@ -439,7 +441,7 @@ private void deleteConnectorDefinitionAndAssociations( .filter(connector -> connectorDefinitionIdGetter.apply(connector).equals(definitionId)) .collect(Collectors.toSet()); for (final T connector : connectors) { - final Set syncs = persistence.listConfigs(ConfigSchema.STANDARD_SYNC, StandardSync.class) + final Set syncs = standardSyncPersistence.listStandardSync() .stream() .filter(sync -> sync.getSourceId().equals(connectorIdGetter.apply(connector)) || sync.getDestinationId().equals(connectorIdGetter.apply(connector))) @@ -719,15 +721,15 @@ public List listDestinationsForDefinition(final UUID defi } public StandardSync getStandardSync(final UUID connectionId) throws JsonValidationException, IOException, ConfigNotFoundException { - return persistence.getConfig(ConfigSchema.STANDARD_SYNC, connectionId.toString(), StandardSync.class); + return standardSyncPersistence.getStandardSync(connectionId); } public void writeStandardSync(final StandardSync standardSync) throws JsonValidationException, IOException { - persistence.writeConfig(ConfigSchema.STANDARD_SYNC, standardSync.getConnectionId().toString(), standardSync); + standardSyncPersistence.writeStandardSync(standardSync); } public List listStandardSyncs() throws IOException, JsonValidationException { - return persistence.listConfigs(ConfigSchema.STANDARD_SYNC, StandardSync.class); + return standardSyncPersistence.listStandardSync(); } public List listStandardSyncsUsingOperation(final UUID operationId) diff --git a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/DatabaseConfigPersistence.java b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/DatabaseConfigPersistence.java index 2f843bc4988d..0ff7a831dd4d 100644 --- a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/DatabaseConfigPersistence.java +++ b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/DatabaseConfigPersistence.java @@ -9,8 +9,6 @@ import static io.airbyte.db.instance.configs.jooq.generated.Tables.ACTOR_CATALOG_FETCH_EVENT; import static io.airbyte.db.instance.configs.jooq.generated.Tables.ACTOR_DEFINITION; import static io.airbyte.db.instance.configs.jooq.generated.Tables.ACTOR_OAUTH_PARAMETER; -import static io.airbyte.db.instance.configs.jooq.generated.Tables.CONNECTION; -import static io.airbyte.db.instance.configs.jooq.generated.Tables.CONNECTION_OPERATION; import static io.airbyte.db.instance.configs.jooq.generated.Tables.OPERATION; import static io.airbyte.db.instance.configs.jooq.generated.Tables.STATE; import static io.airbyte.db.instance.configs.jooq.generated.Tables.WORKSPACE; @@ -42,14 +40,12 @@ import io.airbyte.config.StandardDestinationDefinition; import io.airbyte.config.StandardSourceDefinition; import io.airbyte.config.StandardSourceDefinition.SourceType; -import io.airbyte.config.StandardSync; import io.airbyte.config.StandardSyncOperation; import io.airbyte.config.StandardSyncOperation.OperatorType; import io.airbyte.config.StandardSyncState; import io.airbyte.config.StandardWorkspace; import io.airbyte.config.State; import io.airbyte.config.WorkspaceServiceAccount; -import io.airbyte.config.helpers.ScheduleHelpers; import io.airbyte.db.Database; import io.airbyte.db.ExceptionWrappingDatabase; import io.airbyte.db.instance.configs.jooq.generated.enums.ActorType; @@ -68,6 +64,7 @@ import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.lang3.NotImplementedException; import org.jooq.DSLContext; import org.jooq.JSONB; import org.jooq.Record; @@ -123,7 +120,7 @@ public T getConfig(final AirbyteConfig configType, final String configId, fi } else if (configType == ConfigSchema.STANDARD_SYNC_OPERATION) { return (T) getStandardSyncOperation(configId); } else if (configType == ConfigSchema.STANDARD_SYNC) { - return (T) getStandardSync(configId); + throw buildUseStandardSyncPersistenceException(); } else if (configType == ConfigSchema.STANDARD_SYNC_STATE) { return (T) getStandardSyncState(configId); } else if (configType == ConfigSchema.ACTOR_CATALOG) { @@ -137,6 +134,10 @@ public T getConfig(final AirbyteConfig configType, final String configId, fi } } + private NotImplementedException buildUseStandardSyncPersistenceException() { + return new NotImplementedException("Use StandardSyncPersistence instead"); + } + private StandardWorkspace getStandardWorkspace(final String configId) throws IOException, ConfigNotFoundException { final List> result = listStandardWorkspaceWithMetadata(Optional.of(UUID.fromString(configId))); validate(configId, result, ConfigSchema.STANDARD_WORKSPACE); @@ -193,12 +194,6 @@ private StandardSyncOperation getStandardSyncOperation(final String configId) th return result.get(0).getConfig(); } - private StandardSync getStandardSync(final String configId) throws IOException, ConfigNotFoundException { - final List> result = listStandardSyncWithMetadata(Optional.of(UUID.fromString(configId))); - validate(configId, result, ConfigSchema.STANDARD_SYNC); - return result.get(0).getConfig(); - } - private StandardSyncState getStandardSyncState(final String configId) throws IOException, ConfigNotFoundException { final List> result = listStandardSyncStateWithMetadata(Optional.of(UUID.fromString(configId))); validate(configId, result, ConfigSchema.STANDARD_SYNC_STATE); @@ -217,20 +212,6 @@ private ActorCatalogFetchEvent getActorCatalogFetchEvent(final String configId) return result.get(0).getConfig(); } - private List connectionOperationIds(final UUID connectionId) throws IOException { - final Result result = database.query(ctx -> ctx.select(asterisk()) - .from(CONNECTION_OPERATION) - .where(CONNECTION_OPERATION.CONNECTION_ID.eq(connectionId)) - .fetch()); - - final List ids = new ArrayList<>(); - for (final Record record : result) { - ids.add(record.get(CONNECTION_OPERATION.OPERATION_ID)); - } - - return ids; - } - private void validate(final String configId, final List> result, final AirbyteConfig airbyteConfig) throws ConfigNotFoundException { if (result.isEmpty()) { @@ -269,7 +250,7 @@ public List> listConfigsWithMetadata(final AirbyteConf } else if (configType == ConfigSchema.STANDARD_SYNC_OPERATION) { listStandardSyncOperationWithMetadata().forEach(c -> configWithMetadata.add((ConfigWithMetadata) c)); } else if (configType == ConfigSchema.STANDARD_SYNC) { - listStandardSyncWithMetadata().forEach(c -> configWithMetadata.add((ConfigWithMetadata) c)); + throw buildUseStandardSyncPersistenceException(); } else if (configType == ConfigSchema.STANDARD_SYNC_STATE) { listStandardSyncStateWithMetadata().forEach(c -> configWithMetadata.add((ConfigWithMetadata) c)); } else if (configType == ConfigSchema.ACTOR_CATALOG) { @@ -538,35 +519,6 @@ private StandardSyncOperation buildStandardSyncOperation(final Record record) { .withTombstone(record.get(OPERATION.TOMBSTONE)); } - private List> listStandardSyncWithMetadata() throws IOException { - return listStandardSyncWithMetadata(Optional.empty()); - } - - private List> listStandardSyncWithMetadata(final Optional configId) throws IOException { - final Result result = database.query(ctx -> { - final SelectJoinStep query = ctx.select(asterisk()).from(CONNECTION); - if (configId.isPresent()) { - return query.where(CONNECTION.ID.eq(configId.get())).fetch(); - } - return query.fetch(); - }); - - final List> standardSyncs = new ArrayList<>(); - for (final Record record : result) { - final StandardSync standardSync = DbConverter.buildStandardSync(record, connectionOperationIds(record.get(CONNECTION.ID))); - if (ScheduleHelpers.isScheduleTypeMismatch(standardSync)) { - throw new RuntimeException("unexpected schedule type mismatch"); - } - standardSyncs.add(new ConfigWithMetadata<>( - record.get(CONNECTION.ID).toString(), - ConfigSchema.STANDARD_SYNC.name(), - record.get(CONNECTION.CREATED_AT).toInstant(), - record.get(CONNECTION.UPDATED_AT).toInstant(), - standardSync)); - } - return standardSyncs; - } - private List> listStandardSyncStateWithMetadata() throws IOException { return listStandardSyncStateWithMetadata(Optional.empty()); } @@ -676,7 +628,7 @@ public void writeConfig(final AirbyteConfig configType, final String configI } else if (configType == ConfigSchema.STANDARD_SYNC_OPERATION) { writeStandardSyncOperation(Collections.singletonList((StandardSyncOperation) config)); } else if (configType == ConfigSchema.STANDARD_SYNC) { - writeStandardSync(Collections.singletonList((StandardSync) config)); + throw buildUseStandardSyncPersistenceException(); } else if (configType == ConfigSchema.STANDARD_SYNC_STATE) { writeStandardSyncState(Collections.singletonList((StandardSyncState) config)); } else if (configType == ConfigSchema.ACTOR_CATALOG) { @@ -1018,112 +970,6 @@ private void writeStandardSyncOperation(final List config }); } - private void writeStandardSync(final List configs) throws IOException { - database.transaction(ctx -> { - writeStandardSync(configs, ctx); - return null; - }); - } - - private void writeStandardSync(final List configs, final DSLContext ctx) { - final OffsetDateTime timestamp = OffsetDateTime.now(); - configs.forEach((standardSync) -> { - final boolean isExistingConfig = ctx.fetchExists(select() - .from(CONNECTION) - .where(CONNECTION.ID.eq(standardSync.getConnectionId()))); - - if (ScheduleHelpers.isScheduleTypeMismatch(standardSync)) { - throw new RuntimeException("unexpected schedule type mismatch"); - } - - if (isExistingConfig) { - ctx.update(CONNECTION) - .set(CONNECTION.ID, standardSync.getConnectionId()) - .set(CONNECTION.NAMESPACE_DEFINITION, Enums.toEnum(standardSync.getNamespaceDefinition().value(), - io.airbyte.db.instance.configs.jooq.generated.enums.NamespaceDefinitionType.class).orElseThrow()) - .set(CONNECTION.NAMESPACE_FORMAT, standardSync.getNamespaceFormat()) - .set(CONNECTION.PREFIX, standardSync.getPrefix()) - .set(CONNECTION.SOURCE_ID, standardSync.getSourceId()) - .set(CONNECTION.DESTINATION_ID, standardSync.getDestinationId()) - .set(CONNECTION.NAME, standardSync.getName()) - .set(CONNECTION.CATALOG, JSONB.valueOf(Jsons.serialize(standardSync.getCatalog()))) - .set(CONNECTION.STATUS, standardSync.getStatus() == null ? null - : Enums.toEnum(standardSync.getStatus().value(), - io.airbyte.db.instance.configs.jooq.generated.enums.StatusType.class).orElseThrow()) - .set(CONNECTION.SCHEDULE, JSONB.valueOf(Jsons.serialize(standardSync.getSchedule()))) - .set(CONNECTION.MANUAL, standardSync.getManual()) - .set(CONNECTION.SCHEDULE_TYPE, - standardSync.getScheduleType() == null ? null - : Enums.toEnum(standardSync.getScheduleType().value(), - io.airbyte.db.instance.configs.jooq.generated.enums.ScheduleType.class) - .orElseThrow()) - .set(CONNECTION.SCHEDULE_DATA, JSONB.valueOf(Jsons.serialize(standardSync.getScheduleData()))) - .set(CONNECTION.RESOURCE_REQUIREMENTS, - JSONB.valueOf(Jsons.serialize(standardSync.getResourceRequirements()))) - .set(CONNECTION.UPDATED_AT, timestamp) - .set(CONNECTION.SOURCE_CATALOG_ID, standardSync.getSourceCatalogId()) - .set(CONNECTION.BREAKING_CHANGE, standardSync.getBreakingChange()) - .set(CONNECTION.GEOGRAPHY, Enums.toEnum(standardSync.getGeography().value(), - io.airbyte.db.instance.configs.jooq.generated.enums.GeographyType.class).orElseThrow()) - .where(CONNECTION.ID.eq(standardSync.getConnectionId())) - .execute(); - - ctx.deleteFrom(CONNECTION_OPERATION) - .where(CONNECTION_OPERATION.CONNECTION_ID.eq(standardSync.getConnectionId())) - .execute(); - for (final UUID operationIdFromStandardSync : standardSync.getOperationIds()) { - ctx.insertInto(CONNECTION_OPERATION) - .set(CONNECTION_OPERATION.ID, UUID.randomUUID()) - .set(CONNECTION_OPERATION.CONNECTION_ID, standardSync.getConnectionId()) - .set(CONNECTION_OPERATION.OPERATION_ID, operationIdFromStandardSync) - .set(CONNECTION_OPERATION.CREATED_AT, timestamp) - .set(CONNECTION_OPERATION.UPDATED_AT, timestamp) - .execute(); - } - } else { - ctx.insertInto(CONNECTION) - .set(CONNECTION.ID, standardSync.getConnectionId()) - .set(CONNECTION.NAMESPACE_DEFINITION, Enums.toEnum(standardSync.getNamespaceDefinition().value(), - io.airbyte.db.instance.configs.jooq.generated.enums.NamespaceDefinitionType.class).orElseThrow()) - .set(CONNECTION.NAMESPACE_FORMAT, standardSync.getNamespaceFormat()) - .set(CONNECTION.PREFIX, standardSync.getPrefix()) - .set(CONNECTION.SOURCE_ID, standardSync.getSourceId()) - .set(CONNECTION.DESTINATION_ID, standardSync.getDestinationId()) - .set(CONNECTION.NAME, standardSync.getName()) - .set(CONNECTION.CATALOG, JSONB.valueOf(Jsons.serialize(standardSync.getCatalog()))) - .set(CONNECTION.STATUS, standardSync.getStatus() == null ? null - : Enums.toEnum(standardSync.getStatus().value(), - io.airbyte.db.instance.configs.jooq.generated.enums.StatusType.class).orElseThrow()) - .set(CONNECTION.SCHEDULE, JSONB.valueOf(Jsons.serialize(standardSync.getSchedule()))) - .set(CONNECTION.MANUAL, standardSync.getManual()) - .set(CONNECTION.SCHEDULE_TYPE, - standardSync.getScheduleType() == null ? null - : Enums.toEnum(standardSync.getScheduleType().value(), - io.airbyte.db.instance.configs.jooq.generated.enums.ScheduleType.class) - .orElseThrow()) - .set(CONNECTION.SCHEDULE_DATA, JSONB.valueOf(Jsons.serialize(standardSync.getScheduleData()))) - .set(CONNECTION.RESOURCE_REQUIREMENTS, - JSONB.valueOf(Jsons.serialize(standardSync.getResourceRequirements()))) - .set(CONNECTION.SOURCE_CATALOG_ID, standardSync.getSourceCatalogId()) - .set(CONNECTION.GEOGRAPHY, Enums.toEnum(standardSync.getGeography().value(), - io.airbyte.db.instance.configs.jooq.generated.enums.GeographyType.class).orElseThrow()) - .set(CONNECTION.BREAKING_CHANGE, standardSync.getBreakingChange()) - .set(CONNECTION.CREATED_AT, timestamp) - .set(CONNECTION.UPDATED_AT, timestamp) - .execute(); - for (final UUID operationIdFromStandardSync : standardSync.getOperationIds()) { - ctx.insertInto(CONNECTION_OPERATION) - .set(CONNECTION_OPERATION.ID, UUID.randomUUID()) - .set(CONNECTION_OPERATION.CONNECTION_ID, standardSync.getConnectionId()) - .set(CONNECTION_OPERATION.OPERATION_ID, operationIdFromStandardSync) - .set(CONNECTION_OPERATION.CREATED_AT, timestamp) - .set(CONNECTION_OPERATION.UPDATED_AT, timestamp) - .execute(); - } - } - }); - } - private void writeStandardSyncState(final List configs) throws IOException { database.transaction(ctx -> { writeStandardSyncState(configs, ctx); @@ -1246,7 +1092,7 @@ public void writeConfigs(final AirbyteConfig configType, final Map (StandardSyncOperation) c).collect(Collectors.toList())); } else if (configType == ConfigSchema.STANDARD_SYNC) { - writeStandardSync(configs.values().stream().map(c -> (StandardSync) c).collect(Collectors.toList())); + throw buildUseStandardSyncPersistenceException(); } else if (configType == ConfigSchema.STANDARD_SYNC_STATE) { writeStandardSyncState(configs.values().stream().map(c -> (StandardSyncState) c).collect(Collectors.toList())); } else if (configType == ConfigSchema.ACTOR_CATALOG) { @@ -1279,7 +1125,7 @@ public void deleteConfig(final AirbyteConfig configType, final String configId) } else if (configType == ConfigSchema.STANDARD_SYNC_OPERATION) { deleteConfig(OPERATION, OPERATION.ID, UUID.fromString(configId)); } else if (configType == ConfigSchema.STANDARD_SYNC) { - deleteStandardSync(configId); + throw buildUseStandardSyncPersistenceException(); } else if (configType == ConfigSchema.STANDARD_SYNC_STATE) { deleteConfig(STATE, STATE.CONNECTION_ID, UUID.fromString(configId)); } else if (configType == ConfigSchema.ACTOR_CATALOG) { @@ -1296,32 +1142,7 @@ public void deleteConfig(final AirbyteConfig configType, final String configId) private void deleteConfig(final TableImpl table, final TableField keyColumn, final UUID configId) throws IOException { database.transaction(ctx -> { - deleteConfig(table, keyColumn, configId, ctx); - return null; - }); - } - - private void deleteConfig(final TableImpl table, - final TableField keyColumn, - final UUID configId, - final DSLContext ctx) { - final boolean isExistingConfig = ctx.fetchExists(select() - .from(table) - .where(keyColumn.eq(configId))); - - if (isExistingConfig) { - ctx.deleteFrom(table) - .where(keyColumn.eq(configId)) - .execute(); - } - } - - private void deleteStandardSync(final String configId) throws IOException { - database.transaction(ctx -> { - final UUID connectionId = UUID.fromString(configId); - deleteConfig(CONNECTION_OPERATION, CONNECTION_OPERATION.CONNECTION_ID, connectionId, ctx); - deleteConfig(STATE, STATE.CONNECTION_ID, connectionId, ctx); - deleteConfig(CONNECTION, CONNECTION.ID, connectionId, ctx); + PersistenceHelpers.deleteConfig(table, keyColumn, configId, ctx); return null; }); } diff --git a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/PersistenceHelpers.java b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/PersistenceHelpers.java index 63c00250fc43..5847a9784914 100644 --- a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/PersistenceHelpers.java +++ b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/PersistenceHelpers.java @@ -4,8 +4,15 @@ package io.airbyte.config.persistence; +import static org.jooq.impl.DSL.select; + +import java.util.UUID; import org.jooq.Condition; +import org.jooq.DSLContext; import org.jooq.Field; +import org.jooq.Record; +import org.jooq.TableField; +import org.jooq.impl.TableImpl; public class PersistenceHelpers { @@ -22,4 +29,27 @@ public static Condition isNullOrEquals(final Field field, final String v return value != null ? field.eq(value) : field.isNull(); } + /** + * Helper to delete records from the database + * + * @param table the table to delete from + * @param keyColumn the column to use as a key + * @param configId the id of the object to delete, must be from the keyColumn + * @param ctx the db context to use + */ + public static void deleteConfig(final TableImpl table, + final TableField keyColumn, + final UUID configId, + final DSLContext ctx) { + final boolean isExistingConfig = ctx.fetchExists(select() + .from(table) + .where(keyColumn.eq(configId))); + + if (isExistingConfig) { + ctx.deleteFrom(table) + .where(keyColumn.eq(configId)) + .execute(); + } + } + } diff --git a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/StandardSyncPersistence.java b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/StandardSyncPersistence.java new file mode 100644 index 000000000000..4e39ead28753 --- /dev/null +++ b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/StandardSyncPersistence.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.config.persistence; + +import static io.airbyte.db.instance.configs.jooq.generated.Tables.CONNECTION; +import static io.airbyte.db.instance.configs.jooq.generated.Tables.CONNECTION_OPERATION; +import static io.airbyte.db.instance.configs.jooq.generated.Tables.STATE; +import static org.jooq.impl.DSL.asterisk; +import static org.jooq.impl.DSL.select; + +import io.airbyte.commons.enums.Enums; +import io.airbyte.commons.json.Jsons; +import io.airbyte.config.ConfigSchema; +import io.airbyte.config.ConfigWithMetadata; +import io.airbyte.config.StandardSync; +import io.airbyte.config.helpers.ScheduleHelpers; +import io.airbyte.db.Database; +import io.airbyte.db.ExceptionWrappingDatabase; +import java.io.IOException; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.jooq.DSLContext; +import org.jooq.JSONB; +import org.jooq.Record; +import org.jooq.Result; +import org.jooq.SelectJoinStep; + +public class StandardSyncPersistence { + + private final ExceptionWrappingDatabase database; + + public StandardSyncPersistence(final Database database) { + this.database = new ExceptionWrappingDatabase(database); + } + + public StandardSync getStandardSync(final UUID connectionId) throws IOException, ConfigNotFoundException { + final List> result = listStandardSyncWithMetadata(Optional.of(connectionId)); + + final boolean foundMoreThanOneConfig = result.size() > 1; + if (result.isEmpty()) { + throw new ConfigNotFoundException(ConfigSchema.STANDARD_SYNC, connectionId.toString()); + } else if (foundMoreThanOneConfig) { + throw new IllegalStateException(String.format("Multiple %s configs found for ID %s: %s", ConfigSchema.STANDARD_SYNC, connectionId, result)); + } + return result.get(0).getConfig(); + } + + public List listStandardSync() throws IOException { + return listStandardSyncWithMetadata(Optional.empty()).stream().map(ConfigWithMetadata::getConfig).toList(); + } + + public void writeStandardSync(final StandardSync standardSync) throws IOException { + database.transaction(ctx -> { + writeStandardSync(standardSync, ctx); + return null; + }); + } + + public void deleteStandardSync(final UUID standardSyncId) throws IOException { + database.transaction(ctx -> { + PersistenceHelpers.deleteConfig(CONNECTION_OPERATION, CONNECTION_OPERATION.CONNECTION_ID, standardSyncId, ctx); + PersistenceHelpers.deleteConfig(STATE, STATE.CONNECTION_ID, standardSyncId, ctx); + PersistenceHelpers.deleteConfig(CONNECTION, CONNECTION.ID, standardSyncId, ctx); + return null; + }); + } + + private List> listStandardSyncWithMetadata(final Optional configId) throws IOException { + final Result result = database.query(ctx -> { + final SelectJoinStep query = ctx.select(asterisk()).from(CONNECTION); + if (configId.isPresent()) { + return query.where(CONNECTION.ID.eq(configId.get())).fetch(); + } + return query.fetch(); + }); + + final List> standardSyncs = new ArrayList<>(); + for (final Record record : result) { + final StandardSync standardSync = DbConverter.buildStandardSync(record, connectionOperationIds(record.get(CONNECTION.ID))); + if (ScheduleHelpers.isScheduleTypeMismatch(standardSync)) { + throw new RuntimeException("unexpected schedule type mismatch"); + } + standardSyncs.add(new ConfigWithMetadata<>( + record.get(CONNECTION.ID).toString(), + ConfigSchema.STANDARD_SYNC.name(), + record.get(CONNECTION.CREATED_AT).toInstant(), + record.get(CONNECTION.UPDATED_AT).toInstant(), + standardSync)); + } + return standardSyncs; + } + + private List connectionOperationIds(final UUID connectionId) throws IOException { + final Result result = database.query(ctx -> ctx.select(asterisk()) + .from(CONNECTION_OPERATION) + .where(CONNECTION_OPERATION.CONNECTION_ID.eq(connectionId)) + .fetch()); + + final List ids = new ArrayList<>(); + for (final Record record : result) { + ids.add(record.get(CONNECTION_OPERATION.OPERATION_ID)); + } + + return ids; + } + + private void writeStandardSync(final StandardSync standardSync, final DSLContext ctx) { + final OffsetDateTime timestamp = OffsetDateTime.now(); + final boolean isExistingConfig = ctx.fetchExists(select() + .from(CONNECTION) + .where(CONNECTION.ID.eq(standardSync.getConnectionId()))); + + if (ScheduleHelpers.isScheduleTypeMismatch(standardSync)) { + throw new RuntimeException("unexpected schedule type mismatch"); + } + + if (isExistingConfig) { + ctx.update(CONNECTION) + .set(CONNECTION.ID, standardSync.getConnectionId()) + .set(CONNECTION.NAMESPACE_DEFINITION, Enums.toEnum(standardSync.getNamespaceDefinition().value(), + io.airbyte.db.instance.configs.jooq.generated.enums.NamespaceDefinitionType.class).orElseThrow()) + .set(CONNECTION.NAMESPACE_FORMAT, standardSync.getNamespaceFormat()) + .set(CONNECTION.PREFIX, standardSync.getPrefix()) + .set(CONNECTION.SOURCE_ID, standardSync.getSourceId()) + .set(CONNECTION.DESTINATION_ID, standardSync.getDestinationId()) + .set(CONNECTION.NAME, standardSync.getName()) + .set(CONNECTION.CATALOG, JSONB.valueOf(Jsons.serialize(standardSync.getCatalog()))) + .set(CONNECTION.STATUS, standardSync.getStatus() == null ? null + : Enums.toEnum(standardSync.getStatus().value(), + io.airbyte.db.instance.configs.jooq.generated.enums.StatusType.class).orElseThrow()) + .set(CONNECTION.SCHEDULE, JSONB.valueOf(Jsons.serialize(standardSync.getSchedule()))) + .set(CONNECTION.MANUAL, standardSync.getManual()) + .set(CONNECTION.SCHEDULE_TYPE, + standardSync.getScheduleType() == null ? null + : Enums.toEnum(standardSync.getScheduleType().value(), + io.airbyte.db.instance.configs.jooq.generated.enums.ScheduleType.class) + .orElseThrow()) + .set(CONNECTION.SCHEDULE_DATA, JSONB.valueOf(Jsons.serialize(standardSync.getScheduleData()))) + .set(CONNECTION.RESOURCE_REQUIREMENTS, + JSONB.valueOf(Jsons.serialize(standardSync.getResourceRequirements()))) + .set(CONNECTION.UPDATED_AT, timestamp) + .set(CONNECTION.SOURCE_CATALOG_ID, standardSync.getSourceCatalogId()) + .set(CONNECTION.BREAKING_CHANGE, standardSync.getBreakingChange()) + .set(CONNECTION.GEOGRAPHY, Enums.toEnum(standardSync.getGeography().value(), + io.airbyte.db.instance.configs.jooq.generated.enums.GeographyType.class).orElseThrow()) + .where(CONNECTION.ID.eq(standardSync.getConnectionId())) + .execute(); + + ctx.deleteFrom(CONNECTION_OPERATION) + .where(CONNECTION_OPERATION.CONNECTION_ID.eq(standardSync.getConnectionId())) + .execute(); + for (final UUID operationIdFromStandardSync : standardSync.getOperationIds()) { + ctx.insertInto(CONNECTION_OPERATION) + .set(CONNECTION_OPERATION.ID, UUID.randomUUID()) + .set(CONNECTION_OPERATION.CONNECTION_ID, standardSync.getConnectionId()) + .set(CONNECTION_OPERATION.OPERATION_ID, operationIdFromStandardSync) + .set(CONNECTION_OPERATION.CREATED_AT, timestamp) + .set(CONNECTION_OPERATION.UPDATED_AT, timestamp) + .execute(); + } + } else { + ctx.insertInto(CONNECTION) + .set(CONNECTION.ID, standardSync.getConnectionId()) + .set(CONNECTION.NAMESPACE_DEFINITION, Enums.toEnum(standardSync.getNamespaceDefinition().value(), + io.airbyte.db.instance.configs.jooq.generated.enums.NamespaceDefinitionType.class).orElseThrow()) + .set(CONNECTION.NAMESPACE_FORMAT, standardSync.getNamespaceFormat()) + .set(CONNECTION.PREFIX, standardSync.getPrefix()) + .set(CONNECTION.SOURCE_ID, standardSync.getSourceId()) + .set(CONNECTION.DESTINATION_ID, standardSync.getDestinationId()) + .set(CONNECTION.NAME, standardSync.getName()) + .set(CONNECTION.CATALOG, JSONB.valueOf(Jsons.serialize(standardSync.getCatalog()))) + .set(CONNECTION.STATUS, standardSync.getStatus() == null ? null + : Enums.toEnum(standardSync.getStatus().value(), + io.airbyte.db.instance.configs.jooq.generated.enums.StatusType.class).orElseThrow()) + .set(CONNECTION.SCHEDULE, JSONB.valueOf(Jsons.serialize(standardSync.getSchedule()))) + .set(CONNECTION.MANUAL, standardSync.getManual()) + .set(CONNECTION.SCHEDULE_TYPE, + standardSync.getScheduleType() == null ? null + : Enums.toEnum(standardSync.getScheduleType().value(), + io.airbyte.db.instance.configs.jooq.generated.enums.ScheduleType.class) + .orElseThrow()) + .set(CONNECTION.SCHEDULE_DATA, JSONB.valueOf(Jsons.serialize(standardSync.getScheduleData()))) + .set(CONNECTION.RESOURCE_REQUIREMENTS, + JSONB.valueOf(Jsons.serialize(standardSync.getResourceRequirements()))) + .set(CONNECTION.SOURCE_CATALOG_ID, standardSync.getSourceCatalogId()) + .set(CONNECTION.GEOGRAPHY, Enums.toEnum(standardSync.getGeography().value(), + io.airbyte.db.instance.configs.jooq.generated.enums.GeographyType.class).orElseThrow()) + .set(CONNECTION.BREAKING_CHANGE, standardSync.getBreakingChange()) + .set(CONNECTION.CREATED_AT, timestamp) + .set(CONNECTION.UPDATED_AT, timestamp) + .execute(); + for (final UUID operationIdFromStandardSync : standardSync.getOperationIds()) { + ctx.insertInto(CONNECTION_OPERATION) + .set(CONNECTION_OPERATION.ID, UUID.randomUUID()) + .set(CONNECTION_OPERATION.CONNECTION_ID, standardSync.getConnectionId()) + .set(CONNECTION_OPERATION.OPERATION_ID, operationIdFromStandardSync) + .set(CONNECTION_OPERATION.CREATED_AT, timestamp) + .set(CONNECTION_OPERATION.UPDATED_AT, timestamp) + .execute(); + } + } + } + +} diff --git a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/BaseDatabaseConfigPersistenceTest.java b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/BaseDatabaseConfigPersistenceTest.java index 9ebba66d0af2..da381448620e 100644 --- a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/BaseDatabaseConfigPersistenceTest.java +++ b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/BaseDatabaseConfigPersistenceTest.java @@ -49,6 +49,7 @@ class BaseDatabaseConfigPersistenceTest { static PostgreSQLContainer container; static Database database; static DatabaseConfigPersistence configPersistence; + static StandardSyncPersistence standardSyncPersistence; static JsonSecretsProcessor jsonSecretsProcessor; static DataSource dataSource; static DSLContext dslContext; diff --git a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryE2EReadWriteTest.java b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryE2EReadWriteTest.java index c33dbb21ba3b..88fe070a2078 100644 --- a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryE2EReadWriteTest.java +++ b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryE2EReadWriteTest.java @@ -98,7 +98,8 @@ void setup() throws IOException, JsonValidationException, SQLException, Database ConfigsDatabaseMigrator.MIGRATION_FILE_LOCATION); database = new ConfigsDatabaseTestProvider(dslContext, flyway).create(false); configPersistence = spy(new DatabaseConfigPersistence(database)); - configRepository = spy(new ConfigRepository(configPersistence, database, new ActorDefinitionMigrator(new ExceptionWrappingDatabase(database)))); + configRepository = spy(new ConfigRepository(configPersistence, database, new ActorDefinitionMigrator(new ExceptionWrappingDatabase(database)), + new StandardSyncPersistence(database))); final ConfigsDatabaseMigrator configsDatabaseMigrator = new ConfigsDatabaseMigrator(database, flyway); final DevDatabaseMigrator devDatabaseMigrator = new DevDatabaseMigrator(configsDatabaseMigrator); diff --git a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryTest.java b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryTest.java index 1893b7a193e3..6f1d503f2d68 100644 --- a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryTest.java +++ b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ConfigRepositoryTest.java @@ -56,14 +56,17 @@ class ConfigRepositoryTest { private static final UUID DESTINATION_DEFINITION_ID = UUID.randomUUID(); private ConfigPersistence configPersistence; + private StandardSyncPersistence standardSyncPersistence; private ConfigRepository configRepository; private Database database; @BeforeEach void setup() { configPersistence = mock(ConfigPersistence.class); + standardSyncPersistence = mock(StandardSyncPersistence.class); database = mock(Database.class); - configRepository = spy(new ConfigRepository(configPersistence, database, new ActorDefinitionMigrator(new ExceptionWrappingDatabase(database)))); + configRepository = spy(new ConfigRepository(configPersistence, database, new ActorDefinitionMigrator(new ExceptionWrappingDatabase(database)), + standardSyncPersistence)); } @AfterEach @@ -287,7 +290,7 @@ void testDeleteSourceDefinitionAndAssociations() throws JsonValidationException, final StandardSync syncToStay = new StandardSync().withConnectionId(UUID.randomUUID()).withSourceId(sourceConnectionToStay.getSourceId()) .withDestinationId(UUID.randomUUID()); - when(configPersistence.listConfigs(ConfigSchema.STANDARD_SYNC, StandardSync.class)).thenReturn(List.of(syncToDelete, syncToStay)); + when(standardSyncPersistence.listStandardSync()).thenReturn(List.of(syncToDelete, syncToStay)); configRepository.deleteSourceDefinitionAndAssociations(sourceDefToDelete.getSourceDefinitionId()); @@ -421,7 +424,7 @@ void testDeleteDestinationDefinitionAndAssociations() throws JsonValidationExcep final StandardSync syncToStay = new StandardSync().withConnectionId(UUID.randomUUID()).withDestinationId(destConnectionToStay.getDestinationId()) .withSourceId(UUID.randomUUID()); - when(configPersistence.listConfigs(ConfigSchema.STANDARD_SYNC, StandardSync.class)).thenReturn(List.of(syncToDelete, syncToStay)); + when(standardSyncPersistence.listStandardSync()).thenReturn(List.of(syncToDelete, syncToStay)); configRepository.deleteDestinationDefinitionAndAssociations(destDefToDelete.getDestinationDefinitionId()); @@ -445,7 +448,7 @@ void testDeleteStandardSync() throws IOException, ConfigNotFoundException { final UUID connectionId = UUID.randomUUID(); configRepository.deleteStandardSyncDefinition(connectionId); - verify(configPersistence).deleteConfig(ConfigSchema.STANDARD_SYNC, connectionId.toString()); + verify(standardSyncPersistence).deleteStandardSync(connectionId); } @Test diff --git a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceE2EReadWriteTest.java b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceE2EReadWriteTest.java index 604859718181..b8d1e383a732 100644 --- a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceE2EReadWriteTest.java +++ b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceE2EReadWriteTest.java @@ -7,6 +7,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.spy; @@ -35,6 +36,8 @@ import io.airbyte.validation.json.JsonValidationException; import java.io.IOException; import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.NotImplementedException; import org.jooq.SQLDialect; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -51,6 +54,7 @@ void setup() throws Exception { ConfigsDatabaseMigrator.MIGRATION_FILE_LOCATION); database = new ConfigsDatabaseTestProvider(dslContext, flyway).create(false); configPersistence = spy(new DatabaseConfigPersistence(database)); + standardSyncPersistence = new StandardSyncPersistence(database); final ConfigsDatabaseMigrator configsDatabaseMigrator = new ConfigsDatabaseMigrator(database, flyway); final DevDatabaseMigrator devDatabaseMigrator = new DevDatabaseMigrator(configsDatabaseMigrator); @@ -79,6 +83,22 @@ void test() throws JsonValidationException, IOException, ConfigNotFoundException standardActorCatalog(); workspaceServiceAccounts(); deletion(); + + checkSafeguards(); + } + + private void checkSafeguards() { + final String anyString = ""; + + // Making sure that the objects that have been migrated out of config persistence are protected with + // an explicit error. + assertThrows(NotImplementedException.class, () -> configPersistence.getConfig(ConfigSchema.STANDARD_SYNC, anyString, StandardSync.class)); + assertThrows(NotImplementedException.class, () -> configPersistence.listConfigs(ConfigSchema.STANDARD_SYNC, StandardSync.class)); + assertThrows(NotImplementedException.class, + () -> configPersistence.writeConfig(ConfigSchema.STANDARD_SYNC, anyString, MockData.standardSyncs().get(0))); + assertThrows(NotImplementedException.class, + () -> configPersistence.writeConfigs(ConfigSchema.STANDARD_SYNC, Map.of(anyString, MockData.standardSyncs().get(0)))); + assertThrows(NotImplementedException.class, () -> configPersistence.deleteConfig(ConfigSchema.STANDARD_SYNC, anyString)); } private void deletion() throws ConfigNotFoundException, IOException, JsonValidationException { @@ -87,7 +107,7 @@ private void deletion() throws ConfigNotFoundException, IOException, JsonValidat configPersistence.deleteConfig(ConfigSchema.STANDARD_WORKSPACE, standardWorkspace.getWorkspaceId().toString()); } assertTrue(configPersistence.listConfigs(ConfigSchema.STANDARD_SYNC_STATE, StandardSyncState.class).isEmpty()); - assertTrue(configPersistence.listConfigs(ConfigSchema.STANDARD_SYNC, StandardSync.class).isEmpty()); + assertTrue(standardSyncPersistence.listStandardSync().isEmpty()); assertTrue(configPersistence.listConfigs(ConfigSchema.STANDARD_SYNC_OPERATION, StandardSyncOperation.class).isEmpty()); assertTrue(configPersistence.listConfigs(ConfigSchema.DESTINATION_CONNECTION, SourceConnection.class).isEmpty()); assertTrue(configPersistence.listConfigs(ConfigSchema.STANDARD_WORKSPACE, StandardWorkspace.class).isEmpty()); @@ -146,16 +166,11 @@ private void standardSyncState() throws JsonValidationException, IOException, Co private void standardSync() throws JsonValidationException, IOException, ConfigNotFoundException { for (final StandardSync standardSync : MockData.standardSyncs()) { - configPersistence.writeConfig(ConfigSchema.STANDARD_SYNC, - standardSync.getConnectionId().toString(), - standardSync); - final StandardSync standardSyncFromDB = configPersistence.getConfig(ConfigSchema.STANDARD_SYNC, - standardSync.getConnectionId().toString(), - StandardSync.class); + standardSyncPersistence.writeStandardSync(standardSync); + final StandardSync standardSyncFromDB = standardSyncPersistence.getStandardSync(standardSync.getConnectionId()); assertEquals(standardSync, standardSyncFromDB); } - final List standardSyncs = configPersistence - .listConfigs(ConfigSchema.STANDARD_SYNC, StandardSync.class); + final List standardSyncs = standardSyncPersistence.listStandardSync(); assertEquals(MockData.standardSyncs().size(), standardSyncs.size()); assertThat(MockData.standardSyncs()).hasSameElementsAs(standardSyncs); } diff --git a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/StatePersistenceTest.java b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/StatePersistenceTest.java index a3a888f9530d..4e85864e61cd 100644 --- a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/StatePersistenceTest.java +++ b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/StatePersistenceTest.java @@ -548,7 +548,8 @@ private void setupTestData() throws JsonValidationException, IOException { configRepository = new ConfigRepository( new DatabaseConfigPersistence(database), database, - new ActorDefinitionMigrator(new ExceptionWrappingDatabase(database))); + new ActorDefinitionMigrator(new ExceptionWrappingDatabase(database)), + new StandardSyncPersistence(database)); final StandardWorkspace workspace = MockData.standardWorkspaces().get(0); final StandardSourceDefinition sourceDefinition = MockData.publicSourceDefinition(); From 5b0ed4fd459d096490572117374f113a2cb65cd3 Mon Sep 17 00:00:00 2001 From: Akash Kulkarni <113392464+akashkulk@users.noreply.github.com> Date: Thu, 3 Nov 2022 13:05:56 -0700 Subject: [PATCH 24/73] Code cleanup in abstract classes (#18811) * Refactor attempt 1 Increasing readability: - Performed audit of methods that are marked as public/protected but should be private - Performed audit of methods that are marked as public but should be protected - Removing @Override from methods that don't need them (are the very first) * Remove .sqlite files * Remove AbstractRelationDbSource class - Removing AbstractRelationalDbSource abstract class and moving contents of it to a Util class * Rename utility class * Add overrides back --- .../source/bigquery/BigQuerySource.java | 26 +++++-- .../source/jdbc/AbstractJdbcSource.java | 26 +++++-- .../source/mssql/MssqlSource.java | 12 ++-- .../source/relationaldb/AbstractDbSource.java | 35 +++++----- .../AbstractRelationalDbSource.java | 69 ------------------- .../relationaldb/RelationalDbQueryUtils.java | 44 ++++++++++++ 6 files changed, 111 insertions(+), 101 deletions(-) delete mode 100644 airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractRelationalDbSource.java create mode 100644 airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/RelationalDbQueryUtils.java diff --git a/airbyte-integrations/connectors/source-bigquery/src/main/java/io/airbyte/integrations/source/bigquery/BigQuerySource.java b/airbyte-integrations/connectors/source-bigquery/src/main/java/io/airbyte/integrations/source/bigquery/BigQuerySource.java index f15a35ac7caf..b1a520a39585 100644 --- a/airbyte-integrations/connectors/source-bigquery/src/main/java/io/airbyte/integrations/source/bigquery/BigQuerySource.java +++ b/airbyte-integrations/connectors/source-bigquery/src/main/java/io/airbyte/integrations/source/bigquery/BigQuerySource.java @@ -4,6 +4,10 @@ package io.airbyte.integrations.source.bigquery; +import static io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils.enquoteIdentifierList; +import static io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils.getFullTableName; +import static io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils.queryTable; + import com.fasterxml.jackson.databind.JsonNode; import com.google.cloud.bigquery.QueryParameterValue; import com.google.cloud.bigquery.StandardSQLTypeName; @@ -18,8 +22,9 @@ import io.airbyte.db.bigquery.BigQuerySourceOperations; import io.airbyte.integrations.base.IntegrationRunner; import io.airbyte.integrations.base.Source; -import io.airbyte.integrations.source.relationaldb.AbstractRelationalDbSource; +import io.airbyte.integrations.source.relationaldb.AbstractDbSource; import io.airbyte.integrations.source.relationaldb.CursorInfo; +import io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils; import io.airbyte.integrations.source.relationaldb.TableInfo; import io.airbyte.protocol.models.CommonField; import io.airbyte.protocol.models.JsonSchemaType; @@ -34,7 +39,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BigQuerySource extends AbstractRelationalDbSource implements Source { +public class BigQuerySource extends AbstractDbSource implements Source { private static final Logger LOGGER = LoggerFactory.getLogger(BigQuerySource.class); private static final String QUOTE = "`"; @@ -76,7 +81,7 @@ public List> getCheckOperations(fin checkList.add(database -> { if (isDatasetConfigured(database)) { database.query(String.format("select 1 from %s where 1=0", - getFullTableName(getConfigDatasetId(database), "INFORMATION_SCHEMA.TABLES"))); + getFullTableName(getConfigDatasetId(database), "INFORMATION_SCHEMA.TABLES", getQuoteString()))); LOGGER.info("The source passed the Dataset query test!"); } else { LOGGER.info("The Dataset query test is skipped due to not configured datasetId!"); @@ -140,12 +145,23 @@ public AutoCloseableIterator queryTableIncremental(final BigQueryDatab final CursorInfo cursorInfo, final StandardSQLTypeName cursorFieldType) { return queryTableWithParams(database, String.format("SELECT %s FROM %s WHERE %s > ?", - enquoteIdentifierList(columnNames), - getFullTableName(schemaName, tableName), + RelationalDbQueryUtils.enquoteIdentifierList(columnNames, getQuoteString()), + getFullTableName(schemaName, tableName, getQuoteString()), cursorInfo.getCursorField()), sourceOperations.getQueryParameter(cursorFieldType, cursorInfo.getCursor())); } + @Override + protected AutoCloseableIterator queryTableFullRefresh(final BigQueryDatabase database, + final List columnNames, + final String schemaName, + final String tableName) { + LOGGER.info("Queueing query for table: {}", tableName); + return queryTable(database, String.format("SELECT %s FROM %s", + enquoteIdentifierList(columnNames, getQuoteString()), + getFullTableName(schemaName, tableName, getQuoteString()))); + } + @Override public boolean isCursorType(final StandardSQLTypeName standardSQLTypeName) { return true; diff --git a/airbyte-integrations/connectors/source-jdbc/src/main/java/io/airbyte/integrations/source/jdbc/AbstractJdbcSource.java b/airbyte-integrations/connectors/source-jdbc/src/main/java/io/airbyte/integrations/source/jdbc/AbstractJdbcSource.java index c14662f4d1f2..9ae17ff938be 100644 --- a/airbyte-integrations/connectors/source-jdbc/src/main/java/io/airbyte/integrations/source/jdbc/AbstractJdbcSource.java +++ b/airbyte-integrations/connectors/source-jdbc/src/main/java/io/airbyte/integrations/source/jdbc/AbstractJdbcSource.java @@ -20,6 +20,9 @@ import static io.airbyte.db.jdbc.JdbcConstants.JDBC_COLUMN_TYPE_NAME; import static io.airbyte.db.jdbc.JdbcConstants.JDBC_IS_NULLABLE; import static io.airbyte.db.jdbc.JdbcUtils.EQUALS; +import static io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils.enquoteIdentifierList; +import static io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils.getFullTableName; +import static io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils.queryTable; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableList; @@ -40,7 +43,7 @@ import io.airbyte.integrations.base.AirbyteStreamNameNamespacePair; import io.airbyte.integrations.base.Source; import io.airbyte.integrations.source.jdbc.dto.JdbcPrivilegeDto; -import io.airbyte.integrations.source.relationaldb.AbstractRelationalDbSource; +import io.airbyte.integrations.source.relationaldb.AbstractDbSource; import io.airbyte.integrations.source.relationaldb.CursorInfo; import io.airbyte.integrations.source.relationaldb.TableInfo; import io.airbyte.integrations.source.relationaldb.state.StateManager; @@ -81,7 +84,7 @@ * relational DB source which can be accessed via JDBC driver. If you are implementing a connector * for a relational DB which has a JDBC driver, make an effort to use this class. */ -public abstract class AbstractJdbcSource extends AbstractRelationalDbSource implements Source { +public abstract class AbstractJdbcSource extends AbstractDbSource implements Source { public static final String SSL_MODE = "sslMode"; @@ -136,12 +139,23 @@ public AbstractJdbcSource(final String driverClass, this.sourceOperations = sourceOperations; } + @Override + protected AutoCloseableIterator queryTableFullRefresh(final JdbcDatabase database, + final List columnNames, + final String schemaName, + final String tableName) { + LOGGER.info("Queueing query for table: {}", tableName); + return queryTable(database, String.format("SELECT %s FROM %s", + enquoteIdentifierList(columnNames, getQuoteString()), + getFullTableName(schemaName, tableName, getQuoteString()))); + } + /** * Configures a list of operations that can be used to check the connection to the source. * * @return list of consumers that run queries for the check command. */ - public List> getCheckOperations(final JsonNode config) throws Exception { + protected List> getCheckOperations(final JsonNode config) throws Exception { return ImmutableList.of(database -> { LOGGER.info("Attempting to get metadata from the database to see if we can connect."); database.bufferedResultSetQuery(connection -> connection.getMetaData().getCatalogs(), sourceOperations::rowToJson); @@ -258,7 +272,7 @@ private JsonNode getColumnMetadata(final ResultSet resultSet) throws SQLExceptio * @param field Essential column information returned from * {@link AbstractJdbcSource#getColumnMetadata}. */ - public Datatype getFieldType(final JsonNode field) { + private Datatype getFieldType(final JsonNode field) { return sourceOperations.getFieldType(field); } @@ -515,7 +529,7 @@ public void close() { * @param config configuration * @return map containing relevant parsed values including location of keystore or an empty map */ - public Map parseSSLConfig(final JsonNode config) { + protected Map parseSSLConfig(final JsonNode config) { LOGGER.debug("source config: {}", config); final Map additionalParameters = new HashMap<>(); @@ -572,7 +586,7 @@ public Map parseSSLConfig(final JsonNode config) { * @param sslParams * @return SSL portion of JDBC question params or and empty string */ - public String toJDBCQueryParams(final Map sslParams) { + protected String toJDBCQueryParams(final Map sslParams) { return Objects.isNull(sslParams) ? "" : sslParams.entrySet() .stream() diff --git a/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlSource.java b/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlSource.java index 76bcf8ed7bbd..6b00ac9b0a3d 100644 --- a/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlSource.java +++ b/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlSource.java @@ -7,6 +7,10 @@ import static io.airbyte.integrations.debezium.AirbyteDebeziumHandler.shouldUseCDC; import static io.airbyte.integrations.debezium.internals.DebeziumEventUtils.CDC_DELETED_AT; import static io.airbyte.integrations.debezium.internals.DebeziumEventUtils.CDC_UPDATED_AT; +import static io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils.enquoteIdentifierList; +import static io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils.getFullTableName; +import static io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils.getIdentifierWithQuoting; +import static io.airbyte.integrations.source.relationaldb.RelationalDbQueryUtils.queryTable; import static java.util.stream.Collectors.toList; import com.fasterxml.jackson.databind.JsonNode; @@ -80,7 +84,7 @@ public AutoCloseableIterator queryTableFullRefresh(final JdbcDatabase LOGGER.info("Queueing query for table: {}", tableName); final String newIdentifiers = getWrappedColumnNames(database, null, columnNames, schemaName, tableName); - final String preparedSqlQuery = String.format("SELECT %s FROM %s", newIdentifiers, getFullTableName(schemaName, tableName)); + final String preparedSqlQuery = String.format("SELECT %s FROM %s", newIdentifiers, getFullTableName(schemaName, tableName, getQuoteString())); LOGGER.info("Prepared SQL query for TableFullRefresh is: " + preparedSqlQuery); return queryTable(database, preparedSqlQuery); @@ -107,8 +111,8 @@ protected String getWrappedColumnNames(final JdbcDatabase database, final SQLServerResultSetMetaData sqlServerResultSetMetaData = (SQLServerResultSetMetaData) database .queryMetadata(String .format("SELECT TOP 1 %s FROM %s", // only first row is enough to get field's type - enquoteIdentifierList(columnNames), - getFullTableName(schemaName, tableName))); + enquoteIdentifierList(columnNames, getQuoteString()), + getFullTableName(schemaName, tableName, getQuoteString()))); // metadata will be null if table doesn't contain records if (sqlServerResultSetMetaData != null) { @@ -127,7 +131,7 @@ protected String getWrappedColumnNames(final JdbcDatabase database, .map( el -> hierarchyIdColumns.contains(el) ? String .format("%s.ToString() as %s%s%s", el, identifierQuoteString, el, identifierQuoteString) - : getIdentifierWithQuoting(el)) + : getIdentifierWithQuoting(el, getQuoteString())) .toList()); } catch (final SQLException e) { LOGGER.error("Failed to fetch metadata to prepare a proper request.", e); diff --git a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java index f6a0d225b7fb..7ea0ddcb8464 100644 --- a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java +++ b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java @@ -7,6 +7,7 @@ import static io.airbyte.integrations.base.errors.messages.ErrorMessage.getErrorMessage; import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import io.airbyte.commons.exceptions.ConnectionErrorException; @@ -234,7 +235,7 @@ private void validateCursorFieldForIncrementalTables( } } - protected List>> discoverWithoutSystemTables( + private List>> discoverWithoutSystemTables( final Database database) throws Exception { final Set systemNameSpaces = getExcludedInternalNameSpaces(); final List>> discoveredTables = discoverInternal(database); @@ -244,7 +245,7 @@ protected List>> discoverWithoutSystemTables( Collectors.toList())); } - protected List> getFullRefreshIterators( + private List> getFullRefreshIterators( final Database database, final ConfiguredAirbyteCatalog catalog, final Map>> tableNameToTable, @@ -287,7 +288,7 @@ protected List> getIncrementalIterators( * sync mode * @return List of AirbyteMessageIterators containing all iterators for a catalog */ - protected List> getSelectedIterators( + private List> getSelectedIterators( final Database database, final ConfiguredAirbyteCatalog catalog, final Map>> tableNameToTable, @@ -331,7 +332,7 @@ protected List> getSelectedIterators( * @param emittedAt Time when data was emitted from the Source database * @return */ - protected AutoCloseableIterator createReadIterator(final Database database, + private AutoCloseableIterator createReadIterator(final Database database, final ConfiguredAirbyteStream airbyteStream, final TableInfo> table, final StateManager stateManager, @@ -414,7 +415,7 @@ protected AutoCloseableIterator createReadIterator(final Databas * @param emittedAt Time when data was emitted from the Source database * @return AirbyteMessage Iterator that */ - protected AutoCloseableIterator getIncrementalStream(final Database database, + private AutoCloseableIterator getIncrementalStream(final Database database, final ConfiguredAirbyteStream airbyteStream, final List selectedDatabaseFields, final TableInfo> table, @@ -456,7 +457,7 @@ protected AutoCloseableIterator getIncrementalStream(final Datab * @param emittedAt Time when data was emitted from the Source database * @return AirbyteMessageIterator with all records for a database source */ - protected AutoCloseableIterator getFullRefreshStream(final Database database, + private AutoCloseableIterator getFullRefreshStream(final Database database, final String streamName, final String namespace, final List selectedDatabaseFields, @@ -468,11 +469,11 @@ protected AutoCloseableIterator getFullRefreshStream(final Datab return getMessageIterator(queryStream, streamName, namespace, emittedAt.toEpochMilli()); } - protected String getFullyQualifiedTableName(final String nameSpace, final String tableName) { + private String getFullyQualifiedTableName(final String nameSpace, final String tableName) { return nameSpace != null ? nameSpace + "." + tableName : tableName; } - public AutoCloseableIterator getMessageIterator( + private AutoCloseableIterator getMessageIterator( final AutoCloseableIterator recordIterator, final String streamName, final String namespace, @@ -493,7 +494,7 @@ public AutoCloseableIterator getMessageIterator( * @return list of table/data structure info * @throws Exception might throw an error during connection to database */ - protected List> getTables(final Database database) throws Exception { + private List> getTables(final Database database) throws Exception { final List>> tableInfos = discoverWithoutSystemTables(database); final Map> fullyQualifiedTableNameToPrimaryKeys = discoverPrimaryKeys( database, tableInfos); @@ -522,7 +523,7 @@ protected List> getTables(final Database database) throws Excep .collect(Collectors.toList()); } - protected Field toField(final CommonField field) { + private Field toField(final CommonField field) { if (getType(field.getType()) == JsonSchemaType.OBJECT && field.getProperties() != null && !field.getProperties().isEmpty()) { final var properties = field.getProperties().stream().map(this::toField).toList(); @@ -532,7 +533,7 @@ protected Field toField(final CommonField field) { } } - protected void assertColumnsWithSameNameAreSame(final String nameSpace, final String tableName, + private void assertColumnsWithSameNameAreSame(final String nameSpace, final String tableName, final List> columns) { columns.stream() .collect(Collectors.groupingBy(CommonField::getName)) @@ -557,7 +558,7 @@ protected void assertColumnsWithSameNameAreSame(final String nameSpace, final St * for SELECT-ing the table with privileges. In some cases such SELECT doesn't require (e.g. in * Oracle DB - the schema is the user, you cannot REVOKE a privilege on a table from its owner). */ - public Set getPrivilegesTableForCurrentUser(final JdbcDatabase database, + protected Set getPrivilegesTableForCurrentUser(final JdbcDatabase database, final String schema) throws SQLException { return Collections.emptySet(); } @@ -585,7 +586,7 @@ public Set getPrivilegesTableForCurrentUser(final JdbcDatabase database, * * @return list of consumers that run queries for the check command. */ - public abstract List> getCheckOperations(JsonNode config) + protected abstract List> getCheckOperations(JsonNode config) throws Exception; /** @@ -601,7 +602,7 @@ public abstract List> getCheckOperations(Js * * @return set of system namespaces(schemas) to be excluded */ - public abstract Set getExcludedInternalNameSpaces(); + protected abstract Set getExcludedInternalNameSpaces(); /** * Discover all available tables in the source database. @@ -653,7 +654,7 @@ protected abstract Map> discoverPrimaryKeys(Database databa * @param tableName target table * @return iterator with read data */ - public abstract AutoCloseableIterator queryTableFullRefresh(final Database database, + protected abstract AutoCloseableIterator queryTableFullRefresh(final Database database, final List columnNames, final String schemaName, final String tableName); @@ -666,7 +667,7 @@ public abstract AutoCloseableIterator queryTableFullRefresh(final Data * * @return iterator with read data */ - public abstract AutoCloseableIterator queryTableIncremental(Database database, + protected abstract AutoCloseableIterator queryTableIncremental(Database database, List columnNames, String schemaName, String tableName, @@ -685,7 +686,7 @@ protected int getStateEmissionFrequency() { /** * @return list of fields that could be used as cursors */ - public abstract boolean isCursorType(DataType type); + protected abstract boolean isCursorType(DataType type); private Database createDatabaseInternal(final JsonNode sourceConfig) throws Exception { final Database database = createDatabase(sourceConfig); diff --git a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractRelationalDbSource.java b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractRelationalDbSource.java deleted file mode 100644 index 1e9697ba1019..000000000000 --- a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractRelationalDbSource.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.source.relationaldb; - -import com.fasterxml.jackson.databind.JsonNode; -import io.airbyte.commons.util.AutoCloseableIterator; -import io.airbyte.commons.util.AutoCloseableIterators; -import io.airbyte.db.SqlDatabase; -import io.airbyte.integrations.base.Source; -import java.util.List; -import java.util.StringJoiner; -import java.util.stream.Stream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class contains helper functions and boilerplate for implementing a source connector for a - * relational DB source. - * - * see io.airbyte.integrations.source.jdbc.AbstractJdbcSource if you are implementing a relational - * DB which can be accessed via JDBC driver. - */ -public abstract class AbstractRelationalDbSource extends - AbstractDbSource implements Source { - - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRelationalDbSource.class); - - @Override - public AutoCloseableIterator queryTableFullRefresh(final Database database, - final List columnNames, - final String schemaName, - final String tableName) { - LOGGER.info("Queueing query for table: {}", tableName); - return queryTable(database, String.format("SELECT %s FROM %s", - enquoteIdentifierList(columnNames), - getFullTableName(schemaName, tableName))); - } - - protected String getIdentifierWithQuoting(final String identifier) { - return getQuoteString() + identifier + getQuoteString(); - } - - protected String enquoteIdentifierList(final List identifiers) { - final StringJoiner joiner = new StringJoiner(","); - for (final String identifier : identifiers) { - joiner.add(getIdentifierWithQuoting(identifier)); - } - return joiner.toString(); - } - - protected String getFullTableName(final String nameSpace, final String tableName) { - return (nameSpace == null || nameSpace.isEmpty() ? getIdentifierWithQuoting(tableName) - : getIdentifierWithQuoting(nameSpace) + "." + getIdentifierWithQuoting(tableName)); - } - - protected AutoCloseableIterator queryTable(final Database database, final String sqlQuery) { - return AutoCloseableIterators.lazyIterator(() -> { - try { - final Stream stream = database.unsafeQuery(sqlQuery); - return AutoCloseableIterators.fromStream(stream); - } catch (final Exception e) { - throw new RuntimeException(e); - } - }); - } - -} diff --git a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/RelationalDbQueryUtils.java b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/RelationalDbQueryUtils.java new file mode 100644 index 000000000000..975068ce3790 --- /dev/null +++ b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/RelationalDbQueryUtils.java @@ -0,0 +1,44 @@ +package io.airbyte.integrations.source.relationaldb; + +import com.fasterxml.jackson.databind.JsonNode; +import io.airbyte.commons.util.AutoCloseableIterator; +import io.airbyte.commons.util.AutoCloseableIterators; +import io.airbyte.db.SqlDatabase; +import java.util.List; +import java.util.StringJoiner; +import java.util.stream.Stream; + +/** + * Utility class for methods to query a relational db. + */ +public class RelationalDbQueryUtils { + + public static String getIdentifierWithQuoting(final String identifier, final String quoteString) { + return quoteString + identifier + quoteString; + } + + public static String enquoteIdentifierList(final List identifiers, final String quoteString) { + final StringJoiner joiner = new StringJoiner(","); + for (final String identifier : identifiers) { + joiner.add(getIdentifierWithQuoting(identifier, quoteString)); + } + return joiner.toString(); + } + + public static String getFullTableName(final String nameSpace, final String tableName, final String quoteString) { + return (nameSpace == null || nameSpace.isEmpty() ? getIdentifierWithQuoting(tableName, quoteString) + : getIdentifierWithQuoting(nameSpace, quoteString) + "." + getIdentifierWithQuoting(tableName, quoteString)); + } + + public static AutoCloseableIterator queryTable(final Database database, final String sqlQuery) { + return AutoCloseableIterators.lazyIterator(() -> { + try { + final Stream stream = database.unsafeQuery(sqlQuery); + return AutoCloseableIterators.fromStream(stream); + } catch (final Exception e) { + throw new RuntimeException(e); + } + }); + } + +} From f7bef97be686b968dcfbf255c9228a2b13a7e21d Mon Sep 17 00:00:00 2001 From: ev Date: Thu, 3 Nov 2022 20:13:13 +0000 Subject: [PATCH 25/73] New Source: Wikipedia Pageviews (#18343) * start adding connector * fix check and stream slicer * pass some tests * fix: github url Co-authored-by: Marcos Marx * add stream slicer for top and fix some tests * remove unneeded files * Increment the version. * add docs and clean up unneeded comments * Bump airbyte-cdk version to 0.2 * add schemaloader * add wikipedia to source def * auto-bump connector version Co-authored-by: Marcos Marx Co-authored-by: marcosmarxm Co-authored-by: Octavia Squidington III --- .../resources/seed/source_definitions.yaml | 7 ++ .../src/main/resources/seed/source_specs.yaml | 77 +++++++++++++++++ .../source-wikipedia-pageviews/.dockerignore | 6 ++ .../source-wikipedia-pageviews/Dockerfile | 38 +++++++++ .../source-wikipedia-pageviews/README.md | 79 ++++++++++++++++++ .../source-wikipedia-pageviews/__init__.py | 3 + .../acceptance-test-config.yml | 30 +++++++ .../acceptance-test-docker.sh | 16 ++++ .../source-wikipedia-pageviews/build.gradle | 9 ++ .../integration_tests/__init__.py | 3 + .../integration_tests/abnormal_state.json | 5 ++ .../integration_tests/acceptance.py | 16 ++++ .../integration_tests/configured_catalog.json | 22 +++++ .../integration_tests/invalid_config.json | 9 ++ .../integration_tests/sample_config.json | 9 ++ .../integration_tests/sample_state.json | 5 ++ .../source-wikipedia-pageviews/main.py | 13 +++ .../requirements.txt | 2 + .../source-wikipedia-pageviews/setup.py | 29 +++++++ .../source_wikipedia_pageviews/__init__.py | 8 ++ .../schemas/per-article.json | 28 +++++++ .../schemas/top.json | 40 +++++++++ .../source_wikipedia_pageviews/source.py | 18 ++++ .../source_wikipedia_pageviews/spec.yaml | 62 ++++++++++++++ .../wikipedia_pageviews.yaml | 83 +++++++++++++++++++ .../sources/wikipedia-pageviews.md | 53 ++++++++++++ 26 files changed, 670 insertions(+) create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/.dockerignore create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/Dockerfile create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/README.md create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/__init__.py create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/acceptance-test-config.yml create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/acceptance-test-docker.sh create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/build.gradle create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/__init__.py create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/abnormal_state.json create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/acceptance.py create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/configured_catalog.json create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/invalid_config.json create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/sample_config.json create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/sample_state.json create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/main.py create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/requirements.txt create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/setup.py create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/__init__.py create mode 100644 airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/schemas/per-article.json create mode 100644 airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/schemas/top.json create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/source.py create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/spec.yaml create mode 100755 airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/wikipedia_pageviews.yaml create mode 100644 docs/integrations/sources/wikipedia-pageviews.md diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index c0e7479070af..ae7b00a4fd97 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -1484,6 +1484,13 @@ documentationUrl: https://docs.airbyte.com/integrations/sources/waiteraid sourceType: api releaseStage: alpha +- name: Wikipedia Pageviews + sourceDefinitionId: 87c58f70-6f7a-4f70-aba5-bab1a458f5ba + dockerRepository: airbyte/source-wikipedia-pageviews + dockerImageTag: 0.1.0 + documentationUrl: https://docs.airbyte.com/integrations/sources/wikipedia-pageviews + sourceType: api + releaseStage: alpha - name: Yandex Metrica sourceDefinitionId: 7865dce4-2211-4f6a-88e5-9d0fe161afe7 dockerRepository: airbyte/source-yandex-metrica diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 759f2e1c7cf1..552e4e2f380b 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -14185,6 +14185,83 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] +- dockerImage: "airbyte/source-wikipedia-pageviews:0.1.0" + spec: + documentationUrl: "https://docsurl.com" + connectionSpecification: + $schema: "http://json-schema.org/draft-07/schema#" + title: "Wikipedia Pageviews Spec" + type: "object" + required: + - "project" + - "access" + - "agent" + - "article" + - "start" + - "end" + - "country" + additionalProperties: true + properties: + project: + type: "string" + title: "Project" + description: "If you want to filter by project, use the domain of any Wikimedia\ + \ project." + examples: + - "en.wikipedia.org" + - "www.mediawiki.org" + - "commons.wikimedia.org" + access: + type: "string" + title: "Access" + description: "If you want to filter by access method, use one of desktop,\ + \ mobile-app or mobile-web. If you are interested in pageviews regardless\ + \ of access method, use all-access." + examples: + - "all-access" + - "desktop" + - "mobile-app" + - "mobile-web" + agent: + type: "string" + title: "Agent" + description: "If you want to filter by agent type, use one of user, automated\ + \ or spider. If you are interested in pageviews regardless of agent type,\ + \ use all-agents." + examples: + - "all-agents" + - "user" + - "spider" + - "automated" + article: + type: "string" + title: "Article" + description: "The title of any article in the specified project. Any spaces\ + \ should be replaced with underscores. It also should be URI-encoded,\ + \ so that non-URI-safe characters like %, / or ? are accepted." + examples: + - "Are_You_the_One%3F" + start: + type: "string" + title: "Start" + description: "The date of the first day to include, in YYYYMMDD or YYYYMMDDHH\ + \ format." + end: + type: "string" + title: "End" + description: "The date of the last day to include, in YYYYMMDD or YYYYMMDDHH\ + \ format." + country: + type: "string" + title: "Country" + description: "The ISO 3166-1 alpha-2 code of a country for which to retrieve\ + \ top articles." + examples: + - "FR" + - "IN" + supportsNormalization: false + supportsDBT: false + supported_destination_sync_modes: [] - dockerImage: "airbyte/source-yandex-metrica:0.1.0" spec: documentationUrl: "https://docsurl.com" diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/.dockerignore b/airbyte-integrations/connectors/source-wikipedia-pageviews/.dockerignore new file mode 100755 index 000000000000..ef12d74d21bc --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/.dockerignore @@ -0,0 +1,6 @@ +* +!Dockerfile +!main.py +!source_wikipedia_pageviews +!setup.py +!secrets diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/Dockerfile b/airbyte-integrations/connectors/source-wikipedia-pageviews/Dockerfile new file mode 100755 index 000000000000..1bc63f17e8b4 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/Dockerfile @@ -0,0 +1,38 @@ +FROM python:3.9.11-alpine3.15 as base + +# build and load all requirements +FROM base as builder +WORKDIR /airbyte/integration_code + +# upgrade pip to the latest version +RUN apk --no-cache upgrade \ + && pip install --upgrade pip \ + && apk --no-cache add tzdata build-base + + +COPY setup.py ./ +# install necessary packages to a temporary folder +RUN pip install --prefix=/install . + +# build a clean environment +FROM base +WORKDIR /airbyte/integration_code + +# copy all loaded and built libraries to a pure basic image +COPY --from=builder /install /usr/local +# add default timezone settings +COPY --from=builder /usr/share/zoneinfo/Etc/UTC /etc/localtime +RUN echo "Etc/UTC" > /etc/timezone + +# bash is installed for more convenient debugging. +RUN apk --no-cache add bash + +# copy payload code only +COPY main.py ./ +COPY source_wikipedia_pageviews ./source_wikipedia_pageviews + +ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" +ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] + +LABEL io.airbyte.version=0.1.0 +LABEL io.airbyte.name=airbyte/source-wikipedia-pageviews diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/README.md b/airbyte-integrations/connectors/source-wikipedia-pageviews/README.md new file mode 100755 index 000000000000..03cbba6a4e21 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/README.md @@ -0,0 +1,79 @@ +# Wikipedia Pageviews Source + +This is the repository for the Wikipedia Pageviews configuration based source connector. +For information about how to use this connector within Airbyte, see [the documentation](https://docs.airbyte.io/integrations/sources/wikipedia-pageviews). + +## Local development + +#### Building via Gradle +You can also build the connector in Gradle. This is typically used in CI and not needed for your development workflow. + +To build using Gradle, from the Airbyte repository root, run: +``` +./gradlew :airbyte-integrations:connectors:source-wikipedia-pageviews:build +``` + +#### Create credentials +**If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.io/integrations/sources/wikipedia-pageviews) +to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `source_wikipedia_pageviews/spec.yaml` file. +Note that any directory named `secrets` is gitignored across the entire Airbyte repo, so there is no danger of accidentally checking in sensitive information. +See `integration_tests/sample_config.json` for a sample config file. + +**If you are an Airbyte core member**, copy the credentials in Lastpass under the secret name `source wikipedia-pageviews test creds` +and place them into `secrets/config.json`. + +### Locally running the connector docker image + +#### Build +First, make sure you build the latest Docker image: +``` +docker build . -t airbyte/source-wikipedia-pageviews:dev +``` + +You can also build the connector image via Gradle: +``` +./gradlew :airbyte-integrations:connectors:source-wikipedia-pageviews:airbyteDocker +``` +When building via Gradle, the docker image name and tag, respectively, are the values of the `io.airbyte.name` and `io.airbyte.version` `LABEL`s in +the Dockerfile. + +#### Run +Then run any of the connector commands as follows: +``` +docker run --rm airbyte/source-wikipedia-pageviews:dev spec +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-wikipedia-pageviews:dev check --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-wikipedia-pageviews:dev discover --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/source-wikipedia-pageviews:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json +``` +## Testing + +#### Acceptance Tests +Customize `acceptance-test-config.yml` file to configure tests. See [Source Acceptance Tests](https://docs.airbyte.io/connector-development/testing-connectors/source-acceptance-tests-reference) for more information. +If your connector requires to create or destroy resources for use during acceptance tests create fixtures for it and place them inside integration_tests/acceptance.py. + +To run your integration tests with docker + +### Using gradle to run tests +All commands should be run from airbyte project root. +To run unit tests: +``` +./gradlew :airbyte-integrations:connectors:source-wikipedia-pageviews:unitTest +``` +To run acceptance and custom integration tests: +``` +./gradlew :airbyte-integrations:connectors:source-wikipedia-pageviews:integrationTest +``` + +## Dependency Management +All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development. +We split dependencies between two groups, dependencies that are: +* required for your connector to work need to go to `MAIN_REQUIREMENTS` list. +* required for the testing need to go to `TEST_REQUIREMENTS` list + +### Publishing a new version of the connector +You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what? +1. Make sure your changes are passing unit and integration tests. +1. Bump the connector version in `Dockerfile` -- just increment the value of the `LABEL io.airbyte.version` appropriately (we use [SemVer](https://semver.org/)). +1. Create a Pull Request. +1. Pat yourself on the back for being an awesome contributor. +1. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master. diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/__init__.py b/airbyte-integrations/connectors/source-wikipedia-pageviews/__init__.py new file mode 100755 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/acceptance-test-config.yml b/airbyte-integrations/connectors/source-wikipedia-pageviews/acceptance-test-config.yml new file mode 100755 index 000000000000..09ee4ecd3451 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/acceptance-test-config.yml @@ -0,0 +1,30 @@ +# See [Source Acceptance Tests](https://docs.airbyte.io/connector-development/testing-connectors/source-acceptance-tests-reference) +# for more information about how to configure these tests +connector_image: airbyte/source-wikipedia-pageviews:dev +tests: + spec: + - spec_path: "source_wikipedia_pageviews/spec.yaml" + connection: + - config_path: "secrets/config.json" + status: "succeed" + - config_path: "integration_tests/invalid_config.json" + status: "failed" + discovery: + - config_path: "secrets/config.json" + basic_read: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" + empty_streams: [] + # TODO uncomment this block to specify that the tests should assert the connector outputs the records provided in the input file a file + # expect_records: + # path: "integration_tests/expected_records.txt" + # extra_fields: no + # exact_order: no + # extra_records: yes + # incremental: # TODO if your connector does not implement incremental sync, remove this block + # - config_path: "secrets/config.json" + # configured_catalog_path: "integration_tests/configured_catalog.json" + # future_state_path: "integration_tests/abnormal_state.json" + full_refresh: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/acceptance-test-docker.sh b/airbyte-integrations/connectors/source-wikipedia-pageviews/acceptance-test-docker.sh new file mode 100755 index 000000000000..c51577d10690 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/acceptance-test-docker.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +# Build latest connector image +docker build . -t $(cat acceptance-test-config.yml | grep "connector_image" | head -n 1 | cut -d: -f2-) + +# Pull latest acctest image +docker pull airbyte/source-acceptance-test:latest + +# Run +docker run --rm -it \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /tmp:/tmp \ + -v $(pwd):/test_input \ + airbyte/source-acceptance-test \ + --acceptance-test-config /test_input + diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/build.gradle b/airbyte-integrations/connectors/source-wikipedia-pageviews/build.gradle new file mode 100755 index 000000000000..2900db7ffacb --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/build.gradle @@ -0,0 +1,9 @@ +plugins { + id 'airbyte-python' + id 'airbyte-docker' + id 'airbyte-source-acceptance-test' +} + +airbytePython { + moduleDirectory 'source_wikipedia_pageviews' +} diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/__init__.py b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/__init__.py new file mode 100755 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/abnormal_state.json b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/abnormal_state.json new file mode 100755 index 000000000000..43c016b9bfaa --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/abnormal_state.json @@ -0,0 +1,5 @@ +{ + "per-article": { + "timestamp": "2099022700" + } +} diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/acceptance.py b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/acceptance.py new file mode 100755 index 000000000000..1302b2f57e10 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/acceptance.py @@ -0,0 +1,16 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import pytest + +pytest_plugins = ("source_acceptance_test.plugin",) + + +@pytest.fixture(scope="session", autouse=True) +def connector_setup(): + """This fixture is a placeholder for external resources that acceptance test might require.""" + # TODO: setup test dependencies if needed. otherwise remove the TODO comments + yield + # TODO: clean up test dependencies diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/configured_catalog.json b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/configured_catalog.json new file mode 100755 index 000000000000..f97acaffc7d7 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/configured_catalog.json @@ -0,0 +1,22 @@ +{ + "streams": [ + { + "stream": { + "name": "per-article", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "top", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/invalid_config.json b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/invalid_config.json new file mode 100755 index 000000000000..7040094d9ba6 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/invalid_config.json @@ -0,0 +1,9 @@ +{ + "project": "en.wikipedia.org", + "access": "all-access", + "agent": "all-agents", + "article": "Are_You_the_One%3F", + "start": "", + "end": "202440101", + "country": "EN" +} diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/sample_config.json b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/sample_config.json new file mode 100755 index 000000000000..e5628b506182 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/sample_config.json @@ -0,0 +1,9 @@ +{ + "project": "en.wikipedia.org", + "access": "all-access", + "agent": "all-agents", + "article": "Are_You_the_One%3F", + "start": "20200101", + "end": "20200201", + "country": "EN" +} diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/sample_state.json b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/sample_state.json new file mode 100755 index 000000000000..d0e7de37580c --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/integration_tests/sample_state.json @@ -0,0 +1,5 @@ +{ + "per-article": { + "timestamp": "20210505" + } +} diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/main.py b/airbyte-integrations/connectors/source-wikipedia-pageviews/main.py new file mode 100755 index 000000000000..6cd40d0b94ca --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/main.py @@ -0,0 +1,13 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import sys + +from airbyte_cdk.entrypoint import launch +from source_wikipedia_pageviews import SourceWikipediaPageviews + +if __name__ == "__main__": + source = SourceWikipediaPageviews() + launch(source, sys.argv[1:]) diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/requirements.txt b/airbyte-integrations/connectors/source-wikipedia-pageviews/requirements.txt new file mode 100755 index 000000000000..0411042aa091 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/requirements.txt @@ -0,0 +1,2 @@ +-e ../../bases/source-acceptance-test +-e . diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/setup.py b/airbyte-integrations/connectors/source-wikipedia-pageviews/setup.py new file mode 100755 index 000000000000..b49e03eabfeb --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/setup.py @@ -0,0 +1,29 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from setuptools import find_packages, setup + +MAIN_REQUIREMENTS = [ + "airbyte-cdk~=0.2", +] + +TEST_REQUIREMENTS = [ + "pytest~=6.1", + "pytest-mock~=3.6.1", + "source-acceptance-test", +] + +setup( + name="source_wikipedia_pageviews", + description="Source implementation for Wikipedia Pageviews.", + author="Airbyte", + author_email="contact@airbyte.io", + packages=find_packages(), + install_requires=MAIN_REQUIREMENTS, + package_data={"": ["*.json", "*.yaml", "schemas/*.json", "schemas/shared/*.json"]}, + extras_require={ + "tests": TEST_REQUIREMENTS, + }, +) diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/__init__.py b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/__init__.py new file mode 100755 index 000000000000..d52fb1e5ee55 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/__init__.py @@ -0,0 +1,8 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from .source import SourceWikipediaPageviews + +__all__ = ["SourceWikipediaPageviews"] diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/schemas/per-article.json b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/schemas/per-article.json new file mode 100644 index 000000000000..6f1907a4713c --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/schemas/per-article.json @@ -0,0 +1,28 @@ +{ + "type": "object", + "properties": { + "project": { + "type": "string" + }, + "access": { + "type": "string" + }, + "article": { + "type": "string" + }, + "agent": { + "type": "string" + }, + "granularity": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "views": { + "type": "integer", + "format": "int64" + } + }, + "$schema": "http://json-schema.org/schema#" +} \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/schemas/top.json b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/schemas/top.json new file mode 100644 index 000000000000..bb3641384605 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/schemas/top.json @@ -0,0 +1,40 @@ +{ + "type": "object", + "properties": { + "project": { + "type": "string" + }, + "access": { + "type": "string" + }, + "year": { + "type": "string" + }, + "month": { + "type": "string" + }, + "day": { + "type": "string" + }, + "articles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "rank": { + "type": "integer", + "format": "int32" + }, + "article": { + "type": "string" + }, + "views": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "$schema": "http://json-schema.org/schema#" +} \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/source.py b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/source.py new file mode 100755 index 000000000000..19ed7ee95fb3 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/source.py @@ -0,0 +1,18 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from airbyte_cdk.sources.declarative.yaml_declarative_source import YamlDeclarativeSource + +""" +This file provides the necessary constructs to interpret a provided declarative YAML configuration file into +source connector. + +WARNING: Do not modify this file. +""" + + +# Declarative Source +class SourceWikipediaPageviews(YamlDeclarativeSource): + def __init__(self): + super().__init__(**{"path_to_yaml": "wikipedia_pageviews.yaml"}) diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/spec.yaml b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/spec.yaml new file mode 100755 index 000000000000..32bba6f7a92d --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/spec.yaml @@ -0,0 +1,62 @@ +documentationUrl: https://docsurl.com +connectionSpecification: + $schema: http://json-schema.org/draft-07/schema# + title: Wikipedia Pageviews Spec + type: object + required: + - project + - access + - agent + - article + - start + - end + - country + additionalProperties: true + properties: + project: + type: string + title: Project + description: If you want to filter by project, use the domain of any Wikimedia project. + examples: + - en.wikipedia.org + - www.mediawiki.org + - commons.wikimedia.org + access: + type: string + title: Access + description: If you want to filter by access method, use one of desktop, mobile-app or mobile-web. If you are interested in pageviews regardless of access method, use all-access. + examples: + - all-access + - desktop + - mobile-app + - mobile-web + agent: + type: string + title: Agent + description: If you want to filter by agent type, use one of user, automated or spider. If you are interested in pageviews regardless of agent type, use all-agents. + examples: + - all-agents + - user + - spider + - automated + article: + type: string + title: Article + description: The title of any article in the specified project. Any spaces should be replaced with underscores. It also should be URI-encoded, so that non-URI-safe characters like %, / or ? are accepted. + examples: + - Are_You_the_One%3F + start: + type: string + title: Start + description: The date of the first day to include, in YYYYMMDD or YYYYMMDDHH format. + end: + type: string + title: End + description: The date of the last day to include, in YYYYMMDD or YYYYMMDDHH format. + country: + type: string + title: Country + description: The ISO 3166-1 alpha-2 code of a country for which to retrieve top articles. + examples: + - FR + - IN diff --git a/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/wikipedia_pageviews.yaml b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/wikipedia_pageviews.yaml new file mode 100755 index 000000000000..03a81cb06bf7 --- /dev/null +++ b/airbyte-integrations/connectors/source-wikipedia-pageviews/source_wikipedia_pageviews/wikipedia_pageviews.yaml @@ -0,0 +1,83 @@ +version: "0.1.0" + +definitions: + selector: + extractor: + field_pointer: [ "items" ] + requester: + url_base: "https://wikimedia.org/api/rest_v1/metrics/pageviews" + http_method: "GET" + request_options_provider: + request_headers: + "User-Agent": "AirbyteWikipediaPageviewsConnector/1.0 (https://github.com/airbytehq/airbyte)" + top_stream_slicer: + type: DatetimeStreamSlicer + start_datetime: + datetime: "{{config.start}}" + datetime_format: "%Y%m%d" + end_datetime: + datetime: "{{config.start}}" + datetime_format: "%Y%m%d" + step: "1d" + cursor_field: "timestamp" + datetime_format: "%Y/%m/%d" + per_article_stream_slicer: + type: DatetimeStreamSlicer + start_datetime: "{{config.start}}" + end_datetime: "{{config.end}}" + step: "1d" + cursor_field: "timestamp" + datetime_format: "%Y%m%d" + + per_article_requester: + $options: + $ref: "*ref(definitions.requester)" + path: "/per-article/{{config.project}}/{{config.access}}/{{config.agent}}/{{config.article}}/daily/{{stream_slice.start_time}}/{{stream_slice.end_time}}" + top_requester: + $options: + $ref: "*ref(definitions.requester)" + path: "/top/{{config.project}}/{{config.access}}/{{stream_slice.start_time}}" + per_article_retriever: + record_selector: + $ref: "*ref(definitions.selector)" + paginator: + type: NoPagination + requester: + $ref: "*ref(definitions.per_article_requester)" + stream_slicer: + $ref: "*ref(definitions.per_article_stream_slicer)" + + top_retriever: + record_selector: + $ref: "*ref(definitions.selector)" + paginator: + type: NoPagination + requester: + $ref: "*ref(definitions.top_requester)" + stream_slicer: + $ref: "*ref(definitions.top_stream_slicer)" + per_article_stream: + schema_loader: + type: JsonSchema + file_path: "./source_wikipedia_pageviews/schemas/{{ options['name'] }}.json" + retriever: + $ref: "*ref(definitions.per_article_retriever)" + $options: + name: "per-article" + top_stream: + schema_loader: + type: JsonSchema + file_path: "./source_wikipedia_pageviews/schemas/{{ options['name'] }}.json" + retriever: + $ref: "*ref(definitions.top_retriever)" + $options: + name: "top" + +streams: + - "*ref(definitions.per_article_stream)" + - "*ref(definitions.top_stream)" + +check: + stream_names: + - "per-article" + - "top" diff --git a/docs/integrations/sources/wikipedia-pageviews.md b/docs/integrations/sources/wikipedia-pageviews.md new file mode 100644 index 000000000000..249204b28334 --- /dev/null +++ b/docs/integrations/sources/wikipedia-pageviews.md @@ -0,0 +1,53 @@ +# Wikipedia Pageviews + +This page contains the setup guide and reference information for the [Wikipedia Pageviews](https://wikimedia.org/api/rest_v1/#/Pageviews%20data) source connector. + +## Prerequisites + +None + +## Setup guide + +## Step 1: Set up the Courier connector in Airbyte + +### For Airbyte Cloud: + +1. [Log into your Airbyte Cloud](https://cloud.airbyte.io/workspaces) account. +2. In the left navigation bar, click **Sources**. In the top-right corner, click **+new source**. +3. On the Set up the source page, enter the name for the Courier connector and select **Wikipedia Pageviews** from the Source type dropdown. +4. Enter your parameters. +5. Click **Set up source**. + +### For Airbyte OSS: + +1. Navigate to the Airbyte Open Source dashboard. +2. Set the name for your source. +3. Enter your parameters. +4. Click **Set up source**. + +## Supported sync modes + +The Wikipedia Pageviews source connector supports the following [sync modes](https://docs.airbyte.com/cloud/core-concepts#connection-sync-modes): + +| Feature | Supported? | +| :---------------------------- | :--------- | +| Full Refresh Sync | Yes | +| Incremental Sync | No | +| Replicate Incremental Deletes | No | +| SSL connection | Yes | +| Namespaces | No | + +## Supported Streams + +- per-article +- top + +## Performance considerations + +100 req/s per endpoint. + +## Changelog + +| Version | Date | Pull Request | Subject | +| :------ | :--------- | :----------------------------------------------------- | :------------- | +| 0.1.0 | 2022-10-31 | [#18343](https://github.com/airbytehq/airbyte/pull/18343) | Initial commit | \ No newline at end of file From 5c870c162640b13763f52f4cf472fd4914909860 Mon Sep 17 00:00:00 2001 From: Eugene Date: Thu, 3 Nov 2022 22:15:24 +0200 Subject: [PATCH 26/73] =?UTF-8?q?=F0=9F=90=9BDestination-dynamodb:=20enfor?= =?UTF-8?q?ce=20ssl=20connection=20(#18672)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [16283] Destination-dynamodb: Added strict-encrypt version and enforced ssl connection on cloud --- .../seed/destination_definitions.yaml | 2 +- .../resources/seed/destination_specs.yaml | 2 +- .../destination-dynamodb/Dockerfile | 2 +- .../destination-dynamodb/build.gradle | 2 +- .../destination/dynamodb/DynamodbChecker.java | 14 +++++ .../dynamodb/DynamodbDestination.java | 5 +- .../dynamodb/DynamodbDestinationRunner.java | 18 ++++++ .../DynamodbDestinationStrictEncrypt.java | 33 ++++++++++ .../DynamodbDestinationStrictEncryptTest.java | 63 +++++++++++++++++++ docs/integrations/destinations/dynamodb.md | 2 + 10 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationRunner.java create mode 100644 airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationStrictEncrypt.java create mode 100644 airbyte-integrations/connectors/destination-dynamodb/src/test/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationStrictEncryptTest.java diff --git a/airbyte-config/init/src/main/resources/seed/destination_definitions.yaml b/airbyte-config/init/src/main/resources/seed/destination_definitions.yaml index 0d7af84e48f8..75ada190c6ff 100644 --- a/airbyte-config/init/src/main/resources/seed/destination_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/destination_definitions.yaml @@ -87,7 +87,7 @@ - name: DynamoDB destinationDefinitionId: 8ccd8909-4e99-4141-b48d-4984b70b2d89 dockerRepository: airbyte/destination-dynamodb - dockerImageTag: 0.1.5 + dockerImageTag: 0.1.7 documentationUrl: https://docs.airbyte.com/integrations/destinations/dynamodb icon: dynamodb.svg releaseStage: alpha diff --git a/airbyte-config/init/src/main/resources/seed/destination_specs.yaml b/airbyte-config/init/src/main/resources/seed/destination_specs.yaml index ea31f59258e3..965bc16c61c3 100644 --- a/airbyte-config/init/src/main/resources/seed/destination_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/destination_specs.yaml @@ -1460,7 +1460,7 @@ supported_destination_sync_modes: - "overwrite" - "append" -- dockerImage: "airbyte/destination-dynamodb:0.1.5" +- dockerImage: "airbyte/destination-dynamodb:0.1.7" spec: documentationUrl: "https://docs.airbyte.com/integrations/destinations/dynamodb" connectionSpecification: diff --git a/airbyte-integrations/connectors/destination-dynamodb/Dockerfile b/airbyte-integrations/connectors/destination-dynamodb/Dockerfile index 027c8b00d737..7abc76bfc120 100644 --- a/airbyte-integrations/connectors/destination-dynamodb/Dockerfile +++ b/airbyte-integrations/connectors/destination-dynamodb/Dockerfile @@ -16,5 +16,5 @@ ENV APPLICATION destination-dynamodb COPY --from=build /airbyte /airbyte -LABEL io.airbyte.version=0.1.5 +LABEL io.airbyte.version=0.1.7 LABEL io.airbyte.name=airbyte/destination-dynamodb diff --git a/airbyte-integrations/connectors/destination-dynamodb/build.gradle b/airbyte-integrations/connectors/destination-dynamodb/build.gradle index f9b3c74559ac..ecfbb13e5710 100644 --- a/airbyte-integrations/connectors/destination-dynamodb/build.gradle +++ b/airbyte-integrations/connectors/destination-dynamodb/build.gradle @@ -5,7 +5,7 @@ plugins { } application { - mainClass = 'io.airbyte.integrations.destination.dynamodb.DynamodbDestination' + mainClass = 'io.airbyte.integrations.destination.dynamodb.DynamodbDestinationRunner' applicationDefaultJvmArgs = ['-XX:+ExitOnOutOfMemoryError', '-XX:MaxRAMPercentage=75.0'] } diff --git a/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbChecker.java b/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbChecker.java index 0224476842fa..5e6faad471f9 100644 --- a/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbChecker.java +++ b/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbChecker.java @@ -77,4 +77,18 @@ public static AmazonDynamoDB getAmazonDynamoDB(final DynamodbDestinationConfig d } } + /** + * Checks that DynamoDb custom endpoint uses a variant that only uses HTTPS + * + * @param endpoint URL string representing an accessible S3 bucket + */ + public static boolean testCustomEndpointSecured(final String endpoint) { + // if user does not use a custom endpoint, do not fail + if (endpoint == null || endpoint.length() == 0) { + return true; + } else { + return endpoint.startsWith("https://"); + } + } + } diff --git a/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestination.java b/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestination.java index 6ff7e999f175..24ed2c81019c 100644 --- a/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestination.java +++ b/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestination.java @@ -27,7 +27,10 @@ public static void main(final String[] args) throws Exception { @Override public AirbyteConnectionStatus check(final JsonNode config) { try { - DynamodbChecker.attemptDynamodbWriteAndDelete(DynamodbDestinationConfig.getDynamodbDestinationConfig(config)); + final DynamodbDestinationConfig dynamodbDestinationConfig = + DynamodbDestinationConfig.getDynamodbDestinationConfig(config); + + DynamodbChecker.attemptDynamodbWriteAndDelete(dynamodbDestinationConfig); return new AirbyteConnectionStatus().withStatus(AirbyteConnectionStatus.Status.SUCCEEDED); } catch (final Exception e) { LOGGER.error("Exception attempting to access the DynamoDB table: ", e); diff --git a/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationRunner.java b/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationRunner.java new file mode 100644 index 000000000000..2a5f7e088b21 --- /dev/null +++ b/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationRunner.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.integrations.destination.dynamodb; + +import io.airbyte.integrations.base.adaptive.AdaptiveDestinationRunner; + +public class DynamodbDestinationRunner { + + public static void main(final String[] args) throws Exception { + AdaptiveDestinationRunner.baseOnEnv() + .withOssDestination(DynamodbDestination::new) + .withCloudDestination(DynamodbDestinationStrictEncrypt::new) + .run(args); + } + +} diff --git a/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationStrictEncrypt.java b/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationStrictEncrypt.java new file mode 100644 index 000000000000..bcf47a4678dd --- /dev/null +++ b/airbyte-integrations/connectors/destination-dynamodb/src/main/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationStrictEncrypt.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.integrations.destination.dynamodb; + +import com.fasterxml.jackson.databind.JsonNode; +import io.airbyte.protocol.models.AirbyteConnectionStatus; + +public class DynamodbDestinationStrictEncrypt extends DynamodbDestination { + + protected static final String NON_SECURE_URL_ERR_MSG = "Server Endpoint requires HTTPS"; + + public DynamodbDestinationStrictEncrypt() { + super(); + } + + @Override + public AirbyteConnectionStatus check(final JsonNode config) { + final DynamodbDestinationConfig dynamodbDestinationConfig = + DynamodbDestinationConfig.getDynamodbDestinationConfig(config); + + // enforce ssl connection + if (!DynamodbChecker.testCustomEndpointSecured(dynamodbDestinationConfig.getEndpoint())) { + return new AirbyteConnectionStatus() + .withStatus(AirbyteConnectionStatus.Status.FAILED) + .withMessage(NON_SECURE_URL_ERR_MSG); + } + + return super.check(config); + } + +} diff --git a/airbyte-integrations/connectors/destination-dynamodb/src/test/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationStrictEncryptTest.java b/airbyte-integrations/connectors/destination-dynamodb/src/test/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationStrictEncryptTest.java new file mode 100644 index 000000000000..aeef3f3afbf6 --- /dev/null +++ b/airbyte-integrations/connectors/destination-dynamodb/src/test/java/io/airbyte/integrations/destination/dynamodb/DynamodbDestinationStrictEncryptTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.integrations.destination.dynamodb; + +import static io.airbyte.integrations.destination.dynamodb.DynamodbDestinationStrictEncrypt.NON_SECURE_URL_ERR_MSG; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.ImmutableMap; +import io.airbyte.commons.io.IOs; +import io.airbyte.commons.json.Jsons; +import io.airbyte.protocol.models.AirbyteConnectionStatus; +import io.airbyte.protocol.models.AirbyteConnectionStatus.Status; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.jupiter.api.Test; + +public class DynamodbDestinationStrictEncryptTest { + + protected static final Path secretFilePath = Path.of("secrets/config.json"); + + /** + * Test that check passes if user is using HTTPS connection + */ + @Test + public void checkPassCustomEndpointIsHttpsOnly() { + final DynamodbDestination destinationWithHttpsOnlyEndpoint = new DynamodbDestinationStrictEncrypt(); + final AirbyteConnectionStatus status = destinationWithHttpsOnlyEndpoint.check(getBaseConfigJson()); + assertEquals(Status.SUCCEEDED, status.getStatus()); + } + + /** + * Test that check fails if user is using a non-secure (http) connection + */ + @Test + public void checkFailCustomEndpointIsHttpsOnly() { + final DynamodbDestination destinationWithHttpsOnlyEndpoint = new DynamodbDestinationStrictEncrypt(); + final AirbyteConnectionStatus status = destinationWithHttpsOnlyEndpoint.check(getUnsecureConfig()); + assertEquals(AirbyteConnectionStatus.Status.FAILED, status.getStatus()); + assertEquals(NON_SECURE_URL_ERR_MSG, status.getMessage()); + } + + protected JsonNode getBaseConfigJson() { + if (!Files.exists(secretFilePath)) { + throw new IllegalStateException("Secret config file doesn't exist. Get a valid secret (for airbyter: " + + "get secret from GSM) and put to ../destination-dynamodb/secrets/secret.json file"); + } + return Jsons.deserialize(IOs.readFile(secretFilePath)); + } + + protected JsonNode getUnsecureConfig() { + return Jsons.jsonNode(ImmutableMap.builder() + .put("dynamodb_endpoint", "http://testurl.com:9000") + .put("dynamodb_table_name_prefix", "integration-test") + .put("dynamodb_region", "us-east-2") + .put("access_key_id", "dummy_access_key_id") + .put("secret_access_key", "dummy_secret_access_key") + .build()); + } + +} diff --git a/docs/integrations/destinations/dynamodb.md b/docs/integrations/destinations/dynamodb.md index 7ca194666b56..a0fbccc87b0b 100644 --- a/docs/integrations/destinations/dynamodb.md +++ b/docs/integrations/destinations/dynamodb.md @@ -61,6 +61,8 @@ This connector by default uses 10 capacity units for both Read and Write in Dyna | Version | Date | Pull Request | Subject | | :--- | :--- | :--- | :--- | +| 0.1.7 | 2022-11-03 | [\#18672](https://github.com/airbytehq/airbyte/pull/18672) | Added strict-encrypt cloud runner | +| 0.1.6 | 2022-11-01 | [\#18672](https://github.com/airbytehq/airbyte/pull/18672) | Enforce to use ssl connection | | 0.1.5 | 2022-08-05 | [\#15350](https://github.com/airbytehq/airbyte/pull/15350) | Added per-stream handling | | 0.1.4 | 2022-06-16 | [\#13852](https://github.com/airbytehq/airbyte/pull/13852) | Updated stacktrace format for any trace message errors | | 0.1.3 | 2022-05-17 | [12820](https://github.com/airbytehq/airbyte/pull/12820) | Improved 'check' operation performance | From 6d23496d02209cf8e68cd95de3646f2373e3ef6b Mon Sep 17 00:00:00 2001 From: Cole Snodgrass Date: Thu, 3 Nov 2022 13:42:04 -0700 Subject: [PATCH 27/73] add project automation (#18935) --- .github/workflows/platform-workflow-labels.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/platform-workflow-labels.yml b/.github/workflows/platform-workflow-labels.yml index df253e2dffc9..d816029812f9 100644 --- a/.github/workflows/platform-workflow-labels.yml +++ b/.github/workflows/platform-workflow-labels.yml @@ -11,19 +11,31 @@ jobs: permissions: issues: write steps: - - name: Label Platform Workflow Issue + - name: Label Issue uses: andymckay/labeler@1.0.4 with: add-labels: "platform-workflow/requires-grooming" repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: Add Issue To Project + uses: action/add-to-project@v0.3.0 + with: + project-url: https://github.com/orgs/airbytehq/projects/25 + github-token: ${{ secrets.PLATFORM_WORKFLOW_PROJECT_AUTOMATION }} unlabel_issues: if: ${{ github.event.action == 'unlabeled' && github.event.label.name == 'team/platform-workflow' }} runs-on: ubuntu-latest permissions: issues: write steps: - - name: Unlabel Platform Workflow Issue + - name: Unlabel Issue uses: andymckay/labeler@1.0.4 with: remove-labels: "platform-workflow/requires-grooming" repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: Remove Issue From Project + uses: monry/actions-delete-issue-from-project@v2.0.1 + with: + github-token: ${{ secrets.PLATFORM_WORKFLOW_PROJECT_AUTOMATION }} + project-owner: airbytehq + project-number: 25 + issue-id: ${{ github.event.issue.node_id }} From 188612c891a830b19972e993dd1e3f139970405d Mon Sep 17 00:00:00 2001 From: Cole Snodgrass Date: Thu, 3 Nov 2022 13:48:59 -0700 Subject: [PATCH 28/73] action -> actions (#18938) --- .github/workflows/platform-workflow-labels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/platform-workflow-labels.yml b/.github/workflows/platform-workflow-labels.yml index d816029812f9..f982ae2e4934 100644 --- a/.github/workflows/platform-workflow-labels.yml +++ b/.github/workflows/platform-workflow-labels.yml @@ -17,7 +17,7 @@ jobs: add-labels: "platform-workflow/requires-grooming" repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Add Issue To Project - uses: action/add-to-project@v0.3.0 + uses: actions/add-to-project@v0.3.0 with: project-url: https://github.com/orgs/airbytehq/projects/25 github-token: ${{ secrets.PLATFORM_WORKFLOW_PROJECT_AUTOMATION }} From 64736f0ab3c8e584bedfcd91f21f286f52f8715b Mon Sep 17 00:00:00 2001 From: Davin Chia Date: Thu, 3 Nov 2022 14:39:35 -0700 Subject: [PATCH 29/73] More Readable Gradle test config. (#18890) The integration testing logs are extremely noisy today. The logs contain the entire test STDOUT and are a pain to read. This PR contains a better test setup config to reduce logging output. The main change is to comment out ShowStandardStreams in the integration tests plugin. Then we add the started event so Gradle shows us when a test is started. Some tests take a longer time. It is useful to know they have begun so it's clear if the job is stuck or not. Standardise the above setting across all of our custom test tasks. --- build.gradle | 15 +++++++++++---- .../groovy/airbyte-integration-test-java.gradle | 5 +++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 727e71510f33..124b8eaa2c37 100644 --- a/build.gradle +++ b/build.gradle @@ -357,8 +357,9 @@ subprojects { subproj -> excludeTags(integrationTagName, slowIntegrationTagName, cloudStorageTestTagName) } testLogging() { - events 'failed' + events "passed", "skipped", "failed" exceptionFormat 'full' + // uncomment to get the full log output // showStandardStreams = true } finalizedBy jacocoTestReport @@ -369,8 +370,10 @@ subprojects { subproj -> includeTags integrationTagName } testLogging() { - events 'failed' + events "passed", "failed", "started" exceptionFormat 'full' + // uncomment to get the full log output + // showStandardStreams = true } finalizedBy jacocoTestReport } @@ -380,8 +383,10 @@ subprojects { subproj -> includeTags slowIntegrationTagName } testLogging() { - events 'failed' + events "passed", "failed", "started" exceptionFormat 'full' + // uncomment to get the full log output + // showStandardStreams = true } finalizedBy jacocoTestReport } @@ -389,8 +394,10 @@ subprojects { subproj -> task allTests(type: Test) { useJUnitPlatform() testLogging() { - events 'failed' + events "passed", "failed", "started" exceptionFormat 'full' + // uncomment to get the full log output + // showStandardStreams = true } finalizedBy jacocoTestReport } diff --git a/buildSrc/src/main/groovy/airbyte-integration-test-java.gradle b/buildSrc/src/main/groovy/airbyte-integration-test-java.gradle index fde263668ce9..767f309d3a0d 100644 --- a/buildSrc/src/main/groovy/airbyte-integration-test-java.gradle +++ b/buildSrc/src/main/groovy/airbyte-integration-test-java.gradle @@ -31,9 +31,10 @@ class AirbyteIntegrationTestJavaPlugin implements Plugin { } testLogging() { - events "passed", "failed" + events "passed", "failed", "started" exceptionFormat "full" - showStandardStreams = true + // uncomment to get the full log output + // showStandardStreams = true } outputs.upToDateWhen { false } From aaeec26de3579e382cda90a1d13b30a8960c1bb1 Mon Sep 17 00:00:00 2001 From: Davin Chia Date: Thu, 3 Nov 2022 14:40:16 -0700 Subject: [PATCH 30/73] Job Persistence Refactor in preparation for progress bar. (#18891) Some refactoring in preparation for the progress bar persistence changes. The main change here was to simplify some of the JobPersistence methods by moving the logic to calculate attemptId into the JobPersistence implementation. This logic currently sits outside the class and is duplicated in multiple places. We could expose a helper method to calculate this logic, however that felt unnecessary at this point. The alternative is further duplicating this logic as the progress bar logic is implemented, so I want to get that out of the way. The other reason it's cleaner to use jobId and attemptNumber is these concepts/terms are more familiar throughout the rest of the codebase and it feels more intuitive to continue speaking this language (in my opinion). Some random bits I wanted to clean up on the way as well. I will leave comments in the files as appropriate. --- .../job/DefaultJobPersistence.java | 74 +++++++++++-------- .../persistence/job/JobPersistence.java | 9 ++- .../job/DefaultJobPersistenceTest.java | 12 +-- 3 files changed, 52 insertions(+), 43 deletions(-) diff --git a/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/DefaultJobPersistence.java b/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/DefaultJobPersistence.java index 1f5f5b2a2381..2f31c3020b21 100644 --- a/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/DefaultJobPersistence.java +++ b/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/DefaultJobPersistence.java @@ -344,26 +344,9 @@ public void writeOutput(final long jobId, final int attemptNumber, final JobOutp .set(ATTEMPTS.UPDATED_AT, now) .where(ATTEMPTS.JOB_ID.eq(jobId), ATTEMPTS.ATTEMPT_NUMBER.eq(attemptNumber)) .execute(); - final Optional record = - ctx.fetch("SELECT id from attempts where job_id = ? AND attempt_number = ?", jobId, - attemptNumber).stream().findFirst(); - final Long attemptId = record.get().get("id", Long.class); - - ctx.insertInto(SYNC_STATS) - .set(SYNC_STATS.ID, UUID.randomUUID()) - .set(SYNC_STATS.UPDATED_AT, now) - .set(SYNC_STATS.CREATED_AT, now) - .set(SYNC_STATS.ATTEMPT_ID, attemptId) - .set(SYNC_STATS.BYTES_EMITTED, syncStats.getBytesEmitted()) - .set(SYNC_STATS.RECORDS_EMITTED, syncStats.getRecordsEmitted()) - .set(SYNC_STATS.RECORDS_COMMITTED, syncStats.getRecordsCommitted()) - .set(SYNC_STATS.SOURCE_STATE_MESSAGES_EMITTED, syncStats.getSourceStateMessagesEmitted()) - .set(SYNC_STATS.DESTINATION_STATE_MESSAGES_EMITTED, syncStats.getDestinationStateMessagesEmitted()) - .set(SYNC_STATS.MAX_SECONDS_BEFORE_SOURCE_STATE_MESSAGE_EMITTED, syncStats.getMaxSecondsBeforeSourceStateMessageEmitted()) - .set(SYNC_STATS.MEAN_SECONDS_BEFORE_SOURCE_STATE_MESSAGE_EMITTED, syncStats.getMeanSecondsBeforeSourceStateMessageEmitted()) - .set(SYNC_STATS.MAX_SECONDS_BETWEEN_STATE_MESSAGE_EMITTED_AND_COMMITTED, syncStats.getMaxSecondsBetweenStateMessageEmittedandCommitted()) - .set(SYNC_STATS.MEAN_SECONDS_BETWEEN_STATE_MESSAGE_EMITTED_AND_COMMITTED, syncStats.getMeanSecondsBetweenStateMessageEmittedandCommitted()) - .execute(); + final Long attemptId = getAttemptId(jobId, attemptNumber, ctx); + + writeSyncStats(now, syncStats, attemptId, ctx); if (normalizationSummary != null) { ctx.insertInto(NORMALIZATION_SUMMARIES) @@ -382,6 +365,24 @@ public void writeOutput(final long jobId, final int attemptNumber, final JobOutp } + private static void writeSyncStats(final OffsetDateTime now, final SyncStats syncStats, final Long attemptId, final DSLContext ctx) { + ctx.insertInto(SYNC_STATS) + .set(SYNC_STATS.ID, UUID.randomUUID()) + .set(SYNC_STATS.UPDATED_AT, now) + .set(SYNC_STATS.CREATED_AT, now) + .set(SYNC_STATS.ATTEMPT_ID, attemptId) + .set(SYNC_STATS.BYTES_EMITTED, syncStats.getBytesEmitted()) + .set(SYNC_STATS.RECORDS_EMITTED, syncStats.getRecordsEmitted()) + .set(SYNC_STATS.RECORDS_COMMITTED, syncStats.getRecordsCommitted()) + .set(SYNC_STATS.SOURCE_STATE_MESSAGES_EMITTED, syncStats.getSourceStateMessagesEmitted()) + .set(SYNC_STATS.DESTINATION_STATE_MESSAGES_EMITTED, syncStats.getDestinationStateMessagesEmitted()) + .set(SYNC_STATS.MAX_SECONDS_BEFORE_SOURCE_STATE_MESSAGE_EMITTED, syncStats.getMaxSecondsBeforeSourceStateMessageEmitted()) + .set(SYNC_STATS.MEAN_SECONDS_BEFORE_SOURCE_STATE_MESSAGE_EMITTED, syncStats.getMeanSecondsBeforeSourceStateMessageEmitted()) + .set(SYNC_STATS.MAX_SECONDS_BETWEEN_STATE_MESSAGE_EMITTED_AND_COMMITTED, syncStats.getMaxSecondsBetweenStateMessageEmittedandCommitted()) + .set(SYNC_STATS.MEAN_SECONDS_BETWEEN_STATE_MESSAGE_EMITTED_AND_COMMITTED, syncStats.getMeanSecondsBetweenStateMessageEmittedandCommitted()) + .execute(); + } + @Override public void writeAttemptFailureSummary(final long jobId, final int attemptNumber, final AttemptFailureSummary failureSummary) throws IOException { final OffsetDateTime now = OffsetDateTime.ofInstant(timeSupplier.get(), ZoneOffset.UTC); @@ -395,21 +396,34 @@ public void writeAttemptFailureSummary(final long jobId, final int attemptNumber } @Override - public List getSyncStats(final Long attemptId) throws IOException { + public List getSyncStats(final long jobId, final int attemptNumber) throws IOException { return jobDatabase - .query(ctx -> ctx.select(DSL.asterisk()).from(DSL.table("sync_stats")).where(SYNC_STATS.ATTEMPT_ID.eq(attemptId)) - .fetch(getSyncStatsRecordMapper()) - .stream() - .toList()); + .query(ctx -> { + final Long attemptId = getAttemptId(jobId, attemptNumber, ctx); + return ctx.select(DSL.asterisk()).from(DSL.table("sync_stats")).where(SYNC_STATS.ATTEMPT_ID.eq(attemptId)) + .fetch(getSyncStatsRecordMapper()) + .stream() + .toList(); + }); } @Override - public List getNormalizationSummary(final Long attemptId) throws IOException, JsonProcessingException { + public List getNormalizationSummary(final long jobId, final int attemptNumber) throws IOException { return jobDatabase - .query(ctx -> ctx.select(DSL.asterisk()).from(NORMALIZATION_SUMMARIES).where(NORMALIZATION_SUMMARIES.ATTEMPT_ID.eq(attemptId)) - .fetch(getNormalizationSummaryRecordMapper()) - .stream() - .toList()); + .query(ctx -> { + final Long attemptId = getAttemptId(jobId, attemptNumber, ctx); + return ctx.select(DSL.asterisk()).from(NORMALIZATION_SUMMARIES).where(NORMALIZATION_SUMMARIES.ATTEMPT_ID.eq(attemptId)) + .fetch(getNormalizationSummaryRecordMapper()) + .stream() + .toList(); + }); + } + + private static Long getAttemptId(final long jobId, final int attemptNumber, final DSLContext ctx) { + final Optional record = + ctx.fetch("SELECT id from attempts where job_id = ? AND attempt_number = ?", jobId, + attemptNumber).stream().findFirst(); + return record.get().get("id", Long.class); } private static RecordMapper getSyncStatsRecordMapper() { diff --git a/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/JobPersistence.java b/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/JobPersistence.java index e5b389cae2f4..91f3905ca6ca 100644 --- a/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/JobPersistence.java +++ b/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/JobPersistence.java @@ -29,14 +29,15 @@ import java.util.stream.Stream; /** - * TODO Introduce a locking mechanism so that no DB operation is allowed when automatic migration is - * running + * General interface methods for persistence to the Jobs database. This database is separate from + * the config database as job-related tables has an order of magnitude higher load and scale + * differently from the config tables. */ public interface JobPersistence { - List getSyncStats(Long attemptId) throws IOException; + List getSyncStats(long jobId, int attemptNumber) throws IOException; - List getNormalizationSummary(Long attemptId) throws IOException; + List getNormalizationSummary(long jobId, int attemptNumber) throws IOException; Job getJob(long jobId) throws IOException; diff --git a/airbyte-persistence/job-persistence/src/test/java/io/airbyte/persistence/job/DefaultJobPersistenceTest.java b/airbyte-persistence/job-persistence/src/test/java/io/airbyte/persistence/job/DefaultJobPersistenceTest.java index 06cdf5c4a2c5..b41c691fbbc8 100644 --- a/airbyte-persistence/job-persistence/src/test/java/io/airbyte/persistence/job/DefaultJobPersistenceTest.java +++ b/airbyte-persistence/job-persistence/src/test/java/io/airbyte/persistence/job/DefaultJobPersistenceTest.java @@ -257,7 +257,7 @@ void testCompleteAttemptSuccess() throws IOException { @Test @DisplayName("Should be able to read what is written") - void testWriteOutput() throws IOException, SQLException { + void testWriteOutput() throws IOException { final long jobId = jobPersistence.enqueueJob(SCOPE, SPEC_JOB_CONFIG).orElseThrow(); final int attemptNumber = jobPersistence.createAttempt(jobId, LOG_PATH); final Job created = jobPersistence.getJob(jobId); @@ -285,13 +285,7 @@ void testWriteOutput() throws IOException, SQLException { assertEquals(Optional.of(jobOutput), updated.getAttempts().get(0).getOutput()); assertNotEquals(created.getAttempts().get(0).getUpdatedAtInSecond(), updated.getAttempts().get(0).getUpdatedAtInSecond()); - final Optional record = - jobDatabase.query(ctx -> ctx.fetch("SELECT id from attempts where job_id = ? AND attempt_number = ?", jobId, - attemptNumber).stream().findFirst()); - - final Long attemptId = record.get().get("id", Long.class); - - final SyncStats storedSyncStats = jobPersistence.getSyncStats(attemptId).stream().findFirst().get(); + final SyncStats storedSyncStats = jobPersistence.getSyncStats(jobId, attemptNumber).stream().findFirst().get(); assertEquals(100L, storedSyncStats.getBytesEmitted()); assertEquals(9L, storedSyncStats.getRecordsEmitted()); assertEquals(10L, storedSyncStats.getRecordsCommitted()); @@ -302,7 +296,7 @@ void testWriteOutput() throws IOException, SQLException { assertEquals(10L, storedSyncStats.getMaxSecondsBetweenStateMessageEmittedandCommitted()); assertEquals(3L, storedSyncStats.getMeanSecondsBetweenStateMessageEmittedandCommitted()); - final NormalizationSummary storedNormalizationSummary = jobPersistence.getNormalizationSummary(attemptId).stream().findFirst().get(); + final NormalizationSummary storedNormalizationSummary = jobPersistence.getNormalizationSummary(jobId, attemptNumber).stream().findFirst().get(); assertEquals(10L, storedNormalizationSummary.getStartTime()); assertEquals(500L, storedNormalizationSummary.getEndTime()); assertEquals(List.of(failureReason1, failureReason2), storedNormalizationSummary.getFailures()); From baf6466a194bbe6981a012665bc3cb5011dcba34 Mon Sep 17 00:00:00 2001 From: Benoit Moriceau Date: Thu, 3 Nov 2022 14:46:52 -0700 Subject: [PATCH 31/73] Extract Operation API (#18928) * Extract Operation API * Format --- .../java/io/airbyte/server/ServerFactory.java | 7 +++ .../airbyte/server/apis/ConfigurationApi.java | 39 +++++++++--- .../server/apis/OperationApiController.java | 59 +++++++++++++++++++ .../apis/binders/OperationApiBinder.java | 21 +++++++ .../apis/factories/OperationApiFactory.java | 29 +++++++++ 5 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 airbyte-server/src/main/java/io/airbyte/server/apis/OperationApiController.java create mode 100644 airbyte-server/src/main/java/io/airbyte/server/apis/binders/OperationApiBinder.java create mode 100644 airbyte-server/src/main/java/io/airbyte/server/apis/factories/OperationApiFactory.java diff --git a/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java b/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java index bf7f3992e0d4..d4956d78e93d 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java +++ b/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java @@ -27,6 +27,7 @@ import io.airbyte.server.apis.LogsApiController; import io.airbyte.server.apis.NotificationsApiController; import io.airbyte.server.apis.OpenapiApiController; +import io.airbyte.server.apis.OperationApiController; import io.airbyte.server.apis.binders.AttemptApiBinder; import io.airbyte.server.apis.binders.ConnectionApiBinder; import io.airbyte.server.apis.binders.DbMigrationBinder; @@ -39,6 +40,7 @@ import io.airbyte.server.apis.binders.LogsApiBinder; import io.airbyte.server.apis.binders.NotificationApiBinder; import io.airbyte.server.apis.binders.OpenapiApiBinder; +import io.airbyte.server.apis.binders.OperationApiBinder; import io.airbyte.server.apis.binders.SourceOauthApiBinder; import io.airbyte.server.apis.factories.AttemptApiFactory; import io.airbyte.server.apis.factories.ConnectionApiFactory; @@ -52,6 +54,7 @@ import io.airbyte.server.apis.factories.LogsApiFactory; import io.airbyte.server.apis.factories.NotificationsApiFactory; import io.airbyte.server.apis.factories.OpenapiApiFactory; +import io.airbyte.server.apis.factories.OperationApiFactory; import io.airbyte.server.apis.factories.SourceOauthApiFactory; import io.airbyte.server.handlers.AttemptHandler; import io.airbyte.server.handlers.ConnectionsHandler; @@ -190,6 +193,8 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul NotificationsApiFactory.setValues(workspacesHandler); + OperationApiFactory.setValues(operationsHandler); + OpenapiApiFactory.setValues(openApiConfigHandler); // server configurations @@ -207,6 +212,7 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul LogsApiController.class, NotificationsApiController.class, OpenapiApiController.class, + OperationApiController.class, SourceOauthApiFactory.class); final Set components = Set.of( @@ -224,6 +230,7 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul new LogsApiBinder(), new NotificationApiBinder(), new OpenapiApiBinder(), + new OperationApiBinder(), new SourceOauthApiBinder()); // construct server diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java b/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java index aeaa7746b76d..40767b5720eb 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java @@ -835,14 +835,22 @@ public JobInfoRead resetConnection(final ConnectionIdRequestBody connectionIdReq // Operations + /** + * This implementation has been moved to {@link OperationApiController}. Since the path of + * {@link OperationApiController} is more granular, it will override this implementation + */ @Override public CheckOperationRead checkOperation(final OperatorConfiguration operatorConfiguration) { - return execute(() -> operationsHandler.checkOperation(operatorConfiguration)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link OperationApiController}. Since the path of + * {@link OperationApiController} is more granular, it will override this implementation + */ @Override public OperationRead createOperation(final OperationCreate operationCreate) { - return execute(() -> operationsHandler.createOperation(operationCreate)); + throw new NotImplementedException(); } @Override @@ -850,27 +858,40 @@ public ConnectionState createOrUpdateState(final ConnectionStateCreateOrUpdate c return ConfigurationApi.execute(() -> stateHandler.createOrUpdateState(connectionStateCreateOrUpdate)); } + /** + * This implementation has been moved to {@link OperationApiController}. Since the path of + * {@link OperationApiController} is more granular, it will override this implementation + */ @Override public void deleteOperation(final OperationIdRequestBody operationIdRequestBody) { - execute(() -> { - operationsHandler.deleteOperation(operationIdRequestBody); - return null; - }); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link OperationApiController}. Since the path of + * {@link OperationApiController} is more granular, it will override this implementation + */ @Override public OperationReadList listOperationsForConnection(final ConnectionIdRequestBody connectionIdRequestBody) { - return execute(() -> operationsHandler.listOperationsForConnection(connectionIdRequestBody)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link OperationApiController}. Since the path of + * {@link OperationApiController} is more granular, it will override this implementation + */ @Override public OperationRead getOperation(final OperationIdRequestBody operationIdRequestBody) { - return execute(() -> operationsHandler.getOperation(operationIdRequestBody)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link OperationApiController}. Since the path of + * {@link OperationApiController} is more granular, it will override this implementation + */ @Override public OperationRead updateOperation(final OperationUpdate operationUpdate) { - return execute(() -> operationsHandler.updateOperation(operationUpdate)); + throw new NotImplementedException(); } @Override diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/OperationApiController.java b/airbyte-server/src/main/java/io/airbyte/server/apis/OperationApiController.java new file mode 100644 index 000000000000..fb6f9b04b0f2 --- /dev/null +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/OperationApiController.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.server.apis; + +import io.airbyte.api.generated.OperationApi; +import io.airbyte.api.model.generated.CheckOperationRead; +import io.airbyte.api.model.generated.ConnectionIdRequestBody; +import io.airbyte.api.model.generated.OperationCreate; +import io.airbyte.api.model.generated.OperationIdRequestBody; +import io.airbyte.api.model.generated.OperationRead; +import io.airbyte.api.model.generated.OperationReadList; +import io.airbyte.api.model.generated.OperationUpdate; +import io.airbyte.api.model.generated.OperatorConfiguration; +import io.airbyte.server.handlers.OperationsHandler; +import javax.ws.rs.Path; +import lombok.AllArgsConstructor; + +@Path("/v1/operations") +@AllArgsConstructor +public class OperationApiController implements OperationApi { + + private final OperationsHandler operationsHandler; + + @Override + public CheckOperationRead checkOperation(final OperatorConfiguration operatorConfiguration) { + return ConfigurationApi.execute(() -> operationsHandler.checkOperation(operatorConfiguration)); + } + + @Override + public OperationRead createOperation(final OperationCreate operationCreate) { + return ConfigurationApi.execute(() -> operationsHandler.createOperation(operationCreate)); + } + + @Override + public void deleteOperation(final OperationIdRequestBody operationIdRequestBody) { + ConfigurationApi.execute(() -> { + operationsHandler.deleteOperation(operationIdRequestBody); + return null; + }); + } + + @Override + public OperationRead getOperation(final OperationIdRequestBody operationIdRequestBody) { + return ConfigurationApi.execute(() -> operationsHandler.getOperation(operationIdRequestBody)); + } + + @Override + public OperationReadList listOperationsForConnection(final ConnectionIdRequestBody connectionIdRequestBody) { + return ConfigurationApi.execute(() -> operationsHandler.listOperationsForConnection(connectionIdRequestBody)); + } + + @Override + public OperationRead updateOperation(final OperationUpdate operationUpdate) { + return ConfigurationApi.execute(() -> operationsHandler.updateOperation(operationUpdate)); + } + +} diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/binders/OperationApiBinder.java b/airbyte-server/src/main/java/io/airbyte/server/apis/binders/OperationApiBinder.java new file mode 100644 index 000000000000..52d55383aeca --- /dev/null +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/binders/OperationApiBinder.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.server.apis.binders; + +import io.airbyte.server.apis.OperationApiController; +import io.airbyte.server.apis.factories.OperationApiFactory; +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.process.internal.RequestScoped; + +public class OperationApiBinder extends AbstractBinder { + + @Override + protected void configure() { + bindFactory(OperationApiFactory.class) + .to(OperationApiController.class) + .in(RequestScoped.class); + } + +} diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/factories/OperationApiFactory.java b/airbyte-server/src/main/java/io/airbyte/server/apis/factories/OperationApiFactory.java new file mode 100644 index 000000000000..d74ad9138170 --- /dev/null +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/factories/OperationApiFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.server.apis.factories; + +import io.airbyte.server.apis.OperationApiController; +import io.airbyte.server.handlers.OperationsHandler; +import org.glassfish.hk2.api.Factory; + +public class OperationApiFactory implements Factory { + + private static OperationsHandler operationsHandler; + + public static void setValues(final OperationsHandler operationsHandler) { + OperationApiFactory.operationsHandler = operationsHandler; + } + + @Override + public OperationApiController provide() { + return new OperationApiController(OperationApiFactory.operationsHandler); + } + + @Override + public void dispose(final OperationApiController instance) { + /* no op */ + } + +} From 0109f5de8562acde3499f10e3259d9dde1b33851 Mon Sep 17 00:00:00 2001 From: "Pedro S. Lopez" Date: Thu, 3 Nov 2022 17:53:15 -0400 Subject: [PATCH 32/73] fix paths specification for oss catalog deploy action (#18940) --- .github/workflows/deploy-oss-catalog.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-oss-catalog.yml b/.github/workflows/deploy-oss-catalog.yml index dcaa9e7c8c86..c5be13bfdde6 100644 --- a/.github/workflows/deploy-oss-catalog.yml +++ b/.github/workflows/deploy-oss-catalog.yml @@ -5,7 +5,7 @@ on: branches: - master paths: - - airbyte-config/init/src/main/resources/seed + - airbyte-config/init/src/main/resources/seed/** workflow_dispatch: From c7f99359e0460fe2a380dfd15750c16fb268609a Mon Sep 17 00:00:00 2001 From: Jimmy Ma Date: Thu, 3 Nov 2022 15:28:57 -0700 Subject: [PATCH 33/73] Revert "Remove cyclic dead code in ConfigPersistence" (#18939) * Revert "Remove unused interfaces (#18880)" This reverts commit bf9cd2bf61eff61cf32cf7e47de7e4a507f55148. * Compat fix for code that has been extracted * Format --- .../config/persistence/ConfigPersistence.java | 6 ++ .../DatabaseConfigPersistence.java | 47 ++++++++++++++- .../persistence/StandardSyncPersistence.java | 12 +++- .../ValidatingConfigPersistence.java | 19 ++++++ ...baseConfigPersistenceE2EReadWriteTest.java | 5 +- .../DatabaseConfigPersistenceTest.java | 15 +++++ .../ValidatingConfigPersistenceTest.java | 58 ++++++++++++++++++- 7 files changed, 154 insertions(+), 8 deletions(-) diff --git a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigPersistence.java b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigPersistence.java index b5f0cab4fbae..abfdbe9b7136 100644 --- a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigPersistence.java +++ b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigPersistence.java @@ -5,6 +5,7 @@ package io.airbyte.config.persistence; import io.airbyte.config.AirbyteConfig; +import io.airbyte.config.ConfigWithMetadata; import io.airbyte.validation.json.JsonValidationException; import java.io.IOException; import java.util.List; @@ -20,6 +21,11 @@ public interface ConfigPersistence { List listConfigs(AirbyteConfig configType, Class clazz) throws JsonValidationException, IOException; + ConfigWithMetadata getConfigWithMetadata(AirbyteConfig configType, String configId, Class clazz) + throws ConfigNotFoundException, JsonValidationException, IOException; + + List> listConfigsWithMetadata(AirbyteConfig configType, Class clazz) throws JsonValidationException, IOException; + void writeConfig(AirbyteConfig configType, String configId, T config) throws JsonValidationException, IOException; void writeConfigs(AirbyteConfig configType, Map configs) throws IOException, JsonValidationException; diff --git a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/DatabaseConfigPersistence.java b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/DatabaseConfigPersistence.java index 0ff7a831dd4d..a7584600dfee 100644 --- a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/DatabaseConfigPersistence.java +++ b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/DatabaseConfigPersistence.java @@ -221,6 +221,14 @@ private void validate(final String configId, final List ConfigWithMetadata validateAndReturn(final String configId, + final List> result, + final AirbyteConfig airbyteConfig) + throws ConfigNotFoundException { + validate(configId, result, airbyteConfig); + return result.get(0); + } + @Override public List listConfigs(final AirbyteConfig configType, final Class clazz) throws JsonValidationException, IOException { final List config = new ArrayList<>(); @@ -228,9 +236,42 @@ public List listConfigs(final AirbyteConfig configType, final Class cl return config; } - // listConfigWithMetadata seems to be unused at this point. - // It is only called by listConfigs and it only reads the config. The "metadata" part seems to be - // unused. + @Override + public ConfigWithMetadata getConfigWithMetadata(final AirbyteConfig configType, final String configId, final Class clazz) + throws ConfigNotFoundException, JsonValidationException, IOException { + final Optional configIdOpt = Optional.of(UUID.fromString(configId)); + if (configType == ConfigSchema.STANDARD_WORKSPACE) { + return (ConfigWithMetadata) validateAndReturn(configId, listStandardWorkspaceWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.STANDARD_SOURCE_DEFINITION) { + return (ConfigWithMetadata) validateAndReturn(configId, listStandardSourceDefinitionWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.STANDARD_DESTINATION_DEFINITION) { + return (ConfigWithMetadata) validateAndReturn(configId, listStandardDestinationDefinitionWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.SOURCE_CONNECTION) { + return (ConfigWithMetadata) validateAndReturn(configId, listSourceConnectionWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.DESTINATION_CONNECTION) { + return (ConfigWithMetadata) validateAndReturn(configId, listDestinationConnectionWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.SOURCE_OAUTH_PARAM) { + return (ConfigWithMetadata) validateAndReturn(configId, listSourceOauthParamWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.DESTINATION_OAUTH_PARAM) { + return (ConfigWithMetadata) validateAndReturn(configId, listDestinationOauthParamWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.STANDARD_SYNC_OPERATION) { + return (ConfigWithMetadata) validateAndReturn(configId, listStandardSyncOperationWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.STANDARD_SYNC) { + throw buildUseStandardSyncPersistenceException(); + } else if (configType == ConfigSchema.STANDARD_SYNC_STATE) { + return (ConfigWithMetadata) validateAndReturn(configId, listStandardSyncStateWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.ACTOR_CATALOG) { + return (ConfigWithMetadata) validateAndReturn(configId, listActorCatalogWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.ACTOR_CATALOG_FETCH_EVENT) { + return (ConfigWithMetadata) validateAndReturn(configId, listActorCatalogFetchEventWithMetadata(configIdOpt), configType); + } else if (configType == ConfigSchema.WORKSPACE_SERVICE_ACCOUNT) { + return (ConfigWithMetadata) validateAndReturn(configId, listWorkspaceServiceAccountWithMetadata(configIdOpt), configType); + } else { + throw new IllegalArgumentException(UNKNOWN_CONFIG_TYPE + configType); + } + } + + @Override public List> listConfigsWithMetadata(final AirbyteConfig configType, final Class clazz) throws IOException { final List> configWithMetadata = new ArrayList<>(); if (configType == ConfigSchema.STANDARD_WORKSPACE) { diff --git a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/StandardSyncPersistence.java b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/StandardSyncPersistence.java index 4e39ead28753..56a74d6ec30d 100644 --- a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/StandardSyncPersistence.java +++ b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/StandardSyncPersistence.java @@ -39,6 +39,10 @@ public StandardSyncPersistence(final Database database) { } public StandardSync getStandardSync(final UUID connectionId) throws IOException, ConfigNotFoundException { + return getStandardSyncWithMetadata(connectionId).getConfig(); + } + + public ConfigWithMetadata getStandardSyncWithMetadata(final UUID connectionId) throws IOException, ConfigNotFoundException { final List> result = listStandardSyncWithMetadata(Optional.of(connectionId)); final boolean foundMoreThanOneConfig = result.size() > 1; @@ -47,11 +51,15 @@ public StandardSync getStandardSync(final UUID connectionId) throws IOException, } else if (foundMoreThanOneConfig) { throw new IllegalStateException(String.format("Multiple %s configs found for ID %s: %s", ConfigSchema.STANDARD_SYNC, connectionId, result)); } - return result.get(0).getConfig(); + return result.get(0); } public List listStandardSync() throws IOException { - return listStandardSyncWithMetadata(Optional.empty()).stream().map(ConfigWithMetadata::getConfig).toList(); + return listStandardSyncWithMetadata().stream().map(ConfigWithMetadata::getConfig).toList(); + } + + public List> listStandardSyncWithMetadata() throws IOException { + return listStandardSyncWithMetadata(Optional.empty()); } public void writeStandardSync(final StandardSync standardSync) throws IOException { diff --git a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ValidatingConfigPersistence.java b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ValidatingConfigPersistence.java index 4cd3aa2e2551..c29e15dbb453 100644 --- a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ValidatingConfigPersistence.java +++ b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ValidatingConfigPersistence.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.JsonNode; import io.airbyte.commons.json.Jsons; import io.airbyte.config.AirbyteConfig; +import io.airbyte.config.ConfigWithMetadata; import io.airbyte.validation.json.JsonSchemaValidator; import io.airbyte.validation.json.JsonValidationException; import java.io.IOException; @@ -50,6 +51,24 @@ public List listConfigs(final AirbyteConfig configType, final Class cl return configs; } + @Override + public ConfigWithMetadata getConfigWithMetadata(final AirbyteConfig configType, final String configId, final Class clazz) + throws ConfigNotFoundException, JsonValidationException, IOException { + final ConfigWithMetadata config = decoratedPersistence.getConfigWithMetadata(configType, configId, clazz); + validateJson(config.getConfig(), configType); + return config; + } + + @Override + public List> listConfigsWithMetadata(final AirbyteConfig configType, final Class clazz) + throws JsonValidationException, IOException { + final List> configs = decoratedPersistence.listConfigsWithMetadata(configType, clazz); + for (final ConfigWithMetadata config : configs) { + validateJson(config.getConfig(), configType); + } + return configs; + } + @Override public void writeConfig(final AirbyteConfig configType, final String configId, final T config) throws JsonValidationException, IOException { diff --git a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceE2EReadWriteTest.java b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceE2EReadWriteTest.java index b8d1e383a732..799ce1e4b4d3 100644 --- a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceE2EReadWriteTest.java +++ b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceE2EReadWriteTest.java @@ -88,12 +88,15 @@ void test() throws JsonValidationException, IOException, ConfigNotFoundException } private void checkSafeguards() { - final String anyString = ""; + final String anyString = "00000000-0000-0000-0000-000000000000"; // Making sure that the objects that have been migrated out of config persistence are protected with // an explicit error. assertThrows(NotImplementedException.class, () -> configPersistence.getConfig(ConfigSchema.STANDARD_SYNC, anyString, StandardSync.class)); + assertThrows(NotImplementedException.class, + () -> configPersistence.getConfigWithMetadata(ConfigSchema.STANDARD_SYNC, anyString, StandardSync.class)); assertThrows(NotImplementedException.class, () -> configPersistence.listConfigs(ConfigSchema.STANDARD_SYNC, StandardSync.class)); + assertThrows(NotImplementedException.class, () -> configPersistence.listConfigsWithMetadata(ConfigSchema.STANDARD_SYNC, StandardSync.class)); assertThrows(NotImplementedException.class, () -> configPersistence.writeConfig(ConfigSchema.STANDARD_SYNC, anyString, MockData.standardSyncs().get(0))); assertThrows(NotImplementedException.class, diff --git a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceTest.java b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceTest.java index 1deefbdb2880..177b79441871 100644 --- a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceTest.java +++ b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/DatabaseConfigPersistenceTest.java @@ -96,6 +96,21 @@ void testWriteAndGetConfig() throws Exception { .hasSameElementsAs(List.of(DESTINATION_SNOWFLAKE, DESTINATION_S3)); } + @Test + void testGetConfigWithMetadata() throws Exception { + final Instant now = Instant.now().minus(Duration.ofSeconds(1)); + writeDestination(configPersistence, DESTINATION_S3); + final ConfigWithMetadata configWithMetadata = configPersistence.getConfigWithMetadata( + STANDARD_DESTINATION_DEFINITION, + DESTINATION_S3.getDestinationDefinitionId().toString(), + StandardDestinationDefinition.class); + assertEquals("STANDARD_DESTINATION_DEFINITION", configWithMetadata.getConfigType()); + assertTrue(configWithMetadata.getCreatedAt().isAfter(now)); + assertTrue(configWithMetadata.getUpdatedAt().isAfter(now)); + assertEquals(DESTINATION_S3.getDestinationDefinitionId().toString(), configWithMetadata.getConfigId()); + assertEquals(DESTINATION_S3, configWithMetadata.getConfig()); + } + @Test void testListConfigWithMetadata() throws Exception { final Instant now = Instant.now().minus(Duration.ofSeconds(1)); diff --git a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ValidatingConfigPersistenceTest.java b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ValidatingConfigPersistenceTest.java index 2f8044222c7c..a07c5a808213 100644 --- a/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ValidatingConfigPersistenceTest.java +++ b/airbyte-config/config-persistence/src/test/java/io/airbyte/config/persistence/ValidatingConfigPersistenceTest.java @@ -15,6 +15,7 @@ import com.google.common.collect.Sets; import io.airbyte.config.ConfigSchema; +import io.airbyte.config.ConfigWithMetadata; import io.airbyte.config.StandardSourceDefinition; import io.airbyte.validation.json.JsonSchemaValidator; import io.airbyte.validation.json.JsonValidationException; @@ -47,14 +48,14 @@ class ValidatingConfigPersistenceTest { private JsonSchemaValidator schemaValidator; private ValidatingConfigPersistence configPersistence; - private DatabaseConfigPersistence decoratedConfigPersistence; + private ConfigPersistence decoratedConfigPersistence; private static final String ERROR_MESSAGE = "error"; @BeforeEach void setUp() { schemaValidator = mock(JsonSchemaValidator.class); - decoratedConfigPersistence = mock(DatabaseConfigPersistence.class); + decoratedConfigPersistence = mock(ConfigPersistence.class); configPersistence = new ValidatingConfigPersistence(decoratedConfigPersistence, schemaValidator); } @@ -143,4 +144,57 @@ void testListConfigsFailure() throws JsonValidationException, IOException { .listConfigs(ConfigSchema.STANDARD_SOURCE_DEFINITION, StandardSourceDefinition.class)); } + @Test + void testGetConfigWithMetadataSuccess() throws IOException, JsonValidationException, ConfigNotFoundException { + when(decoratedConfigPersistence.getConfigWithMetadata(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1.toString(), StandardSourceDefinition.class)) + .thenReturn(withMetadata(SOURCE_1)); + final ConfigWithMetadata actualConfig = configPersistence + .getConfigWithMetadata(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1.toString(), StandardSourceDefinition.class); + + assertEquals(withMetadata(SOURCE_1), actualConfig); + } + + @Test + void testGetConfigWithMetadataFailure() throws IOException, JsonValidationException, ConfigNotFoundException { + doThrow(new JsonValidationException(ERROR_MESSAGE)).when(schemaValidator).ensure(any(), any()); + when(decoratedConfigPersistence.getConfigWithMetadata(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1.toString(), StandardSourceDefinition.class)) + .thenReturn(withMetadata(SOURCE_1)); + + assertThrows( + JsonValidationException.class, + () -> configPersistence.getConfigWithMetadata(ConfigSchema.STANDARD_SOURCE_DEFINITION, UUID_1.toString(), StandardSourceDefinition.class)); + } + + @Test + void testListConfigsWithMetadataSuccess() throws JsonValidationException, IOException { + when(decoratedConfigPersistence.listConfigsWithMetadata(ConfigSchema.STANDARD_SOURCE_DEFINITION, StandardSourceDefinition.class)) + .thenReturn(List.of(withMetadata(SOURCE_1), withMetadata(SOURCE_2))); + + final List> actualConfigs = configPersistence + .listConfigsWithMetadata(ConfigSchema.STANDARD_SOURCE_DEFINITION, StandardSourceDefinition.class); + + // noinspection unchecked + assertEquals( + Sets.newHashSet(withMetadata(SOURCE_1), withMetadata(SOURCE_2)), + Sets.newHashSet(actualConfigs)); + } + + @Test + void testListConfigsWithMetadataFailure() throws JsonValidationException, IOException { + doThrow(new JsonValidationException(ERROR_MESSAGE)).when(schemaValidator).ensure(any(), any()); + when(decoratedConfigPersistence.listConfigsWithMetadata(ConfigSchema.STANDARD_SOURCE_DEFINITION, StandardSourceDefinition.class)) + .thenReturn(List.of(withMetadata(SOURCE_1), withMetadata(SOURCE_2))); + + assertThrows(JsonValidationException.class, () -> configPersistence + .listConfigsWithMetadata(ConfigSchema.STANDARD_SOURCE_DEFINITION, StandardSourceDefinition.class)); + } + + private static ConfigWithMetadata withMetadata(final StandardSourceDefinition sourceDef) { + return new ConfigWithMetadata<>(sourceDef.getSourceDefinitionId().toString(), + ConfigSchema.STANDARD_SOURCE_DEFINITION.name(), + INSTANT, + INSTANT, + sourceDef); + } + } From 4e905cabfd966dbf3369345b82cae2917683d4a2 Mon Sep 17 00:00:00 2001 From: Benoit Moriceau Date: Thu, 3 Nov 2022 15:43:55 -0700 Subject: [PATCH 34/73] Bmoric/extract scheduler api (#18941) * Extract Operation API * Extract scheduler API * Format --- .../java/io/airbyte/server/ServerFactory.java | 7 ++++ .../airbyte/server/apis/ConfigurationApi.java | 18 ++++++++-- .../server/apis/SchedulerApiController.java | 35 +++++++++++++++++++ .../apis/binders/SchedulerApiBinder.java | 21 +++++++++++ .../apis/factories/SchedulerApiFactory.java | 29 +++++++++++++++ 5 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 airbyte-server/src/main/java/io/airbyte/server/apis/SchedulerApiController.java create mode 100644 airbyte-server/src/main/java/io/airbyte/server/apis/binders/SchedulerApiBinder.java create mode 100644 airbyte-server/src/main/java/io/airbyte/server/apis/factories/SchedulerApiFactory.java diff --git a/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java b/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java index d4956d78e93d..e6fc1463c326 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java +++ b/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java @@ -28,6 +28,7 @@ import io.airbyte.server.apis.NotificationsApiController; import io.airbyte.server.apis.OpenapiApiController; import io.airbyte.server.apis.OperationApiController; +import io.airbyte.server.apis.SchedulerApiController; import io.airbyte.server.apis.binders.AttemptApiBinder; import io.airbyte.server.apis.binders.ConnectionApiBinder; import io.airbyte.server.apis.binders.DbMigrationBinder; @@ -41,6 +42,7 @@ import io.airbyte.server.apis.binders.NotificationApiBinder; import io.airbyte.server.apis.binders.OpenapiApiBinder; import io.airbyte.server.apis.binders.OperationApiBinder; +import io.airbyte.server.apis.binders.SchedulerApiBinder; import io.airbyte.server.apis.binders.SourceOauthApiBinder; import io.airbyte.server.apis.factories.AttemptApiFactory; import io.airbyte.server.apis.factories.ConnectionApiFactory; @@ -55,6 +57,7 @@ import io.airbyte.server.apis.factories.NotificationsApiFactory; import io.airbyte.server.apis.factories.OpenapiApiFactory; import io.airbyte.server.apis.factories.OperationApiFactory; +import io.airbyte.server.apis.factories.SchedulerApiFactory; import io.airbyte.server.apis.factories.SourceOauthApiFactory; import io.airbyte.server.handlers.AttemptHandler; import io.airbyte.server.handlers.ConnectionsHandler; @@ -197,6 +200,8 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul OpenapiApiFactory.setValues(openApiConfigHandler); + SchedulerApiFactory.setValues(schedulerHandler); + // server configurations final Set> componentClasses = Set.of( ConfigurationApi.class, @@ -213,6 +218,7 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul NotificationsApiController.class, OpenapiApiController.class, OperationApiController.class, + SchedulerApiController.class, SourceOauthApiFactory.class); final Set components = Set.of( @@ -231,6 +237,7 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul new NotificationApiBinder(), new OpenapiApiBinder(), new OperationApiBinder(), + new SchedulerApiBinder(), new SourceOauthApiBinder()); // construct server diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java b/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java index 40767b5720eb..e115d559cae2 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java @@ -900,19 +900,31 @@ public ConnectionState getState(final ConnectionIdRequestBody connectionIdReques } // SCHEDULER + /** + * This implementation has been moved to {@link SchedulerApiController}. Since the path of + * {@link SchedulerApiController} is more granular, it will override this implementation + */ @Override public CheckConnectionRead executeSourceCheckConnection(final SourceCoreConfig sourceConfig) { - return execute(() -> schedulerHandler.checkSourceConnectionFromSourceCreate(sourceConfig)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SchedulerApiController}. Since the path of + * {@link SchedulerApiController} is more granular, it will override this implementation + */ @Override public CheckConnectionRead executeDestinationCheckConnection(final DestinationCoreConfig destinationConfig) { - return execute(() -> schedulerHandler.checkDestinationConnectionFromDestinationCreate(destinationConfig)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SchedulerApiController}. Since the path of + * {@link SchedulerApiController} is more granular, it will override this implementation + */ @Override public SourceDiscoverSchemaRead executeSourceDiscoverSchema(final SourceCoreConfig sourceCreate) { - return execute(() -> schedulerHandler.discoverSchemaForSourceFromSourceCreate(sourceCreate)); + throw new NotImplementedException(); } /** diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/SchedulerApiController.java b/airbyte-server/src/main/java/io/airbyte/server/apis/SchedulerApiController.java new file mode 100644 index 000000000000..a3cd0baecbe1 --- /dev/null +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/SchedulerApiController.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.server.apis; + +import io.airbyte.api.generated.SchedulerApi; +import io.airbyte.api.model.generated.CheckConnectionRead; +import io.airbyte.api.model.generated.DestinationCoreConfig; +import io.airbyte.api.model.generated.SourceCoreConfig; +import io.airbyte.api.model.generated.SourceDiscoverSchemaRead; +import io.airbyte.server.handlers.SchedulerHandler; +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public class SchedulerApiController implements SchedulerApi { + + private final SchedulerHandler schedulerHandler; + + @Override + public CheckConnectionRead executeDestinationCheckConnection(final DestinationCoreConfig destinationCoreConfig) { + return ConfigurationApi.execute(() -> schedulerHandler.checkDestinationConnectionFromDestinationCreate(destinationCoreConfig)); + } + + @Override + public CheckConnectionRead executeSourceCheckConnection(final SourceCoreConfig sourceCoreConfig) { + return ConfigurationApi.execute(() -> schedulerHandler.checkSourceConnectionFromSourceCreate(sourceCoreConfig)); + } + + @Override + public SourceDiscoverSchemaRead executeSourceDiscoverSchema(final SourceCoreConfig sourceCoreConfig) { + return ConfigurationApi.execute(() -> schedulerHandler.discoverSchemaForSourceFromSourceCreate(sourceCoreConfig)); + } + +} diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/binders/SchedulerApiBinder.java b/airbyte-server/src/main/java/io/airbyte/server/apis/binders/SchedulerApiBinder.java new file mode 100644 index 000000000000..64a904193b90 --- /dev/null +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/binders/SchedulerApiBinder.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.server.apis.binders; + +import io.airbyte.server.apis.SchedulerApiController; +import io.airbyte.server.apis.factories.SchedulerApiFactory; +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.process.internal.RequestScoped; + +public class SchedulerApiBinder extends AbstractBinder { + + @Override + protected void configure() { + bindFactory(SchedulerApiFactory.class) + .to(SchedulerApiController.class) + .in(RequestScoped.class); + } + +} diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/factories/SchedulerApiFactory.java b/airbyte-server/src/main/java/io/airbyte/server/apis/factories/SchedulerApiFactory.java new file mode 100644 index 000000000000..7ba4cf9b9ff2 --- /dev/null +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/factories/SchedulerApiFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.server.apis.factories; + +import io.airbyte.server.apis.SchedulerApiController; +import io.airbyte.server.handlers.SchedulerHandler; +import org.glassfish.hk2.api.Factory; + +public class SchedulerApiFactory implements Factory { + + private static SchedulerHandler schedulerHandler; + + public static void setValues(final SchedulerHandler schedulerHandler) { + SchedulerApiFactory.schedulerHandler = schedulerHandler; + } + + @Override + public SchedulerApiController provide() { + return new SchedulerApiController(SchedulerApiFactory.schedulerHandler); + } + + @Override + public void dispose(final SchedulerApiController instance) { + /* no op */ + } + +} From 535e8da9e3670a9937b52201645b36cb3509f1af Mon Sep 17 00:00:00 2001 From: Lake Mossman Date: Thu, 3 Nov 2022 16:32:33 -0700 Subject: [PATCH 35/73] Connector builder test result display (#18533) * [SPIKE] add Builder page with editor * add YamlEditor component * export colors from CSS * move template into dedicated file * fix initial load from local storage * move download button into separate component * fix stylelint * remove console log * add todo * make monaco background transparent and apply gradient to parent div background * clarify comment * remove unnecessary 180deg * lock the builder UI behind a feature * use rgb instead of hex to fix stylelint * use _colors.scss and disable hex length stylelint rule * disable rule in file * generify ConnectorDocumentationLayout into TwoPanelLayout * use TwoPanelLayout for BuilderPage * add darker gradient color to _colors.scss and use in gradient * move /builder to /connector-builder * rename TwoPanelLayout to ResizablePanels * put gradient on parent container instead * make lightOverlay actually overlay instead of un-rendering children * add testing panel component and stream selector * fix rotated text * fix more styling * remove unnecessary comment * add starting flex to right panel * replace react-select dropdown with headless-ui listbox * add test controls and fix button icon styling * add Configure Test Input button and modal * add connector builder client * move connector builder state into dedicated context * fix bold prop in Text component to not throw error * pass parsed yaml->json into query * store config in connector builder state context * add result display * fix styles of result display * move config menu into testing panel * capitalize stream names * undo changes to Text component, since that is being addressed in a separate PR * fix more merge issues and fix generated schema usage * capitalize header * remove console log * rename data to streamRead * fix stylelint and use variables * use another variable for spacing * use stream name in state data object * add paginator component * save progress on result display * generify stream selector and add slice selector * add page display with tabs * fix scrolling and add logic to make mocking results easier * make mocks more unique * wire up slice selector to content shown * improve placeholder text style * add gap in page display * make controlled component and fix mocks * move tab titles into intl * fix typo * move placeholder into intl * update listbox and paginator to be more generic * clean up paginator styles * undo change to App.tsx * cleanup * use intl for slice label fallback * remove manifest and config from react-query keys to prevent losing results when editing yaml * switch to functional style for generic components --- airbyte-webapp/package-lock.json | 39 ++++++++ airbyte-webapp/package.json | 2 + .../PageDisplay.module.scss | 37 ++++++++ .../StreamTestingPanel/PageDisplay.tsx | 58 ++++++++++++ .../ResultDisplay.module.scss | 41 +++++---- .../StreamTestingPanel/ResultDisplay.tsx | 65 ++++++-------- .../SliceSelector.module.scss | 16 ++++ .../StreamTestingPanel/SliceSelector.tsx | 72 +++++++++++++++ .../StreamSelector.module.scss | 31 ------- .../StreamTestingPanel/StreamSelector.tsx | 58 ++++++------ .../StreamTestingPanel.module.scss | 20 +++++ .../StreamTestingPanel/StreamTestingPanel.tsx | 12 ++- .../StreamTestingPanel/TestControls.tsx | 6 +- .../components/ui/ListBox/ListBox.module.scss | 45 ++++++++++ .../src/components/ui/ListBox/ListBox.tsx | 67 ++++++++++++++ .../src/components/ui/ListBox/index.tsx | 1 + .../ui/Paginator/Paginator.module.scss | 56 ++++++++++++ .../src/components/ui/Paginator/Paginator.tsx | 45 ++++++++++ .../src/components/ui/Paginator/index.tsx | 1 + .../ConnectorBuilderRequestService.ts | 89 ++++++++++++------- airbyte-webapp/src/locales/en.json | 8 +- .../ConnectorBuilderApiService.ts | 13 ++- .../src/main/openapi/openapi.yaml | 8 +- 23 files changed, 630 insertions(+), 160 deletions(-) create mode 100644 airbyte-webapp/src/components/StreamTestingPanel/PageDisplay.module.scss create mode 100644 airbyte-webapp/src/components/StreamTestingPanel/PageDisplay.tsx create mode 100644 airbyte-webapp/src/components/StreamTestingPanel/SliceSelector.module.scss create mode 100644 airbyte-webapp/src/components/StreamTestingPanel/SliceSelector.tsx create mode 100644 airbyte-webapp/src/components/ui/ListBox/ListBox.module.scss create mode 100644 airbyte-webapp/src/components/ui/ListBox/ListBox.tsx create mode 100644 airbyte-webapp/src/components/ui/ListBox/index.tsx create mode 100644 airbyte-webapp/src/components/ui/Paginator/Paginator.module.scss create mode 100644 airbyte-webapp/src/components/ui/Paginator/Paginator.tsx create mode 100644 airbyte-webapp/src/components/ui/Paginator/index.tsx diff --git a/airbyte-webapp/package-lock.json b/airbyte-webapp/package-lock.json index 6536213ddd70..4b9bff7b1037 100644 --- a/airbyte-webapp/package-lock.json +++ b/airbyte-webapp/package-lock.json @@ -37,6 +37,7 @@ "react-intl": "^6.1.1", "react-lazylog": "^4.5.3", "react-markdown": "^7.0.1", + "react-paginate": "^8.1.3", "react-query": "^3.39.1", "react-reflex": "^4.0.9", "react-router-dom": "^6.3.0", @@ -83,6 +84,7 @@ "@types/react-dom": "^17.0.11", "@types/react-helmet": "^6.1.5", "@types/react-lazylog": "^4.5.1", + "@types/react-paginate": "^7.1.1", "@types/react-slick": "^0.23.10", "@types/react-table": "^7.7.12", "@types/react-widgets": "^4.4.7", @@ -14642,6 +14644,15 @@ "immutable": ">=3.8.2" } }, + "node_modules/@types/react-paginate": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/react-paginate/-/react-paginate-7.1.1.tgz", + "integrity": "sha512-94cEJHfBaINba2XGQOWFJF/tYe+AImIhOPqMCfqyeFOgk0qUpDZyDOOW76A1rgdtWndR8UwsMPgV/uuTM8vZ7w==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-slick": { "version": "0.23.10", "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.10.tgz", @@ -36562,6 +36573,17 @@ "react-dom": ">0.13.0" } }, + "node_modules/react-paginate": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/react-paginate/-/react-paginate-8.1.3.tgz", + "integrity": "sha512-zBp80DBRcaeBnAeHUfbGKD0XHfbGNUolQ+S60Ymfs8o7rusYaJYZMAt1j93ADDNLlzRmJ0tMF/NeTlcdKf7dlQ==", + "dependencies": { + "prop-types": "^15.6.1" + }, + "peerDependencies": { + "react": "^16 || ^17 || ^18" + } + }, "node_modules/react-query": { "version": "3.39.1", "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.1.tgz", @@ -58635,6 +58657,15 @@ "immutable": ">=3.8.2" } }, + "@types/react-paginate": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/react-paginate/-/react-paginate-7.1.1.tgz", + "integrity": "sha512-94cEJHfBaINba2XGQOWFJF/tYe+AImIhOPqMCfqyeFOgk0qUpDZyDOOW76A1rgdtWndR8UwsMPgV/uuTM8vZ7w==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-slick": { "version": "0.23.10", "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.10.tgz", @@ -75516,6 +75547,14 @@ "resize-observer-polyfill": "^1.5.0" } }, + "react-paginate": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/react-paginate/-/react-paginate-8.1.3.tgz", + "integrity": "sha512-zBp80DBRcaeBnAeHUfbGKD0XHfbGNUolQ+S60Ymfs8o7rusYaJYZMAt1j93ADDNLlzRmJ0tMF/NeTlcdKf7dlQ==", + "requires": { + "prop-types": "^15.6.1" + } + }, "react-query": { "version": "3.39.1", "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.1.tgz", diff --git a/airbyte-webapp/package.json b/airbyte-webapp/package.json index b72e1e333051..9c35073c5022 100644 --- a/airbyte-webapp/package.json +++ b/airbyte-webapp/package.json @@ -54,6 +54,7 @@ "react-intl": "^6.1.1", "react-lazylog": "^4.5.3", "react-markdown": "^7.0.1", + "react-paginate": "^8.1.3", "react-query": "^3.39.1", "react-reflex": "^4.0.9", "react-router-dom": "^6.3.0", @@ -100,6 +101,7 @@ "@types/react-dom": "^17.0.11", "@types/react-helmet": "^6.1.5", "@types/react-lazylog": "^4.5.1", + "@types/react-paginate": "^7.1.1", "@types/react-slick": "^0.23.10", "@types/react-table": "^7.7.12", "@types/react-widgets": "^4.4.7", diff --git a/airbyte-webapp/src/components/StreamTestingPanel/PageDisplay.module.scss b/airbyte-webapp/src/components/StreamTestingPanel/PageDisplay.module.scss new file mode 100644 index 000000000000..5964f623492d --- /dev/null +++ b/airbyte-webapp/src/components/StreamTestingPanel/PageDisplay.module.scss @@ -0,0 +1,37 @@ +@use "scss/variables"; +@use "scss/colors"; + +.tabList { + flex: 0 0 auto; + display: flex; +} + +.tab { + flex: 1; + background-color: transparent; + border: 0; +} + +.tabTitle { + border-bottom: variables.$border-thin solid colors.$grey-50; + color: colors.$grey-300; + font-weight: 500; + font-size: 10px; + cursor: pointer; + padding: 3px; +} + +.selected { + border-bottom-color: colors.$grey-300; + color: colors.$dark-blue; +} + +.tabPanelContainer { + flex: 1; + min-height: 0; +} + +.tabPanel { + max-height: 100%; + overflow-y: auto; +} diff --git a/airbyte-webapp/src/components/StreamTestingPanel/PageDisplay.tsx b/airbyte-webapp/src/components/StreamTestingPanel/PageDisplay.tsx new file mode 100644 index 000000000000..eba4c77e0aad --- /dev/null +++ b/airbyte-webapp/src/components/StreamTestingPanel/PageDisplay.tsx @@ -0,0 +1,58 @@ +import { Tab } from "@headlessui/react"; +import classNames from "classnames"; +import { useIntl } from "react-intl"; + +import { Text } from "components/ui/Text"; + +import { + HttpRequest, + HttpResponse, + StreamReadSlicesItemPagesItem, + StreamReadSlicesItemPagesItemRecordsItem, +} from "core/request/ConnectorBuilderClient"; + +import styles from "./PageDisplay.module.scss"; + +interface PageDisplayProps { + page: StreamReadSlicesItemPagesItem; + className?: string; +} + +interface TabData { + title: string; + content: StreamReadSlicesItemPagesItemRecordsItem[] | HttpRequest | HttpResponse; +} + +export const PageDisplay: React.FC = ({ page, className }) => { + const { formatMessage } = useIntl(); + const tabs: TabData[] = [{ title: formatMessage({ id: "connectorBuilder.recordsTab" }), content: page.records }]; + if (page.request) { + tabs.push({ title: formatMessage({ id: "connectorBuilder.requestTab" }), content: page.request }); + } + if (page.response) { + tabs.push({ title: formatMessage({ id: "connectorBuilder.responseTab" }), content: page.response }); + } + + return ( +
+ + + {tabs.map((tab) => ( + + {({ selected }) => ( + {tab.title} + )} + + ))} + + + {tabs.map((tab) => ( + +
{JSON.stringify(tab.content, null, 2)}
+
+ ))} +
+
+
+ ); +}; diff --git a/airbyte-webapp/src/components/StreamTestingPanel/ResultDisplay.module.scss b/airbyte-webapp/src/components/StreamTestingPanel/ResultDisplay.module.scss index 891f922f3245..585ac3abddb8 100644 --- a/airbyte-webapp/src/components/StreamTestingPanel/ResultDisplay.module.scss +++ b/airbyte-webapp/src/components/StreamTestingPanel/ResultDisplay.module.scss @@ -1,34 +1,37 @@ @use "scss/colors"; @use "scss/variables"; -.displayBox { - padding: variables.$spacing-md; - border-radius: variables.$border-radius-xs; - overflow-x: auto; -} - .container { display: flex; flex-direction: column; - gap: variables.$spacing-md; + gap: variables.$spacing-lg; } -.slice { - background-color: colors.$blue-200; +.sliceSelector { + flex: 0 0 auto; } -.page { - background-color: colors.$blue-100; -} - -.pageData { - background-color: colors.$blue-50; +.pageDisplay { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + gap: variables.$spacing-sm; } -.state { - background-color: colors.$orange-50; +.paginator { + display: flex; + gap: variables.$spacing-sm; + align-self: center; + justify-self: flex-end; + margin-top: auto; + margin-bottom: 0; + flex: 0 0 auto; } -.logs { - background-color: colors.$grey-200; +.pageLabel { + display: flex; + flex-direction: column; + justify-content: center; + font-size: 10px; } diff --git a/airbyte-webapp/src/components/StreamTestingPanel/ResultDisplay.tsx b/airbyte-webapp/src/components/StreamTestingPanel/ResultDisplay.tsx index b66301e92b83..31fb6f68e710 100644 --- a/airbyte-webapp/src/components/StreamTestingPanel/ResultDisplay.tsx +++ b/airbyte-webapp/src/components/StreamTestingPanel/ResultDisplay.tsx @@ -1,52 +1,45 @@ import classNames from "classnames"; +import { useState } from "react"; +import { Paginator } from "components/ui/Paginator"; import { Text } from "components/ui/Text"; import { StreamRead } from "core/request/ConnectorBuilderClient"; +import { PageDisplay } from "./PageDisplay"; import styles from "./ResultDisplay.module.scss"; +import { SliceSelector } from "./SliceSelector"; interface ResultDisplayProps { streamRead: StreamRead; + className?: string; } -export const ResultDisplay: React.FC = ({ streamRead }) => { +export const ResultDisplay: React.FC = ({ streamRead, className }) => { + const [selectedSliceIndex, setSelectedSliceIndex] = useState(0); + const [selectedPage, setSelectedPage] = useState(0); + + const handlePageChange = (selectedPageIndex: number) => { + setSelectedPage(selectedPageIndex); + }; + + const slice = streamRead.slices[selectedSliceIndex]; + const numPages = slice.pages.length; + const page = slice.pages[selectedPage]; + return ( -
- {streamRead.slices.map((slice) => ( -
- Slice {JSON.stringify(slice.sliceDescriptor)} - {slice.pages.map((page, pageNumber) => ( -
- Page {pageNumber} -
- Request: -
{JSON.stringify(page.request, null, 2)}
-
-
- Response: -
{JSON.stringify(page.response, null, 2)}
-
-
- Records: -
{JSON.stringify(page.records, null, 2)}
-
-
- ))} - {slice.state && ( -
- State: -
{JSON.stringify(slice.state, null, 2)}
-
- )} -
- ))} - {streamRead.logs.length > 0 && ( -
- Logs: -
{JSON.stringify(streamRead.logs, null, 2)}
-
- )} +
+ + +
+ Page: + +
); }; diff --git a/airbyte-webapp/src/components/StreamTestingPanel/SliceSelector.module.scss b/airbyte-webapp/src/components/StreamTestingPanel/SliceSelector.module.scss new file mode 100644 index 000000000000..6df588b61b01 --- /dev/null +++ b/airbyte-webapp/src/components/StreamTestingPanel/SliceSelector.module.scss @@ -0,0 +1,16 @@ +@use "scss/variables"; +@use "scss/colors"; + +.button { + padding: variables.$spacing-sm variables.$spacing-md; + background-color: transparent; + border: variables.$border-thin solid colors.$dark-blue; + border-radius: variables.$border-radius-xs; + display: flex; + align-items: center; +} + +.arrow { + margin-left: auto; + font-size: 10px; +} diff --git a/airbyte-webapp/src/components/StreamTestingPanel/SliceSelector.tsx b/airbyte-webapp/src/components/StreamTestingPanel/SliceSelector.tsx new file mode 100644 index 000000000000..666fa05fbed6 --- /dev/null +++ b/airbyte-webapp/src/components/StreamTestingPanel/SliceSelector.tsx @@ -0,0 +1,72 @@ +import { faAngleDown } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useCallback, useMemo } from "react"; +import { useIntl } from "react-intl"; + +import { ListBox, ListBoxControlButtonProps } from "components/ui/ListBox"; +import { Text } from "components/ui/Text"; + +import { StreamReadSlicesItem } from "core/request/ConnectorBuilderClient"; + +import styles from "./SliceSelector.module.scss"; + +interface SliceSelectorProps { + className?: string; + slices: StreamReadSlicesItem[]; + selectedSliceIndex: number; + onSelect: (sliceIndex: number) => void; +} + +const ControlButton: React.FC> = ({ selectedOption }) => { + return ( + <> + {selectedOption.label} + + + ); +}; + +export const SliceSelector: React.FC = ({ className, slices, selectedSliceIndex, onSelect }) => { + const { formatMessage } = useIntl(); + + const getSliceLabel = useCallback( + (slice: StreamReadSlicesItem, sliceIndex: number) => { + const fallback = `${formatMessage({ id: "connectorBuilder.sliceLabel" })} ${sliceIndex}`; + + const sliceDescriptor = slice.sliceDescriptor; + + if (!sliceDescriptor) { + return fallback; + } + + const listItem = sliceDescriptor.listItem; + const startDatetime = sliceDescriptor.startDatetime; + + if (!listItem && !startDatetime) { + return fallback; + } + + return [listItem, startDatetime].filter(Boolean).join(" | "); + }, + [formatMessage] + ); + + const options = useMemo( + () => + slices.map((slice, index) => { + return { label: getSliceLabel(slice, index), value: index }; + }), + [slices, getSliceLabel] + ); + + return ( + onSelect(selected)} + buttonClassName={styles.button} + controlButton={ControlButton} + /> + ); +}; diff --git a/airbyte-webapp/src/components/StreamTestingPanel/StreamSelector.module.scss b/airbyte-webapp/src/components/StreamTestingPanel/StreamSelector.module.scss index 0fc013f4b68b..7515993a37d2 100644 --- a/airbyte-webapp/src/components/StreamTestingPanel/StreamSelector.module.scss +++ b/airbyte-webapp/src/components/StreamTestingPanel/StreamSelector.module.scss @@ -13,7 +13,6 @@ background-color: transparent; border-radius: variables.$border-radius-md; border: none; - cursor: pointer; display: flex; justify-content: center; } @@ -23,33 +22,3 @@ margin-top: -1px; color: colors.$blue; } - -.optionsMenu { - background-color: colors.$white; - border-radius: variables.$border-radius-md; - box-shadow: 0 7px 15px -5px colors.$grey; - padding: variables.$spacing-md; - margin-top: 0; - margin-bottom: 0; - position: absolute; - right: 0; - left: 0; -} - -.option { - list-style-type: none; -} - -.optionValue { - padding: variables.$spacing-lg variables.$spacing-md; - border-radius: variables.$border-radius-md; - cursor: pointer; -} - -.active { - background-color: colors.$grey-100; -} - -.capitalized { - text-transform: capitalize; -} diff --git a/airbyte-webapp/src/components/StreamTestingPanel/StreamSelector.tsx b/airbyte-webapp/src/components/StreamTestingPanel/StreamSelector.tsx index 578d29940b2d..badc4d6ed5e4 100644 --- a/airbyte-webapp/src/components/StreamTestingPanel/StreamSelector.tsx +++ b/airbyte-webapp/src/components/StreamTestingPanel/StreamSelector.tsx @@ -1,42 +1,44 @@ import { faSortDown } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Listbox } from "@headlessui/react"; import classNames from "classnames"; +import { capitalize } from "lodash"; -import { Text } from "components/ui/Text"; +import { Heading } from "components/ui/Heading"; +import { ListBox, ListBoxControlButtonProps } from "components/ui/ListBox"; import { useConnectorBuilderState } from "services/connectorBuilder/ConnectorBuilderStateService"; -import { Heading } from "../ui/Heading"; import styles from "./StreamSelector.module.scss"; -export const StreamSelector: React.FC = () => { +interface StreamSelectorProps { + className?: string; +} + +const ControlButton: React.FC> = ({ selectedOption }) => { + return ( + <> + + {selectedOption.label} + + + + ); +}; + +export const StreamSelector: React.FC = ({ className }) => { const { streams, selectedStream, setSelectedStream } = useConnectorBuilderState(); + const options = streams.map((stream) => { + return { label: capitalize(stream.name), value: stream.name }; + }); return ( - - - - {selectedStream.name} - - - - {/* wrap in div to make `position: absolute` on Listbox.Options result in correct vertical positioning */} -
- - {streams.map(({ name: streamName }) => ( - - {({ active }) => ( -
- - {streamName} - -
- )} -
- ))} -
-
-
+ ); }; diff --git a/airbyte-webapp/src/components/StreamTestingPanel/StreamTestingPanel.module.scss b/airbyte-webapp/src/components/StreamTestingPanel/StreamTestingPanel.module.scss index a65ff7f01c86..34d1abcff149 100644 --- a/airbyte-webapp/src/components/StreamTestingPanel/StreamTestingPanel.module.scss +++ b/airbyte-webapp/src/components/StreamTestingPanel/StreamTestingPanel.module.scss @@ -4,4 +4,24 @@ padding: variables.$spacing-xl; display: flex; flex-direction: column; + height: 100%; + gap: variables.$spacing-xl; +} + +.streamSelector { + flex: 0 0 auto; +} + +.testControls { + flex: 0 0 auto; +} + +.resultDisplay { + flex: 1; + min-height: 0; +} + +.placeholder { + margin-left: auto; + margin-right: auto; } diff --git a/airbyte-webapp/src/components/StreamTestingPanel/StreamTestingPanel.tsx b/airbyte-webapp/src/components/StreamTestingPanel/StreamTestingPanel.tsx index 05b676314b7d..2169d0cbdc92 100644 --- a/airbyte-webapp/src/components/StreamTestingPanel/StreamTestingPanel.tsx +++ b/airbyte-webapp/src/components/StreamTestingPanel/StreamTestingPanel.tsx @@ -1,3 +1,5 @@ +import { useIntl } from "react-intl"; + import { useReadStream } from "services/connectorBuilder/ConnectorBuilderApiService"; import { useConnectorBuilderState } from "services/connectorBuilder/ConnectorBuilderStateService"; @@ -7,6 +9,7 @@ import styles from "./StreamTestingPanel.module.scss"; import { TestControls } from "./TestControls"; export const StreamTestingPanel: React.FC = () => { + const { formatMessage } = useIntl(); const { jsonManifest, selectedStream, configJson } = useConnectorBuilderState(); const { data: streamReadData, refetch: readStream } = useReadStream({ manifest: jsonManifest, @@ -16,13 +19,18 @@ export const StreamTestingPanel: React.FC = () => { return (
- + { readStream(); }} /> - {streamReadData && } + {streamReadData && streamReadData.slices.length !== 0 ? ( + + ) : ( +
{formatMessage({ id: "connectorBuilder.resultsPlaceholder" })}
+ )}
); }; diff --git a/airbyte-webapp/src/components/StreamTestingPanel/TestControls.tsx b/airbyte-webapp/src/components/StreamTestingPanel/TestControls.tsx index 50b764bbf674..a9eae2c29c4e 100644 --- a/airbyte-webapp/src/components/StreamTestingPanel/TestControls.tsx +++ b/airbyte-webapp/src/components/StreamTestingPanel/TestControls.tsx @@ -1,3 +1,4 @@ +import classNames from "classnames"; import { FormattedMessage } from "react-intl"; import { RotateIcon } from "components/icons/RotateIcon"; @@ -11,13 +12,14 @@ import styles from "./TestControls.module.scss"; interface TestControlsProps { onClickTest: () => void; + className?: string; } -export const TestControls: React.FC = ({ onClickTest }) => { +export const TestControls: React.FC = ({ onClickTest, className }) => { const { selectedStream } = useConnectorBuilderState(); return ( -
+
{selectedStream.url} diff --git a/airbyte-webapp/src/components/ui/ListBox/ListBox.module.scss b/airbyte-webapp/src/components/ui/ListBox/ListBox.module.scss new file mode 100644 index 000000000000..62ba6782ae7a --- /dev/null +++ b/airbyte-webapp/src/components/ui/ListBox/ListBox.module.scss @@ -0,0 +1,45 @@ +@use "scss/variables"; +@use "scss/colors"; + +.button { + width: 100%; + height: 100%; + cursor: pointer; +} + +.optionsContainer { + position: relative; +} + +.optionsMenu { + background-color: colors.$white; + border-radius: variables.$border-radius-md; + box-shadow: 0 7px 15px -5px colors.$grey; + padding: variables.$spacing-md; + margin-top: 0; + margin-bottom: 0; + position: absolute; + right: 0; + left: 0; + width: 100%; +} + +.option { + list-style-type: none; +} + +.optionValue { + padding: variables.$spacing-lg variables.$spacing-md; + border-radius: variables.$border-radius-md; + cursor: pointer; +} + +.active { + background-color: colors.$grey-50; + height: 100%; + width: 100%; +} + +.selected { + background-color: colors.$blue-50; +} diff --git a/airbyte-webapp/src/components/ui/ListBox/ListBox.tsx b/airbyte-webapp/src/components/ui/ListBox/ListBox.tsx new file mode 100644 index 000000000000..2addb2069c3f --- /dev/null +++ b/airbyte-webapp/src/components/ui/ListBox/ListBox.tsx @@ -0,0 +1,67 @@ +import { Listbox } from "@headlessui/react"; +import classNames from "classnames"; +import React from "react"; + +import styles from "./ListBox.module.scss"; + +export interface ListBoxControlButtonProps { + selectedOption: Option; +} + +const DefaultControlButton = ({ selectedOption }: ListBoxControlButtonProps) => { + return <>{selectedOption.label}; +}; + +export interface Option { + label: string; + value: T; +} + +interface ListBoxProps { + className?: string; + options: Array>; + selectedValue: T; + onSelect: (selectedValue: T) => void; + buttonClassName?: string; + controlButton?: React.ComponentType>; +} + +export const ListBox = ({ + className, + options, + selectedValue, + onSelect, + buttonClassName, + controlButton: ControlButton = DefaultControlButton, +}: ListBoxProps) => { + const selectedOption = options.find((option) => option.value === selectedValue) ?? { + label: String(selectedValue), + value: selectedValue, + }; + + return ( +
+ + + + + {/* wrap in div to make `position: absolute` on Listbox.Options result in correct vertical positioning */} +
+ + {options.map(({ label, value }) => ( + + {({ active, selected }) => ( +
+ {label} +
+ )} +
+ ))} +
+
+
+
+ ); +}; diff --git a/airbyte-webapp/src/components/ui/ListBox/index.tsx b/airbyte-webapp/src/components/ui/ListBox/index.tsx new file mode 100644 index 000000000000..de85b45a3a97 --- /dev/null +++ b/airbyte-webapp/src/components/ui/ListBox/index.tsx @@ -0,0 +1 @@ +export * from "./ListBox"; diff --git a/airbyte-webapp/src/components/ui/Paginator/Paginator.module.scss b/airbyte-webapp/src/components/ui/Paginator/Paginator.module.scss new file mode 100644 index 000000000000..623b0ce13f04 --- /dev/null +++ b/airbyte-webapp/src/components/ui/Paginator/Paginator.module.scss @@ -0,0 +1,56 @@ +@use "scss/colors"; +@use "scss/variables"; + +$containerHeight: 23px; + +.container { + padding: 0; + height: $containerHeight; + width: 80%; + display: flex; + gap: variables.$spacing-sm; + font-size: 10px; + margin: 0; +} + +.button { + list-style-type: none; + border-radius: variables.$border-radius-xs; + min-width: $containerHeight; + cursor: pointer; + + a { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + user-select: none; + } + + &:hover:not(.active) { + background-color: colors.$grey-100; + } +} + +.page { + justify-self: center; +} + +.previous { + justify-self: flex-start; + margin-left: 0; + margin-right: auto; +} + +.next { + justify-self: flex-end; + margin-right: 0; + margin-left: auto; +} + +.active { + background: colors.$dark-blue; + color: colors.$white; +} diff --git a/airbyte-webapp/src/components/ui/Paginator/Paginator.tsx b/airbyte-webapp/src/components/ui/Paginator/Paginator.tsx new file mode 100644 index 000000000000..6da26d04bc4f --- /dev/null +++ b/airbyte-webapp/src/components/ui/Paginator/Paginator.tsx @@ -0,0 +1,45 @@ +import classNames from "classnames"; +import ReactPaginate from "react-paginate"; + +import styles from "./Paginator.module.scss"; + +interface PaginatorProps { + className?: string; + numPages: number; + onPageChange: (selectedPageIndex: number) => void; + selectedPage: number; +} + +// this keeps the number of elements displayed constant regardless of which page is selected +function pageRangeDisplayed(numPages: number, selectedPageIndex: number): number { + if (selectedPageIndex === 0 || numPages - selectedPageIndex <= 3) { + return 6; + } else if (selectedPageIndex === 1 || selectedPageIndex === 2) { + return 5; + } else if (selectedPageIndex === 3 || numPages - selectedPageIndex === 4) { + return 4; + } + return 3; +} + +export const Paginator: React.FC = ({ className, numPages, onPageChange, selectedPage }) => { + return ( + { + onPageChange(event.selected); + }} + breakLabel="…" + nextLabel=">" + previousLabel="<" + pageRangeDisplayed={pageRangeDisplayed(numPages, selectedPage)} + marginPagesDisplayed={2} + containerClassName={classNames(className, styles.container)} + pageClassName={classNames(styles.button, styles.page)} + breakClassName={classNames(styles.button, styles.break)} + activeClassName={styles.active} + previousClassName={classNames(styles.button, styles.previous)} + nextClassName={classNames(styles.button, styles.next)} + /> + ); +}; diff --git a/airbyte-webapp/src/components/ui/Paginator/index.tsx b/airbyte-webapp/src/components/ui/Paginator/index.tsx new file mode 100644 index 000000000000..9705534bb66e --- /dev/null +++ b/airbyte-webapp/src/components/ui/Paginator/index.tsx @@ -0,0 +1 @@ +export * from "./Paginator"; diff --git a/airbyte-webapp/src/core/domain/connectorBuilder/ConnectorBuilderRequestService.ts b/airbyte-webapp/src/core/domain/connectorBuilder/ConnectorBuilderRequestService.ts index 1ac81e5dd9e0..5f151f6433f9 100644 --- a/airbyte-webapp/src/core/domain/connectorBuilder/ConnectorBuilderRequestService.ts +++ b/airbyte-webapp/src/core/domain/connectorBuilder/ConnectorBuilderRequestService.ts @@ -7,6 +7,61 @@ import { import { AirbyteRequestService } from "../../request/AirbyteRequestService"; +function mockRecord(streamName: string, recordNum: number, pageNum: number, sliceDay: number) { + return { + id: `day_${sliceDay}_page_${pageNum}_record_${recordNum}`, + object: streamName, + amount: recordNum * 1000, + }; +} + +function mockPage(streamName: string, pageNum: number, sliceDay: number, numRecords: number) { + const records = Array.from(Array(numRecords).keys()).map((i) => mockRecord(streamName, i, pageNum, sliceDay)); + + return { + records, + request: { + url: `https://api.com/${streamName}?page=${pageNum}`, + headers: { + Accept: "*/*", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en-US,en;q=0.9", + "Cache-Control": "no-cache", + Connection: "keep-alive", + }, + parameters: { + page: pageNum, + }, + }, + response: { + status: 200, + headers: { + "Content-Type": "application/json", + "Content-Length": "2626", + Connection: "keep-alive", + "cache-control": "no-cache, no-store", + }, + body: { + data: records, + }, + }, + }; +} + +function mockSlice(streamName: string, day: number, numPages: number, numRecords: number) { + const pages = Array.from(Array(numPages).keys()).map((i) => mockPage(streamName, i + 1, day, numRecords)); + + return { + sliceDescriptor: { startDatetime: `${day} Jan 2022`, listItem: "airbyte-cloud" }, + state: { + type: "STREAM", + stream: { stream_descriptor: { name: streamName }, stream_state: { date: `2022-01-0${day}` } }, + data: { [streamName]: { date: `2022-01-0${day}` } }, + }, + pages, + }; +} + export class ConnectorBuilderRequestService extends AirbyteRequestService { public readStream(readParams: StreamReadRequestBody): Promise { // TODO: uncomment this and remove mock responses once there is a real API to call @@ -16,42 +71,14 @@ export class ConnectorBuilderRequestService extends AirbyteRequestService { console.log(`Connector manifest:\n${JSON.stringify(readParams.manifest)}`); console.log(`Config:\n${JSON.stringify(readParams.config)}`); return new Promise((resolve) => setTimeout(resolve, 200)).then(() => { + const slices = Array.from(Array(4).keys()).map((i) => mockSlice(readParams.stream, i + 1, 20, 20)); + return { logs: [ { level: "INFO", message: `Syncing stream: ${readParams.stream}` }, { level: "INFO", message: `Setting state of ${readParams.stream} to {'date': '2022-09-25'}` }, ], - slices: [ - { - sliceDescriptor: { start: "Jan 1, 2022", end: "Jan 2, 2022" }, - state: { - type: "STREAM", - stream: { stream_descriptor: { name: readParams.stream }, stream_state: { date: "2022-09-26" } }, - data: { [readParams.stream]: { date: "2022-09-26" } }, - }, - pages: [ - { - records: [ - { - stream: readParams.stream, - data: { - id: "dp_123", - object: readParams.stream, - amount: 2000, - balance_transaction: "txn_123", - }, - }, - ], - request: { - url: `https://api.com/${readParams.stream}`, - }, - response: { - status: 200, - }, - }, - ], - }, - ], + slices, }; }); } diff --git a/airbyte-webapp/src/locales/en.json b/airbyte-webapp/src/locales/en.json index d3b783c79e52..ffccf2121070 100644 --- a/airbyte-webapp/src/locales/en.json +++ b/airbyte-webapp/src/locales/en.json @@ -583,8 +583,12 @@ "airbyte.datatype.boolean": "Boolean", "connectorBuilder.downloadYaml": "Download YAML", - "connectorBuilder.expandConfiguration": "Expand this pane to continue building your connector", "connectorBuilder.testButton": "Test", "connectorBuilder.configMenuTitle": "Configure Test Input", - "connectorBuilder.configMenuConfirm": "Confirm" + "connectorBuilder.configMenuConfirm": "Confirm", + "connectorBuilder.recordsTab": "Records", + "connectorBuilder.requestTab": "Request", + "connectorBuilder.responseTab": "Response", + "connectorBuilder.resultsPlaceholder": "Click Test to fetch data for this stream", + "connectorBuilder.sliceLabel": "Slice" } diff --git a/airbyte-webapp/src/services/connectorBuilder/ConnectorBuilderApiService.ts b/airbyte-webapp/src/services/connectorBuilder/ConnectorBuilderApiService.ts index c1fb27b0e745..0fcb91ce037e 100644 --- a/airbyte-webapp/src/services/connectorBuilder/ConnectorBuilderApiService.ts +++ b/airbyte-webapp/src/services/connectorBuilder/ConnectorBuilderApiService.ts @@ -4,7 +4,6 @@ import { useConfig } from "config"; import { ConnectorBuilderRequestService } from "core/domain/connectorBuilder/ConnectorBuilderRequestService"; import { StreamReadRequestBody, - StreamReadRequestBodyConfig, StreamReadRequestBodyManifest, StreamsListRequestBody, } from "core/request/ConnectorBuilderClient"; @@ -14,8 +13,7 @@ import { useInitService } from "services/useInitService"; const connectorBuilderKeys = { all: ["connectorBuilder"] as const, - read: (streamName: string, manifest: StreamReadRequestBodyManifest, config: StreamReadRequestBodyConfig) => - [...connectorBuilderKeys.all, "read", { streamName, manifest, config }] as const, + read: (streamName: string) => [...connectorBuilderKeys.all, "read", { streamName }] as const, list: (manifest: StreamReadRequestBodyManifest) => [...connectorBuilderKeys.all, "list", { manifest }] as const, }; @@ -31,11 +29,10 @@ function useConnectorBuilderService() { export const useReadStream = (params: StreamReadRequestBody) => { const service = useConnectorBuilderService(); - return useQuery( - connectorBuilderKeys.read(params.stream, params.manifest, params.config), - () => service.readStream(params), - { refetchOnWindowFocus: false, enabled: false } - ); + return useQuery(connectorBuilderKeys.read(params.stream), () => service.readStream(params), { + refetchOnWindowFocus: false, + enabled: false, + }); }; export const useListStreams = (params: StreamsListRequestBody) => { diff --git a/connector-builder-server/src/main/openapi/openapi.yaml b/connector-builder-server/src/main/openapi/openapi.yaml index 732621351fe3..d396c7a6a756 100644 --- a/connector-builder-server/src/main/openapi/openapi.yaml +++ b/connector-builder-server/src/main/openapi/openapi.yaml @@ -112,7 +112,13 @@ components: $ref: "#/components/schemas/HttpResponse" sliceDescriptor: type: object - description: 'An object describing the current slice, e.g. {start_time: "2021-01-01", end_time: "2021-01-31"}. This can be omitted if a stream slicer is not configured.' + description: "An object describing the current slice. This can be omitted if a stream slicer is not configured." + properties: + startDatetime: + type: string + format: date-time + listItem: + type: string state: type: object description: The STATE AirbyteMessage emitted at the end of this slice. This can be omitted if a stream slicer is not configured. From 838aebe32235312498f4a31ccaf563f620e59d22 Mon Sep 17 00:00:00 2001 From: Balasubramanian T K Date: Fri, 4 Nov 2022 06:44:39 +0530 Subject: [PATCH 36/73] =?UTF-8?q?=F0=9F=8E=89=20New=20Source:=20SpaceX=20A?= =?UTF-8?q?PI=20[low-code=20cdk]=20(#18311)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Init: New Source: SpaceX API * Chore: Removed duplicate and unwanted files * fix: Reconfigured schema and matched the read records. chore: Acceptance test run and results passed without errors * chore: Added documentation, updated airbyte docs specific to the connector * fix conflict * Chore: delete unwanted files * chore: Created bootstrap.md * chore: Update doc url, removed unwanted files * fix: Fixed schema after crosscheck with several schema validators * fix: resolved .vscode setting conflict, resolved merge conflict * feat: Added support for all endpoints * chore: updated documentation * feat: changes to stream path to accept options and id * fix: Resolve coomments * chore: resolved comments * chore: Delete unwanted files * chore: Update Readme.md after resolving merge conflict * update connector * add spacex api to source def * run format * add schemaloader * auto-bump connector version Co-authored-by: marcosmarxm Co-authored-by: Marcos Marx Co-authored-by: Octavia Squidington III --- .../resources/seed/source_definitions.yaml | 7 + .../src/main/resources/seed/source_specs.yaml | 21 ++ .../source-spacex-api/.dockerignore | 6 + .../connectors/source-spacex-api/Dockerfile | 38 +++ .../connectors/source-spacex-api/README.md | 103 ++++++ .../connectors/source-spacex-api/__init__.py | 3 + .../acceptance-test-config.yml | 20 ++ .../acceptance-test-docker.sh | 16 + .../connectors/source-spacex-api/bootstrap.md | 35 +++ .../connectors/source-spacex-api/build.gradle | 9 + .../integration_tests/__init__.py | 3 + .../integration_tests/abnormal_state.json | 5 + .../integration_tests/acceptance.py | 16 + .../integration_tests/configured_catalog.json | 112 +++++++ .../integration_tests/invalid_config.json | 4 + .../integration_tests/sample_config.json | 3 + .../integration_tests/sample_state.json | 5 + .../connectors/source-spacex-api/main.py | 13 + .../source-spacex-api/requirements.txt | 2 + .../connectors/source-spacex-api/setup.py | 29 ++ .../source_spacex_api/__init__.py | 8 + .../source_spacex_api/schemas/capsules.json | 40 +++ .../source_spacex_api/schemas/company.json | 88 ++++++ .../source_spacex_api/schemas/cores.json | 65 ++++ .../source_spacex_api/schemas/crew.json | 43 +++ .../source_spacex_api/schemas/dragons.json | 211 +++++++++++++ .../source_spacex_api/schemas/history.json | 42 +++ .../source_spacex_api/schemas/landpads.json | 44 +++ .../source_spacex_api/schemas/launches.json | 287 +++++++++++++++++ .../source_spacex_api/schemas/payloads.json | 162 ++++++++++ .../source_spacex_api/schemas/roadster.json | 97 ++++++ .../source_spacex_api/schemas/rockets.json | 292 ++++++++++++++++++ .../source_spacex_api/schemas/ships.json | 111 +++++++ .../source_spacex_api/schemas/starlink.json | 210 +++++++++++++ .../source_spacex_api/source.py | 18 ++ .../source_spacex_api/spacex_api.yaml | 147 +++++++++ .../source_spacex_api/spec.yaml | 15 + docs/integrations/sources/spacex-api.md | 75 +++++ 38 files changed, 2405 insertions(+) create mode 100644 airbyte-integrations/connectors/source-spacex-api/.dockerignore create mode 100644 airbyte-integrations/connectors/source-spacex-api/Dockerfile create mode 100644 airbyte-integrations/connectors/source-spacex-api/README.md create mode 100644 airbyte-integrations/connectors/source-spacex-api/__init__.py create mode 100644 airbyte-integrations/connectors/source-spacex-api/acceptance-test-config.yml create mode 100644 airbyte-integrations/connectors/source-spacex-api/acceptance-test-docker.sh create mode 100644 airbyte-integrations/connectors/source-spacex-api/bootstrap.md create mode 100644 airbyte-integrations/connectors/source-spacex-api/build.gradle create mode 100644 airbyte-integrations/connectors/source-spacex-api/integration_tests/__init__.py create mode 100644 airbyte-integrations/connectors/source-spacex-api/integration_tests/abnormal_state.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/integration_tests/acceptance.py create mode 100644 airbyte-integrations/connectors/source-spacex-api/integration_tests/configured_catalog.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/integration_tests/invalid_config.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/integration_tests/sample_config.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/integration_tests/sample_state.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/main.py create mode 100644 airbyte-integrations/connectors/source-spacex-api/requirements.txt create mode 100644 airbyte-integrations/connectors/source-spacex-api/setup.py create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/__init__.py create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/capsules.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/company.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/cores.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/crew.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/dragons.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/history.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/landpads.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/launches.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/payloads.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/roadster.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/rockets.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/ships.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/starlink.json create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/source.py create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/spacex_api.yaml create mode 100644 airbyte-integrations/connectors/source-spacex-api/source_spacex_api/spec.yaml create mode 100644 docs/integrations/sources/spacex-api.md diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index ae7b00a4fd97..077e92f16f80 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -1184,6 +1184,13 @@ documentationUrl: https://docs.airbyte.com/integrations/sources/sonar-cloud sourceType: api releaseStage: alpha +- name: SpaceX API + sourceDefinitionId: 62235e65-af7a-4138-9130-0bda954eb6a8 + dockerRepository: airbyte/source-spacex-api + dockerImageTag: 0.1.0 + documentationUrl: https://docs.airbyte.com/integrations/sources/spacex-api + sourceType: api + releaseStage: alpha - name: Square sourceDefinitionId: 77225a51-cd15-4a13-af02-65816bd0ecf4 dockerRepository: airbyte/source-square diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 552e4e2f380b..da22c26eceff 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -11774,6 +11774,27 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] +- dockerImage: "airbyte/source-spacex-api:0.1.0" + spec: + documentationUrl: "https://docs.airbyte.com/integrations/sources/spacex-api" + connectionSpecification: + $schema: "http://json-schema.org/draft-07/schema#" + title: "Spacex Api Spec" + type: "object" + additionalProperties: true + properties: + id: + title: "Unique ID for specific source target" + type: "string" + desciption: "Optional, For a specific ID" + options: + title: "Configuration options for endpoints" + type: "string" + desciption: "Optional, Possible values for an endpoint. Example values for\ + \ launches-latest, upcoming, past" + supportsNormalization: false + supportsDBT: false + supported_destination_sync_modes: [] - dockerImage: "airbyte/source-square:0.1.4" spec: documentationUrl: "https://docs.airbyte.com/integrations/sources/square" diff --git a/airbyte-integrations/connectors/source-spacex-api/.dockerignore b/airbyte-integrations/connectors/source-spacex-api/.dockerignore new file mode 100644 index 000000000000..2b730161e62c --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/.dockerignore @@ -0,0 +1,6 @@ +* +!Dockerfile +!main.py +!source_spacex_api +!setup.py +!secrets diff --git a/airbyte-integrations/connectors/source-spacex-api/Dockerfile b/airbyte-integrations/connectors/source-spacex-api/Dockerfile new file mode 100644 index 000000000000..15e9c34652c0 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/Dockerfile @@ -0,0 +1,38 @@ +FROM python:3.9.11-alpine3.15 as base + +# build and load all requirements +FROM base as builder +WORKDIR /airbyte/integration_code + +# upgrade pip to the latest version +RUN apk --no-cache upgrade \ + && pip install --upgrade pip \ + && apk --no-cache add tzdata build-base + + +COPY setup.py ./ +# install necessary packages to a temporary folder +RUN pip install --prefix=/install . + +# build a clean environment +FROM base +WORKDIR /airbyte/integration_code + +# copy all loaded and built libraries to a pure basic image +COPY --from=builder /install /usr/local +# add default timezone settings +COPY --from=builder /usr/share/zoneinfo/Etc/UTC /etc/localtime +RUN echo "Etc/UTC" > /etc/timezone + +# bash is installed for more convenient debugging. +RUN apk --no-cache add bash + +# copy payload code only +COPY main.py ./ +COPY source_spacex_api ./source_spacex_api + +ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" +ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] + +LABEL io.airbyte.version=0.1.0 +LABEL io.airbyte.name=airbyte/source-spacex-api diff --git a/airbyte-integrations/connectors/source-spacex-api/README.md b/airbyte-integrations/connectors/source-spacex-api/README.md new file mode 100644 index 000000000000..3cdce9f5bcd8 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/README.md @@ -0,0 +1,103 @@ +# Spacex Api Source + +This is the repository for the Spacex Api configuration based source connector. +For information about how to use this connector within Airbyte, see [the documentation](https://docs.airbyte.io/integrations/sources/spacex-api). + +## Local development + +### Prerequisites +**To iterate on this connector, make sure to complete this prerequisites section.** + +#### Minimum Python version required `= 3.9.0` + +#### Build & Activate Virtual Environment and install dependencies +From this connector directory, create a virtual environment: +``` +python -m venv .venv +``` + +This will generate a virtualenv for this module in `.venv/`. Make sure this venv is active in your +development environment of choice. To activate it from the terminal, run: +``` +source .venv/bin/activate +pip install -r requirements.txt +``` +If you are in an IDE, follow your IDE's instructions to activate the virtualenv. + +Note that while we are installing dependencies from `requirements.txt`, you should only edit `setup.py` for your dependencies. `requirements.txt` is +used for editable installs (`pip install -e`) to pull in Python dependencies from the monorepo and will call `setup.py`. +If this is mumbo jumbo to you, don't worry about it, just put your deps in `setup.py` but install using `pip install -r requirements.txt` and everything +should work as you expect. + +#### Building via Gradle +You can also build the connector in Gradle. This is typically used in CI and not needed for your development workflow. + +To build using Gradle, from the Airbyte repository root, run: +``` +./gradlew :airbyte-integrations:connectors:source-spacex-api:build +``` + +#### Create credentials +**If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.io/integrations/sources/spacex-api) +to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `source_spacex_api/spec.yaml` file. +Note that any directory named `secrets` is gitignored across the entire Airbyte repo, so there is no danger of accidentally checking in sensitive information. +See `integration_tests/sample_config.json` for a sample config file. + +**If you are an Airbyte core member**, copy the credentials in Lastpass under the secret name `source spacex-api test creds` +and place them into `secrets/config.json`. + +### Locally running the connector docker image + +#### Build +First, make sure you build the latest Docker image: +``` +docker build . -t airbyte/source-spacex-api:dev +``` + +You can also build the connector image via Gradle: +``` +./gradlew :airbyte-integrations:connectors:source-spacex-api:airbyteDocker +``` +When building via Gradle, the docker image name and tag, respectively, are the values of the `io.airbyte.name` and `io.airbyte.version` `LABEL`s in +the Dockerfile. + +#### Run +Then run any of the connector commands as follows: +``` +docker run --rm airbyte/source-spacex-api:dev spec +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-spacex-api:dev check --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-spacex-api:dev discover --config /secrets/config.json +docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/source-spacex-api:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json +``` +## Testing + +#### Acceptance Tests +Customize `acceptance-test-config.yml` file to configure tests. See [Source Acceptance Tests](https://docs.airbyte.io/connector-development/testing-connectors/source-acceptance-tests-reference) for more information. +If your connector requires to create or destroy resources for use during acceptance tests create fixtures for it and place them inside integration_tests/acceptance.py. + +To run your integration tests with docker + +### Using gradle to run tests +All commands should be run from airbyte project root. +To run unit tests: +``` +./gradlew :airbyte-integrations:connectors:source-spacex-api:unitTest +``` +To run acceptance and custom integration tests: +``` +./gradlew :airbyte-integrations:connectors:source-spacex-api:integrationTest +``` + +## Dependency Management +All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development. +We split dependencies between two groups, dependencies that are: +* required for your connector to work need to go to `MAIN_REQUIREMENTS` list. +* required for the testing need to go to `TEST_REQUIREMENTS` list + +### Publishing a new version of the connector +You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what? +1. Make sure your changes are passing unit and integration tests. +1. Bump the connector version in `Dockerfile` -- just increment the value of the `LABEL io.airbyte.version` appropriately (we use [SemVer](https://semver.org/)). +1. Create a Pull Request. +1. Pat yourself on the back for being an awesome contributor. +1. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master. diff --git a/airbyte-integrations/connectors/source-spacex-api/__init__.py b/airbyte-integrations/connectors/source-spacex-api/__init__.py new file mode 100644 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-spacex-api/acceptance-test-config.yml b/airbyte-integrations/connectors/source-spacex-api/acceptance-test-config.yml new file mode 100644 index 000000000000..9b1901392261 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/acceptance-test-config.yml @@ -0,0 +1,20 @@ +# See [Source Acceptance Tests](https://docs.airbyte.com/connector-development/testing-connectors/source-acceptance-tests-reference) +# for more information about how to configure these tests +connector_image: airbyte/source-spacex-api:dev +tests: + spec: + - spec_path: "source_spacex_api/spec.yaml" + connection: + - config_path: "secrets/config.json" + status: "succeed" + - config_path: "integration_tests/invalid_config.json" + status: "failed" + discovery: + - config_path: "secrets/config.json" + basic_read: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" + empty_streams: [] + full_refresh: + - config_path: "secrets/config.json" + configured_catalog_path: "integration_tests/configured_catalog.json" diff --git a/airbyte-integrations/connectors/source-spacex-api/acceptance-test-docker.sh b/airbyte-integrations/connectors/source-spacex-api/acceptance-test-docker.sh new file mode 100644 index 000000000000..c51577d10690 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/acceptance-test-docker.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +# Build latest connector image +docker build . -t $(cat acceptance-test-config.yml | grep "connector_image" | head -n 1 | cut -d: -f2-) + +# Pull latest acctest image +docker pull airbyte/source-acceptance-test:latest + +# Run +docker run --rm -it \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /tmp:/tmp \ + -v $(pwd):/test_input \ + airbyte/source-acceptance-test \ + --acceptance-test-config /test_input + diff --git a/airbyte-integrations/connectors/source-spacex-api/bootstrap.md b/airbyte-integrations/connectors/source-spacex-api/bootstrap.md new file mode 100644 index 000000000000..a0fd4f888d1e --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/bootstrap.md @@ -0,0 +1,35 @@ +# SpaceX-API + +The connector uses the v4 API documented here: https://github.com/r-spacex/SpaceX-API . It is +straightforward HTTP REST API with no authentication. + +## Dummy API key + +Api key is mandate for this connector to work as it could be used in future enhancements. +Just pass any dummy api key for establishing the connection. Example:123 + +## Implementation details + +## Setup guide + +### Step 1: Set up SpaceX connection + +- Have a dummy API key (Example: 12345) +- A specific id (If specific info is needed) + +## Step 2: Generate schema for the endpoint + +### Custom schema is generated and tested with different IDs + +## Step 3: Spec, Secrets, and connector yaml files are configured with reference to the Airbyte documentation. + +## In a nutshell: + +1. Navigate to the Airbyte Open Source dashboard. +2. Set the name for your source. +3. Enter your `api_key`. +5. Enter your `id` if needed. (Optional) +6. Click **Set up source**. + + * We use only GET methods, all endpoints are straightforward. We emit what we receive as HTTP response. + diff --git a/airbyte-integrations/connectors/source-spacex-api/build.gradle b/airbyte-integrations/connectors/source-spacex-api/build.gradle new file mode 100644 index 000000000000..f1fa129e4e42 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/build.gradle @@ -0,0 +1,9 @@ +plugins { + id 'airbyte-python' + id 'airbyte-docker' + id 'airbyte-source-acceptance-test' +} + +airbytePython { + moduleDirectory 'source_spacex_api' +} diff --git a/airbyte-integrations/connectors/source-spacex-api/integration_tests/__init__.py b/airbyte-integrations/connectors/source-spacex-api/integration_tests/__init__.py new file mode 100644 index 000000000000..1100c1c58cf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/integration_tests/__init__.py @@ -0,0 +1,3 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# diff --git a/airbyte-integrations/connectors/source-spacex-api/integration_tests/abnormal_state.json b/airbyte-integrations/connectors/source-spacex-api/integration_tests/abnormal_state.json new file mode 100644 index 000000000000..4816d588ac1b --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/integration_tests/abnormal_state.json @@ -0,0 +1,5 @@ +{ + "launches": { + "id": "" + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/integration_tests/acceptance.py b/airbyte-integrations/connectors/source-spacex-api/integration_tests/acceptance.py new file mode 100644 index 000000000000..1302b2f57e10 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/integration_tests/acceptance.py @@ -0,0 +1,16 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import pytest + +pytest_plugins = ("source_acceptance_test.plugin",) + + +@pytest.fixture(scope="session", autouse=True) +def connector_setup(): + """This fixture is a placeholder for external resources that acceptance test might require.""" + # TODO: setup test dependencies if needed. otherwise remove the TODO comments + yield + # TODO: clean up test dependencies diff --git a/airbyte-integrations/connectors/source-spacex-api/integration_tests/configured_catalog.json b/airbyte-integrations/connectors/source-spacex-api/integration_tests/configured_catalog.json new file mode 100644 index 000000000000..d1740d2cc488 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/integration_tests/configured_catalog.json @@ -0,0 +1,112 @@ +{ + "streams": [ + { + "stream": { + "name": "launches", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "capsules", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "crew", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "company", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "cores", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "dragons", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "landpads", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "payloads", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "roadster", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "rockets", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "ships", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "starlink", + "json_schema": {}, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-spacex-api/integration_tests/invalid_config.json b/airbyte-integrations/connectors/source-spacex-api/integration_tests/invalid_config.json new file mode 100644 index 000000000000..4cb60ac1397d --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/integration_tests/invalid_config.json @@ -0,0 +1,4 @@ +{ + "api_key": "wrongAPIkey", + "id": "" +} diff --git a/airbyte-integrations/connectors/source-spacex-api/integration_tests/sample_config.json b/airbyte-integrations/connectors/source-spacex-api/integration_tests/sample_config.json new file mode 100644 index 000000000000..a2e7cf6390e7 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/integration_tests/sample_config.json @@ -0,0 +1,3 @@ +{ + "id": "605b4b6aaa5433645e37d03f" +} diff --git a/airbyte-integrations/connectors/source-spacex-api/integration_tests/sample_state.json b/airbyte-integrations/connectors/source-spacex-api/integration_tests/sample_state.json new file mode 100644 index 000000000000..33aa82b06e33 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/integration_tests/sample_state.json @@ -0,0 +1,5 @@ +{ + "launches": { + "id": "605b4b6aaa5433645e37d03f" + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/main.py b/airbyte-integrations/connectors/source-spacex-api/main.py new file mode 100644 index 000000000000..45dab85d2c05 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/main.py @@ -0,0 +1,13 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +import sys + +from airbyte_cdk.entrypoint import launch +from source_spacex_api import SourceSpacexApi + +if __name__ == "__main__": + source = SourceSpacexApi() + launch(source, sys.argv[1:]) diff --git a/airbyte-integrations/connectors/source-spacex-api/requirements.txt b/airbyte-integrations/connectors/source-spacex-api/requirements.txt new file mode 100644 index 000000000000..0411042aa091 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/requirements.txt @@ -0,0 +1,2 @@ +-e ../../bases/source-acceptance-test +-e . diff --git a/airbyte-integrations/connectors/source-spacex-api/setup.py b/airbyte-integrations/connectors/source-spacex-api/setup.py new file mode 100644 index 000000000000..53b970cfadfb --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/setup.py @@ -0,0 +1,29 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from setuptools import find_packages, setup + +MAIN_REQUIREMENTS = [ + "airbyte-cdk~=0.1", +] + +TEST_REQUIREMENTS = [ + "pytest~=6.1", + "pytest-mock~=3.6.1", + "source-acceptance-test", +] + +setup( + name="source_spacex_api", + description="Source implementation for Spacex Api.", + author="Airbyte", + author_email="contact@airbyte.io", + packages=find_packages(), + install_requires=MAIN_REQUIREMENTS, + package_data={"": ["*.json", "*.yaml", "schemas/*.json", "schemas/shared/*.json"]}, + extras_require={ + "tests": TEST_REQUIREMENTS, + }, +) diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/__init__.py b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/__init__.py new file mode 100644 index 000000000000..bec62af8ccf5 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/__init__.py @@ -0,0 +1,8 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + + +from .source import SourceSpacexApi + +__all__ = ["SourceSpacexApi"] diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/capsules.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/capsules.json new file mode 100644 index 000000000000..27d3f20054cf --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/capsules.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "capsules": { + "title": "capsules", + "type": "object", + "properties": { + "serial": { "type": "string" }, + "status": { + "type": "string", + "enum": ["unknown", "active", "retired", "destroyed"] + }, + "type": { + "type": "string", + "enum": ["Dragon 1.0", "Dragon 1.1", "Dragon 2.0"] + }, + "dragon": { + "type": "string", + "x-ref": "Dragon", + "description": "Refers to Dragon" + }, + "reuse_count": { "type": "number", "default": 0 }, + "water_landings": { "type": "number", "default": 0 }, + "land_landings": { "type": "number", "default": 0 }, + "last_update": { "type": ["string", "null"], "default": null }, + "launches": { + "type": "array", + "items": { + "type": "string", + "x-ref": "Launch", + "description": "Refers to Launch" + } + } + }, + "required": ["serial", "status", "type"] + }, + "id": { "type": "string", "pattern": "^[0-9a-fA-F]{24}$" } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/company.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/company.json new file mode 100644 index 000000000000..ec948f3229dd --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/company.json @@ -0,0 +1,88 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "company": { + "title": "company", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "founder": { + "type": "string" + }, + "founded": { + "type": "number" + }, + "employees": { + "type": "number" + }, + "vehicles": { + "type": "number" + }, + "launch_sites": { + "type": "number" + }, + "test_sites": { + "type": "number" + }, + "ceo": { + "type": "string" + }, + "cto": { + "type": "string" + }, + "coo": { + "type": "string" + }, + "cto_propulsion": { + "type": "string" + }, + "valuation": { + "type": "number" + }, + "headquarters": { + "title": "headquarters", + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "city": { + "type": "string" + }, + "state": { + "type": "string" + } + } + }, + "links": { + "title": "links", + "type": "object", + "properties": { + "website": { + "type": "string" + }, + "flickr": { + "type": "string" + }, + "twitter": { + "type": "string" + }, + "elon_twitter": { + "type": "string" + } + } + }, + "summary": { + "type": "string" + } + } + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/cores.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/cores.json new file mode 100644 index 000000000000..95c5e1cf0246 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/cores.json @@ -0,0 +1,65 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "cores": { + "title": "cores", + "type": "object", + "properties": { + "serial": { + "type": "string" + }, + "block": { + "type": ["number", "null"], + "default": null + }, + "status": { + "type": "string", + "enum": [ + "active", + "inactive", + "unknown", + "expended", + "lost", + "retired" + ] + }, + "reuse_count": { + "type": "number", + "default": 0 + }, + "rtls_attempts": { + "type": "number", + "default": 0 + }, + "rtls_landings": { + "type": "number", + "default": 0 + }, + "asds_attempts": { + "type": "number", + "default": 0 + }, + "asds_landings": { + "type": "number", + "default": 0 + }, + "last_update": { + "type": ["string", "null"], + "default": null + }, + "launches": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["serial", "status"] + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/crew.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/crew.json new file mode 100644 index 000000000000..effdd0a1d06c --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/crew.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "crew": { + "title": "crew", + "type": "object", + "properties": { + "name": { + "type": ["string", "null"], + "default": null + }, + "status": { + "type": "string", + "enum": ["active", "inactive", "retired", "unknown"] + }, + "agency": { + "type": ["string", "null"], + "default": null + }, + "image": { + "type": ["string", "null"], + "default": null + }, + "wikipedia": { + "type": ["string", "null"], + "default": null + }, + "launches": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["status"] + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/dragons.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/dragons.json new file mode 100644 index 000000000000..052c552cff8a --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/dragons.json @@ -0,0 +1,211 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "dragons": { + "title": "dragons", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "active": { + "type": "boolean" + }, + "crew_capacity": { + "type": "number" + }, + "sidewall_angle_deg": { + "type": "number" + }, + "orbit_duration_yr": { + "type": "number" + }, + "dry_mass_kg": { + "type": "number" + }, + "dry_mass_lb": { + "type": "number" + }, + "first_flight": { + "type": ["string", "null"], + "default": null + }, + "heat_shield": { + "title": "heat_shield", + "type": "object", + "properties": { + "material": { + "type": "string" + }, + "size_meters": { + "type": "number" + }, + "temp_degrees": { + "type": "number" + }, + "dev_partner": { + "type": "string" + } + }, + "required": ["material", "size_meters"] + }, + "thrusters": { + "type": "array", + "items": { + "type": "string" + } + }, + "launch_payload_mass": { + "title": "launch_payload_mass", + "type": "object", + "properties": { + "kg": { + "type": "number" + }, + "lb": { + "type": "number" + } + } + }, + "launch_payload_vol": { + "title": "launch_payload_vol", + "type": "object", + "properties": { + "cubic_meters": { + "type": "number" + }, + "cubic_feet": { + "type": "number" + } + } + }, + "return_payload_mass": { + "title": "return_payload_mass", + "type": "object", + "properties": { + "kg": { + "type": "number" + }, + "lb": { + "type": "number" + } + } + }, + "return_payload_vol": { + "title": "return_payload_vol", + "type": "object", + "properties": { + "cubic_meters": { + "type": "number" + }, + "cubic_feet": { + "type": "number" + } + } + }, + "pressurized_capsule": { + "title": "pressurized_capsule", + "type": "object", + "properties": { + "payload_volume": { + "title": "payload_volume", + "type": "object", + "properties": { + "cubic_meters": { + "type": "number" + }, + "cubic_feet": { + "type": "number" + } + } + } + } + }, + "trunk": { + "title": "trunk", + "type": "object", + "properties": { + "trunk_volume": { + "title": "trunk_volume", + "type": "object", + "properties": { + "cubic_meters": { + "type": "number" + }, + "cubic_feet": { + "type": "number" + } + } + }, + "cargo": { + "title": "cargo", + "type": "object", + "properties": { + "solar_array": { + "type": "number" + }, + "unpressurized_cargo": { + "type": "boolean" + } + } + } + } + }, + "height_w_trunk": { + "title": "height_w_trunk", + "type": "object", + "properties": { + "meters": { + "type": "number" + }, + "feet": { + "type": "number" + } + } + }, + "diameter": { + "title": "diameter", + "type": "object", + "properties": { + "meters": { + "type": "number" + }, + "feet": { + "type": "number" + } + } + }, + "flickr_images": { + "type": "array", + "items": { + "type": "string" + } + }, + "wikipedia": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "name", + "type", + "active", + "crew_capacity", + "sidewall_angle_deg", + "orbit_duration_yr", + "dry_mass_kg", + "dry_mass_lb" + ] + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/history.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/history.json new file mode 100644 index 000000000000..9653d18b2c8d --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/history.json @@ -0,0 +1,42 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "history": { + "title": "history", + "type": "object", + "properties": { + "title": { + "type": ["string", "null"], + "default": null + }, + "event_date_utc": { + "type": ["string", "null"], + "default": null + }, + "event_date_unix": { + "type": ["number", "null"], + "default": null + }, + "details": { + "type": ["string", "null"], + "default": null + }, + "links": { + "title": "links", + "type": "object", + "properties": { + "article": { + "type": ["string", "null"], + "default": null + } + } + } + } + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/landpads.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/landpads.json new file mode 100644 index 000000000000..a990d9d006d6 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/landpads.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "landpads": { + "title": "landpads", + "type": "object", + "properties": { + "name": { "type": ["string", "null"], "default": null }, + "full_name": { "type": ["string", "null"], "default": null }, + "status": { + "type": "string", + "enum": [ + "active", + "inactive", + "unknown", + "retired", + "lost", + "under construction" + ] + }, + "type": { "type": ["string", "null"], "default": null }, + "locality": { "type": ["string", "null"], "default": null }, + "region": { "type": ["string", "null"], "default": null }, + "latitude": { "type": ["number", "null"], "default": null }, + "longitude": { "type": ["number", "null"], "default": null }, + "landing_attempts": { "type": "number", "default": 0 }, + "landing_successes": { "type": "number", "default": 0 }, + "wikipedia": { "type": ["string", "null"], "default": null }, + "details": { "type": ["string", "null"], "default": null }, + "launches": { "type": "array", "items": { "type": "string" } }, + "images": { + "title": "images", + "type": "object", + "properties": { + "large": { "type": "array", "items": { "type": "string" } } + } + } + }, + "required": ["status"] + }, + "id": { "type": "string", "pattern": "^[0-9a-fA-F]{24}$" } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/launches.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/launches.json new file mode 100644 index 000000000000..767e5902b1df --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/launches.json @@ -0,0 +1,287 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "flight_number": { + "type": "number" + }, + "name": { + "type": "string" + }, + "date_utc": { + "type": "string" + }, + "date_unix": { + "type": "number" + }, + "date_local": { + "type": "string" + }, + "date_precision": { + "type": "string", + "enum": ["half", "quarter", "year", "month", "day", "hour"] + }, + "static_fire_date_utc": { + "type": ["string", "null"], + "default": null + }, + "static_fire_date_unix": { + "type": ["number", "null"], + "default": null + }, + "tbd": { + "type": "boolean", + "default": false + }, + "net": { + "type": "boolean", + "default": false + }, + "window": { + "type": ["number", "null"], + "default": null + }, + "rocket": { + "type": ["string", "null"], + "default": null + }, + "success": { + "type": ["boolean", "null"], + "default": null + }, + "failures": { + "type": "array", + "items": { + "title": "itemOf_failures", + "type": "object", + "properties": { + "time": { + "type": ["null", "number"] + }, + "altitude": { + "type": ["null", "number"] + }, + "reason": { + "type": ["null", "string"] + } + } + } + }, + "upcoming": { + "type": "boolean" + }, + "details": { + "type": ["string", "null"], + "default": null + }, + "fairings": { + "title": "fairings", + "type": ["object", "null"], + "properties": { + "reused": { + "type": ["boolean", "null"], + "default": null + }, + "recovery_attempt": { + "type": ["boolean", "null"], + "default": null + }, + "recovered": { + "type": ["boolean", "null"], + "default": null + }, + "ships": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "crew": { + "type": ["array", "string"], + "items": { + "title": "itemOf_crew", + "type": ["object", "string"], + "properties": { + "crew": { + "type": ["string", "null"], + "default": null + }, + "role": { + "type": ["string", "null"], + "default": null + } + } + } + }, + "ships": { + "type": "array", + "items": { + "type": "string" + } + }, + "capsules": { + "type": "array", + "items": { + "type": "string" + } + }, + "payloads": { + "type": "array", + "items": { + "type": "string" + } + }, + "launchpad": { + "type": ["string", "null"], + "default": null + }, + "cores": { + "type": "array", + "items": { + "title": "itemOf_cores", + "type": "object", + "properties": { + "core": { + "type": ["string", "null"], + "default": null + }, + "flight": { + "type": ["number", "null"], + "default": null + }, + "gridfins": { + "type": ["boolean", "null"], + "default": null + }, + "legs": { + "type": ["boolean", "null"], + "default": null + }, + "reused": { + "type": ["boolean", "null"], + "default": null + }, + "landing_attempt": { + "type": ["boolean", "null"], + "default": null + }, + "landing_success": { + "type": ["boolean", "null"], + "default": null + }, + "landing_type": { + "type": ["string", "null"], + "default": null + }, + "landpad": { + "type": ["string", "null"], + "default": null + } + } + } + }, + "links": { + "title": "links", + "type": "object", + "properties": { + "patch": { + "title": "patch", + "type": ["object", "null"], + "properties": { + "small": { + "type": ["string", "null"], + "default": null + }, + "large": { + "type": ["string", "null"], + "default": null + } + } + }, + "reddit": { + "title": "reddit", + "type": ["object", "null"], + "properties": { + "campaign": { + "type": ["string", "null"], + "default": null + }, + "launch": { + "type": ["string", "null"], + "default": null + }, + "media": { + "type": ["string", "null"], + "default": null + }, + "recovery": { + "type": ["string", "null"], + "default": null + } + } + }, + "flickr": { + "title": "flickr", + "type": "object", + "properties": { + "small": { + "type": "array", + "items": { + "type": "string" + } + }, + "original": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "presskit": { + "type": ["string", "null"], + "default": null + }, + "webcast": { + "type": ["string", "null"], + "default": null + }, + "youtube_id": { + "type": ["string", "null"], + "default": null + }, + "article": { + "type": ["string", "null"], + "default": null + }, + "wikipedia": { + "type": ["string", "null"], + "default": null + } + } + }, + "auto_update": { + "type": "boolean", + "default": true + }, + "launch_library_id": { + "type": ["string", "null"], + "default": null + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + }, + "required": [ + "flight_number", + "name", + "date_utc", + "date_unix", + "date_local", + "date_precision", + "upcoming" + ] +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/payloads.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/payloads.json new file mode 100644 index 000000000000..4fccb0f859e9 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/payloads.json @@ -0,0 +1,162 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "payload": { + "title": "payload", + "type": "object", + "properties": { + "name": { + "type": ["string", "null"], + "default": null + }, + "type": { + "type": ["string", "null"], + "default": null + }, + "reused": { + "type": "boolean", + "default": false + }, + "launch": { + "type": ["string", "null"], + "default": null + }, + "customers": { + "type": "array", + "items": { + "type": "string" + } + }, + "norad_ids": { + "type": "array", + "items": { + "type": "number" + } + }, + "nationalities": { + "type": "array", + "items": { + "type": "string" + } + }, + "manufacturers": { + "type": "array", + "items": { + "type": "string" + } + }, + "mass_kg": { + "type": ["number", "null"], + "default": null + }, + "mass_lbs": { + "type": ["number", "null"], + "default": null + }, + "orbit": { + "type": ["string", "null"], + "default": null + }, + "reference_system": { + "type": ["string", "null"], + "default": null + }, + "regime": { + "type": ["string", "null"], + "default": null + }, + "longitude": { + "type": ["number", "null"], + "default": null + }, + "semi_major_axis_km": { + "type": ["number", "null"], + "default": null + }, + "eccentricity": { + "type": ["number", "null"], + "default": null + }, + "periapsis_km": { + "type": ["number", "null"], + "default": null + }, + "apoapsis_km": { + "type": ["number", "null"], + "default": null + }, + "inclination_deg": { + "type": ["number", "null"], + "default": null + }, + "period_min": { + "type": ["number", "null"], + "default": null + }, + "lifespan_years": { + "type": ["number", "null"], + "default": null + }, + "epoch": { + "type": ["string", "null"], + "default": null + }, + "mean_motion": { + "type": ["number", "null"], + "default": null + }, + "raan": { + "type": ["number", "null"], + "default": null + }, + "arg_of_pericenter": { + "type": ["number", "null"], + "default": null + }, + "mean_anomaly": { + "type": ["number", "null"], + "default": null + }, + "dragon": { + "title": "dragon", + "type": "object", + "properties": { + "capsule": { + "type": ["string", "null"], + "default": null + }, + "mass_returned_kg": { + "type": ["number", "null"], + "default": null + }, + "mass_returned_lbs": { + "type": ["number", "null"], + "default": null + }, + "flight_time_sec": { + "type": ["number", "null"], + "default": null + }, + "manifest": { + "type": ["string", "null"], + "default": null + }, + "water_landing": { + "type": ["boolean", "null"], + "default": null + }, + "land_landing": { + "type": ["boolean", "null"], + "default": null + } + } + } + } + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/roadster.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/roadster.json new file mode 100644 index 000000000000..223dd6b8e1e8 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/roadster.json @@ -0,0 +1,97 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "roadster": { + "title": "roadster", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "launch_date_utc": { + "type": "string" + }, + "launch_date_unix": { + "type": "number" + }, + "launch_mass_kg": { + "type": "number" + }, + "launch_mass_lbs": { + "type": "number" + }, + "norad_id": { + "type": "number" + }, + "epoch_jd": { + "type": "number" + }, + "orbit_type": { + "type": "string" + }, + "apoapsis_au": { + "type": "number" + }, + "periapsis_au": { + "type": "number" + }, + "semi_major_axis_au": { + "type": "number" + }, + "eccentricity": { + "type": "number" + }, + "inclination": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "periapsis_arg": { + "type": "number" + }, + "period_days": { + "type": "number" + }, + "speed_kph": { + "type": "number" + }, + "speed_mph": { + "type": "number" + }, + "earth_distance_km": { + "type": "number" + }, + "earth_distance_mi": { + "type": "number" + }, + "mars_distance_km": { + "type": "number" + }, + "mars_distance_mi": { + "type": "number" + }, + "flickr_images": { + "type": "array", + "items": { + "type": "string" + } + }, + "wikipedia": { + "type": "string" + }, + "video": { + "type": "string" + }, + "details": { + "type": "string" + } + } + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/rockets.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/rockets.json new file mode 100644 index 000000000000..93d9dd73b38b --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/rockets.json @@ -0,0 +1,292 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "rockets": { + "title": "rockets", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "active": { + "type": "boolean" + }, + "stages": { + "type": "number" + }, + "boosters": { + "type": "number" + }, + "cost_per_launch": { + "type": "number" + }, + "success_rate_pct": { + "type": "number" + }, + "first_flight": { + "type": "string" + }, + "country": { + "type": "string" + }, + "company": { + "type": "string" + }, + "height": { + "title": "height", + "type": "object", + "properties": { + "meters": { + "type": "number" + }, + "feet": { + "type": "number" + } + } + }, + "diameter": { + "title": "diameter", + "type": "object", + "properties": { + "meters": { + "type": "number" + }, + "feet": { + "type": "number" + } + } + }, + "mass": { + "title": "mass", + "type": "object", + "properties": { + "kg": { + "type": "number" + }, + "lb": { + "type": "number" + } + } + }, + "payload_weights": { + "type": "array", + "items": { + "type": "number" + } + }, + "first_stage": { + "title": "first_stage", + "type": "object", + "properties": { + "reusable": { + "type": "boolean" + }, + "engines": { + "type": "number" + }, + "fuel_amount_tons": { + "type": "number" + }, + "burn_time_sec": { + "type": "number" + }, + "thrust_sea_level": { + "title": "thrust_sea_level", + "type": "object", + "properties": { + "kN": { + "type": "number" + }, + "lbf": { + "type": "number" + } + } + }, + "thrust_vacuum": { + "title": "thrust_vacuum", + "type": "object", + "properties": { + "kN": { + "type": "number" + }, + "lbf": { + "type": "number" + } + } + } + } + }, + "second_stage": { + "title": "second_stage", + "type": "object", + "properties": { + "reusable": { + "type": "boolean" + }, + "engines": { + "type": "number" + }, + "fuel_amount_tons": { + "type": "number" + }, + "burn_time_sec": { + "type": "number" + }, + "thrust": { + "title": "thrust", + "type": "object", + "properties": { + "kN": { + "type": "number" + }, + "lbf": { + "type": "number" + } + } + }, + "payloads": { + "title": "payloads", + "type": "object", + "properties": { + "option_1": { + "type": "string" + }, + "composite_fairing": { + "title": "composite_fairing", + "type": "object", + "properties": { + "height": { + "title": "height", + "type": "object", + "properties": { + "meters": { + "type": "number" + }, + "feet": { + "type": "number" + } + } + }, + "diameter": { + "title": "diameter", + "type": "object", + "properties": { + "meters": { + "type": "number" + }, + "feet": { + "type": "number" + } + } + } + } + } + } + } + } + }, + "engines": { + "title": "engines", + "type": "object", + "properties": { + "number": { + "type": "number" + }, + "type": { + "type": "string" + }, + "version": { + "type": "string" + }, + "layout": { + "type": "string" + }, + "isp": { + "title": "isp", + "type": "object", + "properties": { + "sea_level": { + "type": "number" + }, + "vacuum": { + "type": "number" + } + } + }, + "engine_loss_max": { + "type": "number" + }, + "propellant_1": { + "type": "string" + }, + "propellant_2": { + "type": "string" + }, + "thrust_sea_level": { + "title": "thrust_sea_level", + "type": "object", + "properties": { + "kN": { + "type": "number" + }, + "lbf": { + "type": "number" + } + } + }, + "thrust_vacuum": { + "title": "thrust_vacuum", + "type": "object", + "properties": { + "kN": { + "type": "number" + }, + "lbf": { + "type": "number" + } + } + }, + "thrust_to_weight": { + "type": "number" + } + } + }, + "landing_legs": { + "title": "landing_legs", + "type": "object", + "properties": { + "number": { + "type": "number" + }, + "material": { + "type": "array", + "items": { + "type": "number" + } + } + } + }, + "flickr_images": { + "type": "array", + "items": { + "type": "string" + } + }, + "wikipedia": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/ships.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/ships.json new file mode 100644 index 000000000000..6a4f25d198da --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/ships.json @@ -0,0 +1,111 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "ships": { + "title": "ships", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "legacy_id": { + "type": ["string", "null"], + "default": null + }, + "model": { + "type": ["string", "null"], + "default": null + }, + "type": { + "type": ["string", "null"], + "default": null + }, + "roles": { + "type": "array", + "items": { + "type": "string" + } + }, + "active": { + "type": "boolean" + }, + "imo": { + "type": ["number", "null"], + "default": null + }, + "mmsi": { + "type": ["number", "null"], + "default": null + }, + "abs": { + "type": ["number", "null"], + "default": null + }, + "class": { + "type": ["number", "null"], + "default": null + }, + "mass_kg": { + "type": ["number", "null"], + "default": null + }, + "mass_lbs": { + "type": ["number", "null"], + "default": null + }, + "year_built": { + "type": ["number", "null"], + "default": null + }, + "home_port": { + "type": ["string", "null"], + "default": null + }, + "status": { + "type": ["string", "null"], + "default": null + }, + "speed_kn": { + "type": ["number", "null"], + "default": null + }, + "course_deg": { + "type": ["number", "null"], + "default": null + }, + "latitude": { + "type": ["number", "null"], + "default": null + }, + "longitude": { + "type": ["number", "null"], + "default": null + }, + "last_ais_update": { + "type": ["string", "null"], + "default": null + }, + "link": { + "type": ["string", "null"], + "default": null + }, + "image": { + "type": ["string", "null"], + "default": null + }, + "launches": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["name", "active"] + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/starlink.json b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/starlink.json new file mode 100644 index 000000000000..48f0c5b1d1ed --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/schemas/starlink.json @@ -0,0 +1,210 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "starlink": { + "title": "starlink", + "type": "object", + "properties": { + "version": { + "type": ["string", "null"], + "default": null + }, + "launch": { + "type": ["string", "null"], + "default": null + }, + "longitude": { + "type": ["number", "null"], + "default": null + }, + "latitude": { + "type": ["number", "null"], + "default": null + }, + "height_km": { + "type": ["number", "null"], + "default": null + }, + "velocity_kms": { + "type": ["number", "null"], + "default": null + }, + "spaceTrack": { + "title": "spaceTrack", + "type": "object", + "properties": { + "CCSDS_OMM_VERS": { + "type": ["string", "null"], + "default": null + }, + "COMMENT": { + "type": ["string", "null"], + "default": null + }, + "CREATION_DATE": { + "type": ["string", "null"], + "default": null + }, + "ORIGINATOR": { + "type": ["string", "null"], + "default": null + }, + "OBJECT_NAME": { + "type": ["string", "null"], + "default": null + }, + "OBJECT_ID": { + "type": ["string", "null"], + "default": null + }, + "CENTER_NAME": { + "type": ["string", "null"], + "default": null + }, + "REF_FRAME": { + "type": ["string", "null"], + "default": null + }, + "TIME_SYSTEM": { + "type": ["string", "null"], + "default": null + }, + "MEAN_ELEMENT_THEORY": { + "type": ["string", "null"], + "default": null + }, + "EPOCH": { + "type": ["string", "null"], + "default": null + }, + "MEAN_MOTION": { + "type": ["number", "null"], + "default": null + }, + "ECCENTRICITY": { + "type": ["number", "null"], + "default": null + }, + "INCLINATION": { + "type": ["number", "null"], + "default": null + }, + "RA_OF_ASC_NODE": { + "type": ["number", "null"], + "default": null + }, + "ARG_OF_PERICENTER": { + "type": ["number", "null"], + "default": null + }, + "MEAN_ANOMALY": { + "type": ["number", "null"], + "default": null + }, + "EPHEMERIS_TYPE": { + "type": ["number", "null"], + "default": null + }, + "CLASSIFICATION_TYPE": { + "type": ["string", "null"], + "default": null + }, + "NORAD_CAT_ID": { + "type": ["number", "null"], + "default": null + }, + "ELEMENT_SET_NO": { + "type": ["number", "null"], + "default": null + }, + "REV_AT_EPOCH": { + "type": ["number", "null"], + "default": null + }, + "BSTAR": { + "type": ["number", "null"], + "default": null + }, + "MEAN_MOTION_DOT": { + "type": ["number", "null"], + "default": null + }, + "MEAN_MOTION_DDOT": { + "type": ["number", "null"], + "default": null + }, + "SEMIMAJOR_AXIS": { + "type": ["number", "null"], + "default": null + }, + "PERIOD": { + "type": ["number", "null"], + "default": null + }, + "APOAPSIS": { + "type": ["number", "null"], + "default": null + }, + "PERIAPSIS": { + "type": ["number", "null"], + "default": null + }, + "OBJECT_TYPE": { + "type": ["string", "null"], + "default": null + }, + "RCS_SIZE": { + "type": ["string", "null"], + "default": null + }, + "COUNTRY_CODE": { + "type": ["string", "null"], + "default": null + }, + "LAUNCH_DATE": { + "type": ["string", "null"], + "default": null + }, + "SITE": { + "type": ["string", "null"], + "default": null + }, + "DECAY_DATE": { + "type": ["string", "null"], + "default": null + }, + "DECAYED": { + "type": ["number", "null"], + "default": null + }, + "FILE": { + "type": ["number", "null"], + "default": null + }, + "GP_ID": { + "type": ["number", "null"], + "default": null + }, + "TLE_LINE0": { + "type": ["string", "null"], + "default": null + }, + "TLE_LINE1": { + "type": ["string", "null"], + "default": null + }, + "TLE_LINE2": { + "type": ["string", "null"], + "default": null + } + } + } + } + }, + "id": { + "type": "string", + "pattern": "^[0-9a-fA-F]{24}$" + } + } +} diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/source.py b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/source.py new file mode 100644 index 000000000000..a847fc0af51c --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/source.py @@ -0,0 +1,18 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from airbyte_cdk.sources.declarative.yaml_declarative_source import YamlDeclarativeSource + +""" +This file provides the necessary constructs to interpret a provided declarative YAML configuration file into +source connector. + +WARNING: Do not modify this file. +""" + + +# Declarative Source +class SourceSpacexApi(YamlDeclarativeSource): + def __init__(self): + super().__init__(**{"path_to_yaml": "spacex_api.yaml"}) diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/spacex_api.yaml b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/spacex_api.yaml new file mode 100644 index 000000000000..67600a87cfd7 --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/spacex_api.yaml @@ -0,0 +1,147 @@ +version: "0.1.0" + +definitions: + selector: + extractor: + field_pointer: [] + + requester: + url_base: "https://api.spacexdata.com/v4/" + http_method: "GET" + + retriever: + record_selector: + $ref: "*ref(definitions.selector)" + paginator: + type: NoPagination + requester: + $ref: "*ref(definitions.requester)" + + base_stream: + schema_loader: + type: JsonSchema + file_path: "./source_spacex_api/schemas/{{ options['name'] }}.json" + retriever: + $ref: "*ref(definitions.retriever)" + + launches_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "launches" + primary_key: "id" + path: "/launches/{{config['options'] or config['id'] or latest}}" + + capsules_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "capsules" + primary_key: "id" + path: "/capsules" + + company_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "company" + primary_key: "id" + path: "/company" + + crew_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "crew" + primary_key: "id" + path: "/crew" + + cores_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "cores" + primary_key: "id" + path: "/cores" + + dragons_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "dragons" + primary_key: "id" + path: "/dragons" + + landpads_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "landpads" + primary_key: "id" + path: "/landpads" + + payloads_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "payloads" + primary_key: "id" + path: "/payloads" + + history_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "history" + primary_key: "id" + path: "/history" + + rockets_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "rockets" + primary_key: "id" + path: "/rockets" + + roadster_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "roadster" + primary_key: "id" + path: "/roadster" + + ships_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "ships" + primary_key: "id" + path: "/ships" + + starlink_stream: + $ref: "*ref(definitions.base_stream)" + $options: + name: "starlink" + primary_key: "id" + path: "/starlink" + +streams: + - "*ref(definitions.launches_stream)" + - "*ref(definitions.capsules_stream)" + - "*ref(definitions.company_stream)" + - "*ref(definitions.crew_stream)" + - "*ref(definitions.cores_stream)" + - "*ref(definitions.dragons_stream)" + - "*ref(definitions.landpads_stream)" + - "*ref(definitions.payloads_stream)" + - "*ref(definitions.history_stream)" + - "*ref(definitions.rockets_stream)" + - "*ref(definitions.roadster_stream)" + - "*ref(definitions.ships_stream)" + - "*ref(definitions.starlink_stream)" + +check: + stream_names: + - "launches" + - "capsules" + - "company" + - "crew" + - "cores" + - "dragons" + - "landpads" + - "payloads" + - "history" + - "rockets" + - "roadster" + - "ships" + - "starlink" diff --git a/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/spec.yaml b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/spec.yaml new file mode 100644 index 000000000000..2344eb7c202b --- /dev/null +++ b/airbyte-integrations/connectors/source-spacex-api/source_spacex_api/spec.yaml @@ -0,0 +1,15 @@ +documentationUrl: https://docs.airbyte.com/integrations/sources/spacex-api +connectionSpecification: + $schema: http://json-schema.org/draft-07/schema# + title: Spacex Api Spec + type: object + additionalProperties: true + properties: + id: + title: Unique ID for specific source target + type: string + desciption: Optional, For a specific ID + options: + title: Configuration options for endpoints + type: string + desciption: Optional, Possible values for an endpoint. Example values for launches-latest, upcoming, past diff --git a/docs/integrations/sources/spacex-api.md b/docs/integrations/sources/spacex-api.md new file mode 100644 index 000000000000..a366856e9f77 --- /dev/null +++ b/docs/integrations/sources/spacex-api.md @@ -0,0 +1,75 @@ +# SpaceX-API + +This page contains the setup guide and reference information for the [SpaceX-API](https://github.com/r-spacex/SpaceX-API) source connector. + +## Prerequisites + +No prerequisites, but a dummy api_key is required as it enhances security in future build. Please check the available routes at [SpaceX Routes](https://github.com/r-spacex/SpaceX-API/tree/master/routes). + +## Setup guide + +### Step 1: Set up SpaceX connection + +- Have a dummy API key (Example: 12345) +- A specific id (If specific info is needed) + +## Step 2: Set up the SpaceX-API connector in Airbyte + +### For Airbyte Cloud: + +1. [Log into your Airbyte Cloud](https://cloud.airbyte.io/workspaces) account. +2. In the left navigation bar, click **Sources**. In the top-right corner, click **+new source**. +3. On the Set up the source page, enter the name for the SpaceX-API connector and select **Spacex-API** from the Source type dropdown. +4. Enter your `api_key`. +5. Enter your `id` if needed. (Optional) +6. Click **Set up source**. + +### For Airbyte OSS: + +1. Navigate to the Airbyte Open Source dashboard. +2. Set the name for your source. +3. Enter your `api_key`. +5. Enter your `id` if needed. (Optional) +6. Click **Set up source**. + +## Supported sync modes + +The SpaceX-API source connector supports the following [sync modes](https://docs.airbyte.com/cloud/core-concepts#connection-sync-modes): + +| Feature | Supported? | +| :---------------------------- | :--------- | +| Full Refresh Sync | Yes | +| Incremental Sync | No | +| Replicate Incremental Deletes | No | +| SSL connection | Yes | +| Namespaces | No | + +## Supported Streams + +- Launches +- Capsules +- Company +- Crew +- Cores +- Dragons +- History +- Landpads +- Payloads +- Roadster +- Rockets +- Ships +- Starlink + +## API method example + +GET https://api.spacexdata.com/v5/launches/latest + +## Performance considerations + +SpaceX's [API reference](https://api.spacexdata.com/v5/) has both v4 an v5 for launches. The connector as default uses V4 as it has minimal bugs. + +## Changelog + +| Version | Date | Pull Request | Subject | +| :------ | :--------- | :----------------------------------------------------- | :------------- | +| 0.1.0 | 2022-10-22 | [Init](https://github.com/airbytehq/airbyte/pull/18311) | Initial commit | From 605fb921c4fe2a4ea6f62b14637706852c787b70 Mon Sep 17 00:00:00 2001 From: Alexandre Girard Date: Thu, 3 Nov 2022 18:50:47 -0700 Subject: [PATCH 37/73] [low-code]: Evaluate backoff strategies at runtime (#18053) * pass options to wait time from header * fix constant backoff * parameterize test * fix tests * missing unit tests * eval header at runtime * eval regex at runtime * evaluate min_wait at runtime * eval factor at runtime * missing unit tests * remove debug print * rename * Add tests * Add tests * Update docs --- .../sources/declarative/parsers/factory.py | 5 +- .../constant_backoff_strategy.py | 17 ++- .../exponential_backoff_strategy.py | 17 ++- .../wait_time_from_header_backoff_strategy.py | 16 ++- ...until_time_from_header_backoff_strategy.py | 36 +++-- .../error_handlers/default_error_handler.py | 3 +- .../test_constant_backoff.py | 20 ++- .../test_exponential_backoff.py | 17 ++- .../test_wait_time_from_header.py | 6 +- .../test_wait_until_time_from_header.py | 30 ++++- .../test_default_error_handler.py | 9 +- .../sources/declarative/test_factory.py | 127 ++++++++++-------- .../error-handling.md | 14 +- 13 files changed, 211 insertions(+), 106 deletions(-) diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/factory.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/factory.py index 676074d174b3..b499ea756132 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/factory.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/factory.py @@ -229,7 +229,7 @@ def _create_subcomponent(self, key, definition, kwargs, config, parent_class, in options = kwargs.get(OPTIONS_STR, {}) try: # enums can't accept options - if issubclass(expected_type, enum.Enum): + if issubclass(expected_type, enum.Enum) or self.is_primitive(definition): return expected_type(definition) else: return expected_type(definition, options=options) @@ -237,6 +237,9 @@ def _create_subcomponent(self, key, definition, kwargs, config, parent_class, in raise Exception(f"failed to instantiate type {expected_type}. {e}") return definition + def is_primitive(self, obj): + return isinstance(obj, (int, float, bool)) + @staticmethod def is_object_definition_with_class_name(definition): return isinstance(definition, dict) and "class_name" in definition diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/constant_backoff_strategy.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/constant_backoff_strategy.py index 3a7df2dc7b36..7f7ba913b108 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/constant_backoff_strategy.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/constant_backoff_strategy.py @@ -2,11 +2,13 @@ # Copyright (c) 2022 Airbyte, Inc., all rights reserved. # -from dataclasses import dataclass -from typing import Optional +from dataclasses import InitVar, dataclass +from typing import Any, Mapping, Optional, Union import requests +from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategy import BackoffStrategy +from airbyte_cdk.sources.declarative.types import Config from dataclasses_jsonschema import JsonSchemaMixin @@ -19,7 +21,14 @@ class ConstantBackoffStrategy(BackoffStrategy, JsonSchemaMixin): backoff_time_in_seconds (float): time to backoff before retrying a retryable request. """ - backoff_time_in_seconds: float + backoff_time_in_seconds: Union[float, InterpolatedString, str] + options: InitVar[Mapping[str, Any]] + config: Config + + def __post_init__(self, options: Mapping[str, Any]): + if not isinstance(self.backoff_time_in_seconds, InterpolatedString): + self.backoff_time_in_seconds = str(self.backoff_time_in_seconds) + self.backoff_time_in_seconds = InterpolatedString.create(self.backoff_time_in_seconds, options=options) def backoff(self, response: requests.Response, attempt_count: int) -> Optional[float]: - return self.backoff_time_in_seconds + return self.backoff_time_in_seconds.eval(self.config) diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/exponential_backoff_strategy.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/exponential_backoff_strategy.py index 75a52ffca375..aec9c98492f9 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/exponential_backoff_strategy.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/exponential_backoff_strategy.py @@ -2,11 +2,13 @@ # Copyright (c) 2022 Airbyte, Inc., all rights reserved. # -from dataclasses import dataclass -from typing import Optional +from dataclasses import InitVar, dataclass +from typing import Any, Mapping, Optional, Union import requests +from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategy import BackoffStrategy +from airbyte_cdk.sources.declarative.types import Config from dataclasses_jsonschema import JsonSchemaMixin @@ -19,7 +21,14 @@ class ExponentialBackoffStrategy(BackoffStrategy, JsonSchemaMixin): factor (float): multiplicative factor """ - factor: float = 5 + options: InitVar[Mapping[str, Any]] + config: Config + factor: Union[float, InterpolatedString, str] = 5 + + def __post_init__(self, options: Mapping[str, Any]): + if not isinstance(self.factor, InterpolatedString): + self.factor = str(self.factor) + self.factor = InterpolatedString.create(self.factor, options=options) def backoff(self, response: requests.Response, attempt_count: int) -> Optional[float]: - return self.factor * 2**attempt_count + return self.factor.eval(self.config) * 2**attempt_count diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_time_from_header_backoff_strategy.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_time_from_header_backoff_strategy.py index 3ff279c78eb5..1c6e65b87248 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_time_from_header_backoff_strategy.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_time_from_header_backoff_strategy.py @@ -3,12 +3,14 @@ # import re -from dataclasses import dataclass -from typing import Optional +from dataclasses import InitVar, dataclass +from typing import Any, Mapping, Optional, Union import requests +from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategies.header_helper import get_numeric_value_from_header from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategy import BackoffStrategy +from airbyte_cdk.sources.declarative.types import Config from dataclasses_jsonschema import JsonSchemaMixin @@ -22,12 +24,16 @@ class WaitTimeFromHeaderBackoffStrategy(BackoffStrategy, JsonSchemaMixin): regex (Optional[str]): optional regex to apply on the header to extract its value """ - header: str + header: Union[InterpolatedString, str] + options: InitVar[Mapping[str, Any]] + config: Config regex: Optional[str] = None - def __post_init__(self): + def __post_init__(self, options: Mapping[str, Any]): self.regex = re.compile(self.regex) if self.regex else None + self.header = InterpolatedString.create(self.header, options=options) def backoff(self, response: requests.Response, attempt_count: int) -> Optional[float]: - header_value = get_numeric_value_from_header(response, self.header, self.regex) + header = self.header.eval(config=self.config) + header_value = get_numeric_value_from_header(response, header, self.regex) return header_value diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_until_time_from_header_backoff_strategy.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_until_time_from_header_backoff_strategy.py index 0e56741035ba..250ca85c7411 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_until_time_from_header_backoff_strategy.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_until_time_from_header_backoff_strategy.py @@ -5,12 +5,14 @@ import numbers import re import time -from dataclasses import dataclass -from typing import Optional +from dataclasses import InitVar, dataclass +from typing import Any, Mapping, Optional, Union import requests +from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategies.header_helper import get_numeric_value_from_header from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategy import BackoffStrategy +from airbyte_cdk.sources.declarative.types import Config from dataclasses_jsonschema import JsonSchemaMixin @@ -26,24 +28,36 @@ class WaitUntilTimeFromHeaderBackoffStrategy(BackoffStrategy, JsonSchemaMixin): regex (Optional[str]): optional regex to apply on the header to extract its value """ - header: str - min_wait: Optional[float] = None - regex: Optional[str] = None + header: Union[InterpolatedString, str] + options: InitVar[Mapping[str, Any]] + config: Config + min_wait: Optional[Union[float, InterpolatedString, str]] = None + regex: Optional[Union[InterpolatedString, str]] = None - def __post_init__(self): - self.regex = re.compile(self.regex) if self.regex else None + def __post_init__(self, options: Mapping[str, Any]): + self.header = InterpolatedString.create(self.header, options=options) + self.regex = InterpolatedString.create(self.regex, options=options) if self.regex else None + if not isinstance(self.min_wait, InterpolatedString): + self.min_wait = InterpolatedString.create(str(self.min_wait), options=options) def backoff(self, response: requests.Response, attempt_count: int) -> Optional[float]: now = time.time() - wait_until = get_numeric_value_from_header(response, self.header, self.regex) + header = self.header.eval(self.config) + if self.regex: + evaled_regex = self.regex.eval(self.config) + regex = re.compile(evaled_regex) + else: + regex = None + wait_until = get_numeric_value_from_header(response, header, regex) + min_wait = self.min_wait.eval(self.config) if wait_until is None or not wait_until: - return self.min_wait + return min_wait if (isinstance(wait_until, str) and wait_until.isnumeric()) or isinstance(wait_until, numbers.Number): wait_time = float(wait_until) - now else: return self.min_wait - if self.min_wait: - return max(wait_time, self.min_wait) + if min_wait: + return max(wait_time, min_wait) elif wait_time < 0: return None return wait_time diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py index 9757ec2da21a..9fe56017f995 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py @@ -94,6 +94,7 @@ class DefaultErrorHandler(ErrorHandler, JsonSchemaMixin): config: Config options: InitVar[Mapping[str, Any]] + config: Config response_filters: Optional[List[HttpResponseFilter]] = None max_retries: Optional[int] = 5 _max_retries: int = field(init=False, repr=False, default=5) @@ -111,7 +112,7 @@ def __post_init__(self, options: Mapping[str, Any]): self.response_filters.append(HttpResponseFilter(ResponseAction.IGNORE, config={}, options={})) if not self.backoff_strategies: - self.backoff_strategies = [DefaultErrorHandler.DEFAULT_BACKOFF_STRATEGY()] + self.backoff_strategies = [DefaultErrorHandler.DEFAULT_BACKOFF_STRATEGY(options=options, config=self.config)] self._last_request_to_attempt_count: MutableMapping[requests.PreparedRequest, int] = {} diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_constant_backoff.py b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_constant_backoff.py index 8ee5af1e57ff..38b946890929 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_constant_backoff.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_constant_backoff.py @@ -8,17 +8,27 @@ from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategies.constant_backoff_strategy import ConstantBackoffStrategy BACKOFF_TIME = 10 +OPTIONS_BACKOFF_TIME = 20 +CONFIG_BACKOFF_TIME = 30 @pytest.mark.parametrize( - "test_name, attempt_count, expected_backoff_time", + "test_name, attempt_count, backofftime, expected_backoff_time", [ - ("test_exponential_backoff", 1, BACKOFF_TIME), - ("test_exponential_backoff", 2, BACKOFF_TIME), + ("test_constant_backoff_first_attempt", 1, BACKOFF_TIME, BACKOFF_TIME), + ("test_constant_backoff_first_attempt_float", 1, 6.7, 6.7), + ("test_constant_backoff_attempt_round_float", 1.0, 6.7, 6.7), + ("test_constant_backoff_attempt_round_float", 1.5, 6.7, 6.7), + ("test_constant_backoff_first_attempt_round_float", 1, 10.0, BACKOFF_TIME), + ("test_constant_backoff_second_attempt_round_float", 2, 10.0, BACKOFF_TIME), + ("test_constant_backoff_from_options", 1, "{{ options['backoff'] }}", OPTIONS_BACKOFF_TIME), + ("test_constant_backoff_from_config", 1, "{{ config['backoff'] }}", CONFIG_BACKOFF_TIME), ], ) -def test_exponential_backoff(test_name, attempt_count, expected_backoff_time): +def test_constant_backoff(test_name, attempt_count, backofftime, expected_backoff_time): response_mock = MagicMock() - backoff_strategy = ConstantBackoffStrategy(backoff_time_in_seconds=BACKOFF_TIME) + backoff_strategy = ConstantBackoffStrategy( + options={"backoff": OPTIONS_BACKOFF_TIME}, backoff_time_in_seconds=backofftime, config={"backoff": CONFIG_BACKOFF_TIME} + ) backoff = backoff_strategy.backoff(response_mock, attempt_count) assert backoff == expected_backoff_time diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_exponential_backoff.py b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_exponential_backoff.py index d60a862770af..eae13908a63d 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_exponential_backoff.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_exponential_backoff.py @@ -9,23 +9,28 @@ ExponentialBackoffStrategy, ) +options = {"backoff": 5} +config = {"backoff": 5} + @pytest.mark.parametrize( - "test_name, attempt_count, expected_backoff_time", + "test_name, attempt_count, factor, expected_backoff_time", [ - ("test_exponential_backoff", 1, 10), - ("test_exponential_backoff", 2, 20), + ("test_exponential_backoff_first_attempt", 1, 5, 10), + ("test_exponential_backoff_second_attempt", 2, 5, 20), + ("test_exponential_backoff_from_options", 2, "{{options['backoff']}}", 20), + ("test_exponential_backoff_from_config", 2, "{{config['backoff']}}", 20), ], ) -def test_exponential_backoff(test_name, attempt_count, expected_backoff_time): +def test_exponential_backoff(test_name, attempt_count, factor, expected_backoff_time): response_mock = MagicMock() - backoff_strategy = ExponentialBackoffStrategy(factor=5) + backoff_strategy = ExponentialBackoffStrategy(factor=factor, options=options, config=config) backoff = backoff_strategy.backoff(response_mock, attempt_count) assert backoff == expected_backoff_time def test_exponential_backoff_default(): response_mock = MagicMock() - backoff_strategy = ExponentialBackoffStrategy() + backoff_strategy = ExponentialBackoffStrategy(options=options, config=config) backoff = backoff_strategy.backoff(response_mock, 3) assert backoff == 40 diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_wait_time_from_header.py b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_wait_time_from_header.py index 915a13762d28..bd1be514d219 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_wait_time_from_header.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_wait_time_from_header.py @@ -17,6 +17,8 @@ [ ("test_wait_time_from_header", "wait_time", SOME_BACKOFF_TIME, None, SOME_BACKOFF_TIME), ("test_wait_time_from_header_string", "wait_time", "60", None, SOME_BACKOFF_TIME), + ("test_wait_time_from_header_options", "{{ options['wait_time'] }}", "60", None, SOME_BACKOFF_TIME), + ("test_wait_time_from_header_config", "{{ config['wait_time'] }}", "60", None, SOME_BACKOFF_TIME), ("test_wait_time_from_header_not_a_number", "wait_time", "61,60", None, None), ("test_wait_time_from_header_with_regex", "wait_time", "61,60", "([-+]?\d+)", 61), # noqa ("test_wait_time_fœrom_header_with_regex_no_match", "wait_time", "...", "[-+]?\d+", None), # noqa @@ -26,6 +28,8 @@ def test_wait_time_from_header(test_name, header, header_value, regex, expected_backoff_time): response_mock = MagicMock() response_mock.headers = {"wait_time": header_value} - backoff_stratery = WaitTimeFromHeaderBackoffStrategy(header, regex) + backoff_stratery = WaitTimeFromHeaderBackoffStrategy( + header=header, regex=regex, options={"wait_time": "wait_time"}, config={"wait_time": "wait_time"} + ) backoff = backoff_stratery.backoff(response_mock, 1) assert backoff == expected_backoff_time diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_wait_until_time_from_header.py b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_wait_until_time_from_header.py index 713ee4c4896f..1ad5afbfa57d 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_wait_until_time_from_header.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_wait_until_time_from_header.py @@ -11,26 +11,54 @@ ) SOME_BACKOFF_TIME = 60 +REGEX = "[-+]?\\d+" @pytest.mark.parametrize( "test_name, header, wait_until, min_wait, regex, expected_backoff_time", [ ("test_wait_until_time_from_header", "wait_until", 1600000060.0, None, None, 60), + ("test_wait_until_time_from_header_options", "{{options['wait_until']}}", 1600000060.0, None, None, 60), + ("test_wait_until_time_from_header_config", "{{config['wait_until']}}", 1600000060.0, None, None, 60), ("test_wait_until_negative_time", "wait_until", 1500000000.0, None, None, None), ("test_wait_until_time_less_than_min", "wait_until", 1600000060.0, 120, None, 120), ("test_wait_until_no_header", "absent_header", 1600000000.0, None, None, None), ("test_wait_until_time_from_header_not_numeric", "wait_until", "1600000000,1600000000", None, None, None), ("test_wait_until_time_from_header_is_numeric", "wait_until", "1600000060", None, None, 60), ("test_wait_until_time_from_header_with_regex", "wait_until", "1600000060,60", None, "[-+]?\d+", 60), # noqa + ("test_wait_until_time_from_header_with_regex_from_options", "wait_until", "1600000060,60", None, "{{options['regex']}}", 60), + # noqa + ("test_wait_until_time_from_header_with_regex_from_config", "wait_until", "1600000060,60", None, "{{config['regex']}}", 60), # noqa ("test_wait_until_time_from_header_with_regex_no_match", "wait_time", "...", None, "[-+]?\d+", None), # noqa ("test_wait_until_no_header_with_min", "absent_header", "1600000000.0", SOME_BACKOFF_TIME, None, SOME_BACKOFF_TIME), + ( + "test_wait_until_no_header_with_min_from_options", + "absent_header", + "1600000000.0", + "{{options['min_wait']}}", + None, + SOME_BACKOFF_TIME, + ), + ( + "test_wait_until_no_header_with_min_from_config", + "absent_header", + "1600000000.0", + "{{config['min_wait']}}", + None, + SOME_BACKOFF_TIME, + ), ], ) @patch("time.time", return_value=1600000000.0) def test_wait_untiltime_from_header(time_mock, test_name, header, wait_until, min_wait, regex, expected_backoff_time): response_mock = MagicMock() response_mock.headers = {"wait_until": wait_until} - backoff_stratery = WaitUntilTimeFromHeaderBackoffStrategy(header, min_wait, regex) + backoff_stratery = WaitUntilTimeFromHeaderBackoffStrategy( + header=header, + min_wait=min_wait, + regex=regex, + options={"wait_until": "wait_until", "regex": REGEX, "min_wait": SOME_BACKOFF_TIME}, + config={"wait_until": "wait_until", "regex": REGEX, "min_wait": SOME_BACKOFF_TIME}, + ) backoff = backoff_stratery.backoff(response_mock, 1) assert backoff == expected_backoff_time diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py index 6bc94aa6be75..ec8793e9f695 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py @@ -30,7 +30,7 @@ None, {}, ResponseStatus.retry(SOME_BACKOFF_TIME), - [ConstantBackoffStrategy(SOME_BACKOFF_TIME)], + [ConstantBackoffStrategy(options={}, backoff_time_in_seconds=SOME_BACKOFF_TIME, config={})], ), ("test_exponential_backoff", HTTPStatus.BAD_GATEWAY, None, None, {}, ResponseStatus.retry(10), None), ( @@ -40,7 +40,7 @@ None, {}, ResponseStatus.retry(10), - [DefaultErrorHandler.DEFAULT_BACKOFF_STRATEGY()], + [DefaultErrorHandler.DEFAULT_BACKOFF_STRATEGY(options={}, config={})], ), ("test_chain_backoff_strategy", HTTPStatus.BAD_GATEWAY, None, None, {}, ResponseStatus.retry(10), None), ( @@ -50,7 +50,10 @@ None, {}, ResponseStatus.retry(10), - [DefaultErrorHandler.DEFAULT_BACKOFF_STRATEGY(), ConstantBackoffStrategy(SOME_BACKOFF_TIME)], + [ + DefaultErrorHandler.DEFAULT_BACKOFF_STRATEGY(options={}, config={}), + ConstantBackoffStrategy(options={}, backoff_time_in_seconds=SOME_BACKOFF_TIME, config={}), + ], ), ("test_200", HTTPStatus.OK, None, None, {}, response_status.SUCCESS, None), ("test_3XX", HTTPStatus.PERMANENT_REDIRECT, None, None, {}, response_status.SUCCESS, None), diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py b/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py index fde611268a42..600044fbc119 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py @@ -415,31 +415,31 @@ def test_create_record_selector(test_name, record_selector, expected_runtime_sel ( "test_option_in_selector", """ - extractor: - type: DpathExtractor - field_pointer: ["{{ options['name'] }}"] - selector: - class_name: airbyte_cdk.sources.declarative.extractors.record_selector.RecordSelector - $options: - name: "selector" - extractor: "*ref(extractor)" - """, + extractor: + type: DpathExtractor + field_pointer: ["{{ options['name'] }}"] + selector: + class_name: airbyte_cdk.sources.declarative.extractors.record_selector.RecordSelector + $options: + name: "selector" + extractor: "*ref(extractor)" + """, "selector", ), ( "test_option_in_extractor", """ - extractor: - type: DpathExtractor - $options: - name: "extractor" - field_pointer: ["{{ options['name'] }}"] - selector: - class_name: airbyte_cdk.sources.declarative.extractors.record_selector.RecordSelector - $options: - name: "selector" - extractor: "*ref(extractor)" - """, + extractor: + type: DpathExtractor + $options: + name: "extractor" + field_pointer: ["{{ options['name'] }}"] + selector: + class_name: airbyte_cdk.sources.declarative.extractors.record_selector.RecordSelector + $options: + name: "selector" + extractor: "*ref(extractor)" + """, "extractor", ), ], @@ -451,8 +451,53 @@ def test_options_propagation(test_name, content, expected_field_pointer_value): assert selector.extractor.field_pointer[0].eval(input_config) == expected_field_pointer_value -def test_create_requester(): - content = """ +@pytest.mark.parametrize( + "test_name, error_handler", + [ + ( + "test_create_requester_constant_error_handler", + """ + error_handler: + backoff_strategies: + - type: "ConstantBackoffStrategy" + backoff_time_in_seconds: 5 + """, + ), + ( + "test_create_requester_exponential_error_handler", + """ + error_handler: + backoff_strategies: + - type: "ExponentialBackoffStrategy" + factor: 5 + """, + ), + ( + "test_create_requester_wait_time_from_header_error_handler", + """ + error_handler: + backoff_strategies: + - type: "WaitTimeFromHeader" + header: "a_header" + """, + ), + ( + "test_create_requester_wait_time_until_from_header_error_handler", + """ + error_handler: + backoff_strategies: + - type: "WaitUntilTimeFromHeader" + header: "a_header" + """, + ), + ( + "test_create_requester_no_error_handler", + """""", + ), + ], +) +def test_create_requester(test_name, error_handler): + content = f""" requester: type: HttpRequester path: "/v3/marketing/lists" @@ -461,13 +506,14 @@ def test_create_requester(): url_base: "https://api.sendgrid.com" authenticator: type: "BasicHttpAuthenticator" - username: "{{ options.name }}" - password: "{{ config.apikey }}" + username: "{{{{ options.name}}}}" + password: "{{{{ config.apikey }}}}" request_options_provider: request_parameters: a_parameter: "something_here" request_headers: header: header_value + {error_handler} """ config = parser.parse(content) @@ -498,7 +544,6 @@ def test_create_composite_error_handler(): - response_filters: - http_codes: [ 403 ] action: RETRY - error_message: "Retryable error received: {{ response.message }}" """ config = parser.parse(content) @@ -510,7 +555,6 @@ def test_create_composite_error_handler(): assert isinstance(component.error_handlers[0].response_filters[0], HttpResponseFilter) assert component.error_handlers[0].response_filters[0].predicate.condition == "{{ 'code' in response }}" assert component.error_handlers[1].response_filters[0].http_codes == [403] - assert component.error_handlers[1].response_filters[0].error_message.string == "Retryable error received: {{ response.message }}" assert isinstance(component, CompositeErrorHandler) @@ -685,37 +729,6 @@ def test_add_fields(self): ] assert expected == component.transformations - def test_add_fields_path_in_options(self): - content = f""" - the_stream: - class_name: airbyte_cdk.sources.declarative.declarative_stream.DeclarativeStream - $options: - {self.base_options} - path: "/wrong_path" - transformations: - - type: AddFields - fields: - - path: ["field1"] - value: "static_value" - """ - config = parser.parse(content) - - factory.create_component(config["the_stream"], input_config, False) - - component = factory.create_component(config["the_stream"], input_config)() - assert isinstance(component, DeclarativeStream) - expected = [ - AddFields( - fields=[ - AddedFieldDefinition( - path=["field1"], value=InterpolatedString(string="static_value", default="static_value", options={}), options={} - ) - ], - options={}, - ) - ] - assert expected == component.transformations - def test_validation_wrong_input_type(): content = """ diff --git a/docs/connector-development/config-based/understanding-the-yaml-file/error-handling.md b/docs/connector-development/config-based/understanding-the-yaml-file/error-handling.md index fdb3a6f07d61..f229190c7425 100644 --- a/docs/connector-development/config-based/understanding-the-yaml-file/error-handling.md +++ b/docs/connector-development/config-based/understanding-the-yaml-file/error-handling.md @@ -157,8 +157,8 @@ Schema: BackoffStrategy: type: object anyOf: - - "$ref": "#/definitions/ExponentialBackoff" - - "$ref": "#/definitions/ConstantBackoff" + - "$ref": "#/definitions/ExponentialBackoffStrategy" + - "$ref": "#/definitions/ConstantBackoffStrategy" - "$ref": "#/definitions/WaitTimeFromHeader" - "$ref": "#/definitions/WaitUntilTimeFromHeader" ``` @@ -170,7 +170,7 @@ This is the default backoff strategy. The requester will backoff with an exponen Schema: ```yaml - ExponentialBackoff: + ExponentialBackoffStrategy: type: object additionalProperties: true properties: @@ -183,12 +183,12 @@ Schema: ### Constant Backoff -When using the `ConstantBackoff` strategy, the requester will backoff with a constant interval. +When using the `ConstantBackoffStrategy` strategy, the requester will backoff with a constant interval. Schema: ```yaml - ConstantBackoff: + ConstantBackoffStrategy: type: object additionalProperties: true required: @@ -340,13 +340,13 @@ requester: - predicate: "{{ 'code' in response }}" action: RETRY backoff_strategies: - - type: "ConstantBackoff" + - type: "ConstantBackoffStrategy" backoff_time_in_seconds: 5 - response_filters: - http_codes: [ 403 ] action: RETRY backoff_strategies: - - type: "ExponentialBackoff" + - type: "ExponentialBackoffStrategy" ``` ## More readings From 186580a6ee364285d753ef3853c8b24d47009be9 Mon Sep 17 00:00:00 2001 From: Brian Lai <51336873+brianjlai@users.noreply.github.com> Date: Thu, 3 Nov 2022 23:25:01 -0400 Subject: [PATCH 38/73] [low-code] replace emptySchemaLoader with DefaultSchemaLoader (#18947) * replace emptySchemaLoader with DefaultSchemaLoader * fix test name * fix test * add logging for when we default to the empty schema * increment patch version * fix formatting * update changelog --- airbyte-cdk/python/CHANGELOG.md | 4 ++ .../sources/declarative/declarative_stream.py | 4 +- .../parsers/class_types_registry.py | 2 - .../default_implementation_registry.py | 4 +- .../sources/declarative/schema/__init__.py | 4 +- .../schema/default_schema_loader.py | 46 +++++++++++++++++++ .../declarative/schema/empty_schema_loader.py | 36 --------------- airbyte-cdk/python/setup.py | 2 +- .../schema/test_default_schema_loader.py | 32 +++++++++++++ ...ema.py => test_json_file_schema_loader.py} | 0 .../sources/declarative/test_factory.py | 4 +- .../test_yaml_declarative_source.py | 2 +- 12 files changed, 92 insertions(+), 48 deletions(-) create mode 100644 airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/default_schema_loader.py delete mode 100644 airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/empty_schema_loader.py create mode 100644 airbyte-cdk/python/unit_tests/sources/declarative/schema/test_default_schema_loader.py rename airbyte-cdk/python/unit_tests/sources/declarative/schema/{test_json_schema.py => test_json_file_schema_loader.py} (100%) diff --git a/airbyte-cdk/python/CHANGELOG.md b/airbyte-cdk/python/CHANGELOG.md index 0d6c5ec08cb4..2c6b82e1c912 100644 --- a/airbyte-cdk/python/CHANGELOG.md +++ b/airbyte-cdk/python/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.5.3 +Low-code: Replace EmptySchemaLoader with DefaultSchemaLoader to retain backwards compatibility +Low-code: Evaluate backoff strategies at runtime + ## 0.5.2 Low-code: Allow for read even when schemas are not defined for a connector yet diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/declarative_stream.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/declarative_stream.py index c998ee98342f..9d98bec41a72 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/declarative_stream.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/declarative_stream.py @@ -7,7 +7,7 @@ from airbyte_cdk.models import SyncMode from airbyte_cdk.sources.declarative.retrievers.retriever import Retriever -from airbyte_cdk.sources.declarative.schema import EmptySchemaLoader +from airbyte_cdk.sources.declarative.schema import DefaultSchemaLoader from airbyte_cdk.sources.declarative.schema.schema_loader import SchemaLoader from airbyte_cdk.sources.declarative.transformations import RecordTransformation from airbyte_cdk.sources.declarative.types import Config, StreamSlice @@ -48,7 +48,7 @@ class DeclarativeStream(Stream, JsonSchemaMixin): def __post_init__(self, options: Mapping[str, Any]): self.stream_cursor_field = self.stream_cursor_field or [] self.transformations = self.transformations or [] - self._schema_loader = self.schema_loader if self.schema_loader else EmptySchemaLoader(config=self.config, options=options) + self._schema_loader = self.schema_loader if self.schema_loader else DefaultSchemaLoader(config=self.config, options=options) @property def primary_key(self) -> Optional[Union[str, List[str], List[List[str]]]]: diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/class_types_registry.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/class_types_registry.py index 2478c4d998a3..6f18376f2a85 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/class_types_registry.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/class_types_registry.py @@ -32,7 +32,6 @@ from airbyte_cdk.sources.declarative.requesters.paginators.strategies.offset_increment import OffsetIncrement from airbyte_cdk.sources.declarative.requesters.paginators.strategies.page_increment import PageIncrement from airbyte_cdk.sources.declarative.retrievers.simple_retriever import SimpleRetriever -from airbyte_cdk.sources.declarative.schema import EmptySchemaLoader from airbyte_cdk.sources.declarative.schema.json_file_schema_loader import JsonFileSchemaLoader from airbyte_cdk.sources.declarative.stream_slicers.cartesian_product_stream_slicer import CartesianProductStreamSlicer from airbyte_cdk.sources.declarative.stream_slicers.datetime_stream_slicer import DatetimeStreamSlicer @@ -59,7 +58,6 @@ "DefaultErrorHandler": DefaultErrorHandler, "DefaultPaginator": DefaultPaginator, "DpathExtractor": DpathExtractor, - "EmptySchemaLoader": EmptySchemaLoader, "ExponentialBackoffStrategy": ExponentialBackoffStrategy, "HttpRequester": HttpRequester, "InterpolatedBoolean": InterpolatedBoolean, diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py index 84e1f3631c05..06cdac4fada9 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py @@ -30,7 +30,7 @@ from airbyte_cdk.sources.declarative.requesters.requester import Requester from airbyte_cdk.sources.declarative.retrievers.retriever import Retriever from airbyte_cdk.sources.declarative.retrievers.simple_retriever import SimpleRetriever -from airbyte_cdk.sources.declarative.schema import EmptySchemaLoader +from airbyte_cdk.sources.declarative.schema import DefaultSchemaLoader from airbyte_cdk.sources.declarative.schema.schema_loader import SchemaLoader from airbyte_cdk.sources.declarative.stream_slicers.single_slice import SingleSlice from airbyte_cdk.sources.declarative.stream_slicers.stream_slicer import StreamSlicer @@ -58,7 +58,7 @@ RequestOptionsProvider: InterpolatedRequestOptionsProvider, Requester: HttpRequester, Retriever: SimpleRetriever, - SchemaLoader: EmptySchemaLoader, + SchemaLoader: DefaultSchemaLoader, Stream: DeclarativeStream, StreamSlicer: SingleSlice, } diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/__init__.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/__init__.py index 85de3cc4f2f6..ce2281d59f0c 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/__init__.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/__init__.py @@ -2,8 +2,8 @@ # Copyright (c) 2022 Airbyte, Inc., all rights reserved. # -from airbyte_cdk.sources.declarative.schema.empty_schema_loader import EmptySchemaLoader +from airbyte_cdk.sources.declarative.schema.default_schema_loader import DefaultSchemaLoader from airbyte_cdk.sources.declarative.schema.json_file_schema_loader import JsonFileSchemaLoader from airbyte_cdk.sources.declarative.schema.schema_loader import SchemaLoader -__all__ = ["JsonFileSchemaLoader", "EmptySchemaLoader", "SchemaLoader"] +__all__ = ["JsonFileSchemaLoader", "DefaultSchemaLoader", "SchemaLoader"] diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/default_schema_loader.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/default_schema_loader.py new file mode 100644 index 000000000000..8e5129ebeab9 --- /dev/null +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/default_schema_loader.py @@ -0,0 +1,46 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +import logging +from dataclasses import InitVar, dataclass +from typing import Any, Mapping + +from airbyte_cdk.sources.declarative.schema.json_file_schema_loader import JsonFileSchemaLoader +from airbyte_cdk.sources.declarative.schema.schema_loader import SchemaLoader +from airbyte_cdk.sources.declarative.types import Config +from dataclasses_jsonschema import JsonSchemaMixin + + +@dataclass +class DefaultSchemaLoader(SchemaLoader, JsonSchemaMixin): + """ + Loads a schema from the default location or returns an empty schema for streams that have not defined their schema file yet. + + Attributes: + config (Config): The user-provided configuration as specified by the source's spec + options (Mapping[str, Any]): Additional arguments to pass to the string interpolation if needed + """ + + config: Config + options: InitVar[Mapping[str, Any]] + + def __post_init__(self, options: Mapping[str, Any]): + self._options = options + self.default_loader = JsonFileSchemaLoader(options=options, config=self.config) + + def get_json_schema(self) -> Mapping[str, Any]: + """ + Attempts to retrieve a schema from the default filepath location or returns the empty schema if a schema cannot be found. + + :return: The empty schema + """ + + try: + return self.default_loader.get_json_schema() + except FileNotFoundError: + # A slight hack since we don't directly have the stream name. However, when building the default filepath we assume the + # runtime options stores stream name 'name' so we'll do the same here + stream_name = self._options.get("name", "") + logging.info(f"Could not find schema for stream {stream_name}, defaulting to the empty schema") + return {} diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/empty_schema_loader.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/empty_schema_loader.py deleted file mode 100644 index 2c189793bf27..000000000000 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/schema/empty_schema_loader.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2022 Airbyte, Inc., all rights reserved. -# - -from dataclasses import InitVar, dataclass -from typing import Any, Mapping - -from airbyte_cdk.sources.declarative.schema.schema_loader import SchemaLoader -from airbyte_cdk.sources.declarative.types import Config -from dataclasses_jsonschema import JsonSchemaMixin - - -@dataclass -class EmptySchemaLoader(SchemaLoader, JsonSchemaMixin): - """ - Loads an empty schema for streams that have not defined their schema file yet. - - Attributes: - config (Config): The user-provided configuration as specified by the source's spec - options (Mapping[str, Any]): Additional arguments to pass to the string interpolation if needed - """ - - config: Config - options: InitVar[Mapping[str, Any]] - - def __post_init__(self, options: Mapping[str, Any]): - pass - - def get_json_schema(self) -> Mapping[str, Any]: - """ - Returns by default the empty schema. - - :return: The empty schema - """ - - return {} diff --git a/airbyte-cdk/python/setup.py b/airbyte-cdk/python/setup.py index b9db9aa0088f..7aec36ec8e5c 100644 --- a/airbyte-cdk/python/setup.py +++ b/airbyte-cdk/python/setup.py @@ -15,7 +15,7 @@ setup( name="airbyte-cdk", - version="0.5.2", + version="0.5.3", description="A framework for writing Airbyte Connectors.", long_description=README, long_description_content_type="text/markdown", diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/schema/test_default_schema_loader.py b/airbyte-cdk/python/unit_tests/sources/declarative/schema/test_default_schema_loader.py new file mode 100644 index 000000000000..fbb71e6e1b51 --- /dev/null +++ b/airbyte-cdk/python/unit_tests/sources/declarative/schema/test_default_schema_loader.py @@ -0,0 +1,32 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +from unittest.mock import MagicMock + +import pytest +from airbyte_cdk.sources.declarative.schema import DefaultSchemaLoader + + +@pytest.mark.parametrize( + "found_schema, found_error, expected_schema", + [ + pytest.param( + {"type": "object", "properties": {}}, None, {"type": "object", "properties": {}}, id="test_has_schema_in_default_location" + ), + pytest.param(None, FileNotFoundError, {}, id="test_schema_file_does_not_exist"), + ], +) +def test_get_json_schema(found_schema, found_error, expected_schema): + default_schema_loader = DefaultSchemaLoader({}, {}) + + json_file_schema_loader = MagicMock() + if found_schema: + json_file_schema_loader.get_json_schema.return_value = {"type": "object", "properties": {}} + if found_error: + json_file_schema_loader.get_json_schema.side_effect = found_error + + default_schema_loader.default_loader = json_file_schema_loader + + actual_schema = default_schema_loader.get_json_schema() + assert actual_schema == expected_schema diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/schema/test_json_schema.py b/airbyte-cdk/python/unit_tests/sources/declarative/schema/test_json_file_schema_loader.py similarity index 100% rename from airbyte-cdk/python/unit_tests/sources/declarative/schema/test_json_schema.py rename to airbyte-cdk/python/unit_tests/sources/declarative/schema/test_json_file_schema_loader.py diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py b/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py index 600044fbc119..8b496c5c0ffd 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py @@ -34,7 +34,7 @@ ) from airbyte_cdk.sources.declarative.requesters.requester import HttpMethod from airbyte_cdk.sources.declarative.retrievers.simple_retriever import SimpleRetriever -from airbyte_cdk.sources.declarative.schema import EmptySchemaLoader +from airbyte_cdk.sources.declarative.schema import DefaultSchemaLoader from airbyte_cdk.sources.declarative.schema.json_file_schema_loader import JsonFileSchemaLoader from airbyte_cdk.sources.declarative.stream_slicers.datetime_stream_slicer import DatetimeStreamSlicer from airbyte_cdk.sources.declarative.stream_slicers.list_stream_slicer import ListStreamSlicer @@ -603,7 +603,7 @@ def test_config_with_defaults(): assert type(stream) == DeclarativeStream assert stream.primary_key == "id" assert stream.name == "lists" - assert type(stream.schema_loader) == EmptySchemaLoader + assert type(stream.schema_loader) == DefaultSchemaLoader assert type(stream.retriever) == SimpleRetriever assert stream.retriever.requester.http_method == HttpMethod.GET diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/test_yaml_declarative_source.py b/airbyte-cdk/python/unit_tests/sources/declarative/test_yaml_declarative_source.py index 5eb99ddd78d1..340d765a52ff 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/test_yaml_declarative_source.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/test_yaml_declarative_source.py @@ -268,7 +268,7 @@ def test_generate_schema(): declarative_stream = schema["definitions"]["DeclarativeStream"] assert {"retriever", "config"}.issubset(declarative_stream["required"]) - assert {"$ref": "#/definitions/EmptySchemaLoader"} in declarative_stream["properties"]["schema_loader"]["anyOf"] + assert {"$ref": "#/definitions/DefaultSchemaLoader"} in declarative_stream["properties"]["schema_loader"]["anyOf"] assert {"$ref": "#/definitions/JsonFileSchemaLoader"} in declarative_stream["properties"]["schema_loader"]["anyOf"] assert declarative_stream["properties"]["retriever"]["$ref"] == "#/definitions/SimpleRetriever" assert declarative_stream["properties"]["name"]["type"] == "string" From 77f3e3b037238518870ec19145e53c75fa57df9d Mon Sep 17 00:00:00 2001 From: Sophia Wiley <106352739+sophia-wiley@users.noreply.github.com> Date: Thu, 3 Nov 2022 23:18:23 -0700 Subject: [PATCH 39/73] Multi-cloud documentation (#18872) I am going to edit some of the wording in later PRs, but merging this for now. * added multicloud info * Update docs/cloud/getting-started-with-airbyte-cloud.md Co-authored-by: Joey Marshment-Howell * edited for clarity * incorporated suggestions Co-authored-by: Joey Marshment-Howell --- .../getting-started-with-airbyte-cloud.md | 66 +++++++------------ docs/cloud/managing-airbyte-cloud.md | 65 +++++++++++++++--- 2 files changed, 79 insertions(+), 52 deletions(-) diff --git a/docs/cloud/getting-started-with-airbyte-cloud.md b/docs/cloud/getting-started-with-airbyte-cloud.md index 1b6705c177bd..d0cebb451707 100644 --- a/docs/cloud/getting-started-with-airbyte-cloud.md +++ b/docs/cloud/getting-started-with-airbyte-cloud.md @@ -60,44 +60,14 @@ A connection is an automated data pipeline that replicates data from a source to Setting up a connection involves configuring the following parameters: - - - - - - - - - - - - - - - - - - - - - - - - - -
Parameter - Description -
Replication frequency - How often should the data sync? -
Destination Namespace and stream names - Where should the replicated data be written? -
Catalog selection - Which streams and fields should be replicated from the source to the destination? -
Sync mode - How should the streams be replicated (read and written)? -
Optional transformations - How should Airbyte protocol messages (raw JSON blob) data be converted into other data representations? -
+| Parameter | Description | +|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Replication frequency | How often should the data sync? | +| Data residency | Where should the data be processed? To choose the preferred data processing location for all of your connections, set your default [data residency](https://docs.airbyte.com/cloud/managing-airbyte-cloud#choose-your-default-data-residency). | +| Destination Namespace and stream names | Where should the replicated data be written? | +| Catalog selection | Which streams and fields should be replicated from the source to the destination? | +| Sync mode | How should the streams be replicated (read and written)? | +| Optional transformations | How should Airbyte protocol messages (raw JSON blob) data be converted into other data representations? | For more information, see [Connections and Sync Modes](../understanding-airbyte/connections/README.md) and [Namespaces](../understanding-airbyte/namespaces.md) @@ -214,7 +184,19 @@ Verify the sync by checking the logs: ## Allowlist IP address -You may need to allowlist one of our IP addresses to enable access to Airbyte: -- 34.106.109.131 -- 34.106.196.165 -- 34.106.60.246 +Depending on your data residency location, you may need to allowlist the following IP addresses to enable access to Airbyte: + +### United States and Airbyte Default +#### GCP region: us-west2 +* 34.106.109.131 +* 34.106.196.165 +* 34.106.60.246 + +### European Union +#### AWS region: eu-west-3 +* 34.106.109.131 +* 34.106.196.165 +* 34.106.60.246 +* 13.37.4.46 +* 13.37.142.60 +* 35.181.124.238 diff --git a/docs/cloud/managing-airbyte-cloud.md b/docs/cloud/managing-airbyte-cloud.md index a7692ca7ee2f..faa3a4c93497 100644 --- a/docs/cloud/managing-airbyte-cloud.md +++ b/docs/cloud/managing-airbyte-cloud.md @@ -38,16 +38,6 @@ To remove a user from your workspace: 4. The **Remove user** dialog displays. Click **Remove**. -### Switch between multiple workspaces - -To switch between workspaces: - -1. On the [Airbyte Cloud](http://cloud.airbyte.io) dashboard, click the current workspace name under the Airbyte logo in the navigation bar. - -2. Click **View all workspaces**. - -3. Click the name of the workspace you want to switch to. - ### Rename a workspace To rename a workspace: @@ -84,6 +74,44 @@ You can use one or multiple workspaces with Airbyte Cloud. | Single | You can use the same payment method for all purchases. | Credits pay for the use of resources in a workspace when you run a sync. Resource usage cannot be divided and paid for separately (for example, you cannot bill different departments in your organization for the usage of some credits in one workspace). | | Multiple | Workspaces are independent of each other, so you can use a different payment method card for each workspace (for example, different credit cards per department in your organization). | You can use the same payment method for different workspaces, but each workspace is billed separately. Managing billing for each workspace can become complicated if you have many workspaces. | +### Switch between multiple workspaces + +To switch between workspaces: + +1. On the [Airbyte Cloud](http://cloud.airbyte.io) dashboard, click the current workspace name under the Airbyte logo in the navigation bar. + +2. Click **View all workspaces**. + +3. Click the name of the workspace you want to switch to. + +### Choose your default data residency +Default data residency allows you to choose where your data is processed. When you set the default data residency, it is applied to all new connections, but it does not affect existing connections. + +For individual connections, you can choose a data residency that is different from the default. You can do this in the [connection settings](#choose-the-data-residency-for-a-connection) or when you create a [new connection](https://docs.airbyte.com/cloud/getting-started-with-airbyte-cloud#set-up-a-connection). + +:::note + +Your data is processed in the chosen residency, but some data is still stored in the US. + +::: + + +To choose your default data residency: + +1. On the [Airbyte Cloud](http://cloud.airbyte.io) dashboard, click **Settings** in the navigation bar. + +2. In the Workspace settings sidebar, click **Default Data Residency**. + +3. Click the dropdown and choose the location for your default data residency. + +4. Click **Save changes**. + +:::info + +Depending on your network configuration, you may need to add [IP addresses](https://docs.airbyte.com/cloud/getting-started-with-airbyte-cloud#allowlist-ip-address) to your allowlist. + +::: + ## Manage Airbyte Cloud notifications To set up Slack notifications: @@ -259,6 +287,23 @@ To display **Connection State**: The **Connection State** displays. +## Choose the data residency for a connection +To choose the data residency for an existing connection: + +1. On the [Airbyte Cloud](http://cloud.airbyte.io) dashboard, click **Connections** in the navigation bar and then click the connection that you want to change. + + The Connection page displays. + +2. Click the **Settings** tab. + +3. Click the **Data residency** dropdown and choose the location for your default data residency. + +:::note + +You can also choose data residency when creating a [new connection](https://docs.airbyte.com/cloud/getting-started-with-airbyte-cloud#set-up-a-connection), or you can set the [default data residency](#choose-your-default-data-residency) for all of your connections. + +::: + ## Buy credits This section guides you through purchasing credits on Airbyte Cloud. An Airbyte [credit](https://airbyte.com/pricing) is a unit of measure used to pay for Airbyte resources when you run a sync. From 6967d146ec38b4369a3890efd9bdf903683ddb58 Mon Sep 17 00:00:00 2001 From: Liren Tu Date: Fri, 4 Nov 2022 01:13:02 -0700 Subject: [PATCH 40/73] =?UTF-8?q?=F0=9F=8E=89=20Source=20redshift=20&=20bi?= =?UTF-8?q?gquery:=20emit=20cursor=20count=20in=20state=20(#18954)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump version for redshift, bigquery, and snowflake * auto-bump connector version * auto-bump connector version * Log failed refresh token response * Revert snowflake version bump Co-authored-by: Octavia Squidington III --- .../init/src/main/resources/seed/source_definitions.yaml | 4 ++-- airbyte-config/init/src/main/resources/seed/source_specs.yaml | 4 ++-- airbyte-integrations/connectors/source-bigquery/Dockerfile | 2 +- airbyte-integrations/connectors/source-redshift/Dockerfile | 2 +- .../SnowflakeDataSourceUtils.java | 2 +- docs/integrations/sources/bigquery.md | 2 +- docs/integrations/sources/redshift.md | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index 077e92f16f80..fb7e5b2bec36 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -148,7 +148,7 @@ - name: BigQuery sourceDefinitionId: bfd1ddf8-ae8a-4620-b1d7-55597d2ba08c dockerRepository: airbyte/source-bigquery - dockerImageTag: 0.2.2 + dockerImageTag: 0.2.3 documentationUrl: https://docs.airbyte.com/integrations/sources/bigquery icon: bigquery.svg sourceType: database @@ -1062,7 +1062,7 @@ - name: Redshift sourceDefinitionId: e87ffa8e-a3b5-f69c-9076-6011339de1f6 dockerRepository: airbyte/source-redshift - dockerImageTag: 0.3.14 + dockerImageTag: 0.3.15 documentationUrl: https://docs.airbyte.com/integrations/sources/redshift icon: redshift.svg sourceType: database diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index da22c26eceff..235f198ab0d3 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -1626,7 +1626,7 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] -- dockerImage: "airbyte/source-bigquery:0.2.2" +- dockerImage: "airbyte/source-bigquery:0.2.3" spec: documentationUrl: "https://docs.airbyte.com/integrations/sources/bigquery" connectionSpecification: @@ -10300,7 +10300,7 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] -- dockerImage: "airbyte/source-redshift:0.3.14" +- dockerImage: "airbyte/source-redshift:0.3.15" spec: documentationUrl: "https://docs.airbyte.com/integrations/destinations/redshift" connectionSpecification: diff --git a/airbyte-integrations/connectors/source-bigquery/Dockerfile b/airbyte-integrations/connectors/source-bigquery/Dockerfile index b03d2204387c..70190771cee5 100644 --- a/airbyte-integrations/connectors/source-bigquery/Dockerfile +++ b/airbyte-integrations/connectors/source-bigquery/Dockerfile @@ -17,5 +17,5 @@ ENV APPLICATION source-bigquery COPY --from=build /airbyte /airbyte # Airbyte's build system uses these labels to know what to name and tag the docker images produced by this Dockerfile. -LABEL io.airbyte.version=0.2.2 +LABEL io.airbyte.version=0.2.3 LABEL io.airbyte.name=airbyte/source-bigquery diff --git a/airbyte-integrations/connectors/source-redshift/Dockerfile b/airbyte-integrations/connectors/source-redshift/Dockerfile index bb4df575ee4c..0a9527c26e36 100644 --- a/airbyte-integrations/connectors/source-redshift/Dockerfile +++ b/airbyte-integrations/connectors/source-redshift/Dockerfile @@ -16,5 +16,5 @@ ENV APPLICATION source-redshift COPY --from=build /airbyte /airbyte -LABEL io.airbyte.version=0.3.14 +LABEL io.airbyte.version=0.3.15 LABEL io.airbyte.name=airbyte/source-redshift diff --git a/airbyte-integrations/connectors/source-snowflake/src/main/java/io.airbyte.integrations.source.snowflake/SnowflakeDataSourceUtils.java b/airbyte-integrations/connectors/source-snowflake/src/main/java/io.airbyte.integrations.source.snowflake/SnowflakeDataSourceUtils.java index 344236f417b7..e0e6f1a1d5fd 100644 --- a/airbyte-integrations/connectors/source-snowflake/src/main/java/io.airbyte.integrations.source.snowflake/SnowflakeDataSourceUtils.java +++ b/airbyte-integrations/connectors/source-snowflake/src/main/java/io.airbyte.integrations.source.snowflake/SnowflakeDataSourceUtils.java @@ -123,7 +123,7 @@ public static String getAccessTokenUsingRefreshToken(final String hostName, } else { LOGGER.error("Failed to obtain accessToken using refresh token. " + jsonResponse); throw new RuntimeException( - "Failed to obtain accessToken using refresh token."); + "Failed to obtain accessToken using refresh token. " + jsonResponse); } } catch (final InterruptedException e) { throw new IOException("Failed to refreshToken", e); diff --git a/docs/integrations/sources/bigquery.md b/docs/integrations/sources/bigquery.md index d8a6968701da..f48fe2d7e258 100644 --- a/docs/integrations/sources/bigquery.md +++ b/docs/integrations/sources/bigquery.md @@ -88,7 +88,7 @@ Once you've configured BigQuery as a source, delete the Service Account Key from | Version | Date | Pull Request | Subject | | :--- | :--- | :--- | :--- | -| | 2022-10-13 | [15535](https://github.com/airbytehq/airbyte/pull/16238) | Update incremental query to avoid data missing when new data is inserted at the same time as a sync starts under non-CDC incremental mode | +| 0.2.3 | 2022-10-13 | [15535](https://github.com/airbytehq/airbyte/pull/16238) | Update incremental query to avoid data missing when new data is inserted at the same time as a sync starts under non-CDC incremental mode | | 0.2.2 | 2022-09-22 | [16902](https://github.com/airbytehq/airbyte/pull/16902) | Source BigQuery: added user agent header | | 0.2.1 | 2022-09-14 | [15668](https://github.com/airbytehq/airbyte/pull/15668) | Wrap logs in AirbyteLogMessage | | 0.2.0 | 2022-07-26 | [14362](https://github.com/airbytehq/airbyte/pull/14362) | Integral columns are now discovered as int64 fields. | diff --git a/docs/integrations/sources/redshift.md b/docs/integrations/sources/redshift.md index 2311a930376a..3b0ba43ac40f 100644 --- a/docs/integrations/sources/redshift.md +++ b/docs/integrations/sources/redshift.md @@ -54,7 +54,7 @@ All Redshift connections are encrypted using SSL | Version | Date | Pull Request | Subject | |:--------|:-----------| :----- |:----------------------------------------------------------------------------------------------------------| -| | 2022-10-13 | [15535](https://github.com/airbytehq/airbyte/pull/16238) | Update incremental query to avoid data missing when new data is inserted at the same time as a sync starts under non-CDC incremental mode | +| 0.3.15 | 2022-10-13 | [15535](https://github.com/airbytehq/airbyte/pull/16238) | Update incremental query to avoid data missing when new data is inserted at the same time as a sync starts under non-CDC incremental mode | | 0.3.14 | 2022-09-01 | [16258](https://github.com/airbytehq/airbyte/pull/16258) | Emit state messages more frequently | | 0.3.13 | 2022-05-25 | | Added JDBC URL params | | 0.3.12 | 2022-08-18 | [14356](https://github.com/airbytehq/airbyte/pull/14356) | DB Sources: only show a table can sync incrementally if at least one column can be used as a cursor field | From bf58536e2b925d664f9b6a3371f2c93855b1dbf0 Mon Sep 17 00:00:00 2001 From: letiescanciano <45267095+letiescanciano@users.noreply.github.com> Date: Fri, 4 Nov 2022 10:01:36 +0100 Subject: [PATCH 41/73] =?UTF-8?q?=F0=9F=AA=9F=C2=A0=F0=9F=94=A7=20=20Add?= =?UTF-8?q?=20Segment=20event=20to=20invite=20users=20modal=20(#18862)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🪟 🔧 Add Segment event to invite users modal --- .github/teams.yml | 3 +++ .github/workflows/label-pr-by-team.yml | 9 +++++++++ airbyte-webapp/src/core/analytics/types.ts | 1 + .../cloud/services/users/InviteUsersModalService.tsx | 9 +++++++-- .../views/users/InviteUsersHint/InviteUsersHint.tsx | 2 +- .../views/users/InviteUsersModal/InviteUsersModal.tsx | 8 +++++++- .../views/users/UsersSettingsView/UsersSettingsView.tsx | 2 +- 7 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 .github/teams.yml create mode 100644 .github/workflows/label-pr-by-team.yml diff --git a/.github/teams.yml b/.github/teams.yml new file mode 100644 index 000000000000..34c12bfffa59 --- /dev/null +++ b/.github/teams.yml @@ -0,0 +1,3 @@ +team/growth: + - "@letiescanciano" + - "@arnaudjnn" diff --git a/.github/workflows/label-pr-by-team.yml b/.github/workflows/label-pr-by-team.yml new file mode 100644 index 000000000000..da86682e1af0 --- /dev/null +++ b/.github/workflows/label-pr-by-team.yml @@ -0,0 +1,9 @@ +name: "Add labels to github PRs based on team" +on: pull_request +jobs: + team-labeler: + runs-on: ubuntu-latest + steps: + - uses: JulienKode/team-labeler-action@v0.1.1 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/airbyte-webapp/src/core/analytics/types.ts b/airbyte-webapp/src/core/analytics/types.ts index f73597c16786..b55359d6c769 100644 --- a/airbyte-webapp/src/core/analytics/types.ts +++ b/airbyte-webapp/src/core/analytics/types.ts @@ -27,6 +27,7 @@ export const enum Action { SELECTION_OPENED = "SelectionOpened", CHECKOUT_START = "CheckoutStart", LOAD_MORE_JOBS = "LoadMoreJobs", + INVITE = "Invite", } export type EventParams = Record; diff --git a/airbyte-webapp/src/packages/cloud/services/users/InviteUsersModalService.tsx b/airbyte-webapp/src/packages/cloud/services/users/InviteUsersModalService.tsx index 7b209f743572..3428b7b3e205 100644 --- a/airbyte-webapp/src/packages/cloud/services/users/InviteUsersModalService.tsx +++ b/airbyte-webapp/src/packages/cloud/services/users/InviteUsersModalService.tsx @@ -19,7 +19,12 @@ export const useInviteUsersModalService = () => { return ctx; }; -export const InviteUsersModalServiceProvider: React.FC> = ({ children }) => { +interface InviteUsersModalServiceProviderProps { + invitedFrom: "source" | "destination" | "user.settings"; +} +export const InviteUsersModalServiceProvider: React.FC< + React.PropsWithChildren +> = ({ children, invitedFrom }) => { const [isOpen, toggleIsOpen] = useToggle(false); const contextValue = useMemo( @@ -33,7 +38,7 @@ export const InviteUsersModalServiceProvider: React.FC {children} - {isOpen && } + {isOpen && } ); }; diff --git a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.tsx b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.tsx index 606f45481dc3..72ead482a842 100644 --- a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.tsx +++ b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersHint/InviteUsersHint.tsx @@ -60,7 +60,7 @@ export const InviteUsersHint: React.VFC = (props) => { const isVisible = useExperiment("connector.inviteUsersHint.visible", false); return isVisible ? ( - + ) : null; diff --git a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersModal/InviteUsersModal.tsx b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersModal/InviteUsersModal.tsx index eb78eef6c241..82ea74f3acac 100644 --- a/airbyte-webapp/src/packages/cloud/views/users/InviteUsersModal/InviteUsersModal.tsx +++ b/airbyte-webapp/src/packages/cloud/views/users/InviteUsersModal/InviteUsersModal.tsx @@ -13,6 +13,8 @@ import { DropDown } from "components/ui/DropDown"; import { Input } from "components/ui/Input"; import { Modal } from "components/ui/Modal"; +import { Action, Namespace } from "core/analytics"; +import { useAnalyticsService } from "hooks/services/Analytics"; import { useNotificationService } from "hooks/services/Notification"; import { useCurrentWorkspace } from "hooks/services/useWorkspace"; import { useUserHook } from "packages/cloud/services/users/UseUserHook"; @@ -56,6 +58,7 @@ const ROLE_OPTIONS = [ export const InviteUsersModal: React.FC<{ onClose: () => void; + invitedFrom: "source" | "destination" | "user.settings"; }> = (props) => { const { formatMessage } = useIntl(); const { workspaceId } = useCurrentWorkspace(); @@ -64,7 +67,7 @@ export const InviteUsersModal: React.FC<{ const { mutateAsync: invite } = inviteUserLogic; const isRoleVisible = false; // Temporarily hiding roles because there's only 'Admin' in cloud. - + const analyticsService = useAnalyticsService(); return ( } onClose={props.onClose}> {({ values, isValid, isSubmitting, dirty, setFieldValue }) => { diff --git a/airbyte-webapp/src/packages/cloud/views/users/UsersSettingsView/UsersSettingsView.tsx b/airbyte-webapp/src/packages/cloud/views/users/UsersSettingsView/UsersSettingsView.tsx index 59e5b582032d..8c624dc0b524 100644 --- a/airbyte-webapp/src/packages/cloud/views/users/UsersSettingsView/UsersSettingsView.tsx +++ b/airbyte-webapp/src/packages/cloud/views/users/UsersSettingsView/UsersSettingsView.tsx @@ -120,7 +120,7 @@ export const UsersSettingsView: React.VFC = () => { useTrackPage(PageTrackingCodes.SETTINGS_ACCESS_MANAGEMENT); return ( - +
From 8145be55a30f4cd8f72afbdf78226cf1f468c73a Mon Sep 17 00:00:00 2001 From: Denys Davydov Date: Fri, 4 Nov 2022 11:44:51 +0200 Subject: [PATCH 42/73] Low-code CDK: safe get response.json (#18931) * low-code cdk: safe get response.json * flake fix --- airbyte-cdk/python/CHANGELOG.md | 3 +++ .../declarative/decoders/json_decoder.py | 5 ++++- .../error_handlers/http_response_filter.py | 11 ++++++++-- airbyte-cdk/python/setup.py | 2 +- .../sources/declarative/decoders/__init__.py | 0 .../declarative/decoders/test_json_decoder.py | 16 ++++++++++++++ .../test_http_response_filter.py | 22 +++++++++++-------- 7 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 airbyte-cdk/python/unit_tests/sources/declarative/decoders/__init__.py create mode 100644 airbyte-cdk/python/unit_tests/sources/declarative/decoders/test_json_decoder.py diff --git a/airbyte-cdk/python/CHANGELOG.md b/airbyte-cdk/python/CHANGELOG.md index 2c6b82e1c912..fda8cd5846ac 100644 --- a/airbyte-cdk/python/CHANGELOG.md +++ b/airbyte-cdk/python/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 0.5.4 +Low-code: Get response.json in a safe way + ## 0.5.3 Low-code: Replace EmptySchemaLoader with DefaultSchemaLoader to retain backwards compatibility Low-code: Evaluate backoff strategies at runtime diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/decoders/json_decoder.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/decoders/json_decoder.py index 1d34b79cd4c1..76533e975c85 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/decoders/json_decoder.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/decoders/json_decoder.py @@ -19,4 +19,7 @@ class JsonDecoder(Decoder, JsonSchemaMixin): options: InitVar[Mapping[str, Any]] def decode(self, response: requests.Response) -> Union[Mapping[str, Any], List]: - return response.json() or {} + try: + return response.json() + except requests.exceptions.JSONDecodeError: + return {} diff --git a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py index e95c5770e210..effd49a7cd41 100644 --- a/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py +++ b/airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py @@ -76,16 +76,23 @@ def _matches_filter(self, response: requests.Response) -> Optional[ResponseActio else: return None + @staticmethod + def _safe_response_json(response: requests.Response) -> dict: + try: + return response.json() + except requests.exceptions.JSONDecodeError: + return {} + def _create_error_message(self, response: requests.Response) -> str: """ Construct an error message based on the specified message template of the filter. :param response: The HTTP response which can be used during interpolation :return: The evaluated error message string to be emitted """ - return self.error_message.eval(self.config, response=response.json(), headers=response.headers) + return self.error_message.eval(self.config, response=self._safe_response_json(response), headers=response.headers) def _response_matches_predicate(self, response: requests.Response) -> bool: - return self.predicate and self.predicate.eval(None, response=response.json(), headers=response.headers) + return self.predicate and self.predicate.eval(None, response=self._safe_response_json(response), headers=response.headers) def _response_contains_error_message(self, response: requests.Response) -> bool: if not self.error_message_contains: diff --git a/airbyte-cdk/python/setup.py b/airbyte-cdk/python/setup.py index 7aec36ec8e5c..d133785a6ec9 100644 --- a/airbyte-cdk/python/setup.py +++ b/airbyte-cdk/python/setup.py @@ -15,7 +15,7 @@ setup( name="airbyte-cdk", - version="0.5.3", + version="0.5.4", description="A framework for writing Airbyte Connectors.", long_description=README, long_description_content_type="text/markdown", diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/decoders/__init__.py b/airbyte-cdk/python/unit_tests/sources/declarative/decoders/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/decoders/test_json_decoder.py b/airbyte-cdk/python/unit_tests/sources/declarative/decoders/test_json_decoder.py new file mode 100644 index 000000000000..04f00fa7379c --- /dev/null +++ b/airbyte-cdk/python/unit_tests/sources/declarative/decoders/test_json_decoder.py @@ -0,0 +1,16 @@ +# +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. +# + +import pytest +import requests +from airbyte_cdk.sources.declarative.decoders.json_decoder import JsonDecoder + + +@pytest.mark.parametrize( + "response_body, expected_json", (("", {}), ('{"healthcheck": {"status": "ok"}}', {"healthcheck": {"status": "ok"}})) +) +def test_json_decoder(requests_mock, response_body, expected_json): + requests_mock.register_uri("GET", "https://airbyte.io/", text=response_body) + response = requests.get("https://airbyte.io/") + assert JsonDecoder(options={}).decode(response) == expected_json diff --git a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/test_http_response_filter.py b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/test_http_response_filter.py index b44a479c7d7b..c24f3189f91d 100644 --- a/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/test_http_response_filter.py +++ b/airbyte-cdk/python/unit_tests/sources/declarative/requesters/error_handlers/test_http_response_filter.py @@ -2,9 +2,10 @@ # Copyright (c) 2022 Airbyte, Inc., all rights reserved. # -from unittest.mock import MagicMock +import json import pytest +import requests from airbyte_cdk.sources.declarative.requesters.error_handlers import HttpResponseFilter from airbyte_cdk.sources.declarative.requesters.error_handlers.response_action import ResponseAction from airbyte_cdk.sources.declarative.requesters.error_handlers.response_status import ResponseStatus @@ -86,18 +87,21 @@ "", None, "", - {"status_code": 403, "headers": {"error", "authentication_error"}, "json": {"reason": "permission denied"}}, + {"status_code": 403, "headers": {"error": "authentication_error"}, "json": {"reason": "permission denied"}}, None, id="test_response_does_not_match_filter", ), ], ) -def test_matches(action, http_codes, predicate, error_contains, back_off, error_message, response, expected_response_status): - mock_response = MagicMock() - mock_response.status_code = response.get("status_code") - mock_response.headers = response.get("headers") - mock_response.json.return_value = response.get("json") - +def test_matches(requests_mock, action, http_codes, predicate, error_contains, back_off, error_message, response, expected_response_status): + requests_mock.register_uri( + "GET", + "https://airbyte.io/", + text=response.get("json") and json.dumps(response.get("json")), + headers=response.get("headers") or {}, + status_code=response.get("status_code"), + ) + response = requests.get("https://airbyte.io/") response_filter = HttpResponseFilter( action=action, config={}, @@ -108,7 +112,7 @@ def test_matches(action, http_codes, predicate, error_contains, back_off, error_ error_message=error_message, ) - actual_response_status = response_filter.matches(mock_response, backoff_time=back_off or 10) + actual_response_status = response_filter.matches(response, backoff_time=back_off or 10) if expected_response_status: assert actual_response_status.action == expected_response_status.action assert actual_response_status.retry_in == expected_response_status.retry_in From 43526869fba12e13c27b49f44760bd53b6336f1e Mon Sep 17 00:00:00 2001 From: Joey Marshment-Howell Date: Fri, 4 Nov 2022 11:55:13 +0100 Subject: [PATCH 43/73] =?UTF-8?q?=F0=9F=AA=9F=20=F0=9F=8E=89=20=20Multi-cl?= =?UTF-8?q?oud:=20edit=20connection=20&=20workspace=20data=20geographies?= =?UTF-8?q?=20in=20the=20UI=20(#18611)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add geographies service and basic dropdown * add feature for changing data geography * add default data residency to workspace settings * add data residency card to connection creation * add data residency editing to connection settings tab --- .../CreateConnection/CreateConnectionForm.tsx | 4 +- .../DataResidency.module.scss | 20 +++ .../CreateConnection/DataResidency.tsx | 64 +++++++++ airbyte-webapp/src/components/Label/Label.tsx | 20 +-- .../LabeledControl/ControlLabels.tsx | 2 - .../components/LabeledInput/LabeledInput.tsx | 21 +-- .../UpdateConnectionDataResidency.module.scss | 21 +++ .../UpdateConnectionDataResidency.tsx | 83 +++++++++++ .../UpdateConnectionDataResidency/index.ts | 1 + .../src/components/ui/Card/Card.module.scss | 8 +- .../src/components/ui/SideMenu/SideMenu.tsx | 2 +- .../services/Analytics/pageTrackingCodes.tsx | 1 + .../ConnectionEditService.test.tsx | 5 + .../ConnectionFormService.test.tsx | 5 + .../src/hooks/services/Feature/types.tsx | 1 + airbyte-webapp/src/locales/en.json | 11 ++ .../domain/geographies/GeographiesService.ts | 8 ++ .../geographies/GeographiesService.ts | 29 ++++ .../views/settings/CloudSettingsPage.tsx | 13 +- .../cloud/views/settings/routePaths.ts | 1 + .../DataResidencyView.module.scss | 39 ++++++ .../DataResidencyView/DataResidencyView.tsx | 129 ++++++++++++++++++ .../workspaces/DataResidencyView/index.ts | 1 + .../ConnectionReplicationTab.test.tsx | 7 + .../ConnectionSettingsTab.tsx | 4 + .../SettingsPage/SettingsPage.module.scss | 4 +- .../src/pages/SettingsPage/SettingsPage.tsx | 1 + .../test-utils/mock-data/mockConnection.json | 1 + .../test-utils/mock-data/mockWorkspace.json | 1 + .../test-utils/mock-data/mockWorkspaceId.ts | 1 + airbyte-webapp/src/utils/links.ts | 1 + .../__snapshots__/formConfig.test.ts.snap | 3 + .../components/NamespaceDefinitionField.tsx | 1 - .../ConnectionForm/formConfig.test.ts | 7 +- .../Connection/ConnectionForm/formConfig.tsx | 7 + .../components/Property/PropertyLabel.tsx | 1 - 36 files changed, 486 insertions(+), 42 deletions(-) create mode 100644 airbyte-webapp/src/components/CreateConnection/DataResidency.module.scss create mode 100644 airbyte-webapp/src/components/CreateConnection/DataResidency.tsx create mode 100644 airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.module.scss create mode 100644 airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.tsx create mode 100644 airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/index.ts create mode 100644 airbyte-webapp/src/packages/cloud/lib/domain/geographies/GeographiesService.ts create mode 100644 airbyte-webapp/src/packages/cloud/services/geographies/GeographiesService.ts create mode 100644 airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.module.scss create mode 100644 airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx create mode 100644 airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/index.ts create mode 100644 airbyte-webapp/src/test-utils/mock-data/mockWorkspaceId.ts diff --git a/airbyte-webapp/src/components/CreateConnection/CreateConnectionForm.tsx b/airbyte-webapp/src/components/CreateConnection/CreateConnectionForm.tsx index 6851a2ef20d4..30358beb2453 100644 --- a/airbyte-webapp/src/components/CreateConnection/CreateConnectionForm.tsx +++ b/airbyte-webapp/src/components/CreateConnection/CreateConnectionForm.tsx @@ -25,6 +25,7 @@ import { import styles from "./CreateConnectionForm.module.scss"; import { CreateConnectionNameField } from "./CreateConnectionNameField"; +import { DataResidency } from "./DataResidency"; import { SchemaError } from "./SchemaError"; interface CreateConnectionProps { @@ -39,7 +40,7 @@ interface CreateConnectionPropsInner extends Pick = ({ schemaError, afterSubmitConnection }) => { const navigate = useNavigate(); - + const canEditDataGeographies = useFeature(FeatureItem.AllowChangeDataGeographies); const { mutateAsync: createConnection } = useCreateConnection(); const { clearFormChange } = useFormChangeTrackerService(); @@ -113,6 +114,7 @@ const CreateConnectionFormInner: React.FC = ({ schem {({ values, isSubmitting, isValid, dirty }) => (
+ {canEditDataGeographies && } setEditingTransformation(true)} diff --git a/airbyte-webapp/src/components/CreateConnection/DataResidency.module.scss b/airbyte-webapp/src/components/CreateConnection/DataResidency.module.scss new file mode 100644 index 000000000000..89f3ded0617c --- /dev/null +++ b/airbyte-webapp/src/components/CreateConnection/DataResidency.module.scss @@ -0,0 +1,20 @@ +@use "scss/variables"; + +.flexRow { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: flex-start; + gap: variables.$spacing-md; +} + +.leftFieldCol { + flex: 1; + max-width: 640px; + padding-right: 30px; +} + +.rightFieldCol { + flex: 1; + max-width: 300px; +} diff --git a/airbyte-webapp/src/components/CreateConnection/DataResidency.tsx b/airbyte-webapp/src/components/CreateConnection/DataResidency.tsx new file mode 100644 index 000000000000..6943c82e3bf0 --- /dev/null +++ b/airbyte-webapp/src/components/CreateConnection/DataResidency.tsx @@ -0,0 +1,64 @@ +import { Field, FieldProps, useFormikContext } from "formik"; +import { FormattedMessage, useIntl } from "react-intl"; + +import { ControlLabels } from "components/LabeledControl"; +import { DropDown } from "components/ui/DropDown"; + +import { useAvailableGeographies } from "packages/cloud/services/geographies/GeographiesService"; +import { links } from "utils/links"; +import { Section } from "views/Connection/ConnectionForm/components/Section"; + +import styles from "./DataResidency.module.scss"; + +interface DataResidencyProps { + name?: string; +} + +export const DataResidency: React.FC = ({ name = "geography" }) => { + const { formatMessage } = useIntl(); + const { setFieldValue } = useFormikContext(); + const { geographies } = useAvailableGeographies(); + + return ( +
+ + {({ field, form }: FieldProps) => ( +
+
+ } + message={ + ( + + {node} + + ), + }} + /> + } + /> +
+
+ ({ + label: formatMessage({ + id: `connection.geography.${geography}`, + defaultMessage: geography.toUpperCase(), + }), + value: geography, + }))} + value={field.value} + onChange={(geography) => setFieldValue(name, geography.value)} + /> +
+
+ )} +
+
+ ); +}; diff --git a/airbyte-webapp/src/components/Label/Label.tsx b/airbyte-webapp/src/components/Label/Label.tsx index fc0a78190cea..999cedeb9ef3 100644 --- a/airbyte-webapp/src/components/Label/Label.tsx +++ b/airbyte-webapp/src/components/Label/Label.tsx @@ -6,20 +6,18 @@ interface IProps { nextLine?: boolean; success?: boolean; message?: string | React.ReactNode; - additionLength?: number; className?: string; onClick?: (data: unknown) => void; htmlFor?: string; } -const Content = styled.label<{ additionLength?: number | string }>` +const Content = styled.label` display: block; font-weight: 500; font-size: 14px; line-height: 17px; color: ${({ theme }) => theme.textColor}; padding-bottom: 5px; - width: calc(100% + ${({ additionLength }) => (additionLength === 0 || additionLength ? additionLength : 30)}px); & a { text-decoration: underline; @@ -31,16 +29,18 @@ const MessageText = styled.span>` white-space: break-spaces; color: ${(props) => props.error ? props.theme.dangerColor : props.success ? props.theme.successColor : props.theme.greyColor40}; - font-size: 13px; + font-size: 12px; + font-weight: 400; + + a:link, + a:hover, + a:visited { + color: ${(props) => props.theme.greyColor40}; + } `; const Label: React.FC> = (props) => ( - + {props.children} {props.message && ( diff --git a/airbyte-webapp/src/components/LabeledControl/ControlLabels.tsx b/airbyte-webapp/src/components/LabeledControl/ControlLabels.tsx index cab7607fdf12..6689a885c1d2 100644 --- a/airbyte-webapp/src/components/LabeledControl/ControlLabels.tsx +++ b/airbyte-webapp/src/components/LabeledControl/ControlLabels.tsx @@ -14,7 +14,6 @@ export interface ControlLabelsProps { success?: boolean; nextLine?: boolean; message?: React.ReactNode; - labelAdditionLength?: number; label?: React.ReactNode; infoTooltipContent?: React.ReactNode; optional?: boolean; @@ -27,7 +26,6 @@ const ControlLabels: React.FC> = (pr error={props.error} success={props.success} message={props.message} - additionLength={props.labelAdditionLength} nextLine={props.nextLine} htmlFor={props.htmlFor} > diff --git a/airbyte-webapp/src/components/LabeledInput/LabeledInput.tsx b/airbyte-webapp/src/components/LabeledInput/LabeledInput.tsx index 8f072745946b..bbbde8e5733b 100644 --- a/airbyte-webapp/src/components/LabeledInput/LabeledInput.tsx +++ b/airbyte-webapp/src/components/LabeledInput/LabeledInput.tsx @@ -3,26 +3,11 @@ import React from "react"; import { ControlLabels, ControlLabelsProps } from "components/LabeledControl"; import { Input, InputProps } from "components/ui/Input"; -type LabeledInputProps = Pick & +type LabeledInputProps = Pick & InputProps & { className?: string }; -const LabeledInput: React.FC = ({ - error, - success, - message, - label, - labelAdditionLength, - className, - ...inputProps -}) => ( - +const LabeledInput: React.FC = ({ error, success, message, label, className, ...inputProps }) => ( + ); diff --git a/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.module.scss b/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.module.scss new file mode 100644 index 000000000000..7b68578ce9f9 --- /dev/null +++ b/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.module.scss @@ -0,0 +1,21 @@ +.wrapper { + display: flex; + align-items: center; + justify-content: space-between; +} + +.dropdownWrapper { + display: flex; + flex: 1 0 310px; +} + +.spinner { + width: 50px; + display: flex; + justify-content: center; + align-items: center; +} + +.dropdown { + flex-grow: 1; +} diff --git a/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.tsx b/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.tsx new file mode 100644 index 000000000000..85e7e56daff9 --- /dev/null +++ b/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/UpdateConnectionDataResidency.tsx @@ -0,0 +1,83 @@ +import React, { useState } from "react"; +import { FormattedMessage, useIntl } from "react-intl"; + +import { ControlLabels } from "components/LabeledControl"; +import { Card } from "components/ui/Card"; +import { DropDown } from "components/ui/DropDown"; +import { Spinner } from "components/ui/Spinner"; + +import { Geography } from "core/request/AirbyteClient"; +import { useConnectionEditService } from "hooks/services/ConnectionEdit/ConnectionEditService"; +import { useNotificationService } from "hooks/services/Notification"; +import { useAvailableGeographies } from "packages/cloud/services/geographies/GeographiesService"; +import { links } from "utils/links"; + +import styles from "./UpdateConnectionDataResidency.module.scss"; + +export const UpdateConnectionDataResidency: React.FC = () => { + const { connection, updateConnection, connectionUpdating } = useConnectionEditService(); + const { registerNotification } = useNotificationService(); + const { formatMessage } = useIntl(); + const [selectedValue, setSelectedValue] = useState(); + + const { geographies } = useAvailableGeographies(); + + const handleSubmit = async ({ value }: { value: Geography }) => { + try { + setSelectedValue(value); + await updateConnection({ + connectionId: connection.connectionId, + geography: value, + }); + } catch (e) { + registerNotification({ + id: "connection.geographyUpdateError", + title: formatMessage({ id: "connection.geographyUpdateError" }), + isError: true, + }); + } + setSelectedValue(undefined); + }; + + return ( + +
+
+ } + message={ + ( + + {node} + + ), + }} + /> + } + /> +
+
+
{connectionUpdating && }
+
+ ({ + label: formatMessage({ + id: `connection.geography.${geography}`, + defaultMessage: geography.toUpperCase(), + }), + value: geography, + }))} + value={selectedValue || connection.geography} + onChange={handleSubmit} + /> +
+
+
+
+ ); +}; diff --git a/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/index.ts b/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/index.ts new file mode 100644 index 000000000000..e6f591b82ff0 --- /dev/null +++ b/airbyte-webapp/src/components/connection/UpdateConnectionDataResidency/index.ts @@ -0,0 +1 @@ +export { UpdateConnectionDataResidency } from "./UpdateConnectionDataResidency"; diff --git a/airbyte-webapp/src/components/ui/Card/Card.module.scss b/airbyte-webapp/src/components/ui/Card/Card.module.scss index 319e7b6a39bd..fb339d67d6b2 100644 --- a/airbyte-webapp/src/components/ui/Card/Card.module.scss +++ b/airbyte-webapp/src/components/ui/Card/Card.module.scss @@ -1,5 +1,5 @@ -@use "../../../scss/colors"; -@use "../../../scss/variables" as vars; +@use "scss/colors"; +@use "scss/variables"; .container { width: auto; @@ -17,9 +17,9 @@ } .title { - padding: 25px 25px 22px; + padding: variables.$spacing-xl; color: colors.$dark-blue; - border-bottom: colors.$grey-100 vars.$border-thin solid; + border-bottom: colors.$grey-100 variables.$border-thin solid; font-weight: 600; letter-spacing: 0.008em; border-top-left-radius: 10px; diff --git a/airbyte-webapp/src/components/ui/SideMenu/SideMenu.tsx b/airbyte-webapp/src/components/ui/SideMenu/SideMenu.tsx index 94788e4b575f..d31fc0511a1a 100644 --- a/airbyte-webapp/src/components/ui/SideMenu/SideMenu.tsx +++ b/airbyte-webapp/src/components/ui/SideMenu/SideMenu.tsx @@ -27,7 +27,7 @@ interface SideMenuProps { } const Content = styled.nav` - min-width: 147px; + min-width: 155px; `; const Category = styled.div` diff --git a/airbyte-webapp/src/hooks/services/Analytics/pageTrackingCodes.tsx b/airbyte-webapp/src/hooks/services/Analytics/pageTrackingCodes.tsx index 0099472cfd1b..117e51a573ba 100644 --- a/airbyte-webapp/src/hooks/services/Analytics/pageTrackingCodes.tsx +++ b/airbyte-webapp/src/hooks/services/Analytics/pageTrackingCodes.tsx @@ -27,6 +27,7 @@ export enum PageTrackingCodes { SETTINGS_NOTIFICATION = "Settings.Notifications", SETTINGS_ACCESS_MANAGEMENT = "Settings.AccessManagement", SETTINGS_METRICS = "Settings.Metrics", + SETTINGS_DATA_RESIDENCY = "Settings.DataResidency", CREDITS = "Credits", WORKSPACES = "Workspaces", PREFERENCES = "Preferences", diff --git a/airbyte-webapp/src/hooks/services/ConnectionEdit/ConnectionEditService.test.tsx b/airbyte-webapp/src/hooks/services/ConnectionEdit/ConnectionEditService.test.tsx index b12e4e2ac8fa..2610a828122d 100644 --- a/airbyte-webapp/src/hooks/services/ConnectionEdit/ConnectionEditService.test.tsx +++ b/airbyte-webapp/src/hooks/services/ConnectionEdit/ConnectionEditService.test.tsx @@ -2,6 +2,7 @@ import { act, renderHook } from "@testing-library/react-hooks"; import React from "react"; import mockConnection from "test-utils/mock-data/mockConnection.json"; import mockDest from "test-utils/mock-data/mockDestinationDefinition.json"; +import mockWorkspace from "test-utils/mock-data/mockWorkspace.json"; import { TestWrapper } from "test-utils/testutils"; import { WebBackendConnectionUpdate } from "core/request/AirbyteClient"; @@ -13,6 +14,10 @@ jest.mock("services/connector/DestinationDefinitionSpecificationService", () => useGetDestinationDefinitionSpecification: () => mockDest, })); +jest.mock("services/workspaces/WorkspacesService", () => ({ + useCurrentWorkspace: () => mockWorkspace, +})); + jest.mock("../useConnectionHook", () => ({ useGetConnection: () => mockConnection, useWebConnectionService: () => ({ diff --git a/airbyte-webapp/src/hooks/services/ConnectionForm/ConnectionFormService.test.tsx b/airbyte-webapp/src/hooks/services/ConnectionForm/ConnectionFormService.test.tsx index b869fdbc0777..4098958ca958 100644 --- a/airbyte-webapp/src/hooks/services/ConnectionForm/ConnectionFormService.test.tsx +++ b/airbyte-webapp/src/hooks/services/ConnectionForm/ConnectionFormService.test.tsx @@ -2,6 +2,7 @@ import { act, renderHook } from "@testing-library/react-hooks"; import React from "react"; import mockConnection from "test-utils/mock-data/mockConnection.json"; import mockDest from "test-utils/mock-data/mockDestinationDefinition.json"; +import mockWorkspace from "test-utils/mock-data/mockWorkspace.json"; import { TestWrapper } from "test-utils/testutils"; import { AirbyteCatalog, WebBackendConnectionRead } from "core/request/AirbyteClient"; @@ -17,6 +18,10 @@ jest.mock("services/connector/DestinationDefinitionSpecificationService", () => useGetDestinationDefinitionSpecification: () => mockDest, })); +jest.mock("services/workspaces/WorkspacesService", () => ({ + useCurrentWorkspace: () => mockWorkspace, +})); + describe("ConnectionFormService", () => { const Wrapper: React.FC[0]> = ({ children, ...props }) => ( diff --git a/airbyte-webapp/src/hooks/services/Feature/types.tsx b/airbyte-webapp/src/hooks/services/Feature/types.tsx index 6b16253cb6ec..a7a252416f69 100644 --- a/airbyte-webapp/src/hooks/services/Feature/types.tsx +++ b/airbyte-webapp/src/hooks/services/Feature/types.tsx @@ -5,6 +5,7 @@ export enum FeatureItem { AllowUpdateConnectors = "ALLOW_UPDATE_CONNECTORS", AllowOAuthConnector = "ALLOW_OAUTH_CONNECTOR", AllowSync = "ALLOW_SYNC", + AllowChangeDataGeographies = "ALLOW_CHANGE_DATA_GEOGRAPHIES", AllowSyncSubOneHourCronExpressions = "ALLOW_SYNC_SUB_ONE_HOUR_CRON_EXPRESSIONS", } diff --git a/airbyte-webapp/src/locales/en.json b/airbyte-webapp/src/locales/en.json index ffccf2121070..289ad9670063 100644 --- a/airbyte-webapp/src/locales/en.json +++ b/airbyte-webapp/src/locales/en.json @@ -367,6 +367,13 @@ "connection.catalogTree.sourceSchema": "'", "connection.catalogTree.destinationSchema": "'", + "connection.geographyTitle": "Data residency", + "connection.geographyDescription": "Depending on your network configuration, you may need to add IP addresses to your allowlist.", + "connection.geography.auto": "Airbyte Default", + "connection.geography.us": "United States", + "connection.geography.eu": "European Union", + "connection.geographyUpdateError": "There was an error updating the data residency for this connection.", + "connection.newConnection": "New connection", "connection.createFirst": "Create your first connection", "connection.newConnectionTitle": "New connection", @@ -510,6 +517,10 @@ "settings.account": "Account", "settings.accountSettings.updateEmailSuccess": "Email updated", "settings.cookiePreferences": "Cookie Preferences", + "settings.dataResidency": "Data Residency", + "settings.defaultDataResidency": "Default Data Residency", + "settings.defaultGeography": "Geography", + "settings.defaultDataResidencyDescription": "Choose the default preferred data processing location for all of your connections. The default data residency setting only affects new connections. Existing connections will retain their data residency setting. Learn more.", "connector.requestConnectorBlock": "Request a new connector", "connector.requestConnector": "Request a new connector", diff --git a/airbyte-webapp/src/packages/cloud/lib/domain/geographies/GeographiesService.ts b/airbyte-webapp/src/packages/cloud/lib/domain/geographies/GeographiesService.ts new file mode 100644 index 000000000000..b512e1a5631b --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/lib/domain/geographies/GeographiesService.ts @@ -0,0 +1,8 @@ +import { WebBackendGeographiesListResult, webBackendListGeographies } from "core/request/AirbyteClient"; +import { AirbyteRequestService } from "core/request/AirbyteRequestService"; + +export class GeographiesService extends AirbyteRequestService { + public async list(): Promise { + return webBackendListGeographies(this.requestOptions); + } +} diff --git a/airbyte-webapp/src/packages/cloud/services/geographies/GeographiesService.ts b/airbyte-webapp/src/packages/cloud/services/geographies/GeographiesService.ts new file mode 100644 index 000000000000..1ea3010085a2 --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/services/geographies/GeographiesService.ts @@ -0,0 +1,29 @@ +import { WebBackendGeographiesListResult } from "core/request/AirbyteClient"; +import { GeographiesService } from "packages/cloud/lib/domain/geographies/GeographiesService"; +import { useConfig } from "packages/cloud/services/config"; +import { useSuspenseQuery } from "services/connector/useSuspenseQuery"; +import { SCOPE_USER } from "services/Scope"; +import { useDefaultRequestMiddlewares } from "services/useDefaultRequestMiddlewares"; +import { useInitService } from "services/useInitService"; + +export const workspaceKeys = { + all: [SCOPE_USER, "geographies"] as const, + list: () => [...workspaceKeys.all, "list"] as const, +}; + +export function useGeographiesService() { + const { apiUrl } = useConfig(); + + const requestAuthMiddleware = useDefaultRequestMiddlewares(); + + return useInitService(() => new GeographiesService(apiUrl, requestAuthMiddleware), [apiUrl, requestAuthMiddleware]); +} + +/** + * Returns a list of data geographies that can be associated with a connection or workspace + **/ +export function useAvailableGeographies() { + const geographiesService = useGeographiesService(); + + return useSuspenseQuery(workspaceKeys.list(), () => geographiesService.list()); +} diff --git a/airbyte-webapp/src/packages/cloud/views/settings/CloudSettingsPage.tsx b/airbyte-webapp/src/packages/cloud/views/settings/CloudSettingsPage.tsx index 8dd379a615c7..8737e29351ec 100644 --- a/airbyte-webapp/src/packages/cloud/views/settings/CloudSettingsPage.tsx +++ b/airbyte-webapp/src/packages/cloud/views/settings/CloudSettingsPage.tsx @@ -6,6 +6,7 @@ import { FeatureItem, useFeature } from "hooks/services/Feature"; import { DbtCloudSettingsView } from "packages/cloud/views/settings/integrations/DbtCloudSettingsView"; import { AccountSettingsView } from "packages/cloud/views/users/AccountSettingsView"; import { UsersSettingsView } from "packages/cloud/views/users/UsersSettingsView"; +import { DataResidencyView } from "packages/cloud/views/workspaces/DataResidencyView"; import { WorkspaceSettingsView } from "packages/cloud/views/workspaces/WorkspaceSettingsView"; import SettingsPage from "pages/SettingsPage"; import { @@ -23,6 +24,7 @@ export const CloudSettingsPage: React.FC = () => { // TODO: uncomment when supported in cloud // const { countNewSourceVersion, countNewDestinationVersion } = useConnector(); const supportsCloudDbtIntegration = useFeature(FeatureItem.AllowDBTCloudIntegration); + const supportsDataResidency = useFeature(FeatureItem.AllowChangeDataGeographies); const pageConfig = useMemo( () => ({ @@ -55,6 +57,15 @@ export const CloudSettingsPage: React.FC = () => { component: WorkspaceSettingsView, id: "workspaceSettings.generalSettings", }, + ...(supportsDataResidency + ? [ + { + path: CloudSettingsRoutes.DataResidency, + name: , + component: DataResidencyView, + }, + ] + : []), { path: CloudSettingsRoutes.Source, name: , @@ -102,7 +113,7 @@ export const CloudSettingsPage: React.FC = () => { : []), ], }), - [supportsCloudDbtIntegration] + [supportsCloudDbtIntegration, supportsDataResidency] ); return ; diff --git a/airbyte-webapp/src/packages/cloud/views/settings/routePaths.ts b/airbyte-webapp/src/packages/cloud/views/settings/routePaths.ts index 5926f6aeaf7e..80c54edfc71a 100644 --- a/airbyte-webapp/src/packages/cloud/views/settings/routePaths.ts +++ b/airbyte-webapp/src/packages/cloud/views/settings/routePaths.ts @@ -6,6 +6,7 @@ export const CloudSettingsRoutes = { Account: SettingsRoute.Account, Source: SettingsRoute.Source, Destination: SettingsRoute.Destination, + DataResidency: SettingsRoute.DataResidency, Workspace: "workspaces", AccessManagement: "access-management", diff --git a/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.module.scss b/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.module.scss new file mode 100644 index 000000000000..8bac0c8d1417 --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.module.scss @@ -0,0 +1,39 @@ +@use "scss/colors"; +@use "scss/variables"; + +.cardContent { + padding: variables.$spacing-xl; +} + +.description { + color: colors.$grey-300; + margin-bottom: variables.$spacing-md; + font-size: 12px; + + a:link, + a:visited { + color: colors.$grey-300; + } +} + +.geographyRow { + margin-top: variables.$spacing-xl; + display: flex; + justify-content: space-between; +} + +.defaultGeographyDropdown { + flex: 0 0 300px; +} + +.buttonGroup { + margin-top: variables.$spacing-xl; + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; + + & > button { + margin-left: variables.$spacing-md; + } +} diff --git a/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx b/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx new file mode 100644 index 000000000000..a24475b5e834 --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx @@ -0,0 +1,129 @@ +import { Field, FieldProps, Form, Formik, FormikHelpers } from "formik"; +import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; + +import { ControlLabels } from "components"; +import { Button } from "components/ui/Button"; +import { DropDown } from "components/ui/DropDown"; +import { Text } from "components/ui/Text"; + +import { Geography } from "core/request/AirbyteClient"; +import { PageTrackingCodes, useTrackPage } from "hooks/services/Analytics"; +import { useNotificationService } from "hooks/services/Notification"; +import { useCurrentWorkspace } from "hooks/services/useWorkspace"; +import { useAvailableGeographies } from "packages/cloud/services/geographies/GeographiesService"; +import { SettingsCard } from "pages/SettingsPage/pages/SettingsComponents"; +import { useUpdateWorkspace } from "services/workspaces/WorkspacesService"; +import { links } from "utils/links"; + +import styles from "./DataResidencyView.module.scss"; + +interface SelectGeographyOption { + label: Geography; + value: Geography; +} + +interface DefaultDataResidencyFormValues { + defaultGeography: Geography | undefined; +} + +export const DataResidencyView: React.FC = () => { + const workspace = useCurrentWorkspace(); + const { geographies } = useAvailableGeographies(); + const { mutateAsync: updateWorkspace } = useUpdateWorkspace(); + const { registerNotification } = useNotificationService(); + + const { formatMessage } = useIntl(); + useTrackPage(PageTrackingCodes.SETTINGS_DATA_RESIDENCY); + + const handleSubmit = async ( + values: DefaultDataResidencyFormValues, + { resetForm }: FormikHelpers + ) => { + try { + await updateWorkspace({ + workspaceId: workspace.workspaceId, + defaultGeography: values.defaultGeography, + }); + resetForm({ values }); + } catch (e) { + registerNotification({ + id: "workspaceSettings.defaultGeographyError", + title: formatMessage({ id: "connection.geographyUpdateError" }), + isError: true, + }); + } + }; + + const initialValues: DefaultDataResidencyFormValues = { + defaultGeography: workspace.defaultGeography, + }; + + return ( + }> +
+ + ( + + {node} + + ), + }} + /> + + + {({ isSubmitting, dirty, isValid, resetForm }) => ( + + + {({ field, form }: FieldProps) => ( +
+ } + message={ + ( + + {node} + + ), + }} + /> + } + /> +
+ ({ + label: formatMessage({ + id: `connection.geography.${geography}`, + defaultMessage: geography.toUpperCase(), + }), + value: geography, + }))} + value={field.value} + onChange={(option) => form.setFieldValue("defaultGeography", option.value)} + /> +
+
+ )} +
+
+ + +
+ + )} +
+
+
+ ); +}; diff --git a/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/index.ts b/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/index.ts new file mode 100644 index 000000000000..463f131fdb1c --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/index.ts @@ -0,0 +1 @@ +export { DataResidencyView } from "./DataResidencyView"; diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.test.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.test.tsx index a63ad3d78c18..816cf1b02320 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.test.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.test.tsx @@ -7,6 +7,8 @@ import React, { Suspense } from "react"; import selectEvent from "react-select-event"; import mockConnection from "test-utils/mock-data/mockConnection.json"; import mockDest from "test-utils/mock-data/mockDestinationDefinition.json"; +import mockWorkspace from "test-utils/mock-data/mockWorkspace.json"; +import { mockWorkspaceId } from "test-utils/mock-data/mockWorkspaceId"; import { TestWrapper } from "test-utils/testutils"; import { WebBackendConnectionUpdate } from "core/request/AirbyteClient"; @@ -21,6 +23,11 @@ jest.mock("services/connector/DestinationDefinitionSpecificationService", () => })); jest.setTimeout(10000); +jest.mock("services/workspaces/WorkspacesService", () => ({ + useCurrentWorkspace: () => mockWorkspace, + useCurrentWorkspaceId: () => mockWorkspaceId, +})); + describe("ConnectionReplicationTab", () => { const Wrapper: React.FC> = ({ children }) => ( I should not show up in a snapshot
}> diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.tsx index 782d63d43c67..1470872500d7 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionSettingsTab.tsx @@ -1,9 +1,11 @@ import React from "react"; import { DeleteBlock } from "components/common/DeleteBlock"; +import { UpdateConnectionDataResidency } from "components/connection/UpdateConnectionDataResidency"; import { PageTrackingCodes, useTrackPage } from "hooks/services/Analytics"; import { useConnectionEditService } from "hooks/services/ConnectionEdit/ConnectionEditService"; +import { FeatureItem, useFeature } from "hooks/services/Feature"; import { useAdvancedModeSetting } from "hooks/services/useAdvancedModeSetting"; import { useDeleteConnection } from "hooks/services/useConnectionHook"; @@ -13,6 +15,7 @@ import { StateBlock } from "./StateBlock"; export const ConnectionSettingsTab: React.FC = () => { const { connection } = useConnectionEditService(); const { mutateAsync: deleteConnection } = useDeleteConnection(); + const canUpdateDataResidency = useFeature(FeatureItem.AllowChangeDataGeographies); const [isAdvancedMode] = useAdvancedModeSetting(); useTrackPage(PageTrackingCodes.CONNECTIONS_ITEM_SETTINGS); @@ -20,6 +23,7 @@ export const ConnectionSettingsTab: React.FC = () => { return (
+ {canUpdateDataResidency && } {isAdvancedMode && }
diff --git a/airbyte-webapp/src/pages/SettingsPage/SettingsPage.module.scss b/airbyte-webapp/src/pages/SettingsPage/SettingsPage.module.scss index 003f7af39281..a756f2ddb779 100644 --- a/airbyte-webapp/src/pages/SettingsPage/SettingsPage.module.scss +++ b/airbyte-webapp/src/pages/SettingsPage/SettingsPage.module.scss @@ -1,4 +1,4 @@ -@use "../../scss/variables"; +@use "scss/variables"; .content { display: flex; @@ -7,6 +7,6 @@ } .mainView { - width: 100%; + flex-grow: 1; margin-left: variables.$spacing-2xl; } diff --git a/airbyte-webapp/src/pages/SettingsPage/SettingsPage.tsx b/airbyte-webapp/src/pages/SettingsPage/SettingsPage.tsx index 733ee6344475..88c85f375f16 100644 --- a/airbyte-webapp/src/pages/SettingsPage/SettingsPage.tsx +++ b/airbyte-webapp/src/pages/SettingsPage/SettingsPage.tsx @@ -32,6 +32,7 @@ export const SettingsRoute = { Configuration: "configuration", Notifications: "notifications", Metrics: "metrics", + DataResidency: "data-residency", } as const; const SettingsPage: React.FC = ({ pageConfig }) => { diff --git a/airbyte-webapp/src/test-utils/mock-data/mockConnection.json b/airbyte-webapp/src/test-utils/mock-data/mockConnection.json index a4cd6916599f..d3ece6b96a8a 100644 --- a/airbyte-webapp/src/test-utils/mock-data/mockConnection.json +++ b/airbyte-webapp/src/test-utils/mock-data/mockConnection.json @@ -6,6 +6,7 @@ "prefix": "", "sourceId": "a3295ed7-4acf-4c0b-b16b-07a00e624a52", "destinationId": "083a53bc-8bc2-4dc0-b05a-4273a96f3b93", + "geography": "auto", "syncCatalog": { "streams": [ { diff --git a/airbyte-webapp/src/test-utils/mock-data/mockWorkspace.json b/airbyte-webapp/src/test-utils/mock-data/mockWorkspace.json index 07ea47bdadb8..a87976333a3c 100644 --- a/airbyte-webapp/src/test-utils/mock-data/mockWorkspace.json +++ b/airbyte-webapp/src/test-utils/mock-data/mockWorkspace.json @@ -5,6 +5,7 @@ "name": "47c74b9b-9b89-4af1-8331-4865af6c4e4d", "slug": "47c74b9b-9b89-4af1-8331-4865af6c4e4d", "initialSetupComplete": true, + "defaultGeography": "auto", "displaySetupWizard": false, "anonymousDataCollection": false, "news": false, diff --git a/airbyte-webapp/src/test-utils/mock-data/mockWorkspaceId.ts b/airbyte-webapp/src/test-utils/mock-data/mockWorkspaceId.ts new file mode 100644 index 000000000000..cce229aafe58 --- /dev/null +++ b/airbyte-webapp/src/test-utils/mock-data/mockWorkspaceId.ts @@ -0,0 +1 @@ +export const mockWorkspaceId = "a8f75674-44e0-4219-b9ed-99ad0c080d03"; diff --git a/airbyte-webapp/src/utils/links.ts b/airbyte-webapp/src/utils/links.ts index 6465ea64e3ec..957f87b08f80 100644 --- a/airbyte-webapp/src/utils/links.ts +++ b/airbyte-webapp/src/utils/links.ts @@ -29,6 +29,7 @@ export const links = { webhookVideoGuideLink: "https://www.youtube.com/watch?v=NjYm8F-KiFc", webhookGuideLink: `${BASE_DOCS_LINK}/operator-guides/configuring-sync-notifications/`, cronReferenceLink: "http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html", + cloudAllowlistIPsLink: `${BASE_DOCS_LINK}/cloud/getting-started-with-airbyte-cloud/#allowlist-ip-address`, } as const; export type OutboundLinks = typeof links; diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/__snapshots__/formConfig.test.ts.snap b/airbyte-webapp/src/views/Connection/ConnectionForm/__snapshots__/formConfig.test.ts.snap index 171ce4d48e02..e25ac64ede60 100644 --- a/airbyte-webapp/src/views/Connection/ConnectionForm/__snapshots__/formConfig.test.ts.snap +++ b/airbyte-webapp/src/views/Connection/ConnectionForm/__snapshots__/formConfig.test.ts.snap @@ -2,6 +2,7 @@ exports[`#useInitialValues should generate initial values w/ 'not create' mode: false 1`] = ` Object { + "geography": "auto", "name": "Scrafty <> Heroku Postgres", "namespaceDefinition": "source", "namespaceFormat": "\${SOURCE_NAMESPACE}", @@ -534,6 +535,7 @@ Object { exports[`#useInitialValues should generate initial values w/ 'not create' mode: true 1`] = ` Object { + "geography": "auto", "namespaceDefinition": "source", "namespaceFormat": "\${SOURCE_NAMESPACE}", "normalization": "basic", @@ -1065,6 +1067,7 @@ Object { exports[`#useInitialValues should generate initial values w/ no 'not create' mode 1`] = ` Object { + "geography": "auto", "name": "Scrafty <> Heroku Postgres", "namespaceDefinition": "source", "namespaceFormat": "\${SOURCE_NAMESPACE}", diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/components/NamespaceDefinitionField.tsx b/airbyte-webapp/src/views/Connection/ConnectionForm/components/NamespaceDefinitionField.tsx index 6b206c42351b..df1e653f9db1 100644 --- a/airbyte-webapp/src/views/Connection/ConnectionForm/components/NamespaceDefinitionField.tsx +++ b/airbyte-webapp/src/views/Connection/ConnectionForm/components/NamespaceDefinitionField.tsx @@ -35,7 +35,6 @@ export const NamespaceDefinitionField: React.FC> = ({ field, } message={} /> diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.test.ts b/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.test.ts index a119935a6553..968ff286f5b7 100644 --- a/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.test.ts +++ b/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.test.ts @@ -1,6 +1,7 @@ import { renderHook } from "@testing-library/react-hooks"; -import mockDestinationDefinition from "test-utils/mock-data//mockDestinationDefinition.json"; import mockConnection from "test-utils/mock-data/mockConnection.json"; +import mockDestinationDefinition from "test-utils/mock-data/mockDestinationDefinition.json"; +import mockWorkspace from "test-utils/mock-data/mockWorkspace.json"; import { TestWrapper as wrapper } from "test-utils/testutils"; import { frequencyConfig } from "config/frequencyConfig"; @@ -14,6 +15,10 @@ import { import { mapFormPropsToOperation, useFrequencyDropdownData, useInitialValues } from "./formConfig"; +jest.mock("services/workspaces/WorkspacesService", () => ({ + useCurrentWorkspace: () => mockWorkspace, +})); + describe("#useFrequencyDropdownData", () => { it("should return only default frequencies when no additional frequency is provided", () => { const { result } = renderHook(() => useFrequencyDropdownData(undefined), { wrapper }); diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.tsx b/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.tsx index a8d99c9e4101..6aab43856633 100644 --- a/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.tsx +++ b/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.tsx @@ -17,6 +17,7 @@ import { ConnectionScheduleType, DestinationDefinitionSpecificationRead, DestinationSyncMode, + Geography, NamespaceDefinitionType, OperationCreate, OperationRead, @@ -41,6 +42,7 @@ export interface FormikConnectionFormValues { namespaceFormat: string; transformations?: OperationRead[]; normalization?: NormalizationType; + geography: Geography; } export type ConnectionFormValues = ValuesProps; @@ -88,6 +90,7 @@ export const createConnectionValidationSchema = ({ .object({ // The connection name during Editing is handled separately from the form name: mode === "create" ? yup.string().required("form.empty.error") : yup.string().notRequired(), + geography: yup.mixed().oneOf(Object.values(Geography)), scheduleType: yup .string() .oneOf([ConnectionScheduleType.manual, ConnectionScheduleType.basic, ConnectionScheduleType.cron]), @@ -266,6 +269,7 @@ export const useInitialValues = ( destDefinition: DestinationDefinitionSpecificationRead, isNotCreateMode?: boolean ): FormikConnectionFormValues => { + const workspace = useCurrentWorkspace(); const { catalogDiff } = connection; const newStreamDescriptors = catalogDiff?.transforms @@ -291,6 +295,7 @@ export const useInitialValues = ( prefix: connection.prefix || "", namespaceDefinition: connection.namespaceDefinition || NamespaceDefinitionType.source, namespaceFormat: connection.namespaceFormat ?? SOURCE_NAMESPACE_TAG, + geography: connection.geography || workspace.defaultGeography || "auto", }; // Is Create Mode @@ -312,6 +317,7 @@ export const useInitialValues = ( }, [ connection.connectionId, connection.destination.name, + connection.geography, connection.name, connection.namespaceDefinition, connection.namespaceFormat, @@ -324,6 +330,7 @@ export const useInitialValues = ( destDefinition.supportsNormalization, initialSchema, isNotCreateMode, + workspace, ]); }; diff --git a/airbyte-webapp/src/views/Connector/ServiceForm/components/Property/PropertyLabel.tsx b/airbyte-webapp/src/views/Connector/ServiceForm/components/Property/PropertyLabel.tsx index a447ea89785c..9584d37b3399 100644 --- a/airbyte-webapp/src/views/Connector/ServiceForm/components/Property/PropertyLabel.tsx +++ b/airbyte-webapp/src/views/Connector/ServiceForm/components/Property/PropertyLabel.tsx @@ -30,7 +30,6 @@ export const PropertyLabel: React.FC return ( Date: Fri, 4 Nov 2022 12:34:25 +0100 Subject: [PATCH 44/73] =?UTF-8?q?=F0=9F=90=9B=20Source=20SalesForce:=20fix?= =?UTF-8?q?=20Bulk=20API=20unsupported=20list=20(#18799)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🐛 Source SalesForce: fix Bulk API unsupported list * 🐛 Source SalesForce: bump version * 🐛 Source Facebook Marketing: docs update * auto-bump connector version Co-authored-by: Octavia Squidington III --- .../init/src/main/resources/seed/source_definitions.yaml | 2 +- airbyte-config/init/src/main/resources/seed/source_specs.yaml | 2 +- airbyte-integrations/connectors/source-salesforce/Dockerfile | 2 +- .../connectors/source-salesforce/source_salesforce/api.py | 4 ++++ docs/integrations/sources/salesforce.md | 3 ++- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index fb7e5b2bec36..d32f536e1d4b 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -1108,7 +1108,7 @@ - name: Salesforce sourceDefinitionId: b117307c-14b6-41aa-9422-947e34922962 dockerRepository: airbyte/source-salesforce - dockerImageTag: 1.0.23 + dockerImageTag: 1.0.24 documentationUrl: https://docs.airbyte.com/integrations/sources/salesforce icon: salesforce.svg sourceType: api diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 235f198ab0d3..a9118f9ccd47 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -10891,7 +10891,7 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] -- dockerImage: "airbyte/source-salesforce:1.0.23" +- dockerImage: "airbyte/source-salesforce:1.0.24" spec: documentationUrl: "https://docs.airbyte.com/integrations/sources/salesforce" connectionSpecification: diff --git a/airbyte-integrations/connectors/source-salesforce/Dockerfile b/airbyte-integrations/connectors/source-salesforce/Dockerfile index 567f40689cff..fea41e693626 100644 --- a/airbyte-integrations/connectors/source-salesforce/Dockerfile +++ b/airbyte-integrations/connectors/source-salesforce/Dockerfile @@ -13,5 +13,5 @@ RUN pip install . ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=1.0.23 +LABEL io.airbyte.version=1.0.24 LABEL io.airbyte.name=airbyte/source-salesforce diff --git a/airbyte-integrations/connectors/source-salesforce/source_salesforce/api.py b/airbyte-integrations/connectors/source-salesforce/source_salesforce/api.py index 6241aa4a2633..8efa5276444d 100644 --- a/airbyte-integrations/connectors/source-salesforce/source_salesforce/api.py +++ b/airbyte-integrations/connectors/source-salesforce/source_salesforce/api.py @@ -130,7 +130,9 @@ # The following objects are not supported by the Bulk API. Listed objects are version specific. UNSUPPORTED_BULK_API_SALESFORCE_OBJECTS = [ "AcceptedEventRelation", + "AssetTokenEvent", "Attachment", + "AttachedContentNote", "CaseStatus", "ContractStatus", "DeclinedEventRelation", @@ -143,12 +145,14 @@ "KnowledgeArticleVoteStat", "OrderStatus", "PartnerRole", + "QuoteTemplateRichTextData", "RecentlyViewed", "ServiceAppointmentStatus", "ShiftStatus", "SolutionStatus", "TaskPriority", "TaskStatus", + "TaskWhoRelation", "UndecidedEventRelation", ] diff --git a/docs/integrations/sources/salesforce.md b/docs/integrations/sources/salesforce.md index 0c51319d0605..078634963a42 100644 --- a/docs/integrations/sources/salesforce.md +++ b/docs/integrations/sources/salesforce.md @@ -120,7 +120,8 @@ Now that you have set up the Salesforce source connector, check out the followin ## Changelog | Version | Date | Pull Request | Subject | -| :------ | :--------- | :------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------- | +|:--------| :--------- |:---------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------| +| 1.0.24 | 2022-11-01 | [18799](https://github.com/airbytehq/airbyte/pull/18799) | Update list of unsupported Bulk API objects | | 1.0.23 | 2022-11-01 | [18753](https://github.com/airbytehq/airbyte/pull/18753) | Add error_display_message for ConnectionError | | 1.0.22 | 2022-10-12 | [17615](https://github.com/airbytehq/airbyte/pull/17615) | Make paging work, if `cursor_field` is not changed inside one page | | 1.0.21 | 2022-10-10 | [17778](https://github.com/airbytehq/airbyte/pull/17778) | Add `EventWhoRelation` to the list of unsupported Bulk API objects. | From e0068fca0c16438cad6822534105d5366103b113 Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Fri, 4 Nov 2022 13:30:11 +0100 Subject: [PATCH 45/73] Improve pre-commit hook (#18903) --- airbyte-webapp/.husky/pre-commit | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/airbyte-webapp/.husky/pre-commit b/airbyte-webapp/.husky/pre-commit index b18fa3a6e0a3..4e96aec869c2 100755 --- a/airbyte-webapp/.husky/pre-commit +++ b/airbyte-webapp/.husky/pre-commit @@ -1 +1,10 @@ -cd airbyte-webapp && npx --no lint-staged \ No newline at end of file +# Only run this pre-commit hook when npx is actually in the path. +# Since CI will fail on misformated frontend code we consider this hook optional +# and don't want to fail if the system doesn't have the requirements to run it. +if command -v npx &> /dev/null; then + # Only run if `npx` is at least version 8, since earlier versions didn't support the --no flag + npxMajorVersion=$(npx --version | cut -d. -f1) + if [ "$npxMajorVersion" -ge "8" ]; then + cd airbyte-webapp && npx --no lint-staged + fi +fi \ No newline at end of file From d35b350876dea1fe361b5e654ccb65ba44d32e3f Mon Sep 17 00:00:00 2001 From: Edmundo Ruiz Ghanem <168664+edmundito@users.noreply.github.com> Date: Fri, 4 Nov 2022 08:31:30 -0400 Subject: [PATCH 46/73] =?UTF-8?q?=F0=9F=AA=9F=20=F0=9F=90=9B=20Fix=20valid?= =?UTF-8?q?ation=20when=20setting=20the=20connection=20stream=20cursor=20o?= =?UTF-8?q?r=20primary=20key=20(#18933)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update sorted streams memo to make a copy of the stream before sorting Move changedStreams from CatalogTreeBody to CatalogTree so that the order of the changedStreams is based on the correct order * Remove sorting when saving changes. It's no longer needed. --- .../connection/CatalogTree/CatalogTree.tsx | 18 +++++++++++++++--- .../connection/CatalogTree/CatalogTreeBody.tsx | 13 ++++--------- .../ConnectionReplicationTab.tsx | 10 +++------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/airbyte-webapp/src/components/connection/CatalogTree/CatalogTree.tsx b/airbyte-webapp/src/components/connection/CatalogTree/CatalogTree.tsx index 932a78b16d5f..b3b3dc37f90f 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/CatalogTree.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/CatalogTree.tsx @@ -28,7 +28,7 @@ const CatalogTreeComponent: React.FC> isLoading, }) => { const isNewStreamsTableEnabled = process.env.REACT_APP_NEW_STREAMS_TABLE ?? false; - const { mode } = useConnectionFormService(); + const { initialValues, mode } = useConnectionFormService(); const [searchString, setSearchString] = useState(""); @@ -38,7 +38,7 @@ const CatalogTreeComponent: React.FC> ); const sortedSchema = useMemo( - () => streams.sort(naturalComparatorBy((syncStream) => syncStream.stream?.name ?? "")), + () => [...streams].sort(naturalComparatorBy((syncStream) => syncStream.stream?.name ?? "")), [streams] ); @@ -53,6 +53,14 @@ const CatalogTreeComponent: React.FC> return sortedSchema.filter((stream) => filters.every((f) => f(stream))); }, [searchString, sortedSchema]); + const changedStreams = useMemo( + () => + streams.filter((stream, idx) => { + return stream.config?.selected !== initialValues.syncCatalog.streams[idx].config?.selected; + }), + [initialValues.syncCatalog.streams, streams] + ); + return ( @@ -69,7 +77,11 @@ const CatalogTreeComponent: React.FC> )} - + {isNewStreamsTableEnabled && } diff --git a/airbyte-webapp/src/components/connection/CatalogTree/CatalogTreeBody.tsx b/airbyte-webapp/src/components/connection/CatalogTree/CatalogTreeBody.tsx index a61d55a9897e..23c4c3c11904 100644 --- a/airbyte-webapp/src/components/connection/CatalogTree/CatalogTreeBody.tsx +++ b/airbyte-webapp/src/components/connection/CatalogTree/CatalogTreeBody.tsx @@ -1,20 +1,21 @@ -import { Field, FieldProps, setIn, useFormikContext } from "formik"; +import { Field, FieldProps, setIn } from "formik"; import React, { useCallback } from "react"; import { SyncSchemaStream } from "core/domain/catalog"; import { AirbyteStreamConfiguration } from "core/request/AirbyteClient"; import { useConnectionFormService } from "hooks/services/ConnectionForm/ConnectionFormService"; -import { ConnectionFormValues, FormikConnectionFormValues } from "views/Connection/ConnectionForm/formConfig"; +import { FormikConnectionFormValues } from "views/Connection/ConnectionForm/formConfig"; import { CatalogSection } from "./CatalogSection"; import styles from "./CatalogTreeBody.module.scss"; interface CatalogTreeBodyProps { streams: SyncSchemaStream[]; + changedStreams: SyncSchemaStream[]; onStreamChanged: (stream: SyncSchemaStream) => void; } -export const CatalogTreeBody: React.FC = ({ streams, onStreamChanged }) => { +export const CatalogTreeBody: React.FC = ({ streams, changedStreams, onStreamChanged }) => { const { mode } = useConnectionFormService(); const onUpdateStream = useCallback( @@ -30,12 +31,6 @@ export const CatalogTreeBody: React.FC = ({ streams, onStr [streams, onStreamChanged] ); - const { initialValues } = useFormikContext(); - - const changedStreams = streams.filter((stream, idx) => { - return stream.config?.selected !== initialValues.syncCatalog.streams[idx].config?.selected; - }); - return (
{streams.map((streamNode) => ( diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.tsx index 1241c2f73541..2973aeac150d 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionReplicationTab.tsx @@ -18,7 +18,7 @@ import { FeatureItem, useFeature } from "hooks/services/Feature"; import { useModalService } from "hooks/services/Modal"; import { useConnectionService, ValuesProps } from "hooks/services/useConnectionHook"; import { useCurrentWorkspaceId } from "services/workspaces/WorkspacesService"; -import { equal, naturalComparatorBy } from "utils/objects"; +import { equal } from "utils/objects"; import { useConfirmCatalogDiff } from "views/Connection/CatalogDiffModal/useConfirmCatalogDiff"; import EditControls from "views/Connection/ConnectionForm/components/EditControls"; import { ConnectionFormFields } from "views/Connection/ConnectionForm/ConnectionFormFields"; @@ -90,12 +90,8 @@ export const ConnectionReplicationTab: React.FC = () => { // This could be due to user changes (e.g. in the sync mode) or due to new/removed // streams due to a "refreshed source schema". const catalogHasChanged = !equal( - formValues.syncCatalog.streams - .filter((s) => s.config?.selected) - .sort(naturalComparatorBy((syncStream) => syncStream.stream?.name ?? "")), - connection.syncCatalog.streams - .filter((s) => s.config?.selected) - .sort(naturalComparatorBy((syncStream) => syncStream.stream?.name ?? "")) + formValues.syncCatalog.streams.filter((s) => s.config?.selected), + connection.syncCatalog.streams.filter((s) => s.config?.selected) ); setSubmitError(null); From 4c6f520d075ddaad065c300bd403bc9d72b2f616 Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Fri, 4 Nov 2022 13:34:33 +0100 Subject: [PATCH 47/73] :window: :tada: New theme for Airbyte UI (#18817) * New Webapp theme * Remove debug banner * Remove GlobalStyles from storybook * Remove beige color palette * Fix storybook styling * Fix hover color in sidebar * Improve transitions --- airbyte-webapp/.storybook/preview.ts | 1 + airbyte-webapp/.storybook/withProvider.tsx | 2 -- airbyte-webapp/public/simpleLogo.svg | 3 -- airbyte-webapp/src/App.tsx | 6 +--- .../src/components/icons/CreditsIcon.tsx | 4 +-- .../ui/Banner/AlertBanner.module.scss | 5 +-- .../src/components/ui/Banner/AlertBanner.tsx | 2 +- .../src/components/ui/InfoBox/InfoBox.tsx | 2 +- .../src/components/ui/StepsMenu/Step.tsx | 2 +- .../src/components/ui/Table/Table.tsx | 2 +- airbyte-webapp/src/global-styles.tsx | 31 ------------------- airbyte-webapp/src/index.tsx | 1 + airbyte-webapp/src/locales/en.json | 1 + airbyte-webapp/src/packages/cloud/App.tsx | 6 +--- .../SpeedyConnectionBanner.module.scss | 4 +-- .../components/RemainingCredits.tsx | 2 +- .../views/layout/SideBar/SideBar.module.scss | 3 +- .../cloud/views/layout/SideBar/SideBar.tsx | 7 +++-- .../ConnectionName.module.scss | 4 +-- .../ConnectionPageTitle.module.scss | 2 +- .../components/ProgressBlock.tsx | 2 +- .../components/images/video-background.svg | 2 +- airbyte-webapp/src/scss/_colors.scss | 6 ++-- airbyte-webapp/src/scss/export.module.scss | 4 --- airbyte-webapp/src/scss/global.scss | 25 +++++++++++++++ airbyte-webapp/src/theme.ts | 7 ----- .../ErrorOccurredView.module.scss | 2 -- .../views/layout/SideBar/SideBar.module.scss | 24 ++++++-------- .../src/views/layout/SideBar/SideBar.tsx | 11 +++++-- .../src/views/layout/SideBar/airbyteLogo.svg | 3 ++ .../SidebarDropdownMenu.module.scss | 17 ++++------ 31 files changed, 81 insertions(+), 112 deletions(-) delete mode 100644 airbyte-webapp/public/simpleLogo.svg delete mode 100644 airbyte-webapp/src/global-styles.tsx create mode 100644 airbyte-webapp/src/scss/global.scss create mode 100644 airbyte-webapp/src/views/layout/SideBar/airbyteLogo.svg diff --git a/airbyte-webapp/.storybook/preview.ts b/airbyte-webapp/.storybook/preview.ts index c3ea6ed642fe..2d3d9392e56b 100644 --- a/airbyte-webapp/.storybook/preview.ts +++ b/airbyte-webapp/.storybook/preview.ts @@ -3,6 +3,7 @@ import { addDecorator } from "@storybook/react"; import { withProviders } from "./withProvider"; import "!style-loader!css-loader!sass-loader!../public/index.css"; +import "../src/scss/global.scss"; addDecorator(withProviders); diff --git a/airbyte-webapp/.storybook/withProvider.tsx b/airbyte-webapp/.storybook/withProvider.tsx index bbf184f559a9..8f5d0e54c2e8 100644 --- a/airbyte-webapp/.storybook/withProvider.tsx +++ b/airbyte-webapp/.storybook/withProvider.tsx @@ -7,7 +7,6 @@ import { QueryClientProvider, QueryClient } from "react-query"; // TODO: theme was not working correctly so imported directly import { theme } from "../src/theme"; -import GlobalStyle from "../src/global-styles"; import messages from "../src/locales/en.json"; import { FeatureService } from "../src/hooks/services/Feature"; import { ConfigServiceProvider, defaultConfig } from "../src/config"; @@ -45,7 +44,6 @@ export const withProviders = (getStory) => ( - {getStory()} diff --git a/airbyte-webapp/public/simpleLogo.svg b/airbyte-webapp/public/simpleLogo.svg deleted file mode 100644 index 4f4f23534f4f..000000000000 --- a/airbyte-webapp/public/simpleLogo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/airbyte-webapp/src/App.tsx b/airbyte-webapp/src/App.tsx index 8806625227e3..4a18cf5bbaa8 100644 --- a/airbyte-webapp/src/App.tsx +++ b/airbyte-webapp/src/App.tsx @@ -25,17 +25,13 @@ import { ValueProvider, windowConfigProvider, } from "./config"; -import GlobalStyle from "./global-styles"; import en from "./locales/en.json"; import { Routing } from "./pages/routes"; import { WorkspaceServiceProvider } from "./services/workspaces/WorkspacesService"; import { theme } from "./theme"; const StyleProvider: React.FC> = ({ children }) => ( - - - {children} - + {children} ); const configProviders: ValueProvider = [envConfigProvider, windowConfigProvider]; diff --git a/airbyte-webapp/src/components/icons/CreditsIcon.tsx b/airbyte-webapp/src/components/icons/CreditsIcon.tsx index b2eafd7de614..5529782ea866 100644 --- a/airbyte-webapp/src/components/icons/CreditsIcon.tsx +++ b/airbyte-webapp/src/components/icons/CreditsIcon.tsx @@ -8,13 +8,13 @@ export const CreditsIcon = ({ color = theme.greyColor20 }: Props) => ( ); diff --git a/airbyte-webapp/src/components/ui/Banner/AlertBanner.module.scss b/airbyte-webapp/src/components/ui/Banner/AlertBanner.module.scss index f46bb95bc53a..a784d1ef788f 100644 --- a/airbyte-webapp/src/components/ui/Banner/AlertBanner.module.scss +++ b/airbyte-webapp/src/components/ui/Banner/AlertBanner.module.scss @@ -16,8 +16,9 @@ } } -.beige { - background-color: colors.$beige-100; +.default { + background-color: colors.$blue; + color: colors.$white; } .red { diff --git a/airbyte-webapp/src/components/ui/Banner/AlertBanner.tsx b/airbyte-webapp/src/components/ui/Banner/AlertBanner.tsx index 7e18fadf65a5..fe815af509e9 100644 --- a/airbyte-webapp/src/components/ui/Banner/AlertBanner.tsx +++ b/airbyte-webapp/src/components/ui/Banner/AlertBanner.tsx @@ -10,7 +10,7 @@ interface AlertBannerProps { export const AlertBanner: React.FC = ({ color, message }) => { const bannerStyle = classnames(styles.alertBannerContainer, { - [styles.beige]: color === "default" || !color, + [styles.default]: color === "default" || !color, [styles.red]: color === "warning", }); diff --git a/airbyte-webapp/src/components/ui/InfoBox/InfoBox.tsx b/airbyte-webapp/src/components/ui/InfoBox/InfoBox.tsx index f901c98e707a..56ee1ad217ae 100644 --- a/airbyte-webapp/src/components/ui/InfoBox/InfoBox.tsx +++ b/airbyte-webapp/src/components/ui/InfoBox/InfoBox.tsx @@ -8,7 +8,7 @@ interface Props { } const Box = styled.div` - background: ${({ theme }) => theme.darkBeigeColor}; + background: ${({ theme }) => theme.yellow100}; border-radius: 8px; padding: 18px 25px 22px; font-size: 14px; diff --git a/airbyte-webapp/src/components/ui/StepsMenu/Step.tsx b/airbyte-webapp/src/components/ui/StepsMenu/Step.tsx index 0b335dd8e353..0ba16732bb14 100644 --- a/airbyte-webapp/src/components/ui/StepsMenu/Step.tsx +++ b/airbyte-webapp/src/components/ui/StepsMenu/Step.tsx @@ -20,7 +20,7 @@ const StepView = styled.div<{ min-width: ${({ lightMode }) => (lightMode ? "100px" : "auto")}; min-height: 28px; padding: 6px 14px; - border-radius: 4px; + border-radius: 28px; pointer-events: ${({ isActive, nonClickable }) => (isActive || nonClickable ? "none" : "all")}; cursor: ${({ nonClickable }) => (nonClickable ? "default" : "pointer")}; text-align: center; diff --git a/airbyte-webapp/src/components/ui/Table/Table.tsx b/airbyte-webapp/src/components/ui/Table/Table.tsx index 94b5805d5a6e..6d07ab6b8a0d 100644 --- a/airbyte-webapp/src/components/ui/Table/Table.tsx +++ b/airbyte-webapp/src/components/ui/Table/Table.tsx @@ -84,7 +84,7 @@ const Th = styled.th` font-size: ${({ light }) => (light ? 11 : 10)}px; line-height: 12px; color: ${({ theme, highlighted }) => (highlighted ? theme.whiteColor : theme.lightTextColor)}; - border-bottom: ${({ theme, light }) => (light ? "none" : ` 1px solid ${theme.backgroundColor}`)}; + border-bottom: none; width: ${({ collapse, customWidth }) => (customWidth ? `${customWidth}%` : collapse ? "0.0000000001%" : "auto")}; font-weight: ${({ light }) => (light ? 400 : 600)}; text-transform: ${({ light }) => (light ? "capitalize" : "uppercase")}; diff --git a/airbyte-webapp/src/global-styles.tsx b/airbyte-webapp/src/global-styles.tsx deleted file mode 100644 index 5ffa58405a81..000000000000 --- a/airbyte-webapp/src/global-styles.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { createGlobalStyle, ThemeProps } from "styled-components"; - -import { Theme } from "./theme"; - -const GlobalStyle = createGlobalStyle>` - #__next, - html, - body, - #root { - height: 100%; - width: 100%; - padding: 0; - margin: 0; - font-weight: normal; - -webkit-font-smoothing: antialiased; - color: ${({ theme }) => theme.textColor}; - font-family: ${({ theme }) => theme.regularFont}; - background: ${({ theme }) => theme.backgroundColor}; - font-size: 14px; - } - - button, input, textarea { - font-family: ${({ theme }) => theme.regularFont}; - } - - * { - box-sizing: border-box; - } -`; - -export default GlobalStyle; diff --git a/airbyte-webapp/src/index.tsx b/airbyte-webapp/src/index.tsx index 751cd8a448c4..9299e3b2ddf9 100644 --- a/airbyte-webapp/src/index.tsx +++ b/airbyte-webapp/src/index.tsx @@ -8,6 +8,7 @@ import { loadOsano } from "utils/dataPrivacy"; import { loadSentry } from "utils/sentry"; import "./globals"; +import "./scss/global.scss"; // We do not follow default config approach since we want to init sentry/datadog asap loadSentry(); diff --git a/airbyte-webapp/src/locales/en.json b/airbyte-webapp/src/locales/en.json index 289ad9670063..680639c8f9dd 100644 --- a/airbyte-webapp/src/locales/en.json +++ b/airbyte-webapp/src/locales/en.json @@ -4,6 +4,7 @@ "notifications.error.somethingWentWrong": "Something went wrong", "notifications.error.noMessage": "No error message", + "sidebar.homepage": "Homepage", "sidebar.sources": "Sources", "sidebar.destinations": "Destinations", "sidebar.admin": "Admin", diff --git a/airbyte-webapp/src/packages/cloud/App.tsx b/airbyte-webapp/src/packages/cloud/App.tsx index f67a6ff60663..47c4bff50a64 100644 --- a/airbyte-webapp/src/packages/cloud/App.tsx +++ b/airbyte-webapp/src/packages/cloud/App.tsx @@ -1,4 +1,3 @@ -import GlobalStyle from "global-styles"; import React, { Suspense } from "react"; import { HelmetProvider } from "react-helmet-async"; import { BrowserRouter as Router } from "react-router-dom"; @@ -28,10 +27,7 @@ import { IntercomProvider } from "./services/thirdParty/intercom/IntercomProvide const messages = { ...en, ...cloudLocales }; const StyleProvider: React.FC> = ({ children }) => ( - - - {children} - + {children} ); const Services: React.FC> = ({ children }) => ( diff --git a/airbyte-webapp/src/packages/cloud/components/experiments/SpeedyConnection/SpeedyConnectionBanner/SpeedyConnectionBanner.module.scss b/airbyte-webapp/src/packages/cloud/components/experiments/SpeedyConnection/SpeedyConnectionBanner/SpeedyConnectionBanner.module.scss index 2519746129c0..c9168e02abc0 100644 --- a/airbyte-webapp/src/packages/cloud/components/experiments/SpeedyConnection/SpeedyConnectionBanner/SpeedyConnectionBanner.module.scss +++ b/airbyte-webapp/src/packages/cloud/components/experiments/SpeedyConnection/SpeedyConnectionBanner/SpeedyConnectionBanner.module.scss @@ -9,11 +9,11 @@ z-index: 3; font-size: 12px; line-height: 15px; - color: colors.$black; padding: 8px; display: flex; align-items: center; - background-color: colors.$beige-100; + background-color: colors.$blue; + color: colors.$white; @media (min-width: 1280px) { height: 50px; diff --git a/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/components/RemainingCredits.tsx b/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/components/RemainingCredits.tsx index 359339ac10fb..ff8f67af93fc 100644 --- a/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/components/RemainingCredits.tsx +++ b/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/components/RemainingCredits.tsx @@ -24,7 +24,7 @@ interface Props { } const Block = styled.div` - background: ${({ theme }) => theme.darkBeigeColor}; + background: ${({ theme }) => theme.blue50}; border-radius: 8px; padding: 18px 25px 22px; font-size: 13px; diff --git a/airbyte-webapp/src/packages/cloud/views/layout/SideBar/SideBar.module.scss b/airbyte-webapp/src/packages/cloud/views/layout/SideBar/SideBar.module.scss index 7441f3b09d25..f1682b72b58a 100644 --- a/airbyte-webapp/src/packages/cloud/views/layout/SideBar/SideBar.module.scss +++ b/airbyte-webapp/src/packages/cloud/views/layout/SideBar/SideBar.module.scss @@ -11,14 +11,13 @@ $sidebar-workspace-font-weight: 400; display: block; height: 21px; width: 100%; - border: 0; + border: variables.$border-thin solid colors.$grey-100; border-radius: variables.$border-radius-md; background-color: rgba(255, 255, 255, 20%); margin-top: variables.$spacing-md; padding: 0 variables.$spacing-md; font-size: $sidebar-workspace-font-size; font-weight: $sidebar-workspace-font-weight; - color: colors.$white; white-space: nowrap; text-overflow: ellipsis; text-align: center; diff --git a/airbyte-webapp/src/packages/cloud/views/layout/SideBar/SideBar.tsx b/airbyte-webapp/src/packages/cloud/views/layout/SideBar/SideBar.tsx index 46476daf7e0f..b73e3961fa45 100644 --- a/airbyte-webapp/src/packages/cloud/views/layout/SideBar/SideBar.tsx +++ b/airbyte-webapp/src/packages/cloud/views/layout/SideBar/SideBar.tsx @@ -3,7 +3,7 @@ import { faEnvelope } from "@fortawesome/free-regular-svg-icons"; import { faDesktop, faQuestionCircle } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import React from "react"; -import { FormattedMessage, FormattedNumber } from "react-intl"; +import { FormattedMessage, FormattedNumber, useIntl } from "react-intl"; import { NavLink } from "react-router-dom"; import { Link } from "components"; @@ -19,6 +19,7 @@ import { useIntercom } from "packages/cloud/services/thirdParty/intercom"; import { useGetCloudWorkspace } from "packages/cloud/services/workspaces/CloudWorkspacesService"; import { WorkspacePopout } from "packages/cloud/views/workspaces/WorkspacePopout"; import { links } from "utils/links"; +import { ReactComponent as AirbyteLogo } from "views/layout/SideBar/airbyteLogo.svg"; import ChatIcon from "views/layout/SideBar/components/ChatIcon"; import ConnectionsIcon from "views/layout/SideBar/components/ConnectionsIcon"; import DestinationIcon from "views/layout/SideBar/components/DestinationIcon"; @@ -40,6 +41,7 @@ const SideBar: React.FC = () => { const { show } = useIntercom(); const handleChatUs = () => show(); const hideOnboardingExperiment = useExperiment("onboarding.hideOnboarding", false); + const { formatMessage } = useIntl(); return (
+
+

SaveStatsRequestBody - Up

+
+
+
jobId
Long format: int64
+
attemptNumber
Integer format: int32
+
stats
+
streamStats (optional)
+
+

SchemaChange - Up

From fe3f459a8f24264fdc58554717a167048b20cc0b Mon Sep 17 00:00:00 2001 From: Subodh Kant Chaturvedi Date: Fri, 4 Nov 2022 23:02:51 +0530 Subject: [PATCH 53/73] mssql-source:upgrade debezium version to 1.9.6 (#18732) * mssql-source:upgrade debezium version to 1.9.6 * more improvements * upgrade version * auto-bump connector version * fix test Co-authored-by: Octavia Squidington III --- .../resources/seed/source_definitions.yaml | 2 +- .../src/main/resources/seed/source_specs.yaml | 14 ++- .../bases/debezium-v1-9-6/build.gradle | 2 +- .../internals/FirstRecordWaitTimeUtil.java | 71 ++++++++++++ .../debezium/internals/MSSQLConverter.java | 104 +++++++++++++++++- .../FirstRecordWaitTimeUtilTest.java | 51 +++++++++ .../integrations/debezium/CdcSourceTest.java | 1 + .../source-mssql-strict-encrypt/Dockerfile | 2 +- .../src/test/resources/expected_spec.json | 9 ++ .../connectors/source-mssql/Dockerfile | 2 +- .../connectors/source-mssql/build.gradle | 7 +- .../source/mssql/MssqlCdcHelper.java | 21 +++- .../source/mssql/MssqlCdcStateHandler.java | 5 + .../source/mssql/MssqlSource.java | 21 +++- .../source-mssql/src/main/resources/spec.json | 9 ++ .../mssql/CdcMssqlSourceAcceptanceTest.java | 2 + .../mssql/CdcMssqlSourceDatatypeTest.java | 2 + .../source/mssql/CdcMssqlSourceTest.java | 13 +++ .../source/mysql/MySqlSource.java | 5 +- .../mysql/helpers/CdcConfigurationHelper.java | 54 --------- .../mysql/CdcConfigurationHelperTest.java | 33 ------ .../source/mysql/CdcMysqlSourceTest.java | 1 - docs/integrations/sources/mssql.md | 1 + 23 files changed, 323 insertions(+), 109 deletions(-) create mode 100644 airbyte-integrations/bases/debezium-v1-9-6/src/main/java/io/airbyte/integrations/debezium/internals/FirstRecordWaitTimeUtil.java create mode 100644 airbyte-integrations/bases/debezium-v1-9-6/src/test/java/io/airbyte/integrations/debezium/internals/FirstRecordWaitTimeUtilTest.java diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index 67e7b4c0c6fb..0d47201322d7 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -765,7 +765,7 @@ - name: Microsoft SQL Server (MSSQL) sourceDefinitionId: b5ea17b1-f170-46dc-bc31-cc744ca984c1 dockerRepository: airbyte/source-mssql - dockerImageTag: 0.4.24 + dockerImageTag: 0.4.25 documentationUrl: https://docs.airbyte.com/integrations/sources/mssql icon: mssql.svg sourceType: database diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index f3512ea919ec..0b7e0d75267d 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -6897,7 +6897,7 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] -- dockerImage: "airbyte/source-mssql:0.4.24" +- dockerImage: "airbyte/source-mssql:0.4.25" spec: documentationUrl: "https://docs.airbyte.com/integrations/destinations/mssql" connectionSpecification: @@ -7071,6 +7071,18 @@ \ the \"Snapshot\" level, you must enable the snapshot isolation mode on the database." order: 2 + initial_waiting_seconds: + type: "integer" + title: "Initial Waiting Time in Seconds (Advanced)" + description: "The amount of time the connector will wait when it launches\ + \ to determine if there is new data to sync or not. Defaults to\ + \ 300 seconds. Valid range: 120 seconds to 1200 seconds. Read about\ + \ initial waiting time." + default: 300 + min: 120 + max: 1200 + order: 3 tunnel_method: type: "object" title: "SSH Tunnel Method" diff --git a/airbyte-integrations/bases/debezium-v1-9-6/build.gradle b/airbyte-integrations/bases/debezium-v1-9-6/build.gradle index 870a3765b234..32cd542b32cf 100644 --- a/airbyte-integrations/bases/debezium-v1-9-6/build.gradle +++ b/airbyte-integrations/bases/debezium-v1-9-6/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation 'io.debezium:debezium-api:1.9.6.Final' implementation 'io.debezium:debezium-embedded:1.9.6.Final' -// implementation 'io.debezium:debezium-connector-sqlserver:1.9.2.Final' + implementation 'io.debezium:debezium-connector-sqlserver:1.9.6.Final' implementation 'io.debezium:debezium-connector-mysql:1.9.6.Final' implementation 'io.debezium:debezium-connector-postgres:1.9.6.Final' implementation 'org.codehaus.plexus:plexus-utils:3.4.2' diff --git a/airbyte-integrations/bases/debezium-v1-9-6/src/main/java/io/airbyte/integrations/debezium/internals/FirstRecordWaitTimeUtil.java b/airbyte-integrations/bases/debezium-v1-9-6/src/main/java/io/airbyte/integrations/debezium/internals/FirstRecordWaitTimeUtil.java new file mode 100644 index 000000000000..6bfffcaafc1d --- /dev/null +++ b/airbyte-integrations/bases/debezium-v1-9-6/src/main/java/io/airbyte/integrations/debezium/internals/FirstRecordWaitTimeUtil.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.integrations.debezium.internals; + +import com.fasterxml.jackson.databind.JsonNode; +import java.time.Duration; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FirstRecordWaitTimeUtil { + + private static final Logger LOGGER = LoggerFactory.getLogger(FirstRecordWaitTimeUtil.class); + + public static final Duration MIN_FIRST_RECORD_WAIT_TIME = Duration.ofMinutes(2); + public static final Duration MAX_FIRST_RECORD_WAIT_TIME = Duration.ofMinutes(20); + public static final Duration DEFAULT_FIRST_RECORD_WAIT_TIME = Duration.ofMinutes(5); + + public static void checkFirstRecordWaitTime(final JsonNode config) { + // we need to skip the check because in tests, we set initial_waiting_seconds + // to 5 seconds for performance reasons, which is shorter than the minimum + // value allowed in production + if (config.has("is_test") && config.get("is_test").asBoolean()) { + return; + } + + final Optional firstRecordWaitSeconds = getFirstRecordWaitSeconds(config); + if (firstRecordWaitSeconds.isPresent()) { + final int seconds = firstRecordWaitSeconds.get(); + if (seconds < MIN_FIRST_RECORD_WAIT_TIME.getSeconds() || seconds > MAX_FIRST_RECORD_WAIT_TIME.getSeconds()) { + throw new IllegalArgumentException( + String.format("initial_waiting_seconds must be between %d and %d seconds", + MIN_FIRST_RECORD_WAIT_TIME.getSeconds(), MAX_FIRST_RECORD_WAIT_TIME.getSeconds())); + } + } + } + + public static Duration getFirstRecordWaitTime(final JsonNode config) { + final boolean isTest = config.has("is_test") && config.get("is_test").asBoolean(); + Duration firstRecordWaitTime = DEFAULT_FIRST_RECORD_WAIT_TIME; + + final Optional firstRecordWaitSeconds = getFirstRecordWaitSeconds(config); + if (firstRecordWaitSeconds.isPresent()) { + firstRecordWaitTime = Duration.ofSeconds(firstRecordWaitSeconds.get()); + if (!isTest && firstRecordWaitTime.compareTo(MIN_FIRST_RECORD_WAIT_TIME) < 0) { + LOGGER.warn("First record waiting time is overridden to {} minutes, which is the min time allowed for safety.", + MIN_FIRST_RECORD_WAIT_TIME.toMinutes()); + firstRecordWaitTime = MIN_FIRST_RECORD_WAIT_TIME; + } else if (!isTest && firstRecordWaitTime.compareTo(MAX_FIRST_RECORD_WAIT_TIME) > 0) { + LOGGER.warn("First record waiting time is overridden to {} minutes, which is the max time allowed for safety.", + MAX_FIRST_RECORD_WAIT_TIME.toMinutes()); + firstRecordWaitTime = MAX_FIRST_RECORD_WAIT_TIME; + } + } + + LOGGER.info("First record waiting time: {} seconds", firstRecordWaitTime.getSeconds()); + return firstRecordWaitTime; + } + + public static Optional getFirstRecordWaitSeconds(final JsonNode config) { + final JsonNode replicationMethod = config.get("replication_method"); + if (replicationMethod != null && replicationMethod.has("initial_waiting_seconds")) { + final int seconds = config.get("replication_method").get("initial_waiting_seconds").asInt(); + return Optional.of(seconds); + } + return Optional.empty(); + } + +} diff --git a/airbyte-integrations/bases/debezium-v1-9-6/src/main/java/io/airbyte/integrations/debezium/internals/MSSQLConverter.java b/airbyte-integrations/bases/debezium-v1-9-6/src/main/java/io/airbyte/integrations/debezium/internals/MSSQLConverter.java index 9420b8ba9758..50a5c77057ff 100644 --- a/airbyte-integrations/bases/debezium-v1-9-6/src/main/java/io/airbyte/integrations/debezium/internals/MSSQLConverter.java +++ b/airbyte-integrations/bases/debezium-v1-9-6/src/main/java/io/airbyte/integrations/debezium/internals/MSSQLConverter.java @@ -4,14 +4,21 @@ package io.airbyte.integrations.debezium.internals; +import com.microsoft.sqlserver.jdbc.Geography; +import com.microsoft.sqlserver.jdbc.Geometry; +import com.microsoft.sqlserver.jdbc.SQLServerException; import io.airbyte.db.DataTypeUtils; import io.debezium.spi.converter.CustomConverter; import io.debezium.spi.converter.RelationalColumn; import java.math.BigDecimal; +import java.nio.charset.Charset; import java.sql.Timestamp; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.Objects; import java.util.Properties; import java.util.Set; +import microsoft.sql.DateTimeOffset; import org.apache.kafka.connect.data.SchemaBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,9 +27,14 @@ public class MSSQLConverter implements CustomConverter DATE_TYPES = Set.of("DATE", "DATETIME", "DATETIME2", "DATETIMEOFFSET", "SMALLDATETIME"); - private final String TIME_TYPE = "TIME"; - private final String SMALLMONEY_TYPE = "SMALLMONEY"; + private final Set DATE_TYPES = Set.of("DATE", "DATETIME", "DATETIME2", "SMALLDATETIME"); + private final Set BINARY = Set.of("VARBINARY", "BINARY"); + private static final String DATETIMEOFFSET = "DATETIMEOFFSET"; + private static final String TIME_TYPE = "TIME"; + private static final String SMALLMONEY_TYPE = "SMALLMONEY"; + private static final String GEOMETRY = "GEOMETRY"; + private static final String GEOGRAPHY = "GEOGRAPHY"; + private static final String DEBEZIUM_DATETIMEOFFSET_FORMAT = "yyyy-MM-dd HH:mm:ss XXX"; @Override public void configure(Properties props) {} @@ -34,11 +46,61 @@ public void converterFor(final RelationalColumn field, registerDate(field, registration); } else if (SMALLMONEY_TYPE.equalsIgnoreCase(field.typeName())) { registerMoney(field, registration); + } else if (BINARY.contains(field.typeName().toUpperCase())) { + registerBinary(field, registration); + } else if (GEOMETRY.equalsIgnoreCase(field.typeName())) { + registerGeometry(field, registration); + } else if (GEOGRAPHY.equalsIgnoreCase(field.typeName())) { + registerGeography(field, registration); } else if (TIME_TYPE.equalsIgnoreCase(field.typeName())) { registerTime(field, registration); + } else if (DATETIMEOFFSET.equalsIgnoreCase(field.typeName())) { + registerDateTimeOffSet(field, registration); } } + private void registerGeometry(final RelationalColumn field, + final ConverterRegistration registration) { + registration.register(SchemaBuilder.string(), input -> { + if (Objects.isNull(input)) { + return DebeziumConverterUtils.convertDefaultValue(field); + } + + if (input instanceof byte[]) { + try { + return Geometry.deserialize((byte[]) input).toString(); + } catch (SQLServerException e) { + LOGGER.error(e.getMessage()); + } + } + + LOGGER.warn("Uncovered Geometry class type '{}'. Use default converter", + input.getClass().getName()); + return input.toString(); + }); + } + + private void registerGeography(final RelationalColumn field, + final ConverterRegistration registration) { + registration.register(SchemaBuilder.string(), input -> { + if (Objects.isNull(input)) { + return DebeziumConverterUtils.convertDefaultValue(field); + } + + if (input instanceof byte[]) { + try { + return Geography.deserialize((byte[]) input).toString(); + } catch (SQLServerException e) { + LOGGER.error(e.getMessage()); + } + } + + LOGGER.warn("Uncovered Geography class type '{}'. Use default converter", + input.getClass().getName()); + return input.toString(); + }); + } + private void registerDate(final RelationalColumn field, final ConverterRegistration registration) { registration.register(SchemaBuilder.string(), input -> { @@ -50,6 +112,25 @@ private void registerDate(final RelationalColumn field, }); } + private void registerDateTimeOffSet(final RelationalColumn field, + final ConverterRegistration registration) { + registration.register(SchemaBuilder.string(), input -> { + if (Objects.isNull(input)) { + return DebeziumConverterUtils.convertDefaultValue(field); + } + + if (input instanceof DateTimeOffset) { + return DataTypeUtils.toISO8601String( + OffsetDateTime.parse(input.toString(), + DateTimeFormatter.ofPattern(DEBEZIUM_DATETIMEOFFSET_FORMAT))); + } + + LOGGER.warn("Uncovered DateTimeOffSet class type '{}'. Use default converter", + input.getClass().getName()); + return input.toString(); + }); + } + private void registerTime(final RelationalColumn field, final ConverterRegistration registration) { registration.register(SchemaBuilder.string(), input -> { @@ -84,4 +165,21 @@ private void registerMoney(final RelationalColumn field, }); } + private void registerBinary(final RelationalColumn field, + final ConverterRegistration registration) { + registration.register(SchemaBuilder.string(), input -> { + if (Objects.isNull(input)) { + return DebeziumConverterUtils.convertDefaultValue(field); + } + + if (input instanceof byte[]) { + return new String((byte[]) input, Charset.defaultCharset()); + } + + LOGGER.warn("Uncovered binary class type '{}'. Use default converter", + input.getClass().getName()); + return input.toString(); + }); + } + } diff --git a/airbyte-integrations/bases/debezium-v1-9-6/src/test/java/io/airbyte/integrations/debezium/internals/FirstRecordWaitTimeUtilTest.java b/airbyte-integrations/bases/debezium-v1-9-6/src/test/java/io/airbyte/integrations/debezium/internals/FirstRecordWaitTimeUtilTest.java new file mode 100644 index 000000000000..360caff71b89 --- /dev/null +++ b/airbyte-integrations/bases/debezium-v1-9-6/src/test/java/io/airbyte/integrations/debezium/internals/FirstRecordWaitTimeUtilTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.integrations.debezium.internals; + +import static io.airbyte.integrations.debezium.internals.FirstRecordWaitTimeUtil.MAX_FIRST_RECORD_WAIT_TIME; +import static io.airbyte.integrations.debezium.internals.FirstRecordWaitTimeUtil.MIN_FIRST_RECORD_WAIT_TIME; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import com.fasterxml.jackson.databind.JsonNode; +import io.airbyte.commons.json.Jsons; +import java.time.Duration; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import org.junit.jupiter.api.Test; + +public class FirstRecordWaitTimeUtilTest { + + @Test + void testGetFirstRecordWaitTime() { + final JsonNode emptyConfig = Jsons.jsonNode(Collections.emptyMap()); + assertDoesNotThrow(() -> FirstRecordWaitTimeUtil.checkFirstRecordWaitTime(emptyConfig)); + assertEquals(Optional.empty(), FirstRecordWaitTimeUtil.getFirstRecordWaitSeconds(emptyConfig)); + assertEquals(FirstRecordWaitTimeUtil.DEFAULT_FIRST_RECORD_WAIT_TIME, FirstRecordWaitTimeUtil.getFirstRecordWaitTime(emptyConfig)); + + final JsonNode normalConfig = Jsons.jsonNode(Map.of("replication_method", + Map.of("method", "CDC", "initial_waiting_seconds", 500))); + assertDoesNotThrow(() -> FirstRecordWaitTimeUtil.checkFirstRecordWaitTime(normalConfig)); + assertEquals(Optional.of(500), FirstRecordWaitTimeUtil.getFirstRecordWaitSeconds(normalConfig)); + assertEquals(Duration.ofSeconds(500), FirstRecordWaitTimeUtil.getFirstRecordWaitTime(normalConfig)); + + final int tooShortTimeout = (int) MIN_FIRST_RECORD_WAIT_TIME.getSeconds() - 1; + final JsonNode tooShortConfig = Jsons.jsonNode(Map.of("replication_method", + Map.of("method", "CDC", "initial_waiting_seconds", tooShortTimeout))); + assertThrows(IllegalArgumentException.class, () -> FirstRecordWaitTimeUtil.checkFirstRecordWaitTime(tooShortConfig)); + assertEquals(Optional.of(tooShortTimeout), FirstRecordWaitTimeUtil.getFirstRecordWaitSeconds(tooShortConfig)); + assertEquals(MIN_FIRST_RECORD_WAIT_TIME, FirstRecordWaitTimeUtil.getFirstRecordWaitTime(tooShortConfig)); + + final int tooLongTimeout = (int) MAX_FIRST_RECORD_WAIT_TIME.getSeconds() + 1; + final JsonNode tooLongConfig = Jsons.jsonNode(Map.of("replication_method", + Map.of("method", "CDC", "initial_waiting_seconds", tooLongTimeout))); + assertThrows(IllegalArgumentException.class, () -> FirstRecordWaitTimeUtil.checkFirstRecordWaitTime(tooLongConfig)); + assertEquals(Optional.of(tooLongTimeout), FirstRecordWaitTimeUtil.getFirstRecordWaitSeconds(tooLongConfig)); + assertEquals(MAX_FIRST_RECORD_WAIT_TIME, FirstRecordWaitTimeUtil.getFirstRecordWaitTime(tooLongConfig)); + } + +} diff --git a/airbyte-integrations/bases/debezium-v1-9-6/src/testFixtures/java/io/airbyte/integrations/debezium/CdcSourceTest.java b/airbyte-integrations/bases/debezium-v1-9-6/src/testFixtures/java/io/airbyte/integrations/debezium/CdcSourceTest.java index ded6b0239afb..e5bf1cfd93df 100644 --- a/airbyte-integrations/bases/debezium-v1-9-6/src/testFixtures/java/io/airbyte/integrations/debezium/CdcSourceTest.java +++ b/airbyte-integrations/bases/debezium-v1-9-6/src/testFixtures/java/io/airbyte/integrations/debezium/CdcSourceTest.java @@ -64,6 +64,7 @@ public abstract class CdcSourceTest { protected static final String COL_ID = "id"; protected static final String COL_MAKE_ID = "make_id"; protected static final String COL_MODEL = "model"; + protected static final int INITIAL_WAITING_SECONDS = 5; protected final List MODEL_RECORDS_RANDOM = ImmutableList.of( Jsons diff --git a/airbyte-integrations/connectors/source-mssql-strict-encrypt/Dockerfile b/airbyte-integrations/connectors/source-mssql-strict-encrypt/Dockerfile index 29a82548717a..7f0a78bc324b 100644 --- a/airbyte-integrations/connectors/source-mssql-strict-encrypt/Dockerfile +++ b/airbyte-integrations/connectors/source-mssql-strict-encrypt/Dockerfile @@ -16,5 +16,5 @@ ENV APPLICATION source-mssql-strict-encrypt COPY --from=build /airbyte /airbyte -LABEL io.airbyte.version=0.4.24 +LABEL io.airbyte.version=0.4.25 LABEL io.airbyte.name=airbyte/source-mssql-strict-encrypt diff --git a/airbyte-integrations/connectors/source-mssql-strict-encrypt/src/test/resources/expected_spec.json b/airbyte-integrations/connectors/source-mssql-strict-encrypt/src/test/resources/expected_spec.json index 7158e7b18507..c1bfccc2b4db 100644 --- a/airbyte-integrations/connectors/source-mssql-strict-encrypt/src/test/resources/expected_spec.json +++ b/airbyte-integrations/connectors/source-mssql-strict-encrypt/src/test/resources/expected_spec.json @@ -147,6 +147,15 @@ "enum": ["Snapshot", "Read Committed"], "description": "Existing data in the database are synced through an initial snapshot. This parameter controls the isolation level that will be used during the initial snapshotting. If you choose the \"Snapshot\" level, you must enable the snapshot isolation mode on the database.", "order": 2 + }, + "initial_waiting_seconds": { + "type": "integer", + "title": "Initial Waiting Time in Seconds (Advanced)", + "description": "The amount of time the connector will wait when it launches to determine if there is new data to sync or not. Defaults to 300 seconds. Valid range: 120 seconds to 1200 seconds. Read about initial waiting time.", + "default": 300, + "min": 120, + "max": 1200, + "order": 3 } } } diff --git a/airbyte-integrations/connectors/source-mssql/Dockerfile b/airbyte-integrations/connectors/source-mssql/Dockerfile index 1b369f4b119d..a079d48b35eb 100644 --- a/airbyte-integrations/connectors/source-mssql/Dockerfile +++ b/airbyte-integrations/connectors/source-mssql/Dockerfile @@ -16,5 +16,5 @@ ENV APPLICATION source-mssql COPY --from=build /airbyte /airbyte -LABEL io.airbyte.version=0.4.24 +LABEL io.airbyte.version=0.4.25 LABEL io.airbyte.name=airbyte/source-mssql diff --git a/airbyte-integrations/connectors/source-mssql/build.gradle b/airbyte-integrations/connectors/source-mssql/build.gradle index 3fec401df68a..a1bceecbf7a0 100644 --- a/airbyte-integrations/connectors/source-mssql/build.gradle +++ b/airbyte-integrations/connectors/source-mssql/build.gradle @@ -15,15 +15,16 @@ dependencies { implementation project(':airbyte-db:db-lib') implementation project(':airbyte-integrations:bases:base-java') - implementation project(':airbyte-integrations:bases:debezium-v1-4-2') + implementation project(':airbyte-integrations:bases:debezium-v1-9-6') implementation project(':airbyte-protocol:protocol-models') implementation project(':airbyte-integrations:connectors:source-jdbc') implementation project(':airbyte-integrations:connectors:source-relational-db') - implementation 'io.debezium:debezium-connector-sqlserver:1.4.2.Final' + implementation 'io.debezium:debezium-connector-sqlserver:1.9.6.Final' implementation 'com.microsoft.sqlserver:mssql-jdbc:8.4.1.jre14' + implementation 'org.codehaus.plexus:plexus-utils:3.4.2' - testImplementation testFixtures(project(':airbyte-integrations:bases:debezium-v1-4-2')) + testImplementation testFixtures(project(':airbyte-integrations:bases:debezium-v1-9-6')) testImplementation testFixtures(project(':airbyte-integrations:connectors:source-jdbc')) testImplementation 'org.apache.commons:commons-lang3:3.11' diff --git a/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlCdcHelper.java b/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlCdcHelper.java index 63c814edef63..ce2732138ea6 100644 --- a/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlCdcHelper.java +++ b/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlCdcHelper.java @@ -5,8 +5,14 @@ package io.airbyte.integrations.source.mssql; import com.fasterxml.jackson.databind.JsonNode; +import io.airbyte.protocol.models.AirbyteStream; +import io.airbyte.protocol.models.ConfiguredAirbyteCatalog; +import io.airbyte.protocol.models.ConfiguredAirbyteStream; +import io.airbyte.protocol.models.SyncMode; import io.debezium.annotation.VisibleForTesting; import java.util.Properties; +import java.util.stream.Collectors; +import org.codehaus.plexus.util.StringUtils; public class MssqlCdcHelper { @@ -130,8 +136,7 @@ static DataToSync getDataToSyncConfig(final JsonNode config) { return DataToSync.EXISTING_AND_NEW; } - @VisibleForTesting - static Properties getDebeziumProperties(final JsonNode config) { + static Properties getDebeziumProperties(final JsonNode config, final ConfiguredAirbyteCatalog catalog) { final Properties props = new Properties(); props.setProperty("connector.class", "io.debezium.connector.sqlserver.SqlServerConnector"); @@ -146,7 +151,19 @@ static Properties getDebeziumProperties(final JsonNode config) { props.setProperty("snapshot.mode", getDataToSyncConfig(config).getDebeziumSnapshotMode()); props.setProperty("snapshot.isolation.mode", getSnapshotIsolationConfig(config).getDebeziumIsolationMode()); + props.setProperty("schema.include.list", getSchema(catalog)); + return props; } + private static String getSchema(final ConfiguredAirbyteCatalog catalog) { + return catalog.getStreams().stream() + .filter(s -> s.getSyncMode() == SyncMode.INCREMENTAL) + .map(ConfiguredAirbyteStream::getStream) + .map(AirbyteStream::getNamespace) + // debezium needs commas escaped to split properly + .map(x -> StringUtils.escape(x, new char[] {','}, "\\,")) + .collect(Collectors.joining(",")); + } + } diff --git a/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlCdcStateHandler.java b/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlCdcStateHandler.java index ad275bda45c2..e626f7bff2de 100644 --- a/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlCdcStateHandler.java +++ b/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlCdcStateHandler.java @@ -50,4 +50,9 @@ public AirbyteMessage saveState(final Map offset, final String d return new AirbyteMessage().withType(Type.STATE).withState(stateMessage); } + @Override + public AirbyteMessage saveStateAfterCompletionOfSnapshotOfNewStreams() { + throw new RuntimeException("Snapshot of individual tables is not implemented in MSSQL"); + } + } diff --git a/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlSource.java b/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlSource.java index 6b00ac9b0a3d..ed44070677c4 100644 --- a/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlSource.java +++ b/airbyte-integrations/connectors/source-mssql/src/main/java/io/airbyte/integrations/source/mssql/MssqlSource.java @@ -29,6 +29,7 @@ import io.airbyte.integrations.base.Source; import io.airbyte.integrations.base.ssh.SshWrappedSource; import io.airbyte.integrations.debezium.AirbyteDebeziumHandler; +import io.airbyte.integrations.debezium.internals.FirstRecordWaitTimeUtil; import io.airbyte.integrations.source.jdbc.AbstractJdbcSource; import io.airbyte.integrations.source.mssql.MssqlCdcHelper.SnapshotIsolation; import io.airbyte.integrations.source.relationaldb.TableInfo; @@ -46,13 +47,16 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.time.Duration; import java.time.Instant; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Properties; import java.util.Set; +import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -366,14 +370,19 @@ public List> getIncrementalIterators( final JsonNode sourceConfig = database.getSourceConfig(); if (MssqlCdcHelper.isCdc(sourceConfig) && shouldUseCDC(catalog)) { LOGGER.info("using CDC: {}", true); - final Properties props = MssqlCdcHelper.getDebeziumProperties(sourceConfig); - final AirbyteDebeziumHandler handler = new AirbyteDebeziumHandler(sourceConfig, - MssqlCdcTargetPosition.getTargetPosition(database, sourceConfig.get(JdbcUtils.DATABASE_KEY).asText()), - props, catalog, true); - return handler.getIncrementalIterators( + final Duration firstRecordWaitTime = FirstRecordWaitTimeUtil.getFirstRecordWaitTime(sourceConfig); + final AirbyteDebeziumHandler handler = + new AirbyteDebeziumHandler(sourceConfig, + MssqlCdcTargetPosition.getTargetPosition(database, sourceConfig.get(JdbcUtils.DATABASE_KEY).asText()), true, firstRecordWaitTime); + + final Supplier> incrementalIteratorSupplier = () -> handler.getIncrementalIterators(catalog, new MssqlCdcSavedInfoFetcher(stateManager.getCdcStateManager().getCdcState()), - new MssqlCdcStateHandler(stateManager), new MssqlCdcConnectorMetadataInjector(), + new MssqlCdcStateHandler(stateManager), + new MssqlCdcConnectorMetadataInjector(), + MssqlCdcHelper.getDebeziumProperties(sourceConfig, catalog), emittedAt); + + return Collections.singletonList(incrementalIteratorSupplier.get()); } else { LOGGER.info("using CDC: {}", false); return super.getIncrementalIterators(database, catalog, tableNameToTable, stateManager, emittedAt); diff --git a/airbyte-integrations/connectors/source-mssql/src/main/resources/spec.json b/airbyte-integrations/connectors/source-mssql/src/main/resources/spec.json index a76671f2dae6..674f9342317d 100644 --- a/airbyte-integrations/connectors/source-mssql/src/main/resources/spec.json +++ b/airbyte-integrations/connectors/source-mssql/src/main/resources/spec.json @@ -160,6 +160,15 @@ "enum": ["Snapshot", "Read Committed"], "description": "Existing data in the database are synced through an initial snapshot. This parameter controls the isolation level that will be used during the initial snapshotting. If you choose the \"Snapshot\" level, you must enable the snapshot isolation mode on the database.", "order": 2 + }, + "initial_waiting_seconds": { + "type": "integer", + "title": "Initial Waiting Time in Seconds (Advanced)", + "description": "The amount of time the connector will wait when it launches to determine if there is new data to sync or not. Defaults to 300 seconds. Valid range: 120 seconds to 1200 seconds. Read about initial waiting time.", + "default": 300, + "min": 120, + "max": 1200, + "order": 3 } } } diff --git a/airbyte-integrations/connectors/source-mssql/src/test-integration/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceAcceptanceTest.java b/airbyte-integrations/connectors/source-mssql/src/test-integration/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceAcceptanceTest.java index c2dd276fc26f..839654e4c507 100644 --- a/airbyte-integrations/connectors/source-mssql/src/test-integration/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceAcceptanceTest.java +++ b/airbyte-integrations/connectors/source-mssql/src/test-integration/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceAcceptanceTest.java @@ -99,6 +99,7 @@ protected void setupEnvironment(final TestDestinationEnv environment) throws Int final JsonNode replicationConfig = Jsons.jsonNode(Map.of( "method", "CDC", "data_to_sync", "Existing and New", + "initial_waiting_seconds", 5, "snapshot_isolation", "Snapshot")); config = Jsons.jsonNode(ImmutableMap.builder() @@ -108,6 +109,7 @@ protected void setupEnvironment(final TestDestinationEnv environment) throws Int .put(JdbcUtils.USERNAME_KEY, TEST_USER_NAME) .put(JdbcUtils.PASSWORD_KEY, TEST_USER_PASSWORD) .put("replication_method", replicationConfig) + .put("is_test", true) .build()); dslContext = DSLContextFactory.create( diff --git a/airbyte-integrations/connectors/source-mssql/src/test-integration/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceDatatypeTest.java b/airbyte-integrations/connectors/source-mssql/src/test-integration/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceDatatypeTest.java index 0a202c36910d..60dc718de835 100644 --- a/airbyte-integrations/connectors/source-mssql/src/test-integration/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceDatatypeTest.java +++ b/airbyte-integrations/connectors/source-mssql/src/test-integration/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceDatatypeTest.java @@ -34,6 +34,7 @@ protected Database setupDatabase() throws Exception { final JsonNode replicationConfig = Jsons.jsonNode(Map.of( "method", "CDC", "data_to_sync", "Existing and New", + "initial_waiting_seconds", 5, "snapshot_isolation", "Snapshot")); config = Jsons.jsonNode(ImmutableMap.builder() @@ -43,6 +44,7 @@ protected Database setupDatabase() throws Exception { .put(JdbcUtils.USERNAME_KEY, container.getUsername()) .put(JdbcUtils.PASSWORD_KEY, container.getPassword()) .put("replication_method", replicationConfig) + .put("is_test", true) .build()); dslContext = DSLContextFactory.create( diff --git a/airbyte-integrations/connectors/source-mssql/src/test/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceTest.java b/airbyte-integrations/connectors/source-mssql/src/test/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceTest.java index 5badf3afcbe0..ff4608d84ecf 100644 --- a/airbyte-integrations/connectors/source-mssql/src/test/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceTest.java +++ b/airbyte-integrations/connectors/source-mssql/src/test/java/io/airbyte/integrations/source/mssql/CdcMssqlSourceTest.java @@ -88,6 +88,7 @@ private void init() { final JsonNode replicationConfig = Jsons.jsonNode(Map.of( "method", "CDC", "data_to_sync", "Existing and New", + "initial_waiting_seconds", INITIAL_WAITING_SECONDS, "snapshot_isolation", "Snapshot")); config = Jsons.jsonNode(ImmutableMap.builder() .put(JdbcUtils.HOST_KEY, container.getHost()) @@ -97,6 +98,7 @@ private void init() { .put(JdbcUtils.USERNAME_KEY, TEST_USER_NAME) .put(JdbcUtils.PASSWORD_KEY, TEST_USER_PASSWORD) .put("replication_method", replicationConfig) + .put("is_test", true) .build()); dataSource = DataSourceFactory.create( @@ -159,6 +161,17 @@ public String createSchemaQuery(final String schemaName) { return "CREATE SCHEMA " + schemaName; } + //TODO : Delete this Override when MSSQL supports individual table snapshot + @Override + public void newTableSnapshotTest() throws Exception { + // Do nothing + } + + @Override + protected String randomTableSchema() { + return MODELS_SCHEMA + "_random"; + } + private void switchCdcOnDatabase(final Boolean enable, final String db) { final String storedProc = enable ? "sys.sp_cdc_enable_db" : "sys.sp_cdc_disable_db"; executeQuery("USE [" + db + "]\n" + "EXEC " + storedProc); diff --git a/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/MySqlSource.java b/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/MySqlSource.java index 522c013befce..74ed8be555f3 100644 --- a/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/MySqlSource.java +++ b/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/MySqlSource.java @@ -27,6 +27,7 @@ import io.airbyte.integrations.base.Source; import io.airbyte.integrations.base.ssh.SshWrappedSource; import io.airbyte.integrations.debezium.AirbyteDebeziumHandler; +import io.airbyte.integrations.debezium.internals.FirstRecordWaitTimeUtil; import io.airbyte.integrations.source.jdbc.AbstractJdbcSource; import io.airbyte.integrations.source.mysql.helpers.CdcConfigurationHelper; import io.airbyte.integrations.source.relationaldb.TableInfo; @@ -125,7 +126,7 @@ public List> getCheckOperations(final J checkOperations.addAll(CdcConfigurationHelper.getCheckOperations()); checkOperations.add(database -> { - CdcConfigurationHelper.checkFirstRecordWaitTime(config); + FirstRecordWaitTimeUtil.checkFirstRecordWaitTime(config); CdcConfigurationHelper.checkServerTimeZoneConfig(config); }); } @@ -237,7 +238,7 @@ public List> getIncrementalIterators(final final Instant emittedAt) { final JsonNode sourceConfig = database.getSourceConfig(); if (isCdc(sourceConfig) && shouldUseCDC(catalog)) { - final Duration firstRecordWaitTime = CdcConfigurationHelper.getFirstRecordWaitTime(sourceConfig); + final Duration firstRecordWaitTime = FirstRecordWaitTimeUtil.getFirstRecordWaitTime(sourceConfig); LOGGER.info("First record waiting time: {} seconds", firstRecordWaitTime.getSeconds()); final AirbyteDebeziumHandler handler = new AirbyteDebeziumHandler(sourceConfig, MySqlCdcTargetPosition.targetPosition(database), true, firstRecordWaitTime); diff --git a/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/helpers/CdcConfigurationHelper.java b/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/helpers/CdcConfigurationHelper.java index 682d4186c54a..a16176bc09f1 100644 --- a/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/helpers/CdcConfigurationHelper.java +++ b/airbyte-integrations/connectors/source-mysql/src/main/java/io/airbyte/integrations/source/mysql/helpers/CdcConfigurationHelper.java @@ -33,10 +33,6 @@ public class CdcConfigurationHelper { private static final String BINLOG_FORMAT = "binlog_format"; private static final String BINLOG_ROW_IMAGE = "binlog_row_image"; - public static final Duration MIN_FIRST_RECORD_WAIT_TIME = Duration.ofMinutes(2); - public static final Duration MAX_FIRST_RECORD_WAIT_TIME = Duration.ofMinutes(20); - public static final Duration DEFAULT_FIRST_RECORD_WAIT_TIME = Duration.ofMinutes(5); - /** * Method will get required configurations for cdc sync * @@ -66,15 +62,6 @@ private static CheckedConsumer getCheckOperation(final }; } - public static Optional getFirstRecordWaitSeconds(final JsonNode config) { - final JsonNode replicationMethod = config.get("replication_method"); - if (replicationMethod != null && replicationMethod.has("initial_waiting_seconds")) { - final int seconds = config.get("replication_method").get("initial_waiting_seconds").asInt(); - return Optional.of(seconds); - } - return Optional.empty(); - } - private static Optional getCdcServerTimezone(final JsonNode config) { final JsonNode replicationMethod = config.get("replication_method"); if (replicationMethod != null && replicationMethod.has("server_time_zone")) { @@ -95,45 +82,4 @@ public static void checkServerTimeZoneConfig(final JsonNode config) { } } - public static void checkFirstRecordWaitTime(final JsonNode config) { - // we need to skip the check because in tests, we set initial_waiting_seconds - // to 5 seconds for performance reasons, which is shorter than the minimum - // value allowed in production - if (config.has("is_test") && config.get("is_test").asBoolean()) { - return; - } - - final Optional firstRecordWaitSeconds = getFirstRecordWaitSeconds(config); - if (firstRecordWaitSeconds.isPresent()) { - final int seconds = firstRecordWaitSeconds.get(); - if (seconds < MIN_FIRST_RECORD_WAIT_TIME.getSeconds() || seconds > MAX_FIRST_RECORD_WAIT_TIME.getSeconds()) { - throw new IllegalArgumentException( - String.format("initial_waiting_seconds must be between %d and %d seconds", - MIN_FIRST_RECORD_WAIT_TIME.getSeconds(), MAX_FIRST_RECORD_WAIT_TIME.getSeconds())); - } - } - } - - public static Duration getFirstRecordWaitTime(final JsonNode config) { - final boolean isTest = config.has("is_test") && config.get("is_test").asBoolean(); - Duration firstRecordWaitTime = DEFAULT_FIRST_RECORD_WAIT_TIME; - - final Optional firstRecordWaitSeconds = getFirstRecordWaitSeconds(config); - if (firstRecordWaitSeconds.isPresent()) { - firstRecordWaitTime = Duration.ofSeconds(firstRecordWaitSeconds.get()); - if (!isTest && firstRecordWaitTime.compareTo(MIN_FIRST_RECORD_WAIT_TIME) < 0) { - LOGGER.warn("First record waiting time is overridden to {} minutes, which is the min time allowed for safety.", - MIN_FIRST_RECORD_WAIT_TIME.toMinutes()); - firstRecordWaitTime = MIN_FIRST_RECORD_WAIT_TIME; - } else if (!isTest && firstRecordWaitTime.compareTo(MAX_FIRST_RECORD_WAIT_TIME) > 0) { - LOGGER.warn("First record waiting time is overridden to {} minutes, which is the max time allowed for safety.", - MAX_FIRST_RECORD_WAIT_TIME.toMinutes()); - firstRecordWaitTime = MAX_FIRST_RECORD_WAIT_TIME; - } - } - - LOGGER.info("First record waiting time: {} seconds", firstRecordWaitTime.getSeconds()); - return firstRecordWaitTime; - } - } diff --git a/airbyte-integrations/connectors/source-mysql/src/test/java/io/airbyte/integrations/source/mysql/CdcConfigurationHelperTest.java b/airbyte-integrations/connectors/source-mysql/src/test/java/io/airbyte/integrations/source/mysql/CdcConfigurationHelperTest.java index 2c15cfd2b456..800ef26ff1d8 100644 --- a/airbyte-integrations/connectors/source-mysql/src/test/java/io/airbyte/integrations/source/mysql/CdcConfigurationHelperTest.java +++ b/airbyte-integrations/connectors/source-mysql/src/test/java/io/airbyte/integrations/source/mysql/CdcConfigurationHelperTest.java @@ -4,51 +4,18 @@ package io.airbyte.integrations.source.mysql; -import static io.airbyte.integrations.source.mysql.helpers.CdcConfigurationHelper.MAX_FIRST_RECORD_WAIT_TIME; -import static io.airbyte.integrations.source.mysql.helpers.CdcConfigurationHelper.MIN_FIRST_RECORD_WAIT_TIME; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import com.fasterxml.jackson.databind.JsonNode; import io.airbyte.commons.json.Jsons; import io.airbyte.integrations.source.mysql.helpers.CdcConfigurationHelper; -import java.time.Duration; import java.util.Collections; import java.util.Map; -import java.util.Optional; import org.junit.jupiter.api.Test; public class CdcConfigurationHelperTest { - @Test - void testGetFirstRecordWaitTime() { - final JsonNode emptyConfig = Jsons.jsonNode(Collections.emptyMap()); - assertDoesNotThrow(() -> CdcConfigurationHelper.checkFirstRecordWaitTime(emptyConfig)); - assertEquals(Optional.empty(), CdcConfigurationHelper.getFirstRecordWaitSeconds(emptyConfig)); - assertEquals(CdcConfigurationHelper.DEFAULT_FIRST_RECORD_WAIT_TIME, CdcConfigurationHelper.getFirstRecordWaitTime(emptyConfig)); - - final JsonNode normalConfig = Jsons.jsonNode(Map.of("replication_method", - Map.of("method", "CDC", "initial_waiting_seconds", 500))); - assertDoesNotThrow(() -> CdcConfigurationHelper.checkFirstRecordWaitTime(normalConfig)); - assertEquals(Optional.of(500), CdcConfigurationHelper.getFirstRecordWaitSeconds(normalConfig)); - assertEquals(Duration.ofSeconds(500), CdcConfigurationHelper.getFirstRecordWaitTime(normalConfig)); - - final int tooShortTimeout = (int) MIN_FIRST_RECORD_WAIT_TIME.getSeconds() - 1; - final JsonNode tooShortConfig = Jsons.jsonNode(Map.of("replication_method", - Map.of("method", "CDC", "initial_waiting_seconds", tooShortTimeout))); - assertThrows(IllegalArgumentException.class, () -> CdcConfigurationHelper.checkFirstRecordWaitTime(tooShortConfig)); - assertEquals(Optional.of(tooShortTimeout), CdcConfigurationHelper.getFirstRecordWaitSeconds(tooShortConfig)); - assertEquals(MIN_FIRST_RECORD_WAIT_TIME, CdcConfigurationHelper.getFirstRecordWaitTime(tooShortConfig)); - - final int tooLongTimeout = (int) MAX_FIRST_RECORD_WAIT_TIME.getSeconds() + 1; - final JsonNode tooLongConfig = Jsons.jsonNode(Map.of("replication_method", - Map.of("method", "CDC", "initial_waiting_seconds", tooLongTimeout))); - assertThrows(IllegalArgumentException.class, () -> CdcConfigurationHelper.checkFirstRecordWaitTime(tooLongConfig)); - assertEquals(Optional.of(tooLongTimeout), CdcConfigurationHelper.getFirstRecordWaitSeconds(tooLongConfig)); - assertEquals(MAX_FIRST_RECORD_WAIT_TIME, CdcConfigurationHelper.getFirstRecordWaitTime(tooLongConfig)); - } - @Test void testServerTimeConfig() { final JsonNode emptyConfig = Jsons.jsonNode(Collections.emptyMap()); diff --git a/airbyte-integrations/connectors/source-mysql/src/test/java/io/airbyte/integrations/source/mysql/CdcMysqlSourceTest.java b/airbyte-integrations/connectors/source-mysql/src/test/java/io/airbyte/integrations/source/mysql/CdcMysqlSourceTest.java index 128ef25def1d..0675f455d49a 100644 --- a/airbyte-integrations/connectors/source-mysql/src/test/java/io/airbyte/integrations/source/mysql/CdcMysqlSourceTest.java +++ b/airbyte-integrations/connectors/source-mysql/src/test/java/io/airbyte/integrations/source/mysql/CdcMysqlSourceTest.java @@ -51,7 +51,6 @@ public class CdcMysqlSourceTest extends CdcSourceTest { private static final String DB_NAME = MODELS_SCHEMA; - protected static final int INITIAL_WAITING_SECONDS = 5; private MySQLContainer container; private Database database; private MySqlSource source; diff --git a/docs/integrations/sources/mssql.md b/docs/integrations/sources/mssql.md index 10f1a90311c5..37f044b77594 100644 --- a/docs/integrations/sources/mssql.md +++ b/docs/integrations/sources/mssql.md @@ -341,6 +341,7 @@ WHERE actor_definition_id ='b5ea17b1-f170-46dc-bc31-cc744ca984c1' AND (configura | Version | Date | Pull Request | Subject | |:--------|:-----------|:------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------| +| 0.4.25 | 2022-11-04 | [18732](https://github.com/airbytehq/airbyte/pull/18732) | Upgrade debezium version to 1.9.6 | | 0.4.24 | 2022-10-25 | [18383](https://github.com/airbytehq/airbyte/pull/18383) | Better SSH error handling + messages | | 0.4.23 | 2022-10-21 | [18263](https://github.com/airbytehq/airbyte/pull/18263) | Fixes bug introduced in [15833](https://github.com/airbytehq/airbyte/pull/15833) and adds better error messaging for SSH tunnel in Desstinations | | 0.4.22 | 2022-10-19 | [18087](https://github.com/airbytehq/airbyte/pull/18087) | Better error messaging for configuration errors (SSH configs, choosing an invalid cursor) | From 9c2601013771ca0cd83b633303d40dcbc1a38b1a Mon Sep 17 00:00:00 2001 From: Etienne Neveu Date: Fri, 4 Nov 2022 18:45:01 +0100 Subject: [PATCH 54/73] Fix typo in source code comment DataDaog ==> Datadog (#18911) --- airbyte-base-java-image/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airbyte-base-java-image/Dockerfile b/airbyte-base-java-image/Dockerfile index db890363e143..13b1fae880ed 100644 --- a/airbyte-base-java-image/Dockerfile +++ b/airbyte-base-java-image/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /app RUN yum install -y tar -# Add the DataDaog Java APM agent +# Add the Datadog Java APM agent ADD https://dtdg.co/latest-java-tracer dd-java-agent.jar # Add the OpenTelemetry Java APM agent From 612b3f14ce25c033f2589d59120e3b3a528f8eb6 Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Fri, 4 Nov 2022 19:16:20 +0100 Subject: [PATCH 55/73] Hash filenames of extracted CSS (#18976) --- airbyte-webapp/craco.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/airbyte-webapp/craco.config.js b/airbyte-webapp/craco.config.js index d714685219be..45bea2176cf5 100644 --- a/airbyte-webapp/craco.config.js +++ b/airbyte-webapp/craco.config.js @@ -15,6 +15,8 @@ module.exports = { }), new MiniCssExtractPlugin({ ignoreOrder: true, + filename: "static/css/[name].[contenthash:8].css", + chunkFilename: "static/css/[name].[contenthash:8].chunk.css", }), ], }; From e5c3f4bd0de2efff129295f3c6da620c7e3f5db6 Mon Sep 17 00:00:00 2001 From: Davin Chia Date: Fri, 4 Nov 2022 11:29:43 -0700 Subject: [PATCH 56/73] Remove unused job persistence methods. (#18952) Closes #12823. Also remove unused dump methods. --- .../job/DefaultJobPersistence.java | 55 ---------------- .../persistence/job/JobPersistence.java | 18 ----- .../job/DefaultJobPersistenceTest.java | 9 --- .../java/io/airbyte/server/ServerApp.java | 38 ----------- .../java/io/airbyte/server/ServerAppTest.java | 65 ------------------- 5 files changed, 185 deletions(-) delete mode 100644 airbyte-server/src/test/java/io/airbyte/server/ServerAppTest.java diff --git a/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/DefaultJobPersistence.java b/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/DefaultJobPersistence.java index 8676cd8c94c8..42d7e14c6a7e 100644 --- a/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/DefaultJobPersistence.java +++ b/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/DefaultJobPersistence.java @@ -91,9 +91,6 @@ public class DefaultJobPersistence implements JobPersistence { private final int JOB_HISTORY_EXCESSIVE_NUMBER_OF_JOBS; private static final Logger LOGGER = LoggerFactory.getLogger(DefaultJobPersistence.class); - private static final Set SYSTEM_SCHEMA = Set - .of("pg_toast", "information_schema", "pg_catalog", "import_backup", "pg_internal", - "catalog_history"); public static final String ATTEMPT_NUMBER = "attempt_number"; private static final String JOB_ID = "job_id"; private static final String WHERE = "WHERE "; @@ -797,18 +794,6 @@ public void setSecretMigrationDone() throws IOException { setMetadata(SECRET_MIGRATION_STATUS, "true"); } - private final String SCHEDULER_MIGRATION_STATUS = "schedulerMigration"; - - @Override - public boolean isSchedulerMigrated() throws IOException { - return getMetadata(SCHEDULER_MIGRATION_STATUS).count() == 1; - } - - @Override - public void setSchedulerMigrationDone() throws IOException { - setMetadata(SCHEDULER_MIGRATION_STATUS, "true"); - } - @Override public Optional getVersion() throws IOException { return getMetadata(AirbyteVersion.AIRBYTE_VERSION_KEY_NAME).findFirst(); @@ -915,27 +900,6 @@ public Map> exportDatabase() throws IOExcep return exportDatabase(DEFAULT_SCHEMA); } - /** - * This is different from {@link #exportDatabase()} cause it exports all the tables in all the - * schemas available - */ - @Override - public Map> dump() throws IOException { - final Map> result = new HashMap<>(); - for (final String schema : listSchemas()) { - final List tables = listAllTables(schema); - - for (final String table : tables) { - if (result.containsKey(table)) { - throw new RuntimeException("Multiple tables found with the same name " + table); - } - result.put(table.toUpperCase(), exportTable(schema, table)); - } - } - - return result; - } - private Map> exportDatabase(final String schema) throws IOException { final List tables = listTables(schema); final Map> result = new HashMap<>(); @@ -982,25 +946,6 @@ public void purgeJobHistory(final LocalDateTime asOfDate) { } } - private List listAllTables(final String schema) throws IOException { - if (schema != null) { - return jobDatabase.query(context -> context.meta().getSchemas(schema).stream() - .flatMap(s -> context.meta(s).getTables().stream()) - .map(Named::getName) - .collect(Collectors.toList())); - } else { - return List.of(); - } - } - - private List listSchemas() throws IOException { - return jobDatabase.query(context -> context.meta().getSchemas().stream() - .map(Named::getName) - .filter(c -> !SYSTEM_SCHEMA.contains(c)) - .collect(Collectors.toList())); - - } - private Stream exportTable(final String schema, final String tableName) throws IOException { final Table tableSql = getTable(schema, tableName); try (final Stream records = jobDatabase.query(ctx -> ctx.select(DSL.asterisk()).from(tableSql).fetchStream())) { diff --git a/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/JobPersistence.java b/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/JobPersistence.java index 91f3905ca6ca..003e0387c6ea 100644 --- a/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/JobPersistence.java +++ b/airbyte-persistence/job-persistence/src/main/java/io/airbyte/persistence/job/JobPersistence.java @@ -280,8 +280,6 @@ List listJobStatusAndTimestampWithConnection(UUID con */ Map> exportDatabase() throws IOException; - Map> dump() throws IOException; - /** * Import all SQL tables from streams of JsonNode objects. * @@ -306,22 +304,6 @@ List listJobStatusAndTimestampWithConnection(UUID con */ void setSecretMigrationDone() throws IOException; - /** - * Check if the scheduler has been migrated to temporal. - * - * TODO (https://github.com/airbytehq/airbyte/issues/12823): remove this method after the next - * "major" version bump as it will no longer be needed. - */ - boolean isSchedulerMigrated() throws IOException; - - /** - * Set that the scheduler migration has been performed. - * - * TODO (https://github.com/airbytehq/airbyte/issues/12823): remove this method after the next - * "major" version bump as it will no longer be needed. - */ - void setSchedulerMigrationDone() throws IOException; - List getAttemptNormalizationStatusesForJob(final Long jobId) throws IOException; } diff --git a/airbyte-persistence/job-persistence/src/test/java/io/airbyte/persistence/job/DefaultJobPersistenceTest.java b/airbyte-persistence/job-persistence/src/test/java/io/airbyte/persistence/job/DefaultJobPersistenceTest.java index 633bffb9571e..74da5251d22f 100644 --- a/airbyte-persistence/job-persistence/src/test/java/io/airbyte/persistence/job/DefaultJobPersistenceTest.java +++ b/airbyte-persistence/job-persistence/src/test/java/io/airbyte/persistence/job/DefaultJobPersistenceTest.java @@ -566,15 +566,6 @@ void testSecretMigrationMetadata() throws IOException { assertTrue(isMigrated); } - @Test - void testSchedulerMigrationMetadata() throws IOException { - boolean isMigrated = jobPersistence.isSchedulerMigrated(); - assertFalse(isMigrated); - jobPersistence.setSchedulerMigrationDone(); - isMigrated = jobPersistence.isSchedulerMigrated(); - assertTrue(isMigrated); - } - @Test void testAirbyteProtocolVersionMaxMetadata() throws IOException { assertTrue(jobPersistence.getAirbyteProtocolVersionMax().isEmpty()); diff --git a/airbyte-server/src/main/java/io/airbyte/server/ServerApp.java b/airbyte-server/src/main/java/io/airbyte/server/ServerApp.java index 6d2dd8633382..c18b5eb84f64 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/ServerApp.java +++ b/airbyte-server/src/main/java/io/airbyte/server/ServerApp.java @@ -4,7 +4,6 @@ package io.airbyte.server; -import com.google.common.annotations.VisibleForTesting; import io.airbyte.analytics.Deployment; import io.airbyte.analytics.TrackingClient; import io.airbyte.analytics.TrackingClientSingleton; @@ -18,10 +17,7 @@ import io.airbyte.commons.version.AirbyteVersion; import io.airbyte.config.Configs; import io.airbyte.config.EnvConfigs; -import io.airbyte.config.StandardSync; -import io.airbyte.config.StandardSync.Status; import io.airbyte.config.helpers.LogClientSingleton; -import io.airbyte.config.persistence.ConfigNotFoundException; import io.airbyte.config.persistence.ConfigRepository; import io.airbyte.config.persistence.SecretsRepositoryReader; import io.airbyte.config.persistence.SecretsRepositoryWriter; @@ -70,16 +66,12 @@ import io.airbyte.server.scheduler.EventRunner; import io.airbyte.server.scheduler.TemporalEventRunner; import io.airbyte.validation.json.JsonSchemaValidator; -import io.airbyte.validation.json.JsonValidationException; import io.airbyte.workers.normalization.NormalizationRunnerFactory; import io.temporal.serviceclient.WorkflowServiceStubs; -import java.io.IOException; import java.net.http.HttpClient; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; import javax.sql.DataSource; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -256,14 +248,6 @@ public static ServerRunnable getServer(final ServerFactory apiFactory, final HttpClient httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build(); final EventRunner eventRunner = new TemporalEventRunner(temporalClient); - // It is important that the migration to the temporal scheduler is performed before the server - // accepts any requests. - // This is why this migration is performed here instead of in the bootloader - so that the server - // blocks on this. - // TODO (https://github.com/airbytehq/airbyte/issues/12823): remove this method after the next - // "major" version bump as it will no longer be needed. - migrateExistingConnectionsToTemporalScheduler(configRepository, jobPersistence, eventRunner); - final WorkspaceHelper workspaceHelper = new WorkspaceHelper(configRepository, jobPersistence); final JsonSchemaValidator schemaValidator = new JsonSchemaValidator(); @@ -370,28 +354,6 @@ public static ServerRunnable getServer(final ServerFactory apiFactory, workspacesHandler); } - @VisibleForTesting - static void migrateExistingConnectionsToTemporalScheduler(final ConfigRepository configRepository, - final JobPersistence jobPersistence, - final EventRunner eventRunner) - throws JsonValidationException, ConfigNotFoundException, IOException { - // Skip the migration if it was already performed, to save on resources/startup time - if (jobPersistence.isSchedulerMigrated()) { - LOGGER.info("Migration to temporal scheduler has already been performed"); - return; - } - - LOGGER.info("Start migration to the new scheduler..."); - final Set connectionIds = - configRepository.listStandardSyncs().stream() - .filter(standardSync -> standardSync.getStatus() == Status.ACTIVE || standardSync.getStatus() == Status.INACTIVE) - .map(StandardSync::getConnectionId) - .collect(Collectors.toSet()); - eventRunner.migrateSyncIfNeeded(connectionIds); - jobPersistence.setSchedulerMigrationDone(); - LOGGER.info("Done migrating to the new scheduler..."); - } - public static void main(final String[] args) { try { final Configs configs = new EnvConfigs(); diff --git a/airbyte-server/src/test/java/io/airbyte/server/ServerAppTest.java b/airbyte-server/src/test/java/io/airbyte/server/ServerAppTest.java deleted file mode 100644 index 11e31422b47a..000000000000 --- a/airbyte-server/src/test/java/io/airbyte/server/ServerAppTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.server; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import io.airbyte.config.StandardSync; -import io.airbyte.config.StandardSync.Status; -import io.airbyte.config.persistence.ConfigRepository; -import io.airbyte.persistence.job.JobPersistence; -import io.airbyte.server.scheduler.EventRunner; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -class ServerAppTest { - - @Mock - private ConfigRepository mConfigRepository; - - @Mock - private JobPersistence mJobPersistence; - - @Mock - private EventRunner mEventRunner; - - @Test - void testMigrationAlreadyPerformed() throws Exception { - when(mJobPersistence.isSchedulerMigrated()).thenReturn(true); - - ServerApp.migrateExistingConnectionsToTemporalScheduler(mConfigRepository, mJobPersistence, mEventRunner); - - verifyNoMoreInteractions(mJobPersistence); - verifyNoMoreInteractions(mConfigRepository); - verifyNoMoreInteractions(mEventRunner); - } - - @Test - void testPerformMigration() throws Exception { - when(mJobPersistence.isSchedulerMigrated()).thenReturn(false); - - final StandardSync activeConnection = new StandardSync().withStatus(Status.ACTIVE).withConnectionId(UUID.randomUUID()); - final StandardSync inactiveConnection = new StandardSync().withStatus(Status.INACTIVE).withConnectionId(UUID.randomUUID()); - final StandardSync deprecatedConnection = new StandardSync().withStatus(Status.DEPRECATED).withConnectionId(UUID.randomUUID()); - when(mConfigRepository.listStandardSyncs()).thenReturn(List.of(activeConnection, inactiveConnection, deprecatedConnection)); - - ServerApp.migrateExistingConnectionsToTemporalScheduler(mConfigRepository, mJobPersistence, mEventRunner); - - verify(mEventRunner).migrateSyncIfNeeded(Set.of(activeConnection.getConnectionId(), inactiveConnection.getConnectionId())); - verify(mJobPersistence).setSchedulerMigrationDone(); - verifyNoMoreInteractions(mJobPersistence); - verifyNoMoreInteractions(mConfigRepository); - verifyNoMoreInteractions(mEventRunner); - } - -} From 3468516a2b9f0ebb9ffbfcdf95a7c2fd8a8cd5fb Mon Sep 17 00:00:00 2001 From: Subodh Kant Chaturvedi Date: Sat, 5 Nov 2022 00:24:26 +0530 Subject: [PATCH 57/73] cleanup: delete debezium 1-4-2 module (#18733) * mssql-source:upgrade debezium version to 1.9.6 * delete debezium 1-4-2 * more improvements --- .../bases/debezium-v1-4-2/build.gradle | 25 - .../debezium/AirbyteDebeziumHandler.java | 131 ---- .../debezium/CdcMetadataInjector.java | 36 - .../debezium/CdcSavedInfoFetcher.java | 20 - .../debezium/CdcStateHandler.java | 19 - .../debezium/CdcTargetPosition.java | 20 - .../AirbyteFileOffsetBackingStore.java | 144 ---- .../AirbyteSchemaHistoryStorage.java | 149 ----- .../internals/DebeziumConverterUtils.java | 69 -- .../internals/DebeziumEventUtils.java | 67 -- .../internals/DebeziumRecordIterator.java | 155 ----- .../internals/DebeziumRecordPublisher.java | 191 ------ .../FilteredFileDatabaseHistory.java | 149 ----- .../debezium/internals/MSSQLConverter.java | 185 ------ .../debezium/internals/MySQLConverter.java | 75 --- .../debezium/internals/PostgresConverter.java | 134 ---- .../debezium/internals/SnapshotMetadata.java | 11 - .../debezium/AirbyteDebeziumHandlerTest.java | 56 -- .../AirbyteFileOffsetBackingStoreTest.java | 50 -- .../debezium/DebeziumEventUtilsTest.java | 88 --- .../debezium/DebeziumRecordPublisherTest.java | 43 -- .../internals/DebeziumConverterUtilsTest.java | 102 --- .../test/resources/delete_change_event.json | 25 - .../src/test/resources/delete_message.json | 8 - .../test/resources/insert_change_event.json | 25 - .../src/test/resources/insert_message.json | 8 - .../test/resources/test_debezium_offset.dat | Bin 308 -> 0 bytes .../test/resources/update_change_event.json | 25 - .../src/test/resources/update_message.json | 8 - .../integrations/debezium/CdcSourceTest.java | 629 ------------------ settings.gradle | 1 - 31 files changed, 2648 deletions(-) delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/build.gradle delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/AirbyteDebeziumHandler.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcMetadataInjector.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcSavedInfoFetcher.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcStateHandler.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcTargetPosition.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/AirbyteFileOffsetBackingStore.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/AirbyteSchemaHistoryStorage.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumConverterUtils.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumEventUtils.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumRecordIterator.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumRecordPublisher.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/FilteredFileDatabaseHistory.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/MSSQLConverter.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/MySQLConverter.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/PostgresConverter.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/SnapshotMetadata.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/AirbyteDebeziumHandlerTest.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/AirbyteFileOffsetBackingStoreTest.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/DebeziumEventUtilsTest.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/DebeziumRecordPublisherTest.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/internals/DebeziumConverterUtilsTest.java delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/delete_change_event.json delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/delete_message.json delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/insert_change_event.json delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/insert_message.json delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/test_debezium_offset.dat delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/update_change_event.json delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/update_message.json delete mode 100644 airbyte-integrations/bases/debezium-v1-4-2/src/testFixtures/java/io/airbyte/integrations/debezium/CdcSourceTest.java diff --git a/airbyte-integrations/bases/debezium-v1-4-2/build.gradle b/airbyte-integrations/bases/debezium-v1-4-2/build.gradle deleted file mode 100644 index 6b0c22a5c1f6..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/build.gradle +++ /dev/null @@ -1,25 +0,0 @@ -plugins { - id "java-test-fixtures" -} - -project.configurations { - testFixturesImplementation.extendsFrom implementation -} -dependencies { - implementation project(':airbyte-protocol:protocol-models') - implementation project(':airbyte-db:db-lib') - - implementation 'io.debezium:debezium-api:1.4.2.Final' - implementation ('io.debezium:debezium-embedded:1.4.2.Final') { exclude group: 'org.slf4j', module: 'slf4j-log4j12' } - implementation 'io.debezium:debezium-connector-mysql:1.4.2.Final' - implementation 'io.debezium:debezium-connector-postgres:1.4.2.Final' - implementation 'io.debezium:debezium-connector-sqlserver:1.4.2.Final' - - testFixturesImplementation project(':airbyte-db:db-lib') - testFixturesImplementation project(':airbyte-integrations:bases:base-java') - - testFixturesImplementation 'org.junit.jupiter:junit-jupiter-engine:5.4.2' - testFixturesImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' - testFixturesImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.2' - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/AirbyteDebeziumHandler.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/AirbyteDebeziumHandler.java deleted file mode 100644 index afb6a5555fa2..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/AirbyteDebeziumHandler.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium; - -import com.fasterxml.jackson.databind.JsonNode; -import io.airbyte.commons.util.AutoCloseableIterator; -import io.airbyte.commons.util.AutoCloseableIterators; -import io.airbyte.commons.util.CompositeIterator; -import io.airbyte.commons.util.MoreIterators; -import io.airbyte.db.jdbc.JdbcUtils; -import io.airbyte.integrations.debezium.internals.AirbyteFileOffsetBackingStore; -import io.airbyte.integrations.debezium.internals.AirbyteSchemaHistoryStorage; -import io.airbyte.integrations.debezium.internals.DebeziumEventUtils; -import io.airbyte.integrations.debezium.internals.DebeziumRecordIterator; -import io.airbyte.integrations.debezium.internals.DebeziumRecordPublisher; -import io.airbyte.integrations.debezium.internals.FilteredFileDatabaseHistory; -import io.airbyte.protocol.models.AirbyteMessage; -import io.airbyte.protocol.models.ConfiguredAirbyteCatalog; -import io.airbyte.protocol.models.ConfiguredAirbyteStream; -import io.airbyte.protocol.models.SyncMode; -import io.debezium.engine.ChangeEvent; -import java.time.Instant; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Properties; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.function.Supplier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class acts as the bridge between Airbyte DB connectors and debezium. If a DB connector wants - * to use debezium for CDC, it should use this class - */ -public class AirbyteDebeziumHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(AirbyteDebeziumHandler.class); - /** - * We use 10000 as capacity cause the default queue size and batch size of debezium is : - * {@link io.debezium.config.CommonConnectorConfig#DEFAULT_MAX_BATCH_SIZE}is 2048 - * {@link io.debezium.config.CommonConnectorConfig#DEFAULT_MAX_QUEUE_SIZE} is 8192 - */ - private static final int QUEUE_CAPACITY = 10000; - - private final Properties connectorProperties; - private final JsonNode config; - private final CdcTargetPosition targetPosition; - private final ConfiguredAirbyteCatalog catalog; - private final boolean trackSchemaHistory; - - private final LinkedBlockingQueue> queue; - - public AirbyteDebeziumHandler(final JsonNode config, - final CdcTargetPosition targetPosition, - final Properties connectorProperties, - final ConfiguredAirbyteCatalog catalog, - final boolean trackSchemaHistory) { - this.config = config; - this.targetPosition = targetPosition; - this.connectorProperties = connectorProperties; - this.catalog = catalog; - this.trackSchemaHistory = trackSchemaHistory; - this.queue = new LinkedBlockingQueue<>(QUEUE_CAPACITY); - } - - public List> getIncrementalIterators(final CdcSavedInfoFetcher cdcSavedInfoFetcher, - final CdcStateHandler cdcStateHandler, - final CdcMetadataInjector cdcMetadataInjector, - final Instant emittedAt) { - LOGGER.info("using CDC: {}", true); - final AirbyteFileOffsetBackingStore offsetManager = AirbyteFileOffsetBackingStore.initializeState(cdcSavedInfoFetcher.getSavedOffset()); - final Optional schemaHistoryManager = schemaHistoryManager(cdcSavedInfoFetcher); - final DebeziumRecordPublisher publisher = new DebeziumRecordPublisher(connectorProperties, config, catalog, offsetManager, - schemaHistoryManager); - publisher.start(queue); - - // handle state machine around pub/sub logic. - final AutoCloseableIterator> eventIterator = new DebeziumRecordIterator( - queue, - targetPosition, - publisher::hasClosed, - publisher::close); - - // convert to airbyte message. - final AutoCloseableIterator messageIterator = AutoCloseableIterators - .transform( - eventIterator, - (event) -> DebeziumEventUtils.toAirbyteMessage(event, cdcMetadataInjector, emittedAt)); - - // our goal is to get the state at the time this supplier is called (i.e. after all message records - // have been produced) - final Supplier stateMessageSupplier = () -> { - final Map offset = offsetManager.read(); - final String dbHistory = trackSchemaHistory ? schemaHistoryManager - .orElseThrow(() -> new RuntimeException("Schema History Tracking is true but manager is not initialised")).read() : null; - - return cdcStateHandler.saveState(offset, dbHistory); - }; - - // wrap the supplier in an iterator so that we can concat it to the message iterator. - final Iterator stateMessageIterator = MoreIterators.singletonIteratorFromSupplier(stateMessageSupplier); - - // this structure guarantees that the debezium engine will be closed, before we attempt to emit the - // state file. we want this so that we have a guarantee that the debezium offset file (which we use - // to produce the state file) is up-to-date. - final CompositeIterator messageIteratorWithStateDecorator = - AutoCloseableIterators.concatWithEagerClose(messageIterator, AutoCloseableIterators.fromIterator(stateMessageIterator)); - - return Collections.singletonList(messageIteratorWithStateDecorator); - } - - private Optional schemaHistoryManager(final CdcSavedInfoFetcher cdcSavedInfoFetcher) { - if (trackSchemaHistory) { - FilteredFileDatabaseHistory.setDatabaseName(config.get(JdbcUtils.DATABASE_KEY).asText()); - return Optional.of(AirbyteSchemaHistoryStorage.initializeDBHistory(cdcSavedInfoFetcher.getSavedSchemaHistory())); - } - - return Optional.empty(); - } - - public static boolean shouldUseCDC(final ConfiguredAirbyteCatalog catalog) { - return catalog.getStreams().stream().map(ConfiguredAirbyteStream::getSyncMode) - .anyMatch(syncMode -> syncMode == SyncMode.INCREMENTAL); - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcMetadataInjector.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcMetadataInjector.java deleted file mode 100644 index f5612fe04508..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcMetadataInjector.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -/** - * This interface is used to add metadata to the records fetched from the database. For instance, in - * Postgres we add the lsn to the records. In MySql we add the file name and position to the - * records. - */ -public interface CdcMetadataInjector { - - /** - * A debezium record contains multiple pieces. Ref : - * https://debezium.io/documentation/reference/1.4/connectors/mysql.html#mysql-create-events - * - * @param event is the actual record which contains data and would be written to the destination - * @param source contains the metadata about the record and we need to extract that metadata and add - * it to the event before writing it to destination - */ - void addMetaData(ObjectNode event, JsonNode source); - - /** - * As part of Airbyte record we need to add the namespace (schema name) - * - * @param source part of debezium record and contains the metadata about the record. We need to - * extract namespace out of this metadata and return Ref : - * https://debezium.io/documentation/reference/1.4/connectors/mysql.html#mysql-create-events - */ - String namespace(JsonNode source); - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcSavedInfoFetcher.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcSavedInfoFetcher.java deleted file mode 100644 index a0efa36f05a8..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcSavedInfoFetcher.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium; - -import com.fasterxml.jackson.databind.JsonNode; -import java.util.Optional; - -/** - * This interface is used to fetch the saved info required for debezium to run incrementally. Each - * connector saves offset and schema history in different manner - */ -public interface CdcSavedInfoFetcher { - - JsonNode getSavedOffset(); - - Optional getSavedSchemaHistory(); - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcStateHandler.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcStateHandler.java deleted file mode 100644 index 7b76186fc9c1..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcStateHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium; - -import io.airbyte.protocol.models.AirbyteMessage; -import java.util.Map; - -/** - * This interface is used to allow connectors to save the offset and schema history in the manner - * which suits them - */ -@FunctionalInterface -public interface CdcStateHandler { - - AirbyteMessage saveState(Map offset, String dbHistory); - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcTargetPosition.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcTargetPosition.java deleted file mode 100644 index 47209ada28f7..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/CdcTargetPosition.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium; - -import com.fasterxml.jackson.databind.JsonNode; - -/** - * This interface is used to define the target position at the beginning of the sync so that once we - * reach the desired target, we can shutdown the sync. This is needed because it might happen that - * while we are syncing the data, new changes are being made in the source database and as a result - * we might end up syncing forever. In order to tackle that, we need to define a point to end at the - * beginning of the sync - */ -public interface CdcTargetPosition { - - boolean reachedTargetPosition(JsonNode valueAsJson); - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/AirbyteFileOffsetBackingStore.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/AirbyteFileOffsetBackingStore.java deleted file mode 100644 index 89dbd3d1f472..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/AirbyteFileOffsetBackingStore.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.base.Preconditions; -import io.airbyte.commons.json.Jsons; -import java.io.EOFException; -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; -import org.apache.commons.io.FileUtils; -import org.apache.kafka.connect.errors.ConnectException; -import org.apache.kafka.connect.util.SafeObjectInputStream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class handles reading and writing a debezium offset file. In many cases it is duplicating - * logic in debezium because that logic is not exposed in the public API. We mostly treat the - * contents of this state file like a black box. We know it is a Map<ByteBuffer, Bytebuffer>. - * We deserialize it to a Map<String, String> so that the state file can be human readable. If - * we ever discover that any of the contents of these offset files is not string serializable we - * will likely have to drop the human readability support and just base64 encode it. - */ -public class AirbyteFileOffsetBackingStore { - - private static final Logger LOGGER = LoggerFactory.getLogger(AirbyteFileOffsetBackingStore.class); - - private final Path offsetFilePath; - - public AirbyteFileOffsetBackingStore(final Path offsetFilePath) { - this.offsetFilePath = offsetFilePath; - } - - public Path getOffsetFilePath() { - return offsetFilePath; - } - - public Map read() { - final Map raw = load(); - - return raw.entrySet().stream().collect(Collectors.toMap( - e -> byteBufferToString(e.getKey()), - e -> byteBufferToString(e.getValue()))); - } - - @SuppressWarnings("unchecked") - public void persist(final JsonNode cdcState) { - final Map mapAsString = - cdcState != null ? Jsons.object(cdcState, Map.class) : Collections.emptyMap(); - final Map mappedAsStrings = mapAsString.entrySet().stream().collect(Collectors.toMap( - e -> stringToByteBuffer(e.getKey()), - e -> stringToByteBuffer(e.getValue()))); - - FileUtils.deleteQuietly(offsetFilePath.toFile()); - save(mappedAsStrings); - } - - private static String byteBufferToString(final ByteBuffer byteBuffer) { - Preconditions.checkNotNull(byteBuffer); - return new String(byteBuffer.array(), StandardCharsets.UTF_8); - } - - private static ByteBuffer stringToByteBuffer(final String s) { - Preconditions.checkNotNull(s); - return ByteBuffer.wrap(s.getBytes(StandardCharsets.UTF_8)); - } - - /** - * See FileOffsetBackingStore#load - logic is mostly borrowed from here. duplicated because this - * method is not public. - */ - @SuppressWarnings("unchecked") - private Map load() { - try (final SafeObjectInputStream is = new SafeObjectInputStream(Files.newInputStream(offsetFilePath))) { - // todo (cgardens) - we currently suppress a security warning for this line. use of readObject from - // untrusted sources is considered unsafe. Since the source is controlled by us in this case it - // should be safe. That said, changing this implementation to not use readObject would remove some - // headache. - final Object obj = is.readObject(); - if (!(obj instanceof HashMap)) - throw new ConnectException("Expected HashMap but found " + obj.getClass()); - final Map raw = (Map) obj; - final Map data = new HashMap<>(); - for (final Map.Entry mapEntry : raw.entrySet()) { - final ByteBuffer key = (mapEntry.getKey() != null) ? ByteBuffer.wrap(mapEntry.getKey()) : null; - final ByteBuffer value = (mapEntry.getValue() != null) ? ByteBuffer.wrap(mapEntry.getValue()) : null; - data.put(key, value); - } - - return data; - } catch (final NoSuchFileException | EOFException e) { - // NoSuchFileException: Ignore, may be new. - // EOFException: Ignore, this means the file was missing or corrupt - return Collections.emptyMap(); - } catch (final IOException | ClassNotFoundException e) { - throw new ConnectException(e); - } - } - - /** - * See FileOffsetBackingStore#save - logic is mostly borrowed from here. duplicated because this - * method is not public. - */ - private void save(final Map data) { - try (final ObjectOutputStream os = new ObjectOutputStream(Files.newOutputStream(offsetFilePath))) { - final Map raw = new HashMap<>(); - for (final Map.Entry mapEntry : data.entrySet()) { - final byte[] key = (mapEntry.getKey() != null) ? mapEntry.getKey().array() : null; - final byte[] value = (mapEntry.getValue() != null) ? mapEntry.getValue().array() : null; - raw.put(key, value); - } - os.writeObject(raw); - } catch (final IOException e) { - throw new ConnectException(e); - } - } - - public static AirbyteFileOffsetBackingStore initializeState(final JsonNode cdcState) { - final Path cdcWorkingDir; - try { - cdcWorkingDir = Files.createTempDirectory(Path.of("/tmp"), "cdc-state-offset"); - } catch (final IOException e) { - throw new RuntimeException(e); - } - final Path cdcOffsetFilePath = cdcWorkingDir.resolve("offset.dat"); - - final AirbyteFileOffsetBackingStore offsetManager = new AirbyteFileOffsetBackingStore(cdcOffsetFilePath); - offsetManager.persist(cdcState); - return offsetManager; - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/AirbyteSchemaHistoryStorage.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/AirbyteSchemaHistoryStorage.java deleted file mode 100644 index c36bd3cc48c1..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/AirbyteSchemaHistoryStorage.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import com.fasterxml.jackson.databind.JsonNode; -import io.airbyte.commons.json.Jsons; -import io.debezium.document.Document; -import io.debezium.document.DocumentReader; -import io.debezium.document.DocumentWriter; -import io.debezium.relational.history.HistoryRecord; -import java.io.BufferedWriter; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.Optional; -import java.util.function.Consumer; -import org.apache.commons.io.FileUtils; - -/** - * The purpose of this class is : to , 1. Read the contents of the file {@link #path} which contains - * the schema history at the end of the sync so that it can be saved in state for future syncs. - * Check {@link #read()} 2. Write the saved content back to the file {@link #path} at the beginning - * of the sync so that debezium can function smoothly. Check persist(Optional<JsonNode>). To - * understand more about file, please refer {@link FilteredFileDatabaseHistory} - */ -public class AirbyteSchemaHistoryStorage { - - private final Path path; - private static final Charset UTF8 = StandardCharsets.UTF_8; - private final DocumentReader reader = DocumentReader.defaultReader(); - private final DocumentWriter writer = DocumentWriter.defaultWriter(); - - public AirbyteSchemaHistoryStorage(final Path path) { - this.path = path; - } - - public Path getPath() { - return path; - } - - /** - * This implementation is kind of similar to - * {@link io.debezium.relational.history.FileDatabaseHistory#recoverRecords(Consumer)} - */ - public String read() { - final StringBuilder fileAsString = new StringBuilder(); - try { - for (final String line : Files.readAllLines(path, UTF8)) { - if (line != null && !line.isEmpty()) { - final Document record = reader.read(line); - final String recordAsString = writer.write(record); - fileAsString.append(recordAsString); - fileAsString.append(System.lineSeparator()); - } - } - return fileAsString.toString(); - } catch (final IOException e) { - throw new RuntimeException(e); - } - } - - /** - * This implementation is kind of similar to - * {@link io.debezium.relational.history.FileDatabaseHistory#start()} - */ - private void makeSureFileExists() { - try { - // Make sure the file exists ... - if (!Files.exists(path)) { - // Create parent directories if we have them ... - if (path.getParent() != null) { - Files.createDirectories(path.getParent()); - } - try { - Files.createFile(path); - } catch (final FileAlreadyExistsException e) { - // do nothing - } - } - } catch (final IOException e) { - throw new IllegalStateException( - "Unable to create history file at " + path + ": " + e.getMessage(), e); - } - } - - public void persist(final Optional schemaHistory) { - if (schemaHistory.isEmpty()) { - return; - } - final String fileAsString = Jsons.object(schemaHistory.get(), String.class); - - if (fileAsString == null || fileAsString.isEmpty()) { - return; - } - - FileUtils.deleteQuietly(path.toFile()); - makeSureFileExists(); - writeToFile(fileAsString); - } - - /** - * This implementation is kind of similar to - * {@link io.debezium.relational.history.FileDatabaseHistory#storeRecord(HistoryRecord)} - * - * @param fileAsString Represents the contents of the file saved in state from previous syncs - */ - private void writeToFile(final String fileAsString) { - try { - final String[] split = fileAsString.split(System.lineSeparator()); - for (final String element : split) { - final Document read = reader.read(element); - final String line = writer.write(read); - - try (final BufferedWriter historyWriter = Files - .newBufferedWriter(path, StandardOpenOption.APPEND)) { - try { - historyWriter.append(line); - historyWriter.newLine(); - } catch (final IOException e) { - throw new RuntimeException(e); - } - } - } - } catch (final IOException e) { - throw new RuntimeException(e); - } - } - - public static AirbyteSchemaHistoryStorage initializeDBHistory(final Optional schemaHistory) { - final Path dbHistoryWorkingDir; - try { - dbHistoryWorkingDir = Files.createTempDirectory(Path.of("/tmp"), "cdc-db-history"); - } catch (final IOException e) { - throw new RuntimeException(e); - } - final Path dbHistoryFilePath = dbHistoryWorkingDir.resolve("dbhistory.dat"); - - final AirbyteSchemaHistoryStorage schemaHistoryManager = new AirbyteSchemaHistoryStorage(dbHistoryFilePath); - schemaHistoryManager.persist(schemaHistory); - return schemaHistoryManager; - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumConverterUtils.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumConverterUtils.java deleted file mode 100644 index ab0a9e6cde16..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumConverterUtils.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import io.airbyte.db.DataTypeUtils; -import io.debezium.spi.converter.RelationalColumn; -import java.sql.Date; -import java.sql.Timestamp; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.format.DateTimeParseException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class DebeziumConverterUtils { - - private static final Logger LOGGER = LoggerFactory.getLogger(DebeziumConverterUtils.class); - - private DebeziumConverterUtils() { - throw new UnsupportedOperationException(); - } - - public static String convertDate(final Object input) { - /** - * While building this custom converter we were not sure what type debezium could return cause there - * is no mention of it in the documentation. Secondly if you take a look at - * {@link io.debezium.connector.mysql.converters.TinyIntOneToBooleanConverter#converterFor(io.debezium.spi.converter.RelationalColumn, io.debezium.spi.converter.CustomConverter.ConverterRegistration)} - * method, even it is handling multiple data types but its not clear under what circumstances which - * data type would be returned. I just went ahead and handled the data types that made sense. - * Secondly, we use LocalDateTime to handle this cause it represents DATETIME datatype in JAVA - */ - if (input instanceof LocalDateTime) { - return DataTypeUtils.toISO8601String((LocalDateTime) input); - } else if (input instanceof LocalDate) { - return DataTypeUtils.toISO8601String((LocalDate) input); - } else if (input instanceof Duration) { - return DataTypeUtils.toISO8601String((Duration) input); - } else if (input instanceof Timestamp) { - return DataTypeUtils.toISO8601StringWithMicroseconds((((Timestamp) input).toInstant())); - } else if (input instanceof Number) { - return DataTypeUtils.toISO8601String( - new Timestamp(((Number) input).longValue()).toLocalDateTime()); - } else if (input instanceof Date) { - return DataTypeUtils.toISO8601String((Date) input); - } else if (input instanceof String) { - try { - return LocalDateTime.parse((String) input).toString(); - } catch (final DateTimeParseException e) { - LOGGER.warn("Cannot convert value '{}' to LocalDateTime type", input); - return input.toString(); - } - } - LOGGER.warn("Uncovered date class type '{}'. Use default converter", input.getClass().getName()); - return input.toString(); - } - - public static Object convertDefaultValue(RelationalColumn field) { - if (field.isOptional()) { - return null; - } else if (field.hasDefaultValue()) { - return field.defaultValue(); - } - return null; - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumEventUtils.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumEventUtils.java deleted file mode 100644 index da31b6143210..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumEventUtils.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.airbyte.commons.json.Jsons; -import io.airbyte.integrations.debezium.CdcMetadataInjector; -import io.airbyte.protocol.models.AirbyteMessage; -import io.airbyte.protocol.models.AirbyteRecordMessage; -import io.debezium.engine.ChangeEvent; -import java.sql.Timestamp; -import java.time.Instant; - -public class DebeziumEventUtils { - - public static final String CDC_UPDATED_AT = "_ab_cdc_updated_at"; - public static final String CDC_DELETED_AT = "_ab_cdc_deleted_at"; - - public static AirbyteMessage toAirbyteMessage(final ChangeEvent event, - final CdcMetadataInjector cdcMetadataInjector, - final Instant emittedAt) { - final JsonNode debeziumRecord = Jsons.deserialize(event.value()); - final JsonNode before = debeziumRecord.get("before"); - final JsonNode after = debeziumRecord.get("after"); - final JsonNode source = debeziumRecord.get("source"); - - final JsonNode data = formatDebeziumData(before, after, source, cdcMetadataInjector); - final String schemaName = cdcMetadataInjector.namespace(source); - final String streamName = source.get("table").asText(); - - final AirbyteRecordMessage airbyteRecordMessage = new AirbyteRecordMessage() - .withStream(streamName) - .withNamespace(schemaName) - .withEmittedAt(emittedAt.toEpochMilli()) - .withData(data); - - return new AirbyteMessage() - .withType(AirbyteMessage.Type.RECORD) - .withRecord(airbyteRecordMessage); - } - - // warning mutates input args. - private static JsonNode formatDebeziumData(final JsonNode before, - final JsonNode after, - final JsonNode source, - final CdcMetadataInjector cdcMetadataInjector) { - final ObjectNode base = (ObjectNode) (after.isNull() ? before : after); - - final long transactionMillis = source.get("ts_ms").asLong(); - final String transactionTimestamp = new Timestamp(transactionMillis).toInstant().toString(); - - base.put(CDC_UPDATED_AT, transactionTimestamp); - cdcMetadataInjector.addMetaData(base, source); - - if (after.isNull()) { - base.put(CDC_DELETED_AT, transactionTimestamp); - } else { - base.put(CDC_DELETED_AT, (String) null); - } - - return base; - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumRecordIterator.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumRecordIterator.java deleted file mode 100644 index 76305dabf259..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumRecordIterator.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.collect.AbstractIterator; -import io.airbyte.commons.concurrency.VoidCallable; -import io.airbyte.commons.json.Jsons; -import io.airbyte.commons.lang.MoreBooleans; -import io.airbyte.commons.util.AutoCloseableIterator; -import io.airbyte.integrations.debezium.CdcTargetPosition; -import io.debezium.engine.ChangeEvent; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The record iterator is the consumer (in the producer / consumer relationship with debezium) - * responsible for 1. making sure every record produced by the record publisher is processed 2. - * signalling to the record publisher when it is time for it to stop producing records. It emits - * this signal either when the publisher had not produced a new record for a long time or when it - * has processed at least all of the records that were present in the database when the source was - * started. Because the publisher might publish more records between the consumer sending this - * signal and the publisher actually shutting down, the consumer must stay alive as long as the - * publisher is not closed. Even after the publisher is closed, the consumer will finish processing - * any produced records before closing. - */ -public class DebeziumRecordIterator extends AbstractIterator> - implements AutoCloseableIterator> { - - private static final Logger LOGGER = LoggerFactory.getLogger(DebeziumRecordIterator.class); - - private static final WaitTime FIRST_RECORD_WAIT_TIME_MINUTES = new WaitTime(5, TimeUnit.MINUTES); - private static final WaitTime SUBSEQUENT_RECORD_WAIT_TIME_SECONDS = new WaitTime(1, TimeUnit.MINUTES); - - private final LinkedBlockingQueue> queue; - private final CdcTargetPosition targetPosition; - private final Supplier publisherStatusSupplier; - private final VoidCallable requestClose; - private boolean receivedFirstRecord; - private boolean hasSnapshotFinished; - private boolean signalledClose; - - public DebeziumRecordIterator(final LinkedBlockingQueue> queue, - final CdcTargetPosition targetPosition, - final Supplier publisherStatusSupplier, - final VoidCallable requestClose) { - this.queue = queue; - this.targetPosition = targetPosition; - this.publisherStatusSupplier = publisherStatusSupplier; - this.requestClose = requestClose; - this.receivedFirstRecord = false; - this.hasSnapshotFinished = true; - this.signalledClose = false; - } - - @Override - protected ChangeEvent computeNext() { - // keep trying until the publisher is closed or until the queue is empty. the latter case is - // possible when the publisher has shutdown but the consumer has not yet processed all messages it - // emitted. - while (!MoreBooleans.isTruthy(publisherStatusSupplier.get()) || !queue.isEmpty()) { - final ChangeEvent next; - try { - final WaitTime waitTime = receivedFirstRecord ? SUBSEQUENT_RECORD_WAIT_TIME_SECONDS : FIRST_RECORD_WAIT_TIME_MINUTES; - next = queue.poll(waitTime.period, waitTime.timeUnit); - } catch (final InterruptedException e) { - throw new RuntimeException(e); - } - - // if within the timeout, the consumer could not get a record, it is time to tell the producer to - // shutdown. - if (next == null) { - LOGGER.info("Closing cause next is returned as null"); - requestClose(); - LOGGER.info("no record found. polling again."); - continue; - } - - final JsonNode eventAsJson = Jsons.deserialize(next.value()); - hasSnapshotFinished = hasSnapshotFinished(eventAsJson); - - // if the last record matches the target file position, it is time to tell the producer to shutdown. - if (!signalledClose && shouldSignalClose(eventAsJson)) { - requestClose(); - } - receivedFirstRecord = true; - return next; - } - return endOfData(); - } - - private boolean hasSnapshotFinished(final JsonNode eventAsJson) { - final SnapshotMetadata snapshot = SnapshotMetadata.valueOf(eventAsJson.get("source").get("snapshot").asText().toUpperCase()); - return SnapshotMetadata.TRUE != snapshot; - } - - /** - * Debezium was built as an ever running process which keeps on listening for new changes on DB and - * immediately processing them. Airbyte needs debezium to work as a start stop mechanism. In order - * to determine when to stop debezium engine we rely on few factors 1. TargetPosition logic. At the - * beginning of the sync we define a target position in the logs of the DB. This can be an LSN or - * anything specific to the DB which can help us identify that we have reached a specific position - * in the log based replication When we start processing records from debezium, we extract the the - * log position from the metadata of the record and compare it with our target that we defined at - * the beginning of the sync. If we have reached the target position, we shutdown the debezium - * engine 2. The TargetPosition logic might not always work and in order to tackle that we have - * another logic where if we do not receive records from debezium for a given duration, we ask - * debezium engine to shutdown 3. We also take the Snapshot into consideration, when a connector is - * running for the first time, we let it complete the snapshot and only after the completion of - * snapshot we should shutdown the engine. If we are closing the engine before completion of - * snapshot, we throw an exception - */ - @Override - public void close() throws Exception { - requestClose(); - } - - private boolean shouldSignalClose(final JsonNode eventAsJson) { - return targetPosition.reachedTargetPosition(eventAsJson); - } - - private void requestClose() { - try { - requestClose.call(); - signalledClose = true; - } catch (final Exception e) { - throw new RuntimeException(e); - } - throwExceptionIfSnapshotNotFinished(); - } - - private void throwExceptionIfSnapshotNotFinished() { - if (!hasSnapshotFinished) { - throw new RuntimeException("Closing down debezium engine but snapshot has not finished"); - } - } - - private static class WaitTime { - - public final int period; - public final TimeUnit timeUnit; - - public WaitTime(final int period, final TimeUnit timeUnit) { - this.period = period; - this.timeUnit = timeUnit; - } - - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumRecordPublisher.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumRecordPublisher.java deleted file mode 100644 index 91a244b8f4b8..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/DebeziumRecordPublisher.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.annotations.VisibleForTesting; -import io.airbyte.db.jdbc.JdbcUtils; -import io.airbyte.protocol.models.ConfiguredAirbyteCatalog; -import io.airbyte.protocol.models.ConfiguredAirbyteStream; -import io.airbyte.protocol.models.SyncMode; -import io.debezium.engine.ChangeEvent; -import io.debezium.engine.DebeziumEngine; -import io.debezium.engine.format.Json; -import io.debezium.engine.spi.OffsetCommitPolicy; -import java.util.Optional; -import java.util.Properties; -import java.util.Queue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; -import org.codehaus.plexus.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The purpose of this class is to intiliaze and spawn the debezium engine with the right properties - * to fetch records - */ -public class DebeziumRecordPublisher implements AutoCloseable { - - private static final Logger LOGGER = LoggerFactory.getLogger(DebeziumRecordPublisher.class); - private final ExecutorService executor; - private DebeziumEngine> engine; - - private final JsonNode config; - private final AirbyteFileOffsetBackingStore offsetManager; - private final Optional schemaHistoryManager; - - private final AtomicBoolean hasClosed; - private final AtomicBoolean isClosing; - private final AtomicReference thrownError; - private final CountDownLatch engineLatch; - private final Properties properties; - private final ConfiguredAirbyteCatalog catalog; - - public DebeziumRecordPublisher(final Properties properties, - final JsonNode config, - final ConfiguredAirbyteCatalog catalog, - final AirbyteFileOffsetBackingStore offsetManager, - final Optional schemaHistoryManager) { - this.properties = properties; - this.config = config; - this.catalog = catalog; - this.offsetManager = offsetManager; - this.schemaHistoryManager = schemaHistoryManager; - this.hasClosed = new AtomicBoolean(false); - this.isClosing = new AtomicBoolean(false); - this.thrownError = new AtomicReference<>(); - this.executor = Executors.newSingleThreadExecutor(); - this.engineLatch = new CountDownLatch(1); - } - - public void start(final Queue> queue) { - engine = DebeziumEngine.create(Json.class) - .using(getDebeziumProperties()) - .using(new OffsetCommitPolicy.AlwaysCommitOffsetPolicy()) - .notifying(e -> { - // debezium outputs a tombstone event that has a value of null. this is an artifact of how it - // interacts with kafka. we want to ignore it. - // more on the tombstone: - // https://debezium.io/documentation/reference/configuration/event-flattening.html - if (e.value() != null) { - boolean inserted = false; - while (!inserted) { - inserted = queue.offer(e); - } - } - }) - .using((success, message, error) -> { - LOGGER.info("Debezium engine shutdown."); - thrownError.set(error); - engineLatch.countDown(); - }) - .build(); - - // Run the engine asynchronously ... - executor.execute(engine); - } - - public boolean hasClosed() { - return hasClosed.get(); - } - - public void close() throws Exception { - if (isClosing.compareAndSet(false, true)) { - // consumers should assume records can be produced until engine has closed. - if (engine != null) { - engine.close(); - } - - // wait for closure before shutting down executor service - engineLatch.await(5, TimeUnit.MINUTES); - - // shut down and await for thread to actually go down - executor.shutdown(); - executor.awaitTermination(5, TimeUnit.MINUTES); - - // after the engine is completely off, we can mark this as closed - hasClosed.set(true); - - if (thrownError.get() != null) { - throw new RuntimeException(thrownError.get()); - } - } - } - - protected Properties getDebeziumProperties() { - final Properties props = new Properties(); - props.putAll(properties); - - // debezium engine configuration - props.setProperty("name", "engine"); - props.setProperty("offset.storage", "org.apache.kafka.connect.storage.FileOffsetBackingStore"); - props.setProperty("offset.storage.file.filename", offsetManager.getOffsetFilePath().toString()); - props.setProperty("offset.flush.interval.ms", "1000"); // todo: make this longer - // default values from debezium CommonConnectorConfig - props.setProperty("max.batch.size", "2048"); - props.setProperty("max.queue.size", "8192"); - - if (schemaHistoryManager.isPresent()) { - // https://debezium.io/documentation/reference/1.4/operations/debezium-server.html#debezium-source-database-history-file-filename - // https://debezium.io/documentation/reference/development/engine.html#_in_the_code - // As mentioned in the documents above, debezium connector for MySQL needs to track the schema - // changes. If we don't do this, we can't fetch records for the table - // We have implemented our own implementation to filter out the schema information from other - // databases that the connector is not syncing - props.setProperty("database.history", "io.airbyte.integrations.debezium.internals.FilteredFileDatabaseHistory"); - props.setProperty("database.history.file.filename", schemaHistoryManager.get().getPath().toString()); - } - - // https://debezium.io/documentation/reference/configuration/avro.html - props.setProperty("key.converter.schemas.enable", "false"); - props.setProperty("value.converter.schemas.enable", "false"); - - // debezium names - props.setProperty("name", config.get(JdbcUtils.DATABASE_KEY).asText()); - props.setProperty("database.server.name", config.get(JdbcUtils.DATABASE_KEY).asText()); - - // db connection configuration - props.setProperty("database.hostname", config.get(JdbcUtils.HOST_KEY).asText()); - props.setProperty("database.port", config.get(JdbcUtils.PORT_KEY).asText()); - props.setProperty("database.user", config.get(JdbcUtils.USERNAME_KEY).asText()); - props.setProperty("database.dbname", config.get(JdbcUtils.DATABASE_KEY).asText()); - - if (config.has(JdbcUtils.PASSWORD_KEY)) { - props.setProperty("database.password", config.get(JdbcUtils.PASSWORD_KEY).asText()); - } - - // By default "decimal.handing.mode=precise" which's caused returning this value as a binary. - // The "double" type may cause a loss of precision, so set Debezium's config to store it as a String - // explicitly in its Kafka messages for more details see: - // https://debezium.io/documentation/reference/1.4/connectors/postgresql.html#postgresql-decimal-types - // https://debezium.io/documentation/faq/#how_to_retrieve_decimal_field_from_binary_representation - props.setProperty("decimal.handling.mode", "string"); - - // table selection - final String tableWhitelist = getTableWhitelist(catalog); - props.setProperty("table.include.list", tableWhitelist); - props.setProperty("database.include.list", config.get(JdbcUtils.DATABASE_KEY).asText()); - - return props; - } - - @VisibleForTesting - public static String getTableWhitelist(final ConfiguredAirbyteCatalog catalog) { - return catalog.getStreams().stream() - .filter(s -> s.getSyncMode() == SyncMode.INCREMENTAL) - .map(ConfiguredAirbyteStream::getStream) - .map(stream -> stream.getNamespace() + "." + stream.getName()) - // debezium needs commas escaped to split properly - .map(x -> StringUtils.escape(x, new char[] {','}, "\\,")) - .collect(Collectors.joining(",")); - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/FilteredFileDatabaseHistory.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/FilteredFileDatabaseHistory.java deleted file mode 100644 index f04690767537..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/FilteredFileDatabaseHistory.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import io.debezium.config.Configuration; -import io.debezium.relational.history.AbstractDatabaseHistory; -import io.debezium.relational.history.DatabaseHistoryException; -import io.debezium.relational.history.DatabaseHistoryListener; -import io.debezium.relational.history.FileDatabaseHistory; -import io.debezium.relational.history.HistoryRecord; -import io.debezium.relational.history.HistoryRecord.Fields; -import io.debezium.relational.history.HistoryRecordComparator; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.function.Consumer; - -/** - * MySQL Debezium connector monitors the database schema evolution over the time and stores the data - * in a database history file. Without this file we can't fetch the records from binlog. We need to - * save the contents of the file. Debezium by default uses - * {@link io.debezium.relational.history.FileDatabaseHistory} class to write the schema information - * in the file. The problem is that the Debezium tracks the schema evolution of all the tables in - * all the databases, because of that the file content can grow. In order to make sure that debezium - * tracks only the schema of the tables that are present in the database that Airbyte is syncing, we - * created this class. In the method {@link #storeRecord(HistoryRecord)}, we introduced a check to - * make sure only those records are being saved whose database name matches the database Airbyte is - * syncing. We tell debezium to use this class by passing it as property in debezium engine. Look - * for "database.history" property in {@link DebeziumRecordPublisher#getDebeziumProperties()} - * Ideally {@link FilteredFileDatabaseHistory} should have extended - * {@link io.debezium.relational.history.FileDatabaseHistory} and overridden the - * {@link #storeRecord(HistoryRecord)} method but {@link FilteredFileDatabaseHistory} is a final - * class and can not be inherited - */ -public class FilteredFileDatabaseHistory extends AbstractDatabaseHistory { - - private final FileDatabaseHistory fileDatabaseHistory; - private static String databaseName; - - public FilteredFileDatabaseHistory() { - this.fileDatabaseHistory = new FileDatabaseHistory(); - } - - /** - * Ideally the databaseName should have been initialized in the constructor of the class. But since - * we supply the class name to debezium and it uses reflection to construct the object of the class, - * we can't pass in the databaseName as a parameter to the constructor. That's why we had to take - * the static approach. - * - * @param databaseName Name of the database that the connector is syncing - */ - public static void setDatabaseName(final String databaseName) { - if (FilteredFileDatabaseHistory.databaseName == null) { - FilteredFileDatabaseHistory.databaseName = databaseName; - } else if (!FilteredFileDatabaseHistory.databaseName.equals(databaseName)) { - throw new RuntimeException( - "Database name has already been set : " + FilteredFileDatabaseHistory.databaseName - + " can't set to : " + databaseName); - } - } - - @Override - public void configure(final Configuration config, - final HistoryRecordComparator comparator, - final DatabaseHistoryListener listener, - final boolean useCatalogBeforeSchema) { - fileDatabaseHistory.configure(config, comparator, listener, useCatalogBeforeSchema); - } - - @Override - public void start() { - fileDatabaseHistory.start(); - } - - @Override - public void storeRecord(final HistoryRecord record) throws DatabaseHistoryException { - if (record == null) { - return; - } - try { - final String dbNameInRecord = record.document().getString(Fields.DATABASE_NAME); - if (databaseName != null && dbNameInRecord != null && !dbNameInRecord.equals(databaseName)) { - return; - } - - /** - * We are using reflection because the method - * {@link io.debezium.relational.history.FileDatabaseHistory#storeRecord(HistoryRecord)} is - * protected and can not be accessed from here - */ - final Method storeRecordMethod = fileDatabaseHistory.getClass() - .getDeclaredMethod("storeRecord", record.getClass()); - storeRecordMethod.setAccessible(true); - storeRecordMethod.invoke(fileDatabaseHistory, record); - } catch (final NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - @Override - public void stop() { - fileDatabaseHistory.stop(); - // this is just for tests - resetDbName(); - } - - public static void resetDbName() { - databaseName = null; - } - - @Override - protected void recoverRecords(final Consumer records) { - try { - /** - * We are using reflection because the method - * {@link io.debezium.relational.history.FileDatabaseHistory#recoverRecords(Consumer)} is protected - * and can not be accessed from here - */ - final Method recoverRecords = fileDatabaseHistory.getClass() - .getDeclaredMethod("recoverRecords", Consumer.class); - recoverRecords.setAccessible(true); - recoverRecords.invoke(fileDatabaseHistory, records); - } catch (final NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - @Override - public boolean storageExists() { - return fileDatabaseHistory.storageExists(); - } - - @Override - public void initializeStorage() { - fileDatabaseHistory.initializeStorage(); - } - - @Override - public boolean exists() { - return fileDatabaseHistory.exists(); - } - - @Override - public String toString() { - return fileDatabaseHistory.toString(); - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/MSSQLConverter.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/MSSQLConverter.java deleted file mode 100644 index 50a5c77057ff..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/MSSQLConverter.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import com.microsoft.sqlserver.jdbc.Geography; -import com.microsoft.sqlserver.jdbc.Geometry; -import com.microsoft.sqlserver.jdbc.SQLServerException; -import io.airbyte.db.DataTypeUtils; -import io.debezium.spi.converter.CustomConverter; -import io.debezium.spi.converter.RelationalColumn; -import java.math.BigDecimal; -import java.nio.charset.Charset; -import java.sql.Timestamp; -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Objects; -import java.util.Properties; -import java.util.Set; -import microsoft.sql.DateTimeOffset; -import org.apache.kafka.connect.data.SchemaBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MSSQLConverter implements CustomConverter { - - private final Logger LOGGER = LoggerFactory.getLogger(MSSQLConverter.class); - - private final Set DATE_TYPES = Set.of("DATE", "DATETIME", "DATETIME2", "SMALLDATETIME"); - private final Set BINARY = Set.of("VARBINARY", "BINARY"); - private static final String DATETIMEOFFSET = "DATETIMEOFFSET"; - private static final String TIME_TYPE = "TIME"; - private static final String SMALLMONEY_TYPE = "SMALLMONEY"; - private static final String GEOMETRY = "GEOMETRY"; - private static final String GEOGRAPHY = "GEOGRAPHY"; - private static final String DEBEZIUM_DATETIMEOFFSET_FORMAT = "yyyy-MM-dd HH:mm:ss XXX"; - - @Override - public void configure(Properties props) {} - - @Override - public void converterFor(final RelationalColumn field, - final ConverterRegistration registration) { - if (DATE_TYPES.contains(field.typeName().toUpperCase())) { - registerDate(field, registration); - } else if (SMALLMONEY_TYPE.equalsIgnoreCase(field.typeName())) { - registerMoney(field, registration); - } else if (BINARY.contains(field.typeName().toUpperCase())) { - registerBinary(field, registration); - } else if (GEOMETRY.equalsIgnoreCase(field.typeName())) { - registerGeometry(field, registration); - } else if (GEOGRAPHY.equalsIgnoreCase(field.typeName())) { - registerGeography(field, registration); - } else if (TIME_TYPE.equalsIgnoreCase(field.typeName())) { - registerTime(field, registration); - } else if (DATETIMEOFFSET.equalsIgnoreCase(field.typeName())) { - registerDateTimeOffSet(field, registration); - } - } - - private void registerGeometry(final RelationalColumn field, - final ConverterRegistration registration) { - registration.register(SchemaBuilder.string(), input -> { - if (Objects.isNull(input)) { - return DebeziumConverterUtils.convertDefaultValue(field); - } - - if (input instanceof byte[]) { - try { - return Geometry.deserialize((byte[]) input).toString(); - } catch (SQLServerException e) { - LOGGER.error(e.getMessage()); - } - } - - LOGGER.warn("Uncovered Geometry class type '{}'. Use default converter", - input.getClass().getName()); - return input.toString(); - }); - } - - private void registerGeography(final RelationalColumn field, - final ConverterRegistration registration) { - registration.register(SchemaBuilder.string(), input -> { - if (Objects.isNull(input)) { - return DebeziumConverterUtils.convertDefaultValue(field); - } - - if (input instanceof byte[]) { - try { - return Geography.deserialize((byte[]) input).toString(); - } catch (SQLServerException e) { - LOGGER.error(e.getMessage()); - } - } - - LOGGER.warn("Uncovered Geography class type '{}'. Use default converter", - input.getClass().getName()); - return input.toString(); - }); - } - - private void registerDate(final RelationalColumn field, - final ConverterRegistration registration) { - registration.register(SchemaBuilder.string(), input -> { - if (Objects.isNull(input)) { - return DebeziumConverterUtils.convertDefaultValue(field); - } - - return DebeziumConverterUtils.convertDate(input); - }); - } - - private void registerDateTimeOffSet(final RelationalColumn field, - final ConverterRegistration registration) { - registration.register(SchemaBuilder.string(), input -> { - if (Objects.isNull(input)) { - return DebeziumConverterUtils.convertDefaultValue(field); - } - - if (input instanceof DateTimeOffset) { - return DataTypeUtils.toISO8601String( - OffsetDateTime.parse(input.toString(), - DateTimeFormatter.ofPattern(DEBEZIUM_DATETIMEOFFSET_FORMAT))); - } - - LOGGER.warn("Uncovered DateTimeOffSet class type '{}'. Use default converter", - input.getClass().getName()); - return input.toString(); - }); - } - - private void registerTime(final RelationalColumn field, - final ConverterRegistration registration) { - registration.register(SchemaBuilder.string(), input -> { - if (Objects.isNull(input)) { - return DebeziumConverterUtils.convertDefaultValue(field); - } - - if (input instanceof Timestamp) { - return DataTypeUtils.toISOTimeString(((Timestamp) input).toLocalDateTime()); - } - - LOGGER.warn("Uncovered time class type '{}'. Use default converter", - input.getClass().getName()); - return input.toString(); - }); - } - - private void registerMoney(final RelationalColumn field, - final ConverterRegistration registration) { - registration.register(SchemaBuilder.float64(), input -> { - if (Objects.isNull(input)) { - return DebeziumConverterUtils.convertDefaultValue(field); - } - - if (input instanceof BigDecimal) { - return ((BigDecimal) input).doubleValue(); - } - - LOGGER.warn("Uncovered money class type '{}'. Use default converter", - input.getClass().getName()); - return input.toString(); - }); - } - - private void registerBinary(final RelationalColumn field, - final ConverterRegistration registration) { - registration.register(SchemaBuilder.string(), input -> { - if (Objects.isNull(input)) { - return DebeziumConverterUtils.convertDefaultValue(field); - } - - if (input instanceof byte[]) { - return new String((byte[]) input, Charset.defaultCharset()); - } - - LOGGER.warn("Uncovered binary class type '{}'. Use default converter", - input.getClass().getName()); - return input.toString(); - }); - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/MySQLConverter.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/MySQLConverter.java deleted file mode 100644 index ac099bc15cdc..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/MySQLConverter.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import io.airbyte.db.DataTypeUtils; -import io.debezium.spi.converter.CustomConverter; -import io.debezium.spi.converter.RelationalColumn; -import java.nio.charset.StandardCharsets; -import java.time.LocalDate; -import java.util.Arrays; -import java.util.Properties; -import org.apache.kafka.connect.data.SchemaBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This is a custom debezium converter used in MySQL to handle the DATETIME data type. We need a - * custom converter cause by default debezium returns the DATETIME values as numbers. We need to - * convert it to proper format. Ref : - * https://debezium.io/documentation/reference/1.4/development/converters.html This is built from - * reference with {@link io.debezium.connector.mysql.converters.TinyIntOneToBooleanConverter} If you - * rename this class then remember to rename the datetime.type property value in - * io.airbyte-integrations.source.mysql.MySqlCdcProperties#getDebeziumProperties() (If you don't - * rename, a test would still fail but it might be tricky to figure out where to change the property - * name) - */ -public class MySQLConverter implements CustomConverter { - - private static final Logger LOGGER = LoggerFactory.getLogger(MySQLConverter.class); - - private final String[] DATE_TYPES = {"DATE", "DATETIME", "TIME"}; - private final String[] TEXT_TYPES = {"CHAR", "VARCHAR", "TEXT", "LONGTEXT", "TINYTEXT", "MEDIUMTEXT"}; - - @Override - public void configure(final Properties props) {} - - @Override - public void converterFor(final RelationalColumn field, final ConverterRegistration registration) { - if (Arrays.stream(DATE_TYPES).anyMatch(s -> s.equalsIgnoreCase(field.typeName()))) { - registerDate(field, registration); - } else if (Arrays.stream(TEXT_TYPES).anyMatch(s -> s.equalsIgnoreCase(field.typeName()))) { - registerText(field, registration); - } - } - - private void registerText(final RelationalColumn field, final ConverterRegistration registration) { - registration.register(SchemaBuilder.string(), x -> { - if (x == null) { - return DebeziumConverterUtils.convertDefaultValue(field); - } - if (x instanceof byte[]) { - return new String((byte[]) x, StandardCharsets.UTF_8); - } else { - return x.toString(); - } - }); - } - - /** - * The debezium driver replaces Zero-value by Null even when this column is mandatory. According to - * the doc, it should be done by driver, but it fails. - */ - private Object convertDefaultValueNullDate(final RelationalColumn field) { - final var defaultValue = DebeziumConverterUtils.convertDefaultValue(field); - return (defaultValue == null && !field.isOptional() ? DataTypeUtils.toISO8601String(LocalDate.EPOCH) : defaultValue); - } - - private void registerDate(final RelationalColumn field, final ConverterRegistration registration) { - registration.register(SchemaBuilder.string(), - x -> x == null ? convertDefaultValueNullDate(field) : DebeziumConverterUtils.convertDate(x)); - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/PostgresConverter.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/PostgresConverter.java deleted file mode 100644 index aee741b6aaca..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/PostgresConverter.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import io.debezium.spi.converter.CustomConverter; -import io.debezium.spi.converter.RelationalColumn; -import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Properties; -import org.apache.kafka.connect.data.SchemaBuilder; -import org.postgresql.util.PGInterval; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class PostgresConverter implements CustomConverter { - - private static final Logger LOGGER = LoggerFactory.getLogger(PostgresConverter.class); - - private final String[] DATE_TYPES = {"DATE", "DATETIME", "TIME", "TIMETZ", "INTERVAL", "TIMESTAMP"}; - private final String[] BIT_TYPES = {"BIT", "VARBIT"}; - private final String[] MONEY_ITEM_TYPE = {"MONEY"}; - private final String[] GEOMETRICS_TYPES = {"BOX", "CIRCLE", "LINE", "LSEG", "POINT", "POLYGON", "PATH"}; - private final String[] TEXT_TYPES = - {"VARCHAR", "VARBINARY", "BLOB", "TEXT", "LONGTEXT", "TINYTEXT", "MEDIUMTEXT", "INVENTORY_ITEM", "TSVECTOR", "TSQUERY"}; - - @Override - public void configure(final Properties props) {} - - @Override - public void converterFor(final RelationalColumn field, final ConverterRegistration registration) { - if (Arrays.stream(DATE_TYPES).anyMatch(s -> s.equalsIgnoreCase(field.typeName()))) { - registerDate(field, registration); - } else if (Arrays.stream(TEXT_TYPES).anyMatch(s -> s.equalsIgnoreCase(field.typeName())) - || Arrays.stream(GEOMETRICS_TYPES).anyMatch(s -> s.equalsIgnoreCase(field.typeName())) - || Arrays.stream(BIT_TYPES).anyMatch(s -> s.equalsIgnoreCase(field.typeName()))) { - registerText(field, registration); - } else if (Arrays.stream(MONEY_ITEM_TYPE).anyMatch(s -> s.equalsIgnoreCase(field.typeName()))) { - registerMoney(field, registration); - } - } - - private void registerText(final RelationalColumn field, final ConverterRegistration registration) { - registration.register(SchemaBuilder.string().optional(), x -> { - if (x == null) { - return DebeziumConverterUtils.convertDefaultValue(field); - } - - if (x instanceof byte[]) { - return new String((byte[]) x, StandardCharsets.UTF_8); - } else { - return x.toString(); - } - }); - } - - private void registerDate(final RelationalColumn field, final ConverterRegistration registration) { - registration.register(SchemaBuilder.string().optional(), x -> { - if (x == null) { - return DebeziumConverterUtils.convertDefaultValue(field); - } else if (x instanceof PGInterval) { - return convertInterval((PGInterval) x); - } else { - return DebeziumConverterUtils.convertDate(x); - } - }); - } - - private String convertInterval(final PGInterval pgInterval) { - final StringBuilder resultInterval = new StringBuilder(); - formatDateUnit(resultInterval, pgInterval.getYears(), " year "); - formatDateUnit(resultInterval, pgInterval.getMonths(), " mons "); - formatDateUnit(resultInterval, pgInterval.getDays(), " days "); - - formatTimeValues(resultInterval, pgInterval); - return resultInterval.toString(); - } - - private void registerMoney(final RelationalColumn field, final ConverterRegistration registration) { - registration.register(SchemaBuilder.string().optional(), x -> { - if (x == null) { - return DebeziumConverterUtils.convertDefaultValue(field); - } else if (x instanceof Double) { - final BigDecimal result = BigDecimal.valueOf((Double) x); - if (result.compareTo(new BigDecimal("999999999999999")) == 1 - || result.compareTo(new BigDecimal("-999999999999999")) == -1) { - return null; - } - return result.toString(); - } else { - return x.toString(); - } - }); - } - - private void formatDateUnit(final StringBuilder resultInterval, final int dateUnit, final String s) { - if (dateUnit != 0) { - resultInterval - .append(dateUnit) - .append(s); - } - } - - private void formatTimeValues(final StringBuilder resultInterval, final PGInterval pgInterval) { - if (isNegativeTime(pgInterval)) { - resultInterval.append("-"); - } - // TODO check if value more or less than Integer.MIN_VALUE Integer.MAX_VALUE, - final int hours = Math.abs(pgInterval.getHours()); - final int minutes = Math.abs(pgInterval.getMinutes()); - final int seconds = Math.abs(pgInterval.getWholeSeconds()); - resultInterval.append(addFirstDigit(hours)); - resultInterval.append(hours); - resultInterval.append(":"); - resultInterval.append(addFirstDigit(minutes)); - resultInterval.append(minutes); - resultInterval.append(":"); - resultInterval.append(addFirstDigit(seconds)); - resultInterval.append(seconds); - } - - private String addFirstDigit(final int hours) { - return hours <= 9 ? "0" : ""; - } - - private boolean isNegativeTime(final PGInterval pgInterval) { - return pgInterval.getHours() < 0 - || pgInterval.getMinutes() < 0 - || pgInterval.getWholeSeconds() < 0; - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/SnapshotMetadata.java b/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/SnapshotMetadata.java deleted file mode 100644 index b24cdf71fbe6..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/main/java/io/airbyte/integrations/debezium/internals/SnapshotMetadata.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -public enum SnapshotMetadata { - TRUE, - FALSE, - LAST -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/AirbyteDebeziumHandlerTest.java b/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/AirbyteDebeziumHandlerTest.java deleted file mode 100644 index 45d50612f792..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/AirbyteDebeziumHandlerTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium; - -import com.google.common.collect.Lists; -import io.airbyte.protocol.models.AirbyteCatalog; -import io.airbyte.protocol.models.CatalogHelpers; -import io.airbyte.protocol.models.ConfiguredAirbyteCatalog; -import io.airbyte.protocol.models.Field; -import io.airbyte.protocol.models.JsonSchemaType; -import io.airbyte.protocol.models.SyncMode; -import java.util.List; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class AirbyteDebeziumHandlerTest { - - @Test - public void shouldUseCdcTestShouldReturnTrue() { - final AirbyteCatalog catalog = new AirbyteCatalog().withStreams(List.of( - CatalogHelpers.createAirbyteStream( - "MODELS_STREAM_NAME", - "MODELS_SCHEMA", - Field.of("COL_ID", JsonSchemaType.NUMBER), - Field.of("COL_MAKE_ID", JsonSchemaType.NUMBER), - Field.of("COL_MODEL", JsonSchemaType.STRING)) - .withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH, SyncMode.INCREMENTAL)) - .withSourceDefinedPrimaryKey(List.of(List.of("COL_ID"))))); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers - .toDefaultConfiguredCatalog(catalog); - // set all streams to incremental. - configuredCatalog.getStreams().forEach(s -> s.setSyncMode(SyncMode.INCREMENTAL)); - - Assertions.assertTrue(AirbyteDebeziumHandler.shouldUseCDC(configuredCatalog)); - } - - @Test - public void shouldUseCdcTestShouldReturnFalse() { - final AirbyteCatalog catalog = new AirbyteCatalog().withStreams(List.of( - CatalogHelpers.createAirbyteStream( - "MODELS_STREAM_NAME", - "MODELS_SCHEMA", - Field.of("COL_ID", JsonSchemaType.NUMBER), - Field.of("COL_MAKE_ID", JsonSchemaType.NUMBER), - Field.of("COL_MODEL", JsonSchemaType.STRING)) - .withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH, SyncMode.INCREMENTAL)) - .withSourceDefinedPrimaryKey(List.of(List.of("COL_ID"))))); - final ConfiguredAirbyteCatalog configuredCatalog = CatalogHelpers - .toDefaultConfiguredCatalog(catalog); - - Assertions.assertFalse(AirbyteDebeziumHandler.shouldUseCDC(configuredCatalog)); - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/AirbyteFileOffsetBackingStoreTest.java b/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/AirbyteFileOffsetBackingStoreTest.java deleted file mode 100644 index 9f1e6d0ea052..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/AirbyteFileOffsetBackingStoreTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.JsonNode; -import io.airbyte.commons.io.IOs; -import io.airbyte.commons.json.Jsons; -import io.airbyte.commons.resources.MoreResources; -import io.airbyte.integrations.debezium.internals.AirbyteFileOffsetBackingStore; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Map; -import org.junit.jupiter.api.Test; - -class AirbyteFileOffsetBackingStoreTest { - - @SuppressWarnings("UnstableApiUsage") - @Test - void test() throws IOException { - final Path testRoot = Files.createTempDirectory(Path.of("/tmp"), "offset-store-test"); - - final byte[] bytes = MoreResources.readBytes("test_debezium_offset.dat"); - final Path templateFilePath = testRoot.resolve("template_offset.dat"); - IOs.writeFile(templateFilePath, bytes); - - final Path writeFilePath = testRoot.resolve("offset.dat"); - - final AirbyteFileOffsetBackingStore offsetStore = new AirbyteFileOffsetBackingStore(templateFilePath); - final Map offset = offsetStore.read(); - - final JsonNode asJson = Jsons.jsonNode(offset); - - final AirbyteFileOffsetBackingStore offsetStore2 = new AirbyteFileOffsetBackingStore(writeFilePath); - offsetStore2.persist(asJson); - - final Map stateFromOffsetStoreRoundTrip = offsetStore2.read(); - - // verify that, after a round trip through the offset store, we get back the same data. - assertEquals(offset, stateFromOffsetStoreRoundTrip); - // verify that the file written by the offset store is identical to the template file. - assertTrue(com.google.common.io.Files.equal(templateFilePath.toFile(), writeFilePath.toFile())); - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/DebeziumEventUtilsTest.java b/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/DebeziumEventUtilsTest.java deleted file mode 100644 index 4de1b36524dd..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/DebeziumEventUtilsTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.airbyte.commons.json.Jsons; -import io.airbyte.commons.resources.MoreResources; -import io.airbyte.integrations.debezium.internals.DebeziumEventUtils; -import io.airbyte.protocol.models.AirbyteMessage; -import io.airbyte.protocol.models.AirbyteRecordMessage; -import io.debezium.engine.ChangeEvent; -import java.io.IOException; -import java.time.Instant; -import org.junit.jupiter.api.Test; - -class DebeziumEventUtilsTest { - - @Test - public void testConvertChangeEvent() throws IOException { - final String stream = "names"; - final Instant emittedAt = Instant.now(); - final CdcMetadataInjector cdcMetadataInjector = new DummyMetadataInjector(); - final ChangeEvent insertChangeEvent = mockChangeEvent("insert_change_event.json"); - final ChangeEvent updateChangeEvent = mockChangeEvent("update_change_event.json"); - final ChangeEvent deleteChangeEvent = mockChangeEvent("delete_change_event.json"); - - final AirbyteMessage actualInsert = DebeziumEventUtils.toAirbyteMessage(insertChangeEvent, cdcMetadataInjector, emittedAt); - final AirbyteMessage actualUpdate = DebeziumEventUtils.toAirbyteMessage(updateChangeEvent, cdcMetadataInjector, emittedAt); - final AirbyteMessage actualDelete = DebeziumEventUtils.toAirbyteMessage(deleteChangeEvent, cdcMetadataInjector, emittedAt); - - final AirbyteMessage expectedInsert = createAirbyteMessage(stream, emittedAt, "insert_message.json"); - final AirbyteMessage expectedUpdate = createAirbyteMessage(stream, emittedAt, "update_message.json"); - final AirbyteMessage expectedDelete = createAirbyteMessage(stream, emittedAt, "delete_message.json"); - - deepCompare(expectedInsert, actualInsert); - deepCompare(expectedUpdate, actualUpdate); - deepCompare(expectedDelete, actualDelete); - } - - private static ChangeEvent mockChangeEvent(final String resourceName) throws IOException { - final ChangeEvent mocked = mock(ChangeEvent.class); - final String resource = MoreResources.readResource(resourceName); - when(mocked.value()).thenReturn(resource); - - return mocked; - } - - private static AirbyteMessage createAirbyteMessage(final String stream, final Instant emittedAt, final String resourceName) throws IOException { - final String data = MoreResources.readResource(resourceName); - - final AirbyteRecordMessage recordMessage = new AirbyteRecordMessage() - .withStream(stream) - .withNamespace("public") - .withData(Jsons.deserialize(data)) - .withEmittedAt(emittedAt.toEpochMilli()); - - return new AirbyteMessage() - .withType(AirbyteMessage.Type.RECORD) - .withRecord(recordMessage); - } - - private static void deepCompare(final Object expected, final Object actual) { - assertEquals(Jsons.deserialize(Jsons.serialize(expected)), Jsons.deserialize(Jsons.serialize(actual))); - } - - public static class DummyMetadataInjector implements CdcMetadataInjector { - - @Override - public void addMetaData(final ObjectNode event, final JsonNode source) { - final long lsn = source.get("lsn").asLong(); - event.put("_ab_cdc_lsn", lsn); - } - - @Override - public String namespace(final JsonNode source) { - return source.get("schema").asText(); - } - - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/DebeziumRecordPublisherTest.java b/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/DebeziumRecordPublisherTest.java deleted file mode 100644 index 31dacbc563ae..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/DebeziumRecordPublisherTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium; - -import static org.junit.jupiter.api.Assertions.*; - -import com.google.common.collect.ImmutableList; -import io.airbyte.integrations.debezium.internals.DebeziumRecordPublisher; -import io.airbyte.protocol.models.CatalogHelpers; -import io.airbyte.protocol.models.ConfiguredAirbyteCatalog; -import io.airbyte.protocol.models.SyncMode; -import org.junit.jupiter.api.Test; - -class DebeziumRecordPublisherTest { - - @Test - public void testWhitelistCreation() { - final ConfiguredAirbyteCatalog catalog = new ConfiguredAirbyteCatalog().withStreams(ImmutableList.of( - CatalogHelpers.createConfiguredAirbyteStream("id_and_name", "public").withSyncMode(SyncMode.INCREMENTAL), - CatalogHelpers.createConfiguredAirbyteStream("id_,something", "public").withSyncMode(SyncMode.INCREMENTAL), - CatalogHelpers.createConfiguredAirbyteStream("n\"aMéS", "public").withSyncMode(SyncMode.INCREMENTAL))); - - final String expectedWhitelist = "public.id_and_name,public.id_\\,something,public.n\"aMéS"; - final String actualWhitelist = DebeziumRecordPublisher.getTableWhitelist(catalog); - - assertEquals(expectedWhitelist, actualWhitelist); - } - - @Test - public void testWhitelistFiltersFullRefresh() { - final ConfiguredAirbyteCatalog catalog = new ConfiguredAirbyteCatalog().withStreams(ImmutableList.of( - CatalogHelpers.createConfiguredAirbyteStream("id_and_name", "public").withSyncMode(SyncMode.INCREMENTAL), - CatalogHelpers.createConfiguredAirbyteStream("id_and_name2", "public").withSyncMode(SyncMode.FULL_REFRESH))); - - final String expectedWhitelist = "public.id_and_name"; - final String actualWhitelist = DebeziumRecordPublisher.getTableWhitelist(catalog); - - assertEquals(expectedWhitelist, actualWhitelist); - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/internals/DebeziumConverterUtilsTest.java b/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/internals/DebeziumConverterUtilsTest.java deleted file mode 100644 index facb86d0bc54..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/test/java/io/airbyte/integrations/debezium/internals/DebeziumConverterUtilsTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2022 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.debezium.internals; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import io.debezium.spi.converter.RelationalColumn; -import java.sql.Timestamp; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -class DebeziumConverterUtilsTest { - - @Test - public void convertDefaultValueTest() { - - final RelationalColumn relationalColumn = mock(RelationalColumn.class); - - when(relationalColumn.isOptional()).thenReturn(true); - Object actualColumnDefaultValue = DebeziumConverterUtils.convertDefaultValue(relationalColumn); - Assertions.assertNull(actualColumnDefaultValue, "Default value for optional relational column should be null"); - - when(relationalColumn.isOptional()).thenReturn(false); - when(relationalColumn.hasDefaultValue()).thenReturn(false); - actualColumnDefaultValue = DebeziumConverterUtils.convertDefaultValue(relationalColumn); - Assertions.assertNull(actualColumnDefaultValue); - - when(relationalColumn.isOptional()).thenReturn(false); - when(relationalColumn.hasDefaultValue()).thenReturn(true); - final String expectedColumnDefaultValue = "default value"; - when(relationalColumn.defaultValue()).thenReturn(expectedColumnDefaultValue); - actualColumnDefaultValue = DebeziumConverterUtils.convertDefaultValue(relationalColumn); - Assertions.assertEquals(actualColumnDefaultValue, expectedColumnDefaultValue); - } - - @Test - public void convertLocalDate() { - final LocalDate localDate = LocalDate.of(2021, 1, 1); - - final String actual = DebeziumConverterUtils.convertDate(localDate); - Assertions.assertEquals("2021-01-01T00:00:00Z", actual); - } - - @Test - public void convertTLocalTime() { - final LocalTime localTime = LocalTime.of(8, 1, 1); - final String actual = DebeziumConverterUtils.convertDate(localTime); - Assertions.assertEquals("08:01:01", actual); - } - - @Test - public void convertLocalDateTime() { - final LocalDateTime localDateTime = LocalDateTime.of(2021, 1, 1, 8, 1, 1); - - final String actual = DebeziumConverterUtils.convertDate(localDateTime); - Assertions.assertEquals("2021-01-01T08:01:01Z", actual); - } - - @Test - @Disabled - public void convertDuration() { - final Duration duration = Duration.ofHours(100_000); - - final String actual = DebeziumConverterUtils.convertDate(duration); - Assertions.assertEquals("1981-05-29T20:00:00Z", actual); - } - - @Test - public void convertTimestamp() { - final LocalDateTime localDateTime = LocalDateTime.of(2021, 1, 1, 8, 1, 1); - final Timestamp timestamp = Timestamp.valueOf(localDateTime); - - final String actual = DebeziumConverterUtils.convertDate(timestamp); - Assertions.assertEquals("2021-01-01T08:01:01.000000Z", actual); - } - - @Test - @Disabled - public void convertNumber() { - final Number number = 100_000; - - final String actual = DebeziumConverterUtils.convertDate(number); - Assertions.assertEquals("1970-01-01T03:01:40Z", actual); - } - - @Test - public void convertStringDateFormat() { - final String stringValue = "2021-01-01T00:00:00Z"; - - final String actual = DebeziumConverterUtils.convertDate(stringValue); - Assertions.assertEquals("2021-01-01T00:00:00Z", actual); - } - -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/delete_change_event.json b/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/delete_change_event.json deleted file mode 100644 index 07b575bf7e2c..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/delete_change_event.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "before": { - "first_name": "san", - "last_name": "goku", - "power": null - }, - "after": null, - "source": { - "version": "1.4.2.Final", - "connector": "postgresql", - "name": "orders", - "ts_ms": 1616775646886, - "snapshot": false, - "db": "db_lwfoyffqvx", - "schema": "public", - "table": "names", - "txId": 498, - "lsn": 23012360, - "xmin": null - }, - "op": "d", - "ts_ms": 1616775646931, - "transaction": null, - "destination": "orders.public.names" -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/delete_message.json b/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/delete_message.json deleted file mode 100644 index 676ee5b74ffe..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/delete_message.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "first_name": "san", - "last_name": "goku", - "power": null, - "_ab_cdc_updated_at": "2021-03-26T16:20:46.886Z", - "_ab_cdc_lsn": 23012360, - "_ab_cdc_deleted_at": "2021-03-26T16:20:46.886Z" -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/insert_change_event.json b/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/insert_change_event.json deleted file mode 100644 index 4b2c2fb6e2cf..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/insert_change_event.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "before": null, - "after": { - "first_name": "san", - "last_name": "goku", - "power": "Infinity" - }, - "source": { - "version": "1.4.2.Final", - "connector": "postgresql", - "name": "orders", - "ts_ms": 1616775642623, - "snapshot": true, - "db": "db_lwfoyffqvx", - "schema": "public", - "table": "names", - "txId": 495, - "lsn": 23011544, - "xmin": null - }, - "op": "r", - "ts_ms": 1616775642624, - "transaction": null, - "destination": "orders.public.names" -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/insert_message.json b/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/insert_message.json deleted file mode 100644 index d971d32c1766..000000000000 --- a/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/insert_message.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "first_name": "san", - "last_name": "goku", - "power": "Infinity", - "_ab_cdc_updated_at": "2021-03-26T16:20:42.623Z", - "_ab_cdc_lsn": 23011544, - "_ab_cdc_deleted_at": null -} diff --git a/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/test_debezium_offset.dat b/airbyte-integrations/bases/debezium-v1-4-2/src/test/resources/test_debezium_offset.dat deleted file mode 100644 index c7e7054916ed110d8431cd9c4bab25521e0df5a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 308 zcmZ9Gu};G<5I~QhLO~3$zf3r~bE{I|EH2ldCto}Ln|BAGkrrRAP^UR93C6r)%tc9- zofG2)3YAf%2U2KrZ^eUDa8A2Z=-Mr+YN{~)ox=9EtsdbStQhJQ8b!Fae-(l!g|+?2 zndXU9BE|SL@VrqJhAwt26=hkNfAnu_nz@xk{=`M2lS)&o@JIgHI0z STREAM_NAMES = Sets - .newHashSet(MODELS_STREAM_NAME); - protected static final String COL_ID = "id"; - protected static final String COL_MAKE_ID = "make_id"; - protected static final String COL_MODEL = "model"; - - protected static final AirbyteCatalog CATALOG = new AirbyteCatalog().withStreams(List.of( - CatalogHelpers.createAirbyteStream( - MODELS_STREAM_NAME, - MODELS_SCHEMA, - Field.of(COL_ID, JsonSchemaType.INTEGER), - Field.of(COL_MAKE_ID, JsonSchemaType.INTEGER), - Field.of(COL_MODEL, JsonSchemaType.STRING)) - .withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH, SyncMode.INCREMENTAL)) - .withSourceDefinedPrimaryKey(List.of(List.of(COL_ID))))); - protected static final ConfiguredAirbyteCatalog CONFIGURED_CATALOG = CatalogHelpers - .toDefaultConfiguredCatalog(CATALOG); - - // set all streams to incremental. - static { - CONFIGURED_CATALOG.getStreams().forEach(s -> s.setSyncMode(SyncMode.INCREMENTAL)); - } - - private static final List MODEL_RECORDS = ImmutableList.of( - Jsons.jsonNode(ImmutableMap.of(COL_ID, 11, COL_MAKE_ID, 1, COL_MODEL, "Fiesta")), - Jsons.jsonNode(ImmutableMap.of(COL_ID, 12, COL_MAKE_ID, 1, COL_MODEL, "Focus")), - Jsons.jsonNode(ImmutableMap.of(COL_ID, 13, COL_MAKE_ID, 1, COL_MODEL, "Ranger")), - Jsons.jsonNode(ImmutableMap.of(COL_ID, 14, COL_MAKE_ID, 2, COL_MODEL, "GLA")), - Jsons.jsonNode(ImmutableMap.of(COL_ID, 15, COL_MAKE_ID, 2, COL_MODEL, "A 220")), - Jsons.jsonNode(ImmutableMap.of(COL_ID, 16, COL_MAKE_ID, 2, COL_MODEL, "E 350"))); - - protected void setup() throws SQLException { - createAndPopulateTables(); - } - - private void createAndPopulateTables() { - createAndPopulateActualTable(); - createAndPopulateRandomTable(); - } - - protected void executeQuery(final String query) { - try { - getDatabase().query( - ctx -> ctx - .execute(query)); - } catch (final SQLException e) { - throw new RuntimeException(e); - } - } - - public String columnClause(final Map columnsWithDataType, final Optional primaryKey) { - final StringBuilder columnClause = new StringBuilder(); - int i = 0; - for (final Map.Entry column : columnsWithDataType.entrySet()) { - columnClause.append(column.getKey()); - columnClause.append(" "); - columnClause.append(column.getValue()); - if (i < (columnsWithDataType.size() - 1)) { - columnClause.append(","); - columnClause.append(" "); - } - i++; - } - primaryKey.ifPresent(s -> columnClause.append(", PRIMARY KEY (").append(s).append(")")); - - return columnClause.toString(); - } - - public void createTable(final String schemaName, final String tableName, final String columnClause) { - executeQuery(createTableQuery(schemaName, tableName, columnClause)); - } - - public String createTableQuery(final String schemaName, final String tableName, final String columnClause) { - return String.format("CREATE TABLE %s.%s(%s);", schemaName, tableName, columnClause); - } - - public void createSchema(final String schemaName) { - executeQuery(createSchemaQuery(schemaName)); - } - - public String createSchemaQuery(final String schemaName) { - return "CREATE DATABASE " + schemaName + ";"; - } - - private void createAndPopulateActualTable() { - createSchema(MODELS_SCHEMA); - createTable(MODELS_SCHEMA, MODELS_STREAM_NAME, - columnClause(ImmutableMap.of(COL_ID, "INTEGER", COL_MAKE_ID, "INTEGER", COL_MODEL, "VARCHAR(200)"), Optional.of(COL_ID))); - for (final JsonNode recordJson : MODEL_RECORDS) { - writeModelRecord(recordJson); - } - } - - /** - * This database and table is not part of Airbyte sync. It is being created just to make sure the - * databases not being synced by Airbyte are not causing issues with our debezium logic - */ - private void createAndPopulateRandomTable() { - createSchema(MODELS_SCHEMA + "_random"); - createTable(MODELS_SCHEMA + "_random", MODELS_STREAM_NAME + "_random", - columnClause(ImmutableMap.of(COL_ID + "_random", "INTEGER", COL_MAKE_ID + "_random", "INTEGER", COL_MODEL + "_random", "VARCHAR(200)"), - Optional.of(COL_ID + "_random"))); - final List MODEL_RECORDS_RANDOM = ImmutableList.of( - Jsons - .jsonNode(ImmutableMap - .of(COL_ID + "_random", 11000, COL_MAKE_ID + "_random", 1, COL_MODEL + "_random", - "Fiesta-random")), - Jsons.jsonNode(ImmutableMap - .of(COL_ID + "_random", 12000, COL_MAKE_ID + "_random", 1, COL_MODEL + "_random", - "Focus-random")), - Jsons - .jsonNode(ImmutableMap - .of(COL_ID + "_random", 13000, COL_MAKE_ID + "_random", 1, COL_MODEL + "_random", - "Ranger-random")), - Jsons.jsonNode(ImmutableMap - .of(COL_ID + "_random", 14000, COL_MAKE_ID + "_random", 2, COL_MODEL + "_random", - "GLA-random")), - Jsons.jsonNode(ImmutableMap - .of(COL_ID + "_random", 15000, COL_MAKE_ID + "_random", 2, COL_MODEL + "_random", - "A 220-random")), - Jsons - .jsonNode(ImmutableMap - .of(COL_ID + "_random", 16000, COL_MAKE_ID + "_random", 2, COL_MODEL + "_random", - "E 350-random"))); - for (final JsonNode recordJson : MODEL_RECORDS_RANDOM) { - writeRecords(recordJson, MODELS_SCHEMA + "_random", MODELS_STREAM_NAME + "_random", - COL_ID + "_random", COL_MAKE_ID + "_random", COL_MODEL + "_random"); - } - } - - private void writeModelRecord(final JsonNode recordJson) { - writeRecords(recordJson, MODELS_SCHEMA, MODELS_STREAM_NAME, COL_ID, COL_MAKE_ID, COL_MODEL); - } - - private void writeRecords( - final JsonNode recordJson, - final String dbName, - final String streamName, - final String idCol, - final String makeIdCol, - final String modelCol) { - executeQuery( - String.format("INSERT INTO %s.%s (%s, %s, %s) VALUES (%s, %s, '%s');", dbName, streamName, - idCol, makeIdCol, modelCol, - recordJson.get(idCol).asInt(), recordJson.get(makeIdCol).asInt(), - recordJson.get(modelCol).asText())); - } - - private static Set removeDuplicates(final Set messages) { - final Set existingDataRecordsWithoutUpdated = new HashSet<>(); - final Set output = new HashSet<>(); - - for (final AirbyteRecordMessage message : messages) { - final ObjectNode node = message.getData().deepCopy(); - node.remove("_ab_cdc_updated_at"); - - if (existingDataRecordsWithoutUpdated.contains(node)) { - LOGGER.info("Removing duplicate node: " + node); - } else { - output.add(message); - existingDataRecordsWithoutUpdated.add(node); - } - } - - return output; - } - - protected Set extractRecordMessages(final List messages) { - final List recordMessageList = messages - .stream() - .filter(r -> r.getType() == Type.RECORD).map(AirbyteMessage::getRecord) - .collect(Collectors.toList()); - final Set recordMessageSet = new HashSet<>(recordMessageList); - - assertEquals(recordMessageList.size(), recordMessageSet.size(), - "Expected no duplicates in airbyte record message output for a single sync."); - - return recordMessageSet; - } - - private List extractStateMessages(final List messages) { - return messages.stream().filter(r -> r.getType() == Type.STATE).map(AirbyteMessage::getState) - .collect(Collectors.toList()); - } - - private void assertExpectedRecords(final Set expectedRecords, final Set actualRecords) { - // assume all streams are cdc. - assertExpectedRecords(expectedRecords, actualRecords, actualRecords.stream().map(AirbyteRecordMessage::getStream).collect(Collectors.toSet())); - } - - private void assertExpectedRecords(final Set expectedRecords, - final Set actualRecords, - final Set cdcStreams) { - assertExpectedRecords(expectedRecords, actualRecords, cdcStreams, STREAM_NAMES); - } - - private void assertExpectedRecords(final Set expectedRecords, - final Set actualRecords, - final Set cdcStreams, - final Set streamNames) { - final Set actualData = actualRecords - .stream() - .map(recordMessage -> { - assertTrue(streamNames.contains(recordMessage.getStream())); - assertNotNull(recordMessage.getEmittedAt()); - - assertEquals(MODELS_SCHEMA, recordMessage.getNamespace()); - - final JsonNode data = recordMessage.getData(); - - if (cdcStreams.contains(recordMessage.getStream())) { - assertCdcMetaData(data, true); - } else { - assertNullCdcMetaData(data); - } - - removeCDCColumns((ObjectNode) data); - - return data; - }) - .collect(Collectors.toSet()); - - assertEquals(expectedRecords, actualData); - } - - @Test - @DisplayName("On the first sync, produce returns records that exist in the database.") - void testExistingData() throws Exception { - final CdcTargetPosition targetPosition = cdcLatestTargetPosition(); - final AutoCloseableIterator read = getSource().read(getConfig(), CONFIGURED_CATALOG, null); - final List actualRecords = AutoCloseableIterators.toListAndClose(read); - - final Set recordMessages = extractRecordMessages(actualRecords); - final List stateMessages = extractStateMessages(actualRecords); - - assertNotNull(targetPosition); - recordMessages.forEach(record -> { - assertEquals(extractPosition(record.getData()), targetPosition); - }); - - assertExpectedRecords(new HashSet<>(MODEL_RECORDS), recordMessages); - assertEquals(1, stateMessages.size()); - assertNotNull(stateMessages.get(0).getData()); - assertExpectedStateMessages(stateMessages); - } - - @Test - @DisplayName("When a record is deleted, produces a deletion record.") - void testDelete() throws Exception { - final AutoCloseableIterator read1 = getSource() - .read(getConfig(), CONFIGURED_CATALOG, null); - final List actualRecords1 = AutoCloseableIterators.toListAndClose(read1); - final List stateMessages1 = extractStateMessages(actualRecords1); - assertEquals(1, stateMessages1.size()); - assertNotNull(stateMessages1.get(0).getData()); - assertExpectedStateMessages(stateMessages1); - - executeQuery(String - .format("DELETE FROM %s.%s WHERE %s = %s", MODELS_SCHEMA, MODELS_STREAM_NAME, COL_ID, - 11)); - - final JsonNode state = Jsons.jsonNode(stateMessages1); - final AutoCloseableIterator read2 = getSource() - .read(getConfig(), CONFIGURED_CATALOG, state); - final List actualRecords2 = AutoCloseableIterators.toListAndClose(read2); - final List recordMessages2 = new ArrayList<>( - extractRecordMessages(actualRecords2)); - final List stateMessages2 = extractStateMessages(actualRecords2); - assertEquals(1, stateMessages2.size()); - assertNotNull(stateMessages2.get(0).getData()); - assertExpectedStateMessages(stateMessages2); - assertEquals(1, recordMessages2.size()); - assertEquals(11, recordMessages2.get(0).getData().get(COL_ID).asInt()); - assertCdcMetaData(recordMessages2.get(0).getData(), false); - } - - @Test - @DisplayName("When a record is updated, produces an update record.") - void testUpdate() throws Exception { - final String updatedModel = "Explorer"; - final AutoCloseableIterator read1 = getSource() - .read(getConfig(), CONFIGURED_CATALOG, null); - final List actualRecords1 = AutoCloseableIterators.toListAndClose(read1); - final List stateMessages1 = extractStateMessages(actualRecords1); - assertEquals(1, stateMessages1.size()); - assertNotNull(stateMessages1.get(0).getData()); - assertExpectedStateMessages(stateMessages1); - - executeQuery(String - .format("UPDATE %s.%s SET %s = '%s' WHERE %s = %s", MODELS_SCHEMA, MODELS_STREAM_NAME, - COL_MODEL, updatedModel, COL_ID, 11)); - - final JsonNode state = Jsons.jsonNode(stateMessages1); - final AutoCloseableIterator read2 = getSource() - .read(getConfig(), CONFIGURED_CATALOG, state); - final List actualRecords2 = AutoCloseableIterators.toListAndClose(read2); - final List recordMessages2 = new ArrayList<>( - extractRecordMessages(actualRecords2)); - final List stateMessages2 = extractStateMessages(actualRecords2); - assertEquals(1, stateMessages2.size()); - assertNotNull(stateMessages2.get(0).getData()); - assertExpectedStateMessages(stateMessages2); - assertEquals(1, recordMessages2.size()); - assertEquals(11, recordMessages2.get(0).getData().get(COL_ID).asInt()); - assertEquals(updatedModel, recordMessages2.get(0).getData().get(COL_MODEL).asText()); - assertCdcMetaData(recordMessages2.get(0).getData(), true); - } - - @SuppressWarnings({"BusyWait", "CodeBlock2Expr"}) - @Test - @DisplayName("Verify that when data is inserted into the database while a sync is happening and after the first sync, it all gets replicated.") - void testRecordsProducedDuringAndAfterSync() throws Exception { - - final int recordsToCreate = 20; - final int[] recordsCreated = {0}; - // first batch of records. 20 created here and 6 created in setup method. - while (recordsCreated[0] < recordsToCreate) { - final JsonNode record = - Jsons.jsonNode(ImmutableMap - .of(COL_ID, 100 + recordsCreated[0], COL_MAKE_ID, 1, COL_MODEL, - "F-" + recordsCreated[0])); - writeModelRecord(record); - recordsCreated[0]++; - } - - final AutoCloseableIterator firstBatchIterator = getSource() - .read(getConfig(), CONFIGURED_CATALOG, null); - final List dataFromFirstBatch = AutoCloseableIterators - .toListAndClose(firstBatchIterator); - final List stateAfterFirstBatch = extractStateMessages(dataFromFirstBatch); - assertEquals(1, stateAfterFirstBatch.size()); - assertNotNull(stateAfterFirstBatch.get(0).getData()); - assertExpectedStateMessages(stateAfterFirstBatch); - final Set recordsFromFirstBatch = extractRecordMessages( - dataFromFirstBatch); - assertEquals((MODEL_RECORDS.size() + recordsToCreate), recordsFromFirstBatch.size()); - - // second batch of records again 20 being created - recordsCreated[0] = 0; - while (recordsCreated[0] < recordsToCreate) { - final JsonNode record = - Jsons.jsonNode(ImmutableMap - .of(COL_ID, 200 + recordsCreated[0], COL_MAKE_ID, 1, COL_MODEL, - "F-" + recordsCreated[0])); - writeModelRecord(record); - recordsCreated[0]++; - } - - final JsonNode state = Jsons.jsonNode(stateAfterFirstBatch); - final AutoCloseableIterator secondBatchIterator = getSource() - .read(getConfig(), CONFIGURED_CATALOG, state); - final List dataFromSecondBatch = AutoCloseableIterators - .toListAndClose(secondBatchIterator); - - final List stateAfterSecondBatch = extractStateMessages(dataFromSecondBatch); - assertEquals(1, stateAfterSecondBatch.size()); - assertNotNull(stateAfterSecondBatch.get(0).getData()); - assertExpectedStateMessages(stateAfterSecondBatch); - - final Set recordsFromSecondBatch = extractRecordMessages( - dataFromSecondBatch); - assertEquals(recordsToCreate, recordsFromSecondBatch.size(), - "Expected 20 records to be replicated in the second sync."); - - // sometimes there can be more than one of these at the end of the snapshot and just before the - // first incremental. - final Set recordsFromFirstBatchWithoutDuplicates = removeDuplicates( - recordsFromFirstBatch); - final Set recordsFromSecondBatchWithoutDuplicates = removeDuplicates( - recordsFromSecondBatch); - - final int recordsCreatedBeforeTestCount = MODEL_RECORDS.size(); - assertTrue(recordsCreatedBeforeTestCount < recordsFromFirstBatchWithoutDuplicates.size(), - "Expected first sync to include records created while the test was running."); - assertEquals((recordsToCreate * 2) + recordsCreatedBeforeTestCount, - recordsFromFirstBatchWithoutDuplicates.size() + recordsFromSecondBatchWithoutDuplicates - .size()); - } - - @Test - @DisplayName("When both incremental CDC and full refresh are configured for different streams in a sync, the data is replicated as expected.") - void testCdcAndFullRefreshInSameSync() throws Exception { - final ConfiguredAirbyteCatalog configuredCatalog = Jsons.clone(CONFIGURED_CATALOG); - - final List MODEL_RECORDS_2 = ImmutableList.of( - Jsons.jsonNode(ImmutableMap.of(COL_ID, 110, COL_MAKE_ID, 1, COL_MODEL, "Fiesta-2")), - Jsons.jsonNode(ImmutableMap.of(COL_ID, 120, COL_MAKE_ID, 1, COL_MODEL, "Focus-2")), - Jsons.jsonNode(ImmutableMap.of(COL_ID, 130, COL_MAKE_ID, 1, COL_MODEL, "Ranger-2")), - Jsons.jsonNode(ImmutableMap.of(COL_ID, 140, COL_MAKE_ID, 2, COL_MODEL, "GLA-2")), - Jsons.jsonNode(ImmutableMap.of(COL_ID, 150, COL_MAKE_ID, 2, COL_MODEL, "A 220-2")), - Jsons.jsonNode(ImmutableMap.of(COL_ID, 160, COL_MAKE_ID, 2, COL_MODEL, "E 350-2"))); - - createTable(MODELS_SCHEMA, MODELS_STREAM_NAME + "_2", - columnClause(ImmutableMap.of(COL_ID, "INTEGER", COL_MAKE_ID, "INTEGER", COL_MODEL, "VARCHAR(200)"), Optional.of(COL_ID))); - - for (final JsonNode recordJson : MODEL_RECORDS_2) { - writeRecords(recordJson, MODELS_SCHEMA, MODELS_STREAM_NAME + "_2", COL_ID, - COL_MAKE_ID, COL_MODEL); - } - - final ConfiguredAirbyteStream airbyteStream = new ConfiguredAirbyteStream() - .withStream(CatalogHelpers.createAirbyteStream( - MODELS_STREAM_NAME + "_2", - MODELS_SCHEMA, - Field.of(COL_ID, JsonSchemaType.NUMBER), - Field.of(COL_MAKE_ID, JsonSchemaType.NUMBER), - Field.of(COL_MODEL, JsonSchemaType.STRING)) - .withSupportedSyncModes( - Lists.newArrayList(SyncMode.FULL_REFRESH, SyncMode.INCREMENTAL)) - .withSourceDefinedPrimaryKey(List.of(List.of(COL_ID)))); - airbyteStream.setSyncMode(SyncMode.FULL_REFRESH); - - final List streams = configuredCatalog.getStreams(); - streams.add(airbyteStream); - configuredCatalog.withStreams(streams); - - final AutoCloseableIterator read1 = getSource() - .read(getConfig(), configuredCatalog, null); - final List actualRecords1 = AutoCloseableIterators.toListAndClose(read1); - - final Set recordMessages1 = extractRecordMessages(actualRecords1); - final List stateMessages1 = extractStateMessages(actualRecords1); - final HashSet names = new HashSet<>(STREAM_NAMES); - names.add(MODELS_STREAM_NAME + "_2"); - assertEquals(1, stateMessages1.size()); - assertNotNull(stateMessages1.get(0).getData()); - assertExpectedStateMessages(stateMessages1); - assertExpectedRecords(Streams.concat(MODEL_RECORDS_2.stream(), MODEL_RECORDS.stream()) - .collect(Collectors.toSet()), - recordMessages1, - Collections.singleton(MODELS_STREAM_NAME), - names); - - final JsonNode puntoRecord = Jsons - .jsonNode(ImmutableMap.of(COL_ID, 100, COL_MAKE_ID, 3, COL_MODEL, "Punto")); - writeModelRecord(puntoRecord); - - final JsonNode state = Jsons.jsonNode(extractStateMessages(actualRecords1)); - final AutoCloseableIterator read2 = getSource() - .read(getConfig(), configuredCatalog, state); - final List actualRecords2 = AutoCloseableIterators.toListAndClose(read2); - - final Set recordMessages2 = extractRecordMessages(actualRecords2); - final List stateMessages2 = extractStateMessages(actualRecords2); - assertEquals(1, stateMessages2.size()); - assertNotNull(stateMessages2.get(0).getData()); - assertExpectedStateMessages(stateMessages2); - assertExpectedRecords( - Streams.concat(MODEL_RECORDS_2.stream(), Stream.of(puntoRecord)) - .collect(Collectors.toSet()), - recordMessages2, - Collections.singleton(MODELS_STREAM_NAME), - names); - } - - @Test - @DisplayName("When no records exist, no records are returned.") - void testNoData() throws Exception { - - executeQuery(String.format("DELETE FROM %s.%s", MODELS_SCHEMA, MODELS_STREAM_NAME)); - - final AutoCloseableIterator read = getSource() - .read(getConfig(), CONFIGURED_CATALOG, null); - final List actualRecords = AutoCloseableIterators.toListAndClose(read); - - final Set recordMessages = extractRecordMessages(actualRecords); - final List stateMessages = extractStateMessages(actualRecords); - - assertExpectedRecords(Collections.emptySet(), recordMessages); - assertEquals(1, stateMessages.size()); - assertNotNull(stateMessages.get(0).getData()); - assertExpectedStateMessages(stateMessages); - } - - @Test - @DisplayName("When no changes have been made to the database since the previous sync, no records are returned.") - void testNoDataOnSecondSync() throws Exception { - final AutoCloseableIterator read1 = getSource() - .read(getConfig(), CONFIGURED_CATALOG, null); - final List actualRecords1 = AutoCloseableIterators.toListAndClose(read1); - final JsonNode state = Jsons.jsonNode(extractStateMessages(actualRecords1)); - - final AutoCloseableIterator read2 = getSource() - .read(getConfig(), CONFIGURED_CATALOG, state); - final List actualRecords2 = AutoCloseableIterators.toListAndClose(read2); - - final Set recordMessages2 = extractRecordMessages(actualRecords2); - final List stateMessages2 = extractStateMessages(actualRecords2); - - assertExpectedRecords(Collections.emptySet(), recordMessages2); - assertEquals(1, stateMessages2.size()); - assertNotNull(stateMessages2.get(0).getData()); - assertExpectedStateMessages(stateMessages2); - } - - @Test - void testCheck() throws Exception { - final AirbyteConnectionStatus status = getSource().check(getConfig()); - assertEquals(status.getStatus(), AirbyteConnectionStatus.Status.SUCCEEDED); - } - - @Test - void testDiscover() throws Exception { - final AirbyteCatalog expectedCatalog = expectedCatalogForDiscover(); - final AirbyteCatalog actualCatalog = getSource().discover(getConfig()); - - assertEquals( - expectedCatalog.getStreams().stream().sorted(Comparator.comparing(AirbyteStream::getName)) - .collect(Collectors.toList()), - actualCatalog.getStreams().stream().sorted(Comparator.comparing(AirbyteStream::getName)) - .collect(Collectors.toList())); - } - - protected AirbyteCatalog expectedCatalogForDiscover() { - final AirbyteCatalog expectedCatalog = Jsons.clone(CATALOG); - - createTable(MODELS_SCHEMA, MODELS_STREAM_NAME + "_2", - columnClause(ImmutableMap.of(COL_ID, "INTEGER", COL_MAKE_ID, "INTEGER", COL_MODEL, "VARCHAR(200)"), Optional.empty())); - - final List streams = expectedCatalog.getStreams(); - // stream with PK - streams.get(0).setSourceDefinedCursor(true); - addCdcMetadataColumns(streams.get(0)); - - final AirbyteStream streamWithoutPK = CatalogHelpers.createAirbyteStream( - MODELS_STREAM_NAME + "_2", - MODELS_SCHEMA, - Field.of(COL_ID, JsonSchemaType.INTEGER), - Field.of(COL_MAKE_ID, JsonSchemaType.INTEGER), - Field.of(COL_MODEL, JsonSchemaType.STRING)); - streamWithoutPK.setSourceDefinedPrimaryKey(Collections.emptyList()); - streamWithoutPK.setSupportedSyncModes(List.of(SyncMode.FULL_REFRESH)); - addCdcMetadataColumns(streamWithoutPK); - - final AirbyteStream randomStream = CatalogHelpers.createAirbyteStream( - MODELS_STREAM_NAME + "_random", - MODELS_SCHEMA + "_random", - Field.of(COL_ID + "_random", JsonSchemaType.INTEGER), - Field.of(COL_MAKE_ID + "_random", JsonSchemaType.INTEGER), - Field.of(COL_MODEL + "_random", JsonSchemaType.STRING)) - .withSourceDefinedCursor(true) - .withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH, SyncMode.INCREMENTAL)) - .withSourceDefinedPrimaryKey(List.of(List.of(COL_ID + "_random"))); - addCdcMetadataColumns(randomStream); - - streams.add(streamWithoutPK); - streams.add(randomStream); - expectedCatalog.withStreams(streams); - return expectedCatalog; - } - - protected abstract CdcTargetPosition cdcLatestTargetPosition(); - - protected abstract CdcTargetPosition extractPosition(JsonNode record); - - protected abstract void assertNullCdcMetaData(JsonNode data); - - protected abstract void assertCdcMetaData(JsonNode data, boolean deletedAtNull); - - protected abstract void removeCDCColumns(ObjectNode data); - - protected abstract void addCdcMetadataColumns(AirbyteStream stream); - - protected abstract Source getSource(); - - protected abstract JsonNode getConfig(); - - protected abstract Database getDatabase(); - - protected abstract void assertExpectedStateMessages(List stateMessages); - -} diff --git a/settings.gradle b/settings.gradle index 2dc801ee0554..7baacf60c542 100644 --- a/settings.gradle +++ b/settings.gradle @@ -113,7 +113,6 @@ if (!System.getenv().containsKey("SUB_BUILD") || System.getenv().get("SUB_BUILD" include ':airbyte-integrations:bases:s3-destination-base-integration-test' include ':airbyte-integrations:bases:standard-source-test' include ':airbyte-integrations:connector-templates:generator' - include ':airbyte-integrations:bases:debezium-v1-4-2' include ':airbyte-integrations:bases:debezium-v1-9-6' // Needed by normalization integration tests From 87870c4bd2832f68e617483c68cec6bfb66bf9a5 Mon Sep 17 00:00:00 2001 From: Subodh Kant Chaturvedi Date: Sat, 5 Nov 2022 00:49:56 +0530 Subject: [PATCH 58/73] fix master build failure (#18982) --- .../destination/tidb/TiDBDestinationTest.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/airbyte-integrations/connectors/destination-tidb/src/test/java/io/airbyte/integrations/destination/tidb/TiDBDestinationTest.java b/airbyte-integrations/connectors/destination-tidb/src/test/java/io/airbyte/integrations/destination/tidb/TiDBDestinationTest.java index 6854c8458179..6292108c5273 100644 --- a/airbyte-integrations/connectors/destination-tidb/src/test/java/io/airbyte/integrations/destination/tidb/TiDBDestinationTest.java +++ b/airbyte-integrations/connectors/destination-tidb/src/test/java/io/airbyte/integrations/destination/tidb/TiDBDestinationTest.java @@ -5,6 +5,7 @@ package io.airbyte.integrations.destination.tidb; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableMap; @@ -25,7 +26,9 @@ import io.airbyte.protocol.models.Field; import io.airbyte.protocol.models.JsonSchemaType; import java.time.Instant; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; import org.junit.jupiter.api.AfterEach; @@ -97,10 +100,13 @@ public void sanityTest() throws Exception { final List actualRecords = database.bufferedResultSetQuery( connection -> connection.createStatement().executeQuery("SELECT * FROM public._airbyte_raw_id_and_name;"), JdbcUtils.getDefaultSourceOperations()::rowToJson); - - assertEquals( - expectedRecords.stream().map(AirbyteMessage::getRecord).map(AirbyteRecordMessage::getData).collect(Collectors.toList()), - actualRecords.stream().map(o -> o.get("_airbyte_data").asText()).map(Jsons::deserialize).collect(Collectors.toList())); + final Map expectedRecordsWithId = new HashMap<>(); + expectedRecords.stream().map(AirbyteMessage::getRecord).map(AirbyteRecordMessage::getData) + .forEach(data -> expectedRecordsWithId.put(data.get("id").asInt(), data)); + actualRecords.stream().map(o -> o.get("_airbyte_data").asText()).map(Jsons::deserialize).forEach(actual -> { + assertTrue(expectedRecordsWithId.containsKey(actual.get("id").asInt())); + assertEquals(expectedRecordsWithId.get(actual.get("id").asInt()), actual); + }); } private List getNRecords(final int n) { From 104c91c519175f7ceb340e91922f168f32f64f3c Mon Sep 17 00:00:00 2001 From: Liren Tu Date: Fri, 4 Nov 2022 13:28:54 -0700 Subject: [PATCH 59/73] Fix migration dev center schema dump by run db-specific initialization script (#18984) * Run db-specific initialization script * Refactor code * Use constants * Add unit test for dev center --- .../io/airbyte/bootloader/BootloaderApp.java | 4 +-- .../db/instance/DatabaseConstants.java | 8 +++-- .../ConfigsDatabaseMigrationDevCenter.java | 10 ++---- .../configs/ConfigsDatabaseTestProvider.java | 2 +- .../ConfigsFlywayMigrationDatabase.java | 2 +- .../development/MigrationDevCenter.java | 34 ++++++++++--------- .../jobs/JobsDatabaseMigrationDevCenter.java | 10 ++---- .../jobs/JobsDatabaseTestProvider.java | 2 +- .../jobs/JobsFlywayMigrationDatabase.java | 2 +- .../impl/ConfigsDatabaseInitializerTest.java | 6 ++-- .../impl/JobsDatabaseInitializerTest.java | 10 +++--- ...ConfigsDatabaseMigrationDevCenterTest.java | 29 ++++++++++++++++ .../configs/ConfigsDatabaseMigratorTest.java | 5 ++- .../JobsDatabaseMigrationDevCenterTest.java | 28 +++++++++++++++ .../jobs/JobsDatabaseMigratorTest.java | 5 ++- 15 files changed, 103 insertions(+), 54 deletions(-) create mode 100644 airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigrationDevCenterTest.java create mode 100644 airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/jobs/JobsDatabaseMigrationDevCenterTest.java diff --git a/airbyte-bootloader/src/main/java/io/airbyte/bootloader/BootloaderApp.java b/airbyte-bootloader/src/main/java/io/airbyte/bootloader/BootloaderApp.java index 9d3d8cfac7b2..1132b5a46ef2 100644 --- a/airbyte-bootloader/src/main/java/io/airbyte/bootloader/BootloaderApp.java +++ b/airbyte-bootloader/src/main/java/io/airbyte/bootloader/BootloaderApp.java @@ -148,10 +148,10 @@ public BootloaderApp(final Configs configs, public void load() throws Exception { LOGGER.info("Initializing databases..."); DatabaseCheckFactory.createConfigsDatabaseInitializer(configsDslContext, - configs.getConfigsDatabaseInitializationTimeoutMs(), MoreResources.readResource(DatabaseConstants.CONFIGS_SCHEMA_PATH)).initialize(); + configs.getConfigsDatabaseInitializationTimeoutMs(), MoreResources.readResource(DatabaseConstants.CONFIGS_INITIAL_SCHEMA_PATH)).initialize(); DatabaseCheckFactory.createJobsDatabaseInitializer(jobsDslContext, - configs.getJobsDatabaseInitializationTimeoutMs(), MoreResources.readResource(DatabaseConstants.JOBS_SCHEMA_PATH)).initialize(); + configs.getJobsDatabaseInitializationTimeoutMs(), MoreResources.readResource(DatabaseConstants.JOBS_INITIAL_SCHEMA_PATH)).initialize(); LOGGER.info("Databases initialized."); LOGGER.info("Setting up config database and default workspace..."); diff --git a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/DatabaseConstants.java b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/DatabaseConstants.java index 52d931505870..468a66dafe43 100644 --- a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/DatabaseConstants.java +++ b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/DatabaseConstants.java @@ -26,7 +26,9 @@ public final class DatabaseConstants { /** * Path to the script that contains the initial schema definition for the Configurations database. */ - public static final String CONFIGS_SCHEMA_PATH = "configs_database/schema.sql"; + public static final String CONFIGS_INITIAL_SCHEMA_PATH = "configs_database/schema.sql"; + + public static final String CONFIGS_SCHEMA_DUMP_PATH = "src/main/resources/configs_database/schema_dump.txt"; /** * Logical name of the Jobs database. @@ -41,7 +43,9 @@ public final class DatabaseConstants { /** * Path to the script that contains the initial schema definition for the Jobs database. */ - public static final String JOBS_SCHEMA_PATH = "jobs_database/schema.sql"; + public static final String JOBS_INITIAL_SCHEMA_PATH = "jobs_database/schema.sql"; + + public static final String JOBS_SCHEMA_DUMP_PATH = "src/main/resources/jobs_database/schema_dump.txt"; /** * Default database connection timeout in milliseconds. diff --git a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigrationDevCenter.java b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigrationDevCenter.java index f4a3a8467363..1a77592b25ba 100644 --- a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigrationDevCenter.java +++ b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigrationDevCenter.java @@ -6,12 +6,11 @@ import io.airbyte.db.Database; import io.airbyte.db.factory.FlywayFactory; +import io.airbyte.db.instance.DatabaseConstants; import io.airbyte.db.instance.FlywayDatabaseMigrator; import io.airbyte.db.instance.development.MigrationDevCenter; -import java.io.IOException; import javax.sql.DataSource; import org.flywaydb.core.Flyway; -import org.jooq.DSLContext; /** * Helper class for migration development. See README for details. @@ -19,7 +18,7 @@ public class ConfigsDatabaseMigrationDevCenter extends MigrationDevCenter { public ConfigsDatabaseMigrationDevCenter() { - super("configs", "src/main/resources/configs_database/schema_dump.txt"); + super("configs", DatabaseConstants.CONFIGS_SCHEMA_DUMP_PATH, DatabaseConstants.CONFIGS_INITIAL_SCHEMA_PATH); } @Override @@ -27,11 +26,6 @@ protected FlywayDatabaseMigrator getMigrator(final Database database, final Flyw return new ConfigsDatabaseMigrator(database, flyway); } - @Override - protected Database getDatabase(final DSLContext dslContext) throws IOException { - return new Database(dslContext); - } - @Override protected Flyway getFlyway(final DataSource dataSource) { return FlywayFactory.create(dataSource, getClass().getSimpleName(), ConfigsDatabaseMigrator.DB_IDENTIFIER, diff --git a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsDatabaseTestProvider.java b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsDatabaseTestProvider.java index d4c18fd5a7c5..98f09191e776 100644 --- a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsDatabaseTestProvider.java +++ b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsDatabaseTestProvider.java @@ -35,7 +35,7 @@ public ConfigsDatabaseTestProvider(final DSLContext dslContext, final Flyway fly @Override public Database create(final boolean runMigration) throws IOException, DatabaseInitializationException { - final String initalSchema = MoreResources.readResource(DatabaseConstants.CONFIGS_SCHEMA_PATH); + final String initalSchema = MoreResources.readResource(DatabaseConstants.CONFIGS_INITIAL_SCHEMA_PATH); DatabaseCheckFactory.createConfigsDatabaseInitializer(dslContext, DatabaseConstants.DEFAULT_CONNECTION_TIMEOUT_MS, initalSchema).initialize(); final Database database = new Database(dslContext); diff --git a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsFlywayMigrationDatabase.java b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsFlywayMigrationDatabase.java index d75bfceb1167..05bb8f7b9224 100644 --- a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsFlywayMigrationDatabase.java +++ b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/ConfigsFlywayMigrationDatabase.java @@ -47,7 +47,7 @@ protected String[] getMigrationFileLocations() { @Override protected void initializeDatabase(final DSLContext dslContext) throws DatabaseInitializationException, IOException { - final String initialSchema = MoreResources.readResource(DatabaseConstants.CONFIGS_SCHEMA_PATH); + final String initialSchema = MoreResources.readResource(DatabaseConstants.CONFIGS_INITIAL_SCHEMA_PATH); DatabaseCheckFactory.createConfigsDatabaseInitializer(dslContext, DatabaseConstants.DEFAULT_CONNECTION_TIMEOUT_MS, initialSchema).initialize(); } diff --git a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/development/MigrationDevCenter.java b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/development/MigrationDevCenter.java index b95580c9f98b..100f2a68e64e 100644 --- a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/development/MigrationDevCenter.java +++ b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/development/MigrationDevCenter.java @@ -4,6 +4,7 @@ package io.airbyte.db.instance.development; +import com.google.common.annotations.VisibleForTesting; import io.airbyte.db.Database; import io.airbyte.db.factory.DSLContextFactory; import io.airbyte.db.factory.DataSourceFactory; @@ -37,30 +38,33 @@ private enum Command { private final String dbIdentifier; private final String schemaDumpFile; + private final String initialScript; - protected MigrationDevCenter(final String dbIdentifier, final String schemaDumpFile) { + protected MigrationDevCenter(final String dbIdentifier, final String schemaDumpFile, final String initialScript) { this.dbIdentifier = dbIdentifier; this.schemaDumpFile = schemaDumpFile; + this.initialScript = initialScript; } - private static PostgreSQLContainer createContainer() { + private PostgreSQLContainer createContainer() { final PostgreSQLContainer container = new PostgreSQLContainer<>("postgres:13-alpine") .withDatabaseName("airbyte") .withUsername("docker") .withPassword("docker"); container.start(); - - initializeDatabase(container); - + final var containerDelegate = new JdbcDatabaseDelegate(container, ""); + ScriptUtils.runInitScript(containerDelegate, initialScript); return container; } protected abstract FlywayDatabaseMigrator getMigrator(Database database, Flyway flyway); - protected abstract Database getDatabase(DSLContext dslContext) throws IOException; - protected abstract Flyway getFlyway(DataSource dataSource); + private Database getDatabase(final DSLContext dslContext) throws IOException { + return new Database(dslContext); + } + private void createMigration() { try (final PostgreSQLContainer container = createContainer()) { final DataSource dataSource = @@ -94,7 +98,8 @@ private void runLastMigration() { } } - private void dumpSchema() { + @VisibleForTesting + public String dumpSchema(final boolean persistToFile) { try (final PostgreSQLContainer container = createContainer()) { final DataSource dataSource = DataSourceFactory.create(container.getUsername(), container.getPassword(), container.getDriverClassName(), container.getJdbcUrl()); @@ -104,19 +109,16 @@ private void dumpSchema() { final FlywayDatabaseMigrator migrator = getMigrator(database, flyway); migrator.migrate(); final String schema = migrator.dumpSchema(); - MigrationDevHelper.dumpSchema(schema, schemaDumpFile, true); + if (persistToFile) { + MigrationDevHelper.dumpSchema(schema, schemaDumpFile, true); + } + return schema; } } catch (final Exception e) { throw new RuntimeException(e); } } - private static void initializeDatabase(final PostgreSQLContainer container) { - final var containerDelegate = new JdbcDatabaseDelegate(container, ""); - ScriptUtils.runInitScript(containerDelegate, "configs_database/schema.sql"); - ScriptUtils.runInitScript(containerDelegate, "jobs_database/schema.sql"); - } - public static void main(final String[] args) { final MigrationDevCenter devCenter; @@ -131,7 +133,7 @@ public static void main(final String[] args) { switch (command) { case CREATE -> devCenter.createMigration(); case MIGRATE -> devCenter.runLastMigration(); - case DUMP_SCHEMA -> devCenter.dumpSchema(); + case DUMP_SCHEMA -> devCenter.dumpSchema(true); default -> throw new IllegalArgumentException("Unexpected command: " + args[1]); } } diff --git a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsDatabaseMigrationDevCenter.java b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsDatabaseMigrationDevCenter.java index 6f8302a54551..336a245d7655 100644 --- a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsDatabaseMigrationDevCenter.java +++ b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsDatabaseMigrationDevCenter.java @@ -6,12 +6,11 @@ import io.airbyte.db.Database; import io.airbyte.db.factory.FlywayFactory; +import io.airbyte.db.instance.DatabaseConstants; import io.airbyte.db.instance.FlywayDatabaseMigrator; import io.airbyte.db.instance.development.MigrationDevCenter; -import java.io.IOException; import javax.sql.DataSource; import org.flywaydb.core.Flyway; -import org.jooq.DSLContext; /** * Helper class for migration development. See README for details. @@ -19,7 +18,7 @@ public class JobsDatabaseMigrationDevCenter extends MigrationDevCenter { public JobsDatabaseMigrationDevCenter() { - super("jobs", "src/main/resources/jobs_database/schema_dump.txt"); + super("jobs", DatabaseConstants.JOBS_SCHEMA_DUMP_PATH, DatabaseConstants.JOBS_INITIAL_SCHEMA_PATH); } @Override @@ -27,11 +26,6 @@ protected FlywayDatabaseMigrator getMigrator(final Database database, final Flyw return new JobsDatabaseMigrator(database, flyway); } - @Override - protected Database getDatabase(final DSLContext dslContext) throws IOException { - return new Database(dslContext); - } - @Override protected Flyway getFlyway(final DataSource dataSource) { return FlywayFactory.create(dataSource, getClass().getSimpleName(), JobsDatabaseMigrator.DB_IDENTIFIER, diff --git a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsDatabaseTestProvider.java b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsDatabaseTestProvider.java index ff43fa0b1a1e..e7059d48acaa 100644 --- a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsDatabaseTestProvider.java +++ b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsDatabaseTestProvider.java @@ -27,7 +27,7 @@ public JobsDatabaseTestProvider(final DSLContext dslContext, final Flyway flyway @Override public Database create(final boolean runMigration) throws IOException, DatabaseInitializationException { - final String initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_SCHEMA_PATH); + final String initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_INITIAL_SCHEMA_PATH); DatabaseCheckFactory.createJobsDatabaseInitializer(dslContext, DatabaseConstants.DEFAULT_CONNECTION_TIMEOUT_MS, initialSchema).initialize(); final Database jobsDatabase = new Database(dslContext); diff --git a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsFlywayMigrationDatabase.java b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsFlywayMigrationDatabase.java index b9e21c339bb3..40326e869e0e 100644 --- a/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsFlywayMigrationDatabase.java +++ b/airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/jobs/JobsFlywayMigrationDatabase.java @@ -47,7 +47,7 @@ protected String[] getMigrationFileLocations() { @Override protected void initializeDatabase(final DSLContext dslContext) throws DatabaseInitializationException, IOException { - final String initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_SCHEMA_PATH); + final String initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_INITIAL_SCHEMA_PATH); DatabaseCheckFactory.createJobsDatabaseInitializer(dslContext, DatabaseConstants.DEFAULT_CONNECTION_TIMEOUT_MS, initialSchema).initialize(); } diff --git a/airbyte-db/db-lib/src/test/java/io/airbyte/db/init/impl/ConfigsDatabaseInitializerTest.java b/airbyte-db/db-lib/src/test/java/io/airbyte/db/init/impl/ConfigsDatabaseInitializerTest.java index 76f2fe44647b..e331e14f5ffd 100644 --- a/airbyte-db/db-lib/src/test/java/io/airbyte/db/init/impl/ConfigsDatabaseInitializerTest.java +++ b/airbyte-db/db-lib/src/test/java/io/airbyte/db/init/impl/ConfigsDatabaseInitializerTest.java @@ -25,7 +25,7 @@ class ConfigsDatabaseInitializerTest extends CommonDatabaseInitializerTest { @Test void testInitializingSchema() throws IOException { final var databaseAvailabilityCheck = mock(ConfigsDatabaseAvailabilityCheck.class); - final var initialSchema = MoreResources.readResource(DatabaseConstants.CONFIGS_SCHEMA_PATH); + final var initialSchema = MoreResources.readResource(DatabaseConstants.CONFIGS_INITIAL_SCHEMA_PATH); final var initializer = new ConfigsDatabaseInitializer(databaseAvailabilityCheck, dslContext, initialSchema); Assertions.assertDoesNotThrow(() -> initializer.initialize()); @@ -35,7 +35,7 @@ void testInitializingSchema() throws IOException { @Test void testInitializingSchemaAlreadyExists() throws IOException { final var databaseAvailabilityCheck = mock(ConfigsDatabaseAvailabilityCheck.class); - final var initialSchema = MoreResources.readResource(DatabaseConstants.CONFIGS_SCHEMA_PATH); + final var initialSchema = MoreResources.readResource(DatabaseConstants.CONFIGS_INITIAL_SCHEMA_PATH); dslContext.execute(initialSchema); final var initializer = new ConfigsDatabaseInitializer(databaseAvailabilityCheck, dslContext, initialSchema); @@ -46,7 +46,7 @@ void testInitializingSchemaAlreadyExists() throws IOException { @Test void testInitializationException() throws IOException, DatabaseCheckException { final var databaseAvailabilityCheck = mock(ConfigsDatabaseAvailabilityCheck.class); - final var initialSchema = MoreResources.readResource(DatabaseConstants.CONFIGS_SCHEMA_PATH); + final var initialSchema = MoreResources.readResource(DatabaseConstants.CONFIGS_INITIAL_SCHEMA_PATH); doThrow(new DatabaseCheckException("test")).when(databaseAvailabilityCheck).check(); diff --git a/airbyte-db/db-lib/src/test/java/io/airbyte/db/init/impl/JobsDatabaseInitializerTest.java b/airbyte-db/db-lib/src/test/java/io/airbyte/db/init/impl/JobsDatabaseInitializerTest.java index 22ce7eb496f1..6343ea99410a 100644 --- a/airbyte-db/db-lib/src/test/java/io/airbyte/db/init/impl/JobsDatabaseInitializerTest.java +++ b/airbyte-db/db-lib/src/test/java/io/airbyte/db/init/impl/JobsDatabaseInitializerTest.java @@ -25,7 +25,7 @@ class JobsDatabaseInitializerTest extends CommonDatabaseInitializerTest { @Test void testInitializingSchema() throws IOException { final var databaseAvailabilityCheck = mock(JobsDatabaseAvailabilityCheck.class); - final var initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_SCHEMA_PATH); + final var initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_INITIAL_SCHEMA_PATH); final var initializer = new JobsDatabaseInitializer(databaseAvailabilityCheck, dslContext, initialSchema); Assertions.assertDoesNotThrow(() -> initializer.initialize()); @@ -35,7 +35,7 @@ void testInitializingSchema() throws IOException { @Test void testInitializingSchemaAlreadyExists() throws IOException { final var databaseAvailabilityCheck = mock(JobsDatabaseAvailabilityCheck.class); - final var initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_SCHEMA_PATH); + final var initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_INITIAL_SCHEMA_PATH); dslContext.execute(initialSchema); final var initializer = new JobsDatabaseInitializer(databaseAvailabilityCheck, dslContext, initialSchema); @@ -46,7 +46,7 @@ void testInitializingSchemaAlreadyExists() throws IOException { @Test void testInitializationException() throws IOException, DatabaseCheckException { final var databaseAvailabilityCheck = mock(JobsDatabaseAvailabilityCheck.class); - final var initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_SCHEMA_PATH); + final var initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_INITIAL_SCHEMA_PATH); doThrow(new DatabaseCheckException("test")).when(databaseAvailabilityCheck).check(); @@ -56,7 +56,7 @@ void testInitializationException() throws IOException, DatabaseCheckException { @Test void testInitializationNullAvailabilityCheck() throws IOException { - final var initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_SCHEMA_PATH); + final var initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_INITIAL_SCHEMA_PATH); final var initializer = new JobsDatabaseInitializer(null, dslContext, initialSchema); Assertions.assertThrows(DatabaseInitializationException.class, () -> initializer.initialize()); } @@ -64,7 +64,7 @@ void testInitializationNullAvailabilityCheck() throws IOException { @Test void testInitializationNullDslContext() throws IOException { final var databaseAvailabilityCheck = mock(JobsDatabaseAvailabilityCheck.class); - final var initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_SCHEMA_PATH); + final var initialSchema = MoreResources.readResource(DatabaseConstants.JOBS_INITIAL_SCHEMA_PATH); final var initializer = new JobsDatabaseInitializer(databaseAvailabilityCheck, null, initialSchema); Assertions.assertThrows(DatabaseInitializationException.class, () -> initializer.initialize()); } diff --git a/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigrationDevCenterTest.java b/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigrationDevCenterTest.java new file mode 100644 index 000000000000..841422994ad6 --- /dev/null +++ b/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigrationDevCenterTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.db.instance.configs; + +import static org.junit.jupiter.api.Assertions.*; + +import io.airbyte.commons.io.IOs; +import io.airbyte.db.instance.DatabaseConstants; +import io.airbyte.db.instance.development.MigrationDevCenter; +import java.nio.file.Path; +import org.junit.jupiter.api.Test; + +class ConfigsDatabaseMigrationDevCenterTest { + + /** + * This test ensures that the dev center is working correctly end-to-end. If it fails, it means + * either the migration is not run properly, or the database initialization is incorrect in the dev + * center implementation. + */ + @Test + void testSchemaDump() { + final MigrationDevCenter devCenter = new ConfigsDatabaseMigrationDevCenter(); + final String schemaDump = IOs.readFile(Path.of(DatabaseConstants.CONFIGS_SCHEMA_DUMP_PATH)); + assertEquals(schemaDump.trim(), devCenter.dumpSchema(false)); + } + +} diff --git a/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigratorTest.java b/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigratorTest.java index 5d82e2d15f59..80c55c021dd9 100644 --- a/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigratorTest.java +++ b/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/configs/ConfigsDatabaseMigratorTest.java @@ -5,6 +5,7 @@ package io.airbyte.db.instance.configs; import io.airbyte.db.factory.FlywayFactory; +import io.airbyte.db.instance.DatabaseConstants; import io.airbyte.db.instance.DatabaseMigrator; import io.airbyte.db.instance.development.MigrationDevHelper; import java.io.IOException; @@ -14,8 +15,6 @@ @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") class ConfigsDatabaseMigratorTest extends AbstractConfigsDatabaseTest { - private static final String SCHEMA_DUMP_FILE = "src/main/resources/configs_database/schema_dump.txt"; - @Test void dumpSchema() throws IOException { final Flyway flyway = FlywayFactory.create(getDataSource(), getClass().getSimpleName(), ConfigsDatabaseMigrator.DB_IDENTIFIER, @@ -23,7 +22,7 @@ void dumpSchema() throws IOException { final DatabaseMigrator migrator = new ConfigsDatabaseMigrator(database, flyway); migrator.migrate(); final String schema = migrator.dumpSchema(); - MigrationDevHelper.dumpSchema(schema, SCHEMA_DUMP_FILE, false); + MigrationDevHelper.dumpSchema(schema, DatabaseConstants.CONFIGS_SCHEMA_DUMP_PATH, false); } } diff --git a/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/jobs/JobsDatabaseMigrationDevCenterTest.java b/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/jobs/JobsDatabaseMigrationDevCenterTest.java new file mode 100644 index 000000000000..a72403fd8a18 --- /dev/null +++ b/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/jobs/JobsDatabaseMigrationDevCenterTest.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.db.instance.jobs; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.airbyte.commons.io.IOs; +import io.airbyte.db.instance.DatabaseConstants; +import io.airbyte.db.instance.development.MigrationDevCenter; +import java.nio.file.Path; +import org.junit.jupiter.api.Test; + +class JobsDatabaseMigrationDevCenterTest { + + /** + * This test ensures that the dev center is working correctly end-to-end. If it fails, it means + * either the migration is not run properly, or the database initialization is incorrect. + */ + @Test + void testSchemaDump() { + final MigrationDevCenter devCenter = new JobsDatabaseMigrationDevCenter(); + final String schemaDump = IOs.readFile(Path.of(DatabaseConstants.JOBS_SCHEMA_DUMP_PATH)); + assertEquals(schemaDump.trim(), devCenter.dumpSchema(false)); + } + +} diff --git a/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/jobs/JobsDatabaseMigratorTest.java b/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/jobs/JobsDatabaseMigratorTest.java index 668b734479d1..688c1ac0111b 100644 --- a/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/jobs/JobsDatabaseMigratorTest.java +++ b/airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/jobs/JobsDatabaseMigratorTest.java @@ -5,6 +5,7 @@ package io.airbyte.db.instance.jobs; import io.airbyte.db.factory.FlywayFactory; +import io.airbyte.db.instance.DatabaseConstants; import io.airbyte.db.instance.DatabaseMigrator; import io.airbyte.db.instance.development.MigrationDevHelper; import java.io.IOException; @@ -14,8 +15,6 @@ @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") class JobsDatabaseMigratorTest extends AbstractJobsDatabaseTest { - private static final String SCHEMA_DUMP_FILE = "src/main/resources/jobs_database/schema_dump.txt"; - @Test void dumpSchema() throws IOException { final Flyway flyway = FlywayFactory.create(getDataSource(), getClass().getSimpleName(), JobsDatabaseMigrator.DB_IDENTIFIER, @@ -23,7 +22,7 @@ void dumpSchema() throws IOException { final DatabaseMigrator migrator = new JobsDatabaseMigrator(database, flyway); migrator.migrate(); final String schema = migrator.dumpSchema(); - MigrationDevHelper.dumpSchema(schema, SCHEMA_DUMP_FILE, false); + MigrationDevHelper.dumpSchema(schema, DatabaseConstants.JOBS_SCHEMA_DUMP_PATH, false); } } From 15143f7238be4ba3e825913b084d679fa0918592 Mon Sep 17 00:00:00 2001 From: Benoit Moriceau Date: Fri, 4 Nov 2022 13:34:05 -0700 Subject: [PATCH 60/73] Fix oauth controller (#18981) --- .../src/main/java/io/airbyte/server/ServerFactory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java b/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java index e6fc1463c326..04fa4436f9b6 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java +++ b/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java @@ -29,6 +29,7 @@ import io.airbyte.server.apis.OpenapiApiController; import io.airbyte.server.apis.OperationApiController; import io.airbyte.server.apis.SchedulerApiController; +import io.airbyte.server.apis.SourceOauthApiController; import io.airbyte.server.apis.binders.AttemptApiBinder; import io.airbyte.server.apis.binders.ConnectionApiBinder; import io.airbyte.server.apis.binders.DbMigrationBinder; @@ -219,7 +220,7 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul OpenapiApiController.class, OperationApiController.class, SchedulerApiController.class, - SourceOauthApiFactory.class); + SourceOauthApiController.class); final Set components = Set.of( new CorsFilter(), From 350d5443a19e0c8db8aec0eae74624e2235c7d3f Mon Sep 17 00:00:00 2001 From: andriikorotkov <88329385+andriikorotkov@users.noreply.github.com> Date: Fri, 4 Nov 2022 23:19:50 +0200 Subject: [PATCH 61/73] Add normalization to destination definition and actor definition table (#18300) * updated StandardDestinationDefinition.yaml, added normalization and tags to the destination_definition.yaml and added information about normalization and DBT to the ACTOR_DEFINITION table * updated docs * updated BootloaderAppTest.java for new migration * updated schema dump * Update normalization version and fix bigquery * Use varchar 255 * Update migration version to the latest * Update normalized table schema file and add comment * Revert "Use varchar 255" This reverts commit e182466e6603d83baed443f8f02a535a5c0f9e11. * Use varchar 255 * Add unit test for migration * Format code Co-authored-by: Liren Tu --- .../airbyte/bootloader/BootloaderAppTest.java | 2 +- .../types/StandardDestinationDefinition.yaml | 7 +++ .../config/persistence/ConfigWriter.java | 6 ++ .../seed/destination_definitions.yaml | 29 ++++++++++ ...rDefinitionNormalizationAndDbtColumns.java | 51 +++++++++++++++++ ...veActorForeignKeyFromOauthParamsTable.java | 4 -- .../normalized_tables_schema.txt | 42 ++++++++------ .../configs_database/schema_dump.txt | 3 + ...initionNormalizationAndDbtColumnsTest.java | 55 +++++++++++++++++++ ...torForeignKeyFromOauthParamsTableTest.java | 3 +- 10 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 airbyte-db/db-lib/src/main/java/io/airbyte/db/instance/configs/migrations/V0_40_18_002__AddActorDefinitionNormalizationAndDbtColumns.java create mode 100644 airbyte-db/db-lib/src/test/java/io/airbyte/db/instance/configs/migrations/V0_40_18_002__AddActorDefinitionNormalizationAndDbtColumnsTest.java diff --git a/airbyte-bootloader/src/test/java/io/airbyte/bootloader/BootloaderAppTest.java b/airbyte-bootloader/src/test/java/io/airbyte/bootloader/BootloaderAppTest.java index 804ab29f70f6..251daa510165 100644 --- a/airbyte-bootloader/src/test/java/io/airbyte/bootloader/BootloaderAppTest.java +++ b/airbyte-bootloader/src/test/java/io/airbyte/bootloader/BootloaderAppTest.java @@ -141,7 +141,7 @@ void testBootloaderAppBlankDb() throws Exception { val configsMigrator = new ConfigsDatabaseMigrator(configDatabase, configsFlyway); // this line should change with every new migration // to show that you meant to make a new migration to the prod database - assertEquals("0.40.18.001", configsMigrator.getLatestMigration().getVersion().getVersion()); + assertEquals("0.40.18.002", configsMigrator.getLatestMigration().getVersion().getVersion()); val jobsPersistence = new DefaultJobPersistence(jobDatabase); assertEquals(VERSION_0330_ALPHA, jobsPersistence.getVersion().get()); diff --git a/airbyte-config/config-models/src/main/resources/types/StandardDestinationDefinition.yaml b/airbyte-config/config-models/src/main/resources/types/StandardDestinationDefinition.yaml index 21be72bb1954..f3f37ebb3971 100644 --- a/airbyte-config/config-models/src/main/resources/types/StandardDestinationDefinition.yaml +++ b/airbyte-config/config-models/src/main/resources/types/StandardDestinationDefinition.yaml @@ -58,3 +58,10 @@ properties: protocolVersion: type: string description: the Airbyte Protocol version supported by the connector + normalizationRepository: + type: string + normalizationTag: + type: string + supportsDbt: + type: boolean + default: false diff --git a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigWriter.java b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigWriter.java index e21b039d3bbd..efcca3a997a2 100644 --- a/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigWriter.java +++ b/airbyte-config/config-persistence/src/main/java/io/airbyte/config/persistence/ConfigWriter.java @@ -130,6 +130,9 @@ static void writeStandardDestinationDefinition(final List Date: Fri, 4 Nov 2022 14:20:07 -0700 Subject: [PATCH 62/73] Add new workspace api endpoint (#18983) * Add new workspace api endpoint --- airbyte-api/src/main/openapi/config.yaml | 23 +++++ .../airbyte/server/apis/ConfigurationApi.java | 5 + .../server/handlers/WorkspacesHandler.java | 6 ++ .../handlers/WorkspacesHandlerTest.java | 23 +++++ .../api/generated-api-html/index.html | 92 +++++++++++++++++++ 5 files changed, 149 insertions(+) diff --git a/airbyte-api/src/main/openapi/config.yaml b/airbyte-api/src/main/openapi/config.yaml index a30a31c0796f..e9691ae1b4e0 100644 --- a/airbyte-api/src/main/openapi/config.yaml +++ b/airbyte-api/src/main/openapi/config.yaml @@ -168,6 +168,29 @@ paths: $ref: "#/components/responses/NotFoundResponse" "422": $ref: "#/components/responses/InvalidInputResponse" + /v1/workspaces/get_by_connection_id: + post: + tags: + - workspace + summary: Find workspace by connection id + operationId: getWorkspaceByConnectionId + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ConnectionIdRequestBody" + required: true + responses: + "200": + description: Successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/WorkspaceRead" + "404": + $ref: "#/components/responses/NotFoundResponse" + "422": + $ref: "#/components/responses/InvalidInputResponse" /v1/workspaces/update: post: tags: diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java b/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java index 87cf9448cd99..872b1735dbdf 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java @@ -253,6 +253,11 @@ public WorkspaceRead getWorkspaceBySlug(final SlugRequestBody slugRequestBody) { return execute(() -> workspacesHandler.getWorkspaceBySlug(slugRequestBody)); } + @Override + public WorkspaceRead getWorkspaceByConnectionId(final ConnectionIdRequestBody connectionIdRequestBody) { + return execute(() -> workspacesHandler.getWorkspaceByConnectionId(connectionIdRequestBody)); + } + @Override public WorkspaceRead updateWorkspace(final WorkspaceUpdate workspaceUpdate) { return execute(() -> workspacesHandler.updateWorkspace(workspaceUpdate)); diff --git a/airbyte-server/src/main/java/io/airbyte/server/handlers/WorkspacesHandler.java b/airbyte-server/src/main/java/io/airbyte/server/handlers/WorkspacesHandler.java index f6658c94be20..05b37a8341e8 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/handlers/WorkspacesHandler.java +++ b/airbyte-server/src/main/java/io/airbyte/server/handlers/WorkspacesHandler.java @@ -9,6 +9,7 @@ import com.google.common.base.Preconditions; import com.google.common.base.Strings; import io.airbyte.analytics.TrackingClientSingleton; +import io.airbyte.api.model.generated.ConnectionIdRequestBody; import io.airbyte.api.model.generated.ConnectionRead; import io.airbyte.api.model.generated.DestinationRead; import io.airbyte.api.model.generated.Geography; @@ -163,6 +164,11 @@ public WorkspaceRead getWorkspaceBySlug(final SlugRequestBody slugRequestBody) return buildWorkspaceRead(workspace); } + public WorkspaceRead getWorkspaceByConnectionId(final ConnectionIdRequestBody connectionIdRequestBody) { + final StandardWorkspace workspace = configRepository.getStandardWorkspaceFromConnection(connectionIdRequestBody.getConnectionId(), false); + return buildWorkspaceRead(workspace); + } + public WorkspaceRead updateWorkspace(final WorkspaceUpdate workspacePatch) throws ConfigNotFoundException, IOException, JsonValidationException { final UUID workspaceId = workspacePatch.getWorkspaceId(); diff --git a/airbyte-server/src/test/java/io/airbyte/server/handlers/WorkspacesHandlerTest.java b/airbyte-server/src/test/java/io/airbyte/server/handlers/WorkspacesHandlerTest.java index b9f64d12c2c7..466671991f58 100644 --- a/airbyte-server/src/test/java/io/airbyte/server/handlers/WorkspacesHandlerTest.java +++ b/airbyte-server/src/test/java/io/airbyte/server/handlers/WorkspacesHandlerTest.java @@ -16,6 +16,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.Lists; +import io.airbyte.api.model.generated.ConnectionIdRequestBody; import io.airbyte.api.model.generated.ConnectionRead; import io.airbyte.api.model.generated.ConnectionReadList; import io.airbyte.api.model.generated.DestinationRead; @@ -333,6 +334,28 @@ void testGetWorkspaceBySlug() throws JsonValidationException, ConfigNotFoundExce assertEquals(workspaceRead, workspacesHandler.getWorkspaceBySlug(slugRequestBody)); } + @Test + void testGetWorkspaceByConnectionId() { + final UUID connectionId = UUID.randomUUID(); + when(configRepository.getStandardWorkspaceFromConnection(connectionId, false)).thenReturn(workspace); + final ConnectionIdRequestBody connectionIdRequestBody = new ConnectionIdRequestBody().connectionId(connectionId); + final WorkspaceRead workspaceRead = new WorkspaceRead() + .workspaceId(workspace.getWorkspaceId()) + .customerId(workspace.getCustomerId()) + .email(TEST_EMAIL) + .name(workspace.getName()) + .slug(workspace.getSlug()) + .initialSetupComplete(workspace.getInitialSetupComplete()) + .displaySetupWizard(workspace.getDisplaySetupWizard()) + .news(workspace.getNews()) + .anonymousDataCollection(workspace.getAnonymousDataCollection()) + .securityUpdates(workspace.getSecurityUpdates()) + .notifications(NotificationConverter.toApiList(workspace.getNotifications())) + .defaultGeography(GEOGRAPHY_AUTO); + + assertEquals(workspaceRead, workspacesHandler.getWorkspaceByConnectionId(connectionIdRequestBody)); + } + @Test void testUpdateWorkspace() throws JsonValidationException, ConfigNotFoundException, IOException { final io.airbyte.api.model.generated.Notification apiNotification = generateApiNotification(); diff --git a/docs/reference/api/generated-api-html/index.html b/docs/reference/api/generated-api-html/index.html index 14e34fd42968..aa977cc55812 100644 --- a/docs/reference/api/generated-api-html/index.html +++ b/docs/reference/api/generated-api-html/index.html @@ -387,6 +387,7 @@

Workspace

  • post /v1/workspaces/create
  • post /v1/workspaces/delete
  • post /v1/workspaces/get
  • +
  • post /v1/workspaces/get_by_connection_id
  • post /v1/workspaces/get_by_slug
  • post /v1/workspaces/list
  • post /v1/workspaces/update
  • @@ -9758,6 +9759,97 @@

    Request body

    +

    Return type

    + + + + +

    Example data

    +
    Content-Type: application/json
    +
    {
    +  "news" : true,
    +  "webhookConfigs" : [ {
    +    "name" : "name",
    +    "id" : "046b6c7f-0b8a-43b9-b35d-6489e6daee91"
    +  }, {
    +    "name" : "name",
    +    "id" : "046b6c7f-0b8a-43b9-b35d-6489e6daee91"
    +  } ],
    +  "displaySetupWizard" : true,
    +  "initialSetupComplete" : true,
    +  "anonymousDataCollection" : true,
    +  "customerId" : "046b6c7f-0b8a-43b9-b35d-6489e6daee91",
    +  "name" : "name",
    +  "firstCompletedSync" : true,
    +  "feedbackDone" : true,
    +  "email" : "email",
    +  "slug" : "slug",
    +  "securityUpdates" : true,
    +  "notifications" : [ {
    +    "slackConfiguration" : {
    +      "webhook" : "webhook"
    +    },
    +    "sendOnSuccess" : false,
    +    "sendOnFailure" : true,
    +    "customerioConfiguration" : "{}"
    +  }, {
    +    "slackConfiguration" : {
    +      "webhook" : "webhook"
    +    },
    +    "sendOnSuccess" : false,
    +    "sendOnFailure" : true,
    +    "customerioConfiguration" : "{}"
    +  } ],
    +  "workspaceId" : "046b6c7f-0b8a-43b9-b35d-6489e6daee91"
    +}
    + +

    Produces

    + This API call produces the following media types according to the Accept request header; + the media type will be conveyed by the Content-Type response header. +
      +
    • application/json
    • +
    + +

    Responses

    +

    200

    + Successful operation + WorkspaceRead +

    404

    + Object with given id was not found. + NotFoundKnownExceptionInfo +

    422

    + Input failed validation + InvalidInputExceptionInfo + +
    +
    +
    + Up +
    post /v1/workspaces/get_by_connection_id
    +
    Find workspace by connection id (getWorkspaceByConnectionId)
    +
    + + +

    Consumes

    + This API call consumes the following media types via the Content-Type request header: +
      +
    • application/json
    • +
    + +

    Request body

    +
    +
    ConnectionIdRequestBody ConnectionIdRequestBody (required)
    + +
    Body Parameter
    + +
    + + + +

    Return type

    WorkspaceRead From 972a8c041900c5daf460b07dad1dc77b9c4c384e Mon Sep 17 00:00:00 2001 From: Akash Kulkarni <113392464+akashkulk@users.noreply.github.com> Date: Fri, 4 Nov 2022 14:38:26 -0700 Subject: [PATCH 63/73] Handling configuration exceptions in IntegrationRunner (#18989) * Hanlde error msgs in integration runner * Add ConfigErrorException * Some formatting --- .../exceptions/ConfigErrorException.java | 29 +++++ .../integrations/base/IntegrationRunner.java | 118 ++++++++++++------ .../source/relationaldb/AbstractDbSource.java | 1 - 3 files changed, 109 insertions(+), 39 deletions(-) create mode 100644 airbyte-commons/src/main/java/io/airbyte/commons/exceptions/ConfigErrorException.java diff --git a/airbyte-commons/src/main/java/io/airbyte/commons/exceptions/ConfigErrorException.java b/airbyte-commons/src/main/java/io/airbyte/commons/exceptions/ConfigErrorException.java new file mode 100644 index 000000000000..2f095f2f5c71 --- /dev/null +++ b/airbyte-commons/src/main/java/io/airbyte/commons/exceptions/ConfigErrorException.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.commons.exceptions; + +/** + * An exception that indicates that there is something wrong with the user's connector setup. This + * exception is caught and emits an AirbyteTraceMessage. + */ +public class ConfigErrorException extends RuntimeException { + + private final String displayMessage; + + public ConfigErrorException(final String displayMessage) { + super(displayMessage); + this.displayMessage = displayMessage; + } + + public ConfigErrorException(final String displayMessage, final Throwable exception) { + super(displayMessage, exception); + this.displayMessage = displayMessage; + } + + public String getDisplayMessage() { + return displayMessage; + } + +} diff --git a/airbyte-integrations/bases/base-java/src/main/java/io/airbyte/integrations/base/IntegrationRunner.java b/airbyte-integrations/bases/base-java/src/main/java/io/airbyte/integrations/base/IntegrationRunner.java index 19f577e1bc6b..f23e913d784c 100644 --- a/airbyte-integrations/bases/base-java/src/main/java/io/airbyte/integrations/base/IntegrationRunner.java +++ b/airbyte-integrations/bases/base-java/src/main/java/io/airbyte/integrations/base/IntegrationRunner.java @@ -9,11 +9,14 @@ import com.fasterxml.jackson.databind.JsonNode; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import io.airbyte.commons.exceptions.ConfigErrorException; +import io.airbyte.commons.exceptions.ConnectionErrorException; import io.airbyte.commons.io.IOs; import io.airbyte.commons.json.Jsons; import io.airbyte.commons.lang.Exceptions.Procedure; import io.airbyte.commons.string.Strings; import io.airbyte.commons.util.AutoCloseableIterator; +import io.airbyte.integrations.base.errors.messages.ErrorMessage; import io.airbyte.protocol.models.AirbyteConnectionStatus; import io.airbyte.protocol.models.AirbyteMessage; import io.airbyte.protocol.models.AirbyteMessage.Type; @@ -105,53 +108,92 @@ private void runInternal(final IntegrationConfig parsed) throws Exception { LOGGER.info("Command: {}", parsed.getCommand()); LOGGER.info("Integration config: {}", parsed); - switch (parsed.getCommand()) { - // common - case SPEC -> outputRecordCollector.accept(new AirbyteMessage().withType(Type.SPEC).withSpec(integration.spec())); - case CHECK -> { - final JsonNode config = parseConfig(parsed.getConfigPath()); - try { - validateConfig(integration.spec().getConnectionSpecification(), config, "CHECK"); - } catch (final Exception e) { - // if validation fails don't throw an exception, return a failed connection check message - outputRecordCollector.accept(new AirbyteMessage().withType(Type.CONNECTION_STATUS).withConnectionStatus( - new AirbyteConnectionStatus().withStatus(AirbyteConnectionStatus.Status.FAILED).withMessage(e.getMessage()))); - } + try { + switch (parsed.getCommand()) { + // common + case SPEC -> outputRecordCollector.accept(new AirbyteMessage().withType(Type.SPEC).withSpec(integration.spec())); + case CHECK -> { + final JsonNode config = parseConfig(parsed.getConfigPath()); + try { + validateConfig(integration.spec().getConnectionSpecification(), config, "CHECK"); + } catch (final Exception e) { + // if validation fails don't throw an exception, return a failed connection check message + outputRecordCollector.accept(new AirbyteMessage().withType(Type.CONNECTION_STATUS).withConnectionStatus( + new AirbyteConnectionStatus().withStatus(AirbyteConnectionStatus.Status.FAILED).withMessage(e.getMessage()))); + } - outputRecordCollector.accept(new AirbyteMessage().withType(Type.CONNECTION_STATUS).withConnectionStatus(integration.check(config))); - } - // source only - case DISCOVER -> { - final JsonNode config = parseConfig(parsed.getConfigPath()); - validateConfig(integration.spec().getConnectionSpecification(), config, "DISCOVER"); - outputRecordCollector.accept(new AirbyteMessage().withType(Type.CATALOG).withCatalog(source.discover(config))); - } - // todo (cgardens) - it is incongruous that that read and write return airbyte message (the - // envelope) while the other commands return what goes inside it. - case READ -> { - final JsonNode config = parseConfig(parsed.getConfigPath()); - validateConfig(integration.spec().getConnectionSpecification(), config, "READ"); - final ConfiguredAirbyteCatalog catalog = parseConfig(parsed.getCatalogPath(), ConfiguredAirbyteCatalog.class); - final Optional stateOptional = parsed.getStatePath().map(IntegrationRunner::parseConfig); - try (final AutoCloseableIterator messageIterator = source.read(config, catalog, stateOptional.orElse(null))) { - produceMessages(messageIterator); + outputRecordCollector.accept(new AirbyteMessage().withType(Type.CONNECTION_STATUS).withConnectionStatus(integration.check(config))); } - } - // destination only - case WRITE -> { - final JsonNode config = parseConfig(parsed.getConfigPath()); - validateConfig(integration.spec().getConnectionSpecification(), config, "WRITE"); - final ConfiguredAirbyteCatalog catalog = parseConfig(parsed.getCatalogPath(), ConfiguredAirbyteCatalog.class); - try (final AirbyteMessageConsumer consumer = destination.getConsumer(config, catalog, outputRecordCollector)) { - runConsumer(consumer); + // source only + case DISCOVER -> { + final JsonNode config = parseConfig(parsed.getConfigPath()); + validateConfig(integration.spec().getConnectionSpecification(), config, "DISCOVER"); + outputRecordCollector.accept(new AirbyteMessage().withType(Type.CATALOG).withCatalog(source.discover(config))); + } + // todo (cgardens) - it is incongruous that that read and write return airbyte message (the + // envelope) while the other commands return what goes inside it. + case READ -> { + final JsonNode config = parseConfig(parsed.getConfigPath()); + validateConfig(integration.spec().getConnectionSpecification(), config, "READ"); + final ConfiguredAirbyteCatalog catalog = parseConfig(parsed.getCatalogPath(), ConfiguredAirbyteCatalog.class); + final Optional stateOptional = parsed.getStatePath().map(IntegrationRunner::parseConfig); + try (final AutoCloseableIterator messageIterator = source.read(config, catalog, stateOptional.orElse(null))) { + produceMessages(messageIterator); + } + } + // destination only + case WRITE -> { + final JsonNode config = parseConfig(parsed.getConfigPath()); + validateConfig(integration.spec().getConnectionSpecification(), config, "WRITE"); + final ConfiguredAirbyteCatalog catalog = parseConfig(parsed.getCatalogPath(), ConfiguredAirbyteCatalog.class); + try (final AirbyteMessageConsumer consumer = destination.getConsumer(config, catalog, outputRecordCollector)) { + runConsumer(consumer); + } } + default -> throw new IllegalStateException("Unexpected value: " + parsed.getCommand()); } - default -> throw new IllegalStateException("Unexpected value: " + parsed.getCommand()); + } catch (final Exception e) { + final String displayMessage = getDisplayMessage(e); + // If the source connector throws a config error, a trace message with the relevant message should + // be surfaced. + if (isConfigError(e)) { + AirbyteTraceMessageUtility.emitConfigErrorTrace(e, displayMessage); + } + if (parsed.getCommand().equals(Command.CHECK)) { + // Currently, special handling is required for the SPEC case since the user display information in + // the trace message is + // not properly surfaced to the FE. In the future, we can remove this and just throw an exception. + outputRecordCollector + .accept( + new AirbyteMessage() + .withType(Type.CONNECTION_STATUS) + .withConnectionStatus( + new AirbyteConnectionStatus() + .withStatus(AirbyteConnectionStatus.Status.FAILED) + .withMessage(displayMessage))); + return; + } + throw e; } LOGGER.info("Completed integration: {}", integration.getClass().getName()); } + private boolean isConfigError(final Exception e) { + return e instanceof ConfigErrorException || e instanceof ConnectionErrorException; + } + + private String getDisplayMessage(final Exception e) { + if (e instanceof ConfigErrorException) { + return ((ConfigErrorException) e).getDisplayMessage(); + } else if (e instanceof ConnectionErrorException) { + final ConnectionErrorException connEx = (ConnectionErrorException) e; + return ErrorMessage.getErrorMessage(connEx.getStateCode(), connEx.getErrorCode(), connEx.getExceptionMessage(), e); + } else { + return "Could not connect with provided configuration. Error: " + e.getMessage(); + } + } + private void produceMessages(final AutoCloseableIterator messageIterator) throws Exception { watchForOrphanThreads( () -> messageIterator.forEachRemaining(outputRecordCollector), diff --git a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java index 7ea0ddcb8464..a02d4b8890be 100644 --- a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java +++ b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java @@ -7,7 +7,6 @@ import static io.airbyte.integrations.base.errors.messages.ErrorMessage.getErrorMessage; import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import io.airbyte.commons.exceptions.ConnectionErrorException; From 633531a882ec283792c1f719ab19c6146f067cf7 Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Fri, 4 Nov 2022 23:25:25 +0100 Subject: [PATCH 64/73] :window: :art: Fix banner link color (#18978) * Fix banner link color * Use inherit --- .../src/components/ui/Banner/AlertBanner.module.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/airbyte-webapp/src/components/ui/Banner/AlertBanner.module.scss b/airbyte-webapp/src/components/ui/Banner/AlertBanner.module.scss index a784d1ef788f..d5b38c740dad 100644 --- a/airbyte-webapp/src/components/ui/Banner/AlertBanner.module.scss +++ b/airbyte-webapp/src/components/ui/Banner/AlertBanner.module.scss @@ -9,10 +9,9 @@ z-index: 3; font-size: 12px; line-height: 30px; - color: colors.$black; & a { - color: colors.$black; + color: inherit; } } @@ -23,4 +22,5 @@ .red { background-color: colors.$red; + color: colors.$black; } From a53b9474d98d4daa1c10328e008f8170adbbd57a Mon Sep 17 00:00:00 2001 From: Akash Kulkarni <113392464+akashkulk@users.noreply.github.com> Date: Fri, 4 Nov 2022 16:14:50 -0700 Subject: [PATCH 65/73] Migrating InvalidCursorException -> ConfigErrorException (#18995) * Migrate InvalidCursorInfo -> ConfigErrorException --- .../source/postgres/PostgresSourceTest.java | 4 +- .../source/relationaldb/AbstractDbSource.java | 90 ++++++++----------- ...eption.java => InvalidCursorInfoUtil.java} | 8 +- 3 files changed, 45 insertions(+), 57 deletions(-) rename airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/{InvalidCursorException.java => InvalidCursorInfoUtil.java} (64%) diff --git a/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/PostgresSourceTest.java b/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/PostgresSourceTest.java index 3af383b76034..99712900e88d 100644 --- a/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/PostgresSourceTest.java +++ b/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/PostgresSourceTest.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import io.airbyte.commons.exceptions.ConfigErrorException; import io.airbyte.commons.io.IOs; import io.airbyte.commons.json.Jsons; import io.airbyte.commons.string.Strings; @@ -26,7 +27,6 @@ import io.airbyte.db.factory.DSLContextFactory; import io.airbyte.db.factory.DatabaseDriver; import io.airbyte.db.jdbc.JdbcUtils; -import io.airbyte.integrations.source.relationaldb.InvalidCursorException; import io.airbyte.protocol.models.AirbyteCatalog; import io.airbyte.protocol.models.AirbyteMessage; import io.airbyte.protocol.models.AirbyteStream; @@ -526,7 +526,7 @@ public void tableWithInvalidCursorShouldThrowException() throws Exception { new ConfiguredAirbyteCatalog().withStreams(Collections.singletonList(tableWithInvalidCursorType)); final Throwable throwable = catchThrowable(() -> MoreIterators.toSet(new PostgresSource().read(config, configuredAirbyteCatalog, null))); - assertThat(throwable).isInstanceOf(InvalidCursorException.class) + assertThat(throwable).isInstanceOf(ConfigErrorException.class) .hasMessageContaining( "The following tables have invalid columns selected as cursor, please select a column with a well-defined ordering as a cursor. {tableName='public.test_table', cursorColumnName='id', cursorSqlType=OTHER}"); } finally { diff --git a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java index a02d4b8890be..6fb801b4d8b9 100644 --- a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java +++ b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/AbstractDbSource.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import io.airbyte.commons.exceptions.ConfigErrorException; import io.airbyte.commons.exceptions.ConnectionErrorException; import io.airbyte.commons.features.EnvVariableFeatureFlags; import io.airbyte.commons.features.FeatureFlags; @@ -26,7 +27,7 @@ import io.airbyte.integrations.base.AirbyteStreamNameNamespacePair; import io.airbyte.integrations.base.AirbyteTraceMessageUtility; import io.airbyte.integrations.base.Source; -import io.airbyte.integrations.source.relationaldb.InvalidCursorException.InvalidCursorInfo; +import io.airbyte.integrations.source.relationaldb.InvalidCursorInfoUtil.InvalidCursorInfo; import io.airbyte.integrations.source.relationaldb.models.DbState; import io.airbyte.integrations.source.relationaldb.state.StateManager; import io.airbyte.integrations.source.relationaldb.state.StateManagerFactory; @@ -142,56 +143,42 @@ public AirbyteCatalog discover(final JsonNode config) throws Exception { */ @Override public AutoCloseableIterator read(final JsonNode config, - final ConfiguredAirbyteCatalog catalog, - final JsonNode state) - throws Exception { - try { - final StateManager stateManager = - StateManagerFactory.createStateManager(getSupportedStateType(config), - deserializeInitialState(state, config), catalog); - final Instant emittedAt = Instant.now(); - - final Database database = createDatabaseInternal(config); - - final Map>> fullyQualifiedTableNameToInfo = - discoverWithoutSystemTables(database) - .stream() - .collect(Collectors.toMap(t -> String.format("%s.%s", t.getNameSpace(), t.getName()), - Function - .identity())); - - validateCursorFieldForIncrementalTables(fullyQualifiedTableNameToInfo, catalog); - - final List> incrementalIterators = - getIncrementalIterators(database, catalog, fullyQualifiedTableNameToInfo, stateManager, - emittedAt); - final List> fullRefreshIterators = - getFullRefreshIterators(database, catalog, fullyQualifiedTableNameToInfo, stateManager, - emittedAt); - final List> iteratorList = Stream - .of(incrementalIterators, fullRefreshIterators) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - - return AutoCloseableIterators - .appendOnClose(AutoCloseableIterators.concatWithEagerClose(iteratorList), () -> { - LOGGER.info("Closing database connection pool."); - Exceptions.toRuntime(this::close); - LOGGER.info("Closed database connection pool."); - }); - } catch (final Exception exception) { - if (isConfigError(exception)) { - AirbyteTraceMessageUtility.emitConfigErrorTrace(exception, exception.getMessage()); - } - throw exception; - } - } + final ConfiguredAirbyteCatalog catalog, + final JsonNode state) + throws Exception { + final StateManager stateManager = + StateManagerFactory.createStateManager(getSupportedStateType(config), + deserializeInitialState(state, config), catalog); + final Instant emittedAt = Instant.now(); + + final Database database = createDatabaseInternal(config); + + final Map>> fullyQualifiedTableNameToInfo = + discoverWithoutSystemTables(database) + .stream() + .collect(Collectors.toMap(t -> String.format("%s.%s", t.getNameSpace(), t.getName()), + Function + .identity())); + + validateCursorFieldForIncrementalTables(fullyQualifiedTableNameToInfo, catalog); + + final List> incrementalIterators = + getIncrementalIterators(database, catalog, fullyQualifiedTableNameToInfo, stateManager, + emittedAt); + final List> fullRefreshIterators = + getFullRefreshIterators(database, catalog, fullyQualifiedTableNameToInfo, stateManager, + emittedAt); + final List> iteratorList = Stream + .of(incrementalIterators, fullRefreshIterators) + .flatMap(Collection::stream) + .collect(Collectors.toList()); - private boolean isConfigError(final Exception exception) { - // For now, enhanced error details should only be shown for InvalidCursorException. In the future, - // enhanced error messages will exist for - // additional error types. - return exception instanceof InvalidCursorException; + return AutoCloseableIterators + .appendOnClose(AutoCloseableIterators.concatWithEagerClose(iteratorList), () -> { + LOGGER.info("Closing database connection pool."); + Exceptions.toRuntime(this::close); + LOGGER.info("Closed database connection pool."); + }); } private void validateCursorFieldForIncrementalTables( @@ -230,7 +217,8 @@ private void validateCursorFieldForIncrementalTables( } if (!tablesWithInvalidCursor.isEmpty()) { - throw new InvalidCursorException(tablesWithInvalidCursor); + throw new ConfigErrorException( + InvalidCursorInfoUtil.getInvalidCursorConfigMessage(tablesWithInvalidCursor)) ; } } diff --git a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/InvalidCursorException.java b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/InvalidCursorInfoUtil.java similarity index 64% rename from airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/InvalidCursorException.java rename to airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/InvalidCursorInfoUtil.java index 70237f4763bc..42d4b9dedbec 100644 --- a/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/InvalidCursorException.java +++ b/airbyte-integrations/connectors/source-relational-db/src/main/java/io/airbyte/integrations/source/relationaldb/InvalidCursorInfoUtil.java @@ -7,12 +7,12 @@ import java.util.List; import java.util.stream.Collectors; -public class InvalidCursorException extends RuntimeException { +public class InvalidCursorInfoUtil { - public InvalidCursorException(final List tablesWithInvalidCursor) { - super("The following tables have invalid columns selected as cursor, please select a column with a well-defined ordering as a cursor. " + public static String getInvalidCursorConfigMessage(final List tablesWithInvalidCursor) { + return "The following tables have invalid columns selected as cursor, please select a column with a well-defined ordering as a cursor. " + tablesWithInvalidCursor.stream().map(InvalidCursorInfo::toString) - .collect(Collectors.joining(","))); + .collect(Collectors.joining(",")); } public record InvalidCursorInfo(String tableName, String cursorColumnName, String cursorSqlType) { From 22efa070c635597eba5af331ba9ca167970ccbef Mon Sep 17 00:00:00 2001 From: Benoit Moriceau Date: Fri, 4 Nov 2022 16:54:35 -0700 Subject: [PATCH 66/73] Bmoric/extract source api (#18944) * Extract Operation API * Extract scheduler API * Format * extract source api --- .../java/io/airbyte/server/ServerApp.java | 1 + .../java/io/airbyte/server/ServerFactory.java | 13 ++- .../airbyte/server/apis/ConfigurationApi.java | 63 +++++++++++--- .../server/apis/SourceApiController.java | 84 +++++++++++++++++++ .../server/apis/binders/SourceApiBinder.java | 21 +++++ .../apis/factories/SourceApiFactory.java | 32 +++++++ 6 files changed, 199 insertions(+), 15 deletions(-) create mode 100644 airbyte-server/src/main/java/io/airbyte/server/apis/SourceApiController.java create mode 100644 airbyte-server/src/main/java/io/airbyte/server/apis/binders/SourceApiBinder.java create mode 100644 airbyte-server/src/main/java/io/airbyte/server/apis/factories/SourceApiFactory.java diff --git a/airbyte-server/src/main/java/io/airbyte/server/ServerApp.java b/airbyte-server/src/main/java/io/airbyte/server/ServerApp.java index c18b5eb84f64..98332508930a 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/ServerApp.java +++ b/airbyte-server/src/main/java/io/airbyte/server/ServerApp.java @@ -351,6 +351,7 @@ public static ServerRunnable getServer(final ServerFactory apiFactory, openApiConfigHandler, operationsHandler, schedulerHandler, + sourceHandler, workspacesHandler); } diff --git a/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java b/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java index 04fa4436f9b6..bc5048a098aa 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java +++ b/airbyte-server/src/main/java/io/airbyte/server/ServerFactory.java @@ -29,7 +29,7 @@ import io.airbyte.server.apis.OpenapiApiController; import io.airbyte.server.apis.OperationApiController; import io.airbyte.server.apis.SchedulerApiController; -import io.airbyte.server.apis.SourceOauthApiController; +import io.airbyte.server.apis.SourceApiController; import io.airbyte.server.apis.binders.AttemptApiBinder; import io.airbyte.server.apis.binders.ConnectionApiBinder; import io.airbyte.server.apis.binders.DbMigrationBinder; @@ -44,6 +44,7 @@ import io.airbyte.server.apis.binders.OpenapiApiBinder; import io.airbyte.server.apis.binders.OperationApiBinder; import io.airbyte.server.apis.binders.SchedulerApiBinder; +import io.airbyte.server.apis.binders.SourceApiBinder; import io.airbyte.server.apis.binders.SourceOauthApiBinder; import io.airbyte.server.apis.factories.AttemptApiFactory; import io.airbyte.server.apis.factories.ConnectionApiFactory; @@ -59,6 +60,7 @@ import io.airbyte.server.apis.factories.OpenapiApiFactory; import io.airbyte.server.apis.factories.OperationApiFactory; import io.airbyte.server.apis.factories.SchedulerApiFactory; +import io.airbyte.server.apis.factories.SourceApiFactory; import io.airbyte.server.apis.factories.SourceOauthApiFactory; import io.airbyte.server.handlers.AttemptHandler; import io.airbyte.server.handlers.ConnectionsHandler; @@ -72,6 +74,7 @@ import io.airbyte.server.handlers.OpenApiConfigHandler; import io.airbyte.server.handlers.OperationsHandler; import io.airbyte.server.handlers.SchedulerHandler; +import io.airbyte.server.handlers.SourceHandler; import io.airbyte.server.handlers.WorkspacesHandler; import io.airbyte.server.scheduler.EventRunner; import io.airbyte.server.scheduler.SynchronousSchedulerClient; @@ -112,6 +115,7 @@ ServerRunnable create(final SynchronousSchedulerClient synchronousSchedulerClien final OpenApiConfigHandler openApiConfigHandler, final OperationsHandler operationsHandler, final SchedulerHandler schedulerHandler, + final SourceHandler sourceHandler, final WorkspacesHandler workspacesHandler); class Api implements ServerFactory { @@ -145,6 +149,7 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul final OpenApiConfigHandler openApiConfigHandler, final OperationsHandler operationsHandler, final SchedulerHandler schedulerHandler, + final SourceHandler sourceHandler, final WorkspacesHandler workspacesHandler) { final Map mdc = MDC.getCopyOfContextMap(); @@ -203,6 +208,8 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul SchedulerApiFactory.setValues(schedulerHandler); + SourceApiFactory.setValues(schedulerHandler, sourceHandler); + // server configurations final Set> componentClasses = Set.of( ConfigurationApi.class, @@ -220,7 +227,8 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul OpenapiApiController.class, OperationApiController.class, SchedulerApiController.class, - SourceOauthApiController.class); + SourceApiController.class, + SourceOauthApiFactory.class); final Set components = Set.of( new CorsFilter(), @@ -239,6 +247,7 @@ public ServerRunnable create(final SynchronousSchedulerClient synchronousSchedul new OpenapiApiBinder(), new OperationApiBinder(), new SchedulerApiBinder(), + new SourceApiBinder(), new SourceOauthApiBinder()); // construct server diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java b/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java index 872b1735dbdf..e58f68c7d3a7 100644 --- a/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/ConfigurationApi.java @@ -447,57 +447,94 @@ public InternalOperationResult setWorkflowInAttempt(final SetWorkflowInAttemptRe // SOURCE IMPLEMENTATION + /** + * This implementation has been moved to {@link SourceApiController}. Since the path of + * {@link SourceApiController} is more granular, it will override this implementation + */ @Override public SourceRead createSource(final SourceCreate sourceCreate) { - return execute(() -> sourceHandler.createSource(sourceCreate)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SourceApiController}. Since the path of + * {@link SourceApiController} is more granular, it will override this implementation + */ @Override public SourceRead updateSource(final SourceUpdate sourceUpdate) { - return execute(() -> sourceHandler.updateSource(sourceUpdate)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SourceApiController}. Since the path of + * {@link SourceApiController} is more granular, it will override this implementation + */ @Override public SourceReadList listSourcesForWorkspace(final WorkspaceIdRequestBody workspaceIdRequestBody) { - return execute(() -> sourceHandler.listSourcesForWorkspace(workspaceIdRequestBody)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SourceApiController}. Since the path of + * {@link SourceApiController} is more granular, it will override this implementation + */ @Override public SourceReadList searchSources(final SourceSearch sourceSearch) { - return execute(() -> sourceHandler.searchSources(sourceSearch)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SourceApiController}. Since the path of + * {@link SourceApiController} is more granular, it will override this implementation + */ @Override public SourceRead getSource(final SourceIdRequestBody sourceIdRequestBody) { - return execute(() -> sourceHandler.getSource(sourceIdRequestBody)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SourceApiController}. Since the path of + * {@link SourceApiController} is more granular, it will override this implementation + */ @Override public void deleteSource(final SourceIdRequestBody sourceIdRequestBody) { - execute(() -> { - sourceHandler.deleteSource(sourceIdRequestBody); - return null; - }); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SourceApiController}. Since the path of + * {@link SourceApiController} is more granular, it will override this implementation + */ @Override public SourceRead cloneSource(final SourceCloneRequestBody sourceCloneRequestBody) { - return execute(() -> sourceHandler.cloneSource(sourceCloneRequestBody)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SourceApiController}. Since the path of + * {@link SourceApiController} is more granular, it will override this implementation + */ @Override public CheckConnectionRead checkConnectionToSource(final SourceIdRequestBody sourceIdRequestBody) { - return execute(() -> schedulerHandler.checkSourceConnectionFromSourceId(sourceIdRequestBody)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SourceApiController}. Since the path of + * {@link SourceApiController} is more granular, it will override this implementation + */ @Override public CheckConnectionRead checkConnectionToSourceForUpdate(final SourceUpdate sourceUpdate) { - return execute(() -> schedulerHandler.checkSourceConnectionFromSourceIdForUpdate(sourceUpdate)); + throw new NotImplementedException(); } + /** + * This implementation has been moved to {@link SourceApiController}. Since the path of + * {@link SourceApiController} is more granular, it will override this implementation + */ @Override public SourceDiscoverSchemaRead discoverSchemaForSource(final SourceDiscoverSchemaRequestBody discoverSchemaRequestBody) { - return execute(() -> schedulerHandler.discoverSchemaForSourceFromSourceId(discoverSchemaRequestBody)); + throw new NotImplementedException(); } // DB MIGRATION diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/SourceApiController.java b/airbyte-server/src/main/java/io/airbyte/server/apis/SourceApiController.java new file mode 100644 index 000000000000..4086da7f60f2 --- /dev/null +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/SourceApiController.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.server.apis; + +import io.airbyte.api.generated.SourceApi; +import io.airbyte.api.model.generated.CheckConnectionRead; +import io.airbyte.api.model.generated.SourceCloneRequestBody; +import io.airbyte.api.model.generated.SourceCreate; +import io.airbyte.api.model.generated.SourceDiscoverSchemaRead; +import io.airbyte.api.model.generated.SourceDiscoverSchemaRequestBody; +import io.airbyte.api.model.generated.SourceIdRequestBody; +import io.airbyte.api.model.generated.SourceRead; +import io.airbyte.api.model.generated.SourceReadList; +import io.airbyte.api.model.generated.SourceSearch; +import io.airbyte.api.model.generated.SourceUpdate; +import io.airbyte.api.model.generated.WorkspaceIdRequestBody; +import io.airbyte.server.handlers.SchedulerHandler; +import io.airbyte.server.handlers.SourceHandler; +import javax.ws.rs.Path; +import lombok.AllArgsConstructor; + +@Path("/v1/sources") +@AllArgsConstructor +public class SourceApiController implements SourceApi { + + private final SchedulerHandler schedulerHandler; + private final SourceHandler sourceHandler; + + @Override + public CheckConnectionRead checkConnectionToSource(final SourceIdRequestBody sourceIdRequestBody) { + return ConfigurationApi.execute(() -> schedulerHandler.checkSourceConnectionFromSourceId(sourceIdRequestBody)); + } + + @Override + public CheckConnectionRead checkConnectionToSourceForUpdate(final SourceUpdate sourceUpdate) { + return ConfigurationApi.execute(() -> schedulerHandler.checkSourceConnectionFromSourceIdForUpdate(sourceUpdate)); + } + + @Override + public SourceRead cloneSource(final SourceCloneRequestBody sourceCloneRequestBody) { + return ConfigurationApi.execute(() -> sourceHandler.cloneSource(sourceCloneRequestBody)); + } + + @Override + public SourceRead createSource(final SourceCreate sourceCreate) { + return ConfigurationApi.execute(() -> sourceHandler.createSource(sourceCreate)); + } + + @Override + public void deleteSource(final SourceIdRequestBody sourceIdRequestBody) { + ConfigurationApi.execute(() -> { + sourceHandler.deleteSource(sourceIdRequestBody); + return null; + }); + } + + @Override + public SourceDiscoverSchemaRead discoverSchemaForSource(final SourceDiscoverSchemaRequestBody sourceDiscoverSchemaRequestBody) { + return ConfigurationApi.execute(() -> schedulerHandler.discoverSchemaForSourceFromSourceId(sourceDiscoverSchemaRequestBody)); + } + + @Override + public SourceRead getSource(final SourceIdRequestBody sourceIdRequestBody) { + return ConfigurationApi.execute(() -> sourceHandler.getSource(sourceIdRequestBody)); + } + + @Override + public SourceReadList listSourcesForWorkspace(final WorkspaceIdRequestBody workspaceIdRequestBody) { + return ConfigurationApi.execute(() -> sourceHandler.listSourcesForWorkspace(workspaceIdRequestBody)); + } + + @Override + public SourceReadList searchSources(final SourceSearch sourceSearch) { + return ConfigurationApi.execute(() -> sourceHandler.searchSources(sourceSearch)); + } + + @Override + public SourceRead updateSource(final SourceUpdate sourceUpdate) { + return ConfigurationApi.execute(() -> sourceHandler.updateSource(sourceUpdate)); + } + +} diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/binders/SourceApiBinder.java b/airbyte-server/src/main/java/io/airbyte/server/apis/binders/SourceApiBinder.java new file mode 100644 index 000000000000..9707ee1d1477 --- /dev/null +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/binders/SourceApiBinder.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.server.apis.binders; + +import io.airbyte.server.apis.SourceApiController; +import io.airbyte.server.apis.factories.SourceApiFactory; +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.process.internal.RequestScoped; + +public class SourceApiBinder extends AbstractBinder { + + @Override + protected void configure() { + bindFactory(SourceApiFactory.class) + .to(SourceApiController.class) + .in(RequestScoped.class); + } + +} diff --git a/airbyte-server/src/main/java/io/airbyte/server/apis/factories/SourceApiFactory.java b/airbyte-server/src/main/java/io/airbyte/server/apis/factories/SourceApiFactory.java new file mode 100644 index 000000000000..aceda0580dde --- /dev/null +++ b/airbyte-server/src/main/java/io/airbyte/server/apis/factories/SourceApiFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 Airbyte, Inc., all rights reserved. + */ + +package io.airbyte.server.apis.factories; + +import io.airbyte.server.apis.SourceApiController; +import io.airbyte.server.handlers.SchedulerHandler; +import io.airbyte.server.handlers.SourceHandler; +import org.glassfish.hk2.api.Factory; + +public class SourceApiFactory implements Factory { + + private static SchedulerHandler schedulerHandler; + private static SourceHandler sourceHandler; + + public static void setValues(final SchedulerHandler schedulerHandler, final SourceHandler sourceHandler) { + SourceApiFactory.schedulerHandler = schedulerHandler; + SourceApiFactory.sourceHandler = sourceHandler; + } + + @Override + public SourceApiController provide() { + return new SourceApiController(schedulerHandler, sourceHandler); + } + + @Override + public void dispose(final SourceApiController instance) { + /* no op */ + } + +} From 16b240c7260fd31e833a273800965a6e84fa7793 Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Sat, 5 Nov 2022 01:01:17 +0100 Subject: [PATCH 67/73] :window: :tada: Load credits consumption separate (#18986) * Load credits consumption separate * rotate(90deg) --- airbyte-webapp/src/packages/cloud/locales/en.json | 1 + .../credits/CreditsPage/CreditsPage.module.scss | 9 +++++++++ .../views/credits/CreditsPage/CreditsPage.tsx | 15 ++++++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/airbyte-webapp/src/packages/cloud/locales/en.json b/airbyte-webapp/src/packages/cloud/locales/en.json index a1770af77576..a2b1dff32fdd 100644 --- a/airbyte-webapp/src/packages/cloud/locales/en.json +++ b/airbyte-webapp/src/packages/cloud/locales/en.json @@ -130,6 +130,7 @@ "credits.date": "Date", "credits.amount": "Credits", + "credits.loadingCreditsUsage": "Loading credits usage …", "credits.usagePerConnection": "Usage per connection", "credits.connection": "Connection", "credits.usage": "Usage", diff --git a/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/CreditsPage.module.scss b/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/CreditsPage.module.scss index 454423237ab9..18a91de2b6f8 100644 --- a/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/CreditsPage.module.scss +++ b/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/CreditsPage.module.scss @@ -7,3 +7,12 @@ .emailVerificationHint { margin-bottom: variables.$spacing-md; } + +.creditUsageLoading { + display: flex; + flex-direction: column; + gap: variables.$spacing-md; + justify-content: center; + align-items: center; + margin: variables.$spacing-2xl auto; +} diff --git a/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/CreditsPage.tsx b/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/CreditsPage.tsx index 733efafbe672..8311dad8824e 100644 --- a/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/CreditsPage.tsx +++ b/airbyte-webapp/src/packages/cloud/views/credits/CreditsPage/CreditsPage.tsx @@ -4,6 +4,8 @@ import { FormattedMessage } from "react-intl"; import { HeadTitle } from "components/common/HeadTitle"; import { MainPageWithScroll } from "components/common/MainPageWithScroll"; import { PageHeader } from "components/ui/PageHeader"; +import { Spinner } from "components/ui/Spinner"; +import { Text } from "components/ui/Text"; import { PageTrackingCodes, useTrackPage } from "hooks/services/Analytics"; import { useAuthService } from "packages/cloud/services/auth/AuthService"; @@ -24,7 +26,18 @@ const CreditsPage: React.FC = () => {
    {!emailVerified && } - + + + + + +
    + } + > + + ); From e2980492228bfba1357083f4f157d37eb62d0a9f Mon Sep 17 00:00:00 2001 From: Sophia Wiley <106352739+sophia-wiley@users.noreply.github.com> Date: Fri, 4 Nov 2022 18:33:25 -0700 Subject: [PATCH 68/73] Edit multi-cloud docs (#18972) Merging now to fix a couple of mistakes, but feel free to leave more comments on this PR. --- .../getting-started-with-airbyte-cloud.md | 9 +++++---- docs/cloud/managing-airbyte-cloud.md | 19 ++++++++----------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/docs/cloud/getting-started-with-airbyte-cloud.md b/docs/cloud/getting-started-with-airbyte-cloud.md index d0cebb451707..93e02469ecdd 100644 --- a/docs/cloud/getting-started-with-airbyte-cloud.md +++ b/docs/cloud/getting-started-with-airbyte-cloud.md @@ -183,20 +183,21 @@ Verify the sync by checking the logs: 3. Check the data at your destination. If you added a Destination Stream Prefix while setting up the connection, make sure to search for the stream name with the prefix. ## Allowlist IP address - -Depending on your data residency location, you may need to allowlist the following IP addresses to enable access to Airbyte: +Depending on your [data residency](https://docs.airbyte.com/cloud/managing-airbyte-cloud#choose-your-default-data-residency) location, you may need to allowlist the following IP addresses to enable access to Airbyte: ### United States and Airbyte Default -#### GCP region: us-west2 +#### GCP region: us-west3 * 34.106.109.131 * 34.106.196.165 * 34.106.60.246 ### European Union -#### AWS region: eu-west-3 +#### GCP region: us-west3 * 34.106.109.131 * 34.106.196.165 * 34.106.60.246 + +#### AWS region: eu-west-3 * 13.37.4.46 * 13.37.142.60 * 35.181.124.238 diff --git a/docs/cloud/managing-airbyte-cloud.md b/docs/cloud/managing-airbyte-cloud.md index faa3a4c93497..ab9482aacee8 100644 --- a/docs/cloud/managing-airbyte-cloud.md +++ b/docs/cloud/managing-airbyte-cloud.md @@ -87,20 +87,15 @@ To switch between workspaces: ### Choose your default data residency Default data residency allows you to choose where your data is processed. When you set the default data residency, it is applied to all new connections, but it does not affect existing connections. -For individual connections, you can choose a data residency that is different from the default. You can do this in the [connection settings](#choose-the-data-residency-for-a-connection) or when you create a [new connection](https://docs.airbyte.com/cloud/getting-started-with-airbyte-cloud#set-up-a-connection). - -:::note - -Your data is processed in the chosen residency, but some data is still stored in the US. - -::: +Your data is processed on a data plane in the chosen data residency, but configuration data, like data associated with sync mode, cursor, and primary key, is stored on our control plane in the US. Because of this, data that must stay in the chosen data residency should not be used as a stream’s cursor or primary key. +For individual connections, you can choose a data residency that is different from the default. You can do this in the [connection settings](#choose-the-data-residency-for-a-connection) or when you create a [new connection](https://docs.airbyte.com/cloud/getting-started-with-airbyte-cloud#set-up-a-connection). To choose your default data residency: 1. On the [Airbyte Cloud](http://cloud.airbyte.io) dashboard, click **Settings** in the navigation bar. -2. In the Workspace settings sidebar, click **Default Data Residency**. +2. In the Workspace settings sidebar, click **Data Residency**. 3. Click the dropdown and choose the location for your default data residency. @@ -288,7 +283,9 @@ To display **Connection State**: The **Connection State** displays. ## Choose the data residency for a connection -To choose the data residency for an existing connection: +You can choose the data residency for your connection in the connection settings. You can also choose data residency when creating a [new connection](https://docs.airbyte.com/cloud/getting-started-with-airbyte-cloud#set-up-a-connection), or you can set the [default data residency](#choose-your-default-data-residency) for your workspace. + +To choose the data residency for your connection: 1. On the [Airbyte Cloud](http://cloud.airbyte.io) dashboard, click **Connections** in the navigation bar and then click the connection that you want to change. @@ -299,8 +296,8 @@ To choose the data residency for an existing connection: 3. Click the **Data residency** dropdown and choose the location for your default data residency. :::note - -You can also choose data residency when creating a [new connection](https://docs.airbyte.com/cloud/getting-started-with-airbyte-cloud#set-up-a-connection), or you can set the [default data residency](#choose-your-default-data-residency) for all of your connections. + +Changes to data residency will not affect any currently running sync. ::: From a5bcea9b9ed5d7b9dce0ab3e3fa7de68a9973ed0 Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants <36314070+artem1205@users.noreply.github.com> Date: Sat, 5 Nov 2022 14:39:04 +0100 Subject: [PATCH 69/73] =?UTF-8?q?=F0=9F=90=9B=20Source=20Facebook=20Market?= =?UTF-8?q?ing:=20handle=20FacebookBadObjectError=20(#18971)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🐛 Source Facebook Marketing: handle FacebookBadObjectError * 🐛 Source Facebook Marketing: bump version; update docs * auto-bump connector version Co-authored-by: Octavia Squidington III --- .../main/resources/seed/source_definitions.yaml | 2 +- .../src/main/resources/seed/source_specs.yaml | 2 +- .../source-facebook-marketing/Dockerfile | 2 +- .../streams/async_job.py | 2 +- .../streams/base_insight_streams.py | 15 ++++++++++++--- docs/integrations/sources/facebook-marketing.md | 1 + 6 files changed, 17 insertions(+), 7 deletions(-) diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index 0d47201322d7..60af228a3740 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -350,7 +350,7 @@ - name: Facebook Marketing sourceDefinitionId: e7778cfc-e97c-4458-9ecb-b4f2bba8946c dockerRepository: airbyte/source-facebook-marketing - dockerImageTag: 0.2.71 + dockerImageTag: 0.2.72 documentationUrl: https://docs.airbyte.com/integrations/sources/facebook-marketing icon: facebook.svg sourceType: api diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 0b7e0d75267d..15a3c8030b74 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -2992,7 +2992,7 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] -- dockerImage: "airbyte/source-facebook-marketing:0.2.71" +- dockerImage: "airbyte/source-facebook-marketing:0.2.72" spec: documentationUrl: "https://docs.airbyte.com/integrations/sources/facebook-marketing" changelogUrl: "https://docs.airbyte.com/integrations/sources/facebook-marketing" diff --git a/airbyte-integrations/connectors/source-facebook-marketing/Dockerfile b/airbyte-integrations/connectors/source-facebook-marketing/Dockerfile index 960519b2afed..5628c15c53eb 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/Dockerfile +++ b/airbyte-integrations/connectors/source-facebook-marketing/Dockerfile @@ -13,5 +13,5 @@ ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.2.71 +LABEL io.airbyte.version=0.2.72 LABEL io.airbyte.name=airbyte/source-facebook-marketing diff --git a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/async_job.py b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/async_job.py index 9f912e1835d8..8ab7cd6c6b76 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/async_job.py +++ b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/async_job.py @@ -27,7 +27,7 @@ # Also, it does not happen while making a call to the API, but later - when parsing the result, # that's why a retry is added to `get_results()` instead of extending the existing retry of `api.call()` with `FacebookBadObjectError`. -backoff_policy = retry_pattern(backoff.expo, FacebookBadObjectError, max_tries=5, factor=5) +backoff_policy = retry_pattern(backoff.expo, FacebookBadObjectError, max_tries=10, factor=5) def update_in_batch(api: FacebookAdsApi, jobs: List["AsyncJob"]): diff --git a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/base_insight_streams.py b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/base_insight_streams.py index 1c074a33be4f..55d4898f2b0c 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/base_insight_streams.py +++ b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/base_insight_streams.py @@ -7,10 +7,12 @@ import airbyte_cdk.sources.utils.casing as casing import pendulum -from airbyte_cdk.models import SyncMode +from airbyte_cdk.models import FailureType, SyncMode from airbyte_cdk.sources.streams.core import package_name_from_class from airbyte_cdk.sources.utils.schema_helpers import ResourceSchemaLoader +from airbyte_cdk.utils import AirbyteTracedException from cached_property import cached_property +from facebook_business.exceptions import FacebookBadObjectError from source_facebook_marketing.streams.async_job import AsyncJob, InsightAsyncJob from source_facebook_marketing.streams.async_job_manager import InsightAsyncJobManager @@ -112,8 +114,15 @@ def read_records( ) -> Iterable[Mapping[str, Any]]: """Waits for current job to finish (slice) and yield its result""" job = stream_slice["insight_job"] - for obj in job.get_result(): - yield obj.export_all_data() + try: + for obj in job.get_result(): + yield obj.export_all_data() + except FacebookBadObjectError as e: + raise AirbyteTracedException( + message=f"API error occurs on Facebook side during job: {job}, wrong (empty) response received with errors: {e} " + f"Please try again later", + failure_type=FailureType.system_error, + ) from e self._completed_slices.add(job.interval.start) if job.interval.start == self._next_cursor_value: diff --git a/docs/integrations/sources/facebook-marketing.md b/docs/integrations/sources/facebook-marketing.md index 25caeb26f633..e67aa3772cb0 100644 --- a/docs/integrations/sources/facebook-marketing.md +++ b/docs/integrations/sources/facebook-marketing.md @@ -133,6 +133,7 @@ Please be informed that the connector uses the `lookback_window` parameter to pe | Version | Date | Pull Request | Subject | |:--------|:-----------|:---------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0.2.72 | 2022-11-04 | [18971](https://github.com/airbytehq/airbyte/pull/18971) | handle FacebookBadObjectError for empty results on async jobs | | 0.2.71 | 2022-10-31 | [18734](https://github.com/airbytehq/airbyte/pull/18734) | Reduce request record limit on retry | | 0.2.70 | 2022-10-26 | [18045](https://github.com/airbytehq/airbyte/pull/18045) | Upgrade FB SDK to v15.0 | | 0.2.69 | 2022-10-17 | [18045](https://github.com/airbytehq/airbyte/pull/18045) | Remove "pixel" field from the Custom Conversions stream schema | From 9c39c0e04539c1eb0b3d9de3f2d9561a87f63b4c Mon Sep 17 00:00:00 2001 From: Eugene Date: Sat, 5 Nov 2022 17:55:06 +0200 Subject: [PATCH 70/73] Fixed tests for destination connectors (#19007) * Fixed tests for destination connectors --- .../destination/DestinationAcceptanceTest.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/airbyte-integrations/bases/standard-destination-test/src/main/java/io/airbyte/integrations/standardtest/destination/DestinationAcceptanceTest.java b/airbyte-integrations/bases/standard-destination-test/src/main/java/io/airbyte/integrations/standardtest/destination/DestinationAcceptanceTest.java index f73f96140200..899f7cb3ff00 100644 --- a/airbyte-integrations/bases/standard-destination-test/src/main/java/io/airbyte/integrations/standardtest/destination/DestinationAcceptanceTest.java +++ b/airbyte-integrations/bases/standard-destination-test/src/main/java/io/airbyte/integrations/standardtest/destination/DestinationAcceptanceTest.java @@ -1217,8 +1217,7 @@ protected void runSyncAndVerifyStateOutput(final JsonNode config, final List destinationOutput = runSync(config, messages, catalog, runNormalization); - Collections.reverse(messages); - final AirbyteMessage expectedStateMessage = messages + final AirbyteMessage expectedStateMessage = reversed(messages) .stream() .filter(m -> m.getType() == Type.STATE) .findFirst() @@ -1238,6 +1237,20 @@ protected void runSyncAndVerifyStateOutput(final JsonNode config, assertEquals(expectedStateMessage, actualStateMessage); } + /** + * Reverses a list by creating a new list with the same elements of the input list and then + * reversing it. The input list will not be altered. + * + * @param list to reverse + * @param type + * @return new list with elements of original reversed. + */ + public static List reversed(final List list) { + final ArrayList reversed = new ArrayList<>(list); + Collections.reverse(reversed); + return reversed; + } + private List runSync( final JsonNode config, final List messages, From a990d8c8777a2de1f391a96f10164bef5e83689c Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Sun, 6 Nov 2022 18:14:35 -1000 Subject: [PATCH 71/73] Unhide DynamoDB destination (#18994) --- airbyte-webapp/src/core/domain/connector/constants.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/airbyte-webapp/src/core/domain/connector/constants.ts b/airbyte-webapp/src/core/domain/connector/constants.ts index 774b35b9581e..0e6a35f0f496 100644 --- a/airbyte-webapp/src/core/domain/connector/constants.ts +++ b/airbyte-webapp/src/core/domain/connector/constants.ts @@ -19,7 +19,6 @@ export const getExcludedConnectorIds = (workspaceId: string) => isCloudApp() ? [ "707456df-6f4f-4ced-b5c6-03f73bcad1c5", // hide Cassandra Destination https://github.com/airbytehq/airbyte-cloud/issues/2606 - "8ccd8909-4e99-4141-b48d-4984b70b2d89", // hide DynamoDB Destination https://github.com/airbytehq/airbyte-cloud/issues/2608 "9f760101-60ae-462f-9ee6-b7a9dafd454d", // hide Kafka Destination https://github.com/airbytehq/airbyte-cloud/issues/2610 "294a4790-429b-40ae-9516-49826b9702e1", // hide MariaDB Destination https://github.com/airbytehq/airbyte-cloud/issues/2611 "8b746512-8c2e-6ac1-4adc-b59faafd473c", // hide MongoDB Destination https://github.com/airbytehq/airbyte-cloud/issues/2612 From 7d73b08606d9fcc6b37c1170bfd342b266319276 Mon Sep 17 00:00:00 2001 From: Augustin Date: Mon, 7 Nov 2022 08:09:34 +0100 Subject: [PATCH 72/73] SAT: basic read on full catalog when `test_strictness_level == high` (#18937) --- .../bases/source-acceptance-test/CHANGELOG.md | 3 + .../bases/source-acceptance-test/Dockerfile | 2 +- .../source_acceptance_test/conftest.py | 64 ++++++----- .../source_acceptance_test/tests/test_core.py | 77 +++++++++++-- .../source_acceptance_test/utils/__init__.py | 15 ++- .../source_acceptance_test/utils/common.py | 69 +++++++++++- .../unit_tests/test_core.py | 78 ++++++++++--- .../unit_tests/test_global_fixtures.py | 20 +++- .../unit_tests/test_utils.py | 104 +++++++++++++++++- .../source-pokeapi/acceptance-test-config.yml | 3 +- .../source-acceptance-tests-reference.md | 22 +++- 11 files changed, 385 insertions(+), 72 deletions(-) diff --git a/airbyte-integrations/bases/source-acceptance-test/CHANGELOG.md b/airbyte-integrations/bases/source-acceptance-test/CHANGELOG.md index c8b79bcb78d8..78123bb4d33e 100644 --- a/airbyte-integrations/bases/source-acceptance-test/CHANGELOG.md +++ b/airbyte-integrations/bases/source-acceptance-test/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 0.2.16 +Run `basic_read` on the discovered catalog in `high` `test_strictness_level`. [#18937](https://github.com/airbytehq/airbyte/pull/18937). + ## 0.2.15 Make `expect_records` mandatory in `high` `test_strictness_level`. [#18497](https://github.com/airbytehq/airbyte/pull/18497/). diff --git a/airbyte-integrations/bases/source-acceptance-test/Dockerfile b/airbyte-integrations/bases/source-acceptance-test/Dockerfile index 96225d466ae4..d1cb06c59e73 100644 --- a/airbyte-integrations/bases/source-acceptance-test/Dockerfile +++ b/airbyte-integrations/bases/source-acceptance-test/Dockerfile @@ -33,7 +33,7 @@ COPY pytest.ini setup.py ./ COPY source_acceptance_test ./source_acceptance_test RUN pip install . -LABEL io.airbyte.version=0.2.15 +LABEL io.airbyte.version=0.2.16 LABEL io.airbyte.name=airbyte/source-acceptance-test ENTRYPOINT ["python", "-m", "pytest", "-p", "source_acceptance_test.plugin", "-r", "fEsx"] diff --git a/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/conftest.py b/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/conftest.py index 72a00b883405..253d400f75f7 100644 --- a/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/conftest.py +++ b/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/conftest.py @@ -13,20 +13,20 @@ from typing import Any, List, MutableMapping, Optional, Set import pytest -from airbyte_cdk.models import ( - AirbyteRecordMessage, - AirbyteStream, - ConfiguredAirbyteCatalog, - ConfiguredAirbyteStream, - ConnectorSpecification, - DestinationSyncMode, - Type, -) +from airbyte_cdk.models import AirbyteRecordMessage, AirbyteStream, ConfiguredAirbyteCatalog, ConnectorSpecification, Type from docker import errors from source_acceptance_test.base import BaseTest -from source_acceptance_test.config import Config, EmptyStreamConfiguration +from source_acceptance_test.config import Config, EmptyStreamConfiguration, ExpectedRecordsConfig from source_acceptance_test.tests import TestBasicRead -from source_acceptance_test.utils import ConnectorRunner, SecretDict, filter_output, load_config, load_yaml_or_json_path +from source_acceptance_test.utils import ( + ConnectorRunner, + SecretDict, + build_configured_catalog_from_custom_catalog, + build_configured_catalog_from_discovered_catalog_and_empty_streams, + filter_output, + load_config, + load_yaml_or_json_path, +) @pytest.fixture(name="acceptance_test_config", scope="session") @@ -44,7 +44,7 @@ def base_path_fixture(pytestconfig, acceptance_test_config) -> Path: @pytest.fixture(name="test_strictness_level", scope="session") -def test_strictness_level_fixture(acceptance_test_config: Config): +def test_strictness_level_fixture(acceptance_test_config: Config) -> Config.TestStrictnessLevel: return acceptance_test_config.test_strictness_level @@ -75,24 +75,17 @@ def configured_catalog_path_fixture(inputs, base_path) -> Optional[str]: @pytest.fixture(name="configured_catalog") -def configured_catalog_fixture(configured_catalog_path, discovered_catalog) -> ConfiguredAirbyteCatalog: - """Take ConfiguredAirbyteCatalog from discover command by default""" +def configured_catalog_fixture( + configured_catalog_path: Optional[str], + discovered_catalog: MutableMapping[str, AirbyteStream], +) -> ConfiguredAirbyteCatalog: + """Build a configured catalog. + If a configured catalog path is given we build a configured catalog from it, we build it from the discovered catalog otherwise. + """ if configured_catalog_path: - catalog = ConfiguredAirbyteCatalog.parse_file(configured_catalog_path) - for configured_stream in catalog.streams: - configured_stream.stream = discovered_catalog.get(configured_stream.stream.name, configured_stream.stream) - return catalog - streams = [ - ConfiguredAirbyteStream( - stream=stream, - sync_mode=stream.supported_sync_modes[0], - destination_sync_mode=DestinationSyncMode.append, - cursor_field=stream.default_cursor_field, - primary_key=stream.source_defined_primary_key, - ) - for _, stream in discovered_catalog.items() - ] - return ConfiguredAirbyteCatalog(streams=streams) + return build_configured_catalog_from_custom_catalog(configured_catalog_path, discovered_catalog) + else: + return build_configured_catalog_from_discovered_catalog_and_empty_streams(discovered_catalog, set()) @pytest.fixture(name="image_tag") @@ -178,12 +171,17 @@ def empty_streams_fixture(inputs, test_strictness_level) -> Set[EmptyStreamConfi return empty_streams +@pytest.fixture(name="expect_records_config") +def expect_records_config_fixture(inputs): + return inputs.expect_records + + @pytest.fixture(name="expected_records_by_stream") def expected_records_by_stream_fixture( test_strictness_level: Config.TestStrictnessLevel, configured_catalog: ConfiguredAirbyteCatalog, empty_streams: Set[EmptyStreamConfiguration], - inputs, + expect_records_config: ExpectedRecordsConfig, base_path, ) -> MutableMapping[str, List[MutableMapping]]: def enforce_high_strictness_level_rules(expect_records_config, configured_catalog, empty_streams, records_by_stream) -> Optional[str]: @@ -197,8 +195,9 @@ def enforce_high_strictness_level_rules(expect_records_config, configured_catalo error_prefix + f"{', '.join(not_seeded_streams)} streams are declared in the catalog but do not have expected records. Please add expected records to {expect_records_config.path} or declare these streams in empty_streams." ) - - expect_records_config = inputs.expect_records + else: + if not getattr(expect_records_config, "bypass_reason", None): + pytest.fail(error_prefix / "A bypass reason must be filled if no path to expected records is provided.") expected_records_by_stream = {} if expect_records_config: @@ -246,7 +245,6 @@ def discovered_catalog_fixture(connector_config, docker_runner: ConnectorRunner, catalogs = [message.catalog for message in output if message.type == Type.CATALOG] for stream in catalogs[-1].streams: cached_schemas[stream.name] = stream - return cached_schemas diff --git a/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py b/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py index 08b5f5717f4d..e4bdc743a2be 100644 --- a/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py +++ b/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py @@ -8,7 +8,8 @@ from collections import Counter, defaultdict from functools import reduce from logging import Logger -from typing import Any, Dict, List, Mapping, MutableMapping, Set +from typing import Any, Dict, List, Mapping, MutableMapping, Optional, Set +from xmlrpc.client import Boolean import dpath.util import jsonschema @@ -27,10 +28,23 @@ from docker.errors import ContainerError from jsonschema._utils import flatten from source_acceptance_test.base import BaseTest -from source_acceptance_test.config import BasicReadTestConfig, ConnectionTestConfig, DiscoveryTestConfig, SpecTestConfig +from source_acceptance_test.config import ( + BasicReadTestConfig, + Config, + ConnectionTestConfig, + DiscoveryTestConfig, + EmptyStreamConfiguration, + ExpectedRecordsConfig, + SpecTestConfig, +) from source_acceptance_test.utils import ConnectorRunner, SecretDict, filter_output, make_hashable, verify_records_schema from source_acceptance_test.utils.backward_compatibility import CatalogDiffChecker, SpecDiffChecker, validate_previous_configs -from source_acceptance_test.utils.common import find_all_values_for_key_in_schema, find_keyword_schema +from source_acceptance_test.utils.common import ( + build_configured_catalog_from_custom_catalog, + build_configured_catalog_from_discovered_catalog_and_empty_streams, + find_all_values_for_key_in_schema, + find_keyword_schema, +) from source_acceptance_test.utils.json_schema_helper import JsonSchemaHelper, get_expected_schema_structure, get_object_structure @@ -462,11 +476,58 @@ def _validate_expected_records( detailed_logger=detailed_logger, ) + @pytest.fixture(name="should_validate_schema") + def should_validate_schema_fixture(self, inputs: BasicReadTestConfig, test_strictness_level: Config.TestStrictnessLevel): + if not inputs.validate_schema and test_strictness_level is Config.TestStrictnessLevel.high: + pytest.fail("High strictness level error: validate_schema must be set to true in the basic read test configuration.") + else: + return inputs.validate_schema + + @pytest.fixture(name="should_validate_data_points") + def should_validate_data_points_fixture(self, inputs: BasicReadTestConfig) -> Boolean: + # TODO: we might want to enforce this when Config.TestStrictnessLevel.high + return inputs.validate_data_points + + @pytest.fixture(name="configured_catalog") + def configured_catalog_fixture( + self, + test_strictness_level: Config.TestStrictnessLevel, + configured_catalog_path: Optional[str], + discovered_catalog: MutableMapping[str, AirbyteStream], + empty_streams: Set[EmptyStreamConfiguration], + ) -> ConfiguredAirbyteCatalog: + """Build a configured catalog for basic read only. + We discard the use of custom configured catalog if: + - No custom configured catalog is declared with configured_catalog_path. + - We are in high test strictness level. + When a custom configured catalog is discarded we use the discovered catalog from which we remove the declared empty streams. + We use a custom configured catalog if a configured_catalog_path is declared and we are not in high test strictness level. + Args: + test_strictness_level (Config.TestStrictnessLevel): The current test strictness level according to the global test configuration. + configured_catalog_path (Optional[str]): Path to a JSON file containing a custom configured catalog. + discovered_catalog (MutableMapping[str, AirbyteStream]): The discovered catalog. + empty_streams (Set[EmptyStreamConfiguration]): The empty streams declared in the test configuration. + + Returns: + ConfiguredAirbyteCatalog: the configured Airbyte catalog. + """ + if test_strictness_level is Config.TestStrictnessLevel.high or not configured_catalog_path: + if configured_catalog_path: + pytest.fail( + "High strictness level error: you can't set a custom configured catalog on the basic read test when strictness level is high." + ) + return build_configured_catalog_from_discovered_catalog_and_empty_streams(discovered_catalog, empty_streams) + else: + return build_configured_catalog_from_custom_catalog(configured_catalog_path, discovered_catalog) + def test_read( self, connector_config, configured_catalog, - inputs: BasicReadTestConfig, + expect_records_config: ExpectedRecordsConfig, + should_validate_schema: Boolean, + should_validate_data_points: Boolean, + empty_streams: Set[EmptyStreamConfiguration], expected_records_by_stream: MutableMapping[str, List[MutableMapping]], docker_runner: ConnectorRunner, detailed_logger, @@ -476,10 +537,10 @@ def test_read( assert records, "At least one record should be read using provided catalog" - if inputs.validate_schema: + if should_validate_schema: self._validate_schema(records=records, configured_catalog=configured_catalog) - self._validate_empty_streams(records=records, configured_catalog=configured_catalog, allowed_empty_streams=inputs.empty_streams) + self._validate_empty_streams(records=records, configured_catalog=configured_catalog, allowed_empty_streams=empty_streams) for pks, record in primary_keys_for_records(streams=configured_catalog.streams, records=records): for pk_path, pk_value in pks.items(): assert ( @@ -487,14 +548,14 @@ def test_read( ), f"Primary key subkeys {repr(pk_path)} have null values or not present in {record.stream} stream records." # TODO: remove this condition after https://github.com/airbytehq/airbyte/issues/8312 is done - if inputs.validate_data_points: + if should_validate_data_points: self._validate_field_appears_at_least_once(records=records, configured_catalog=configured_catalog) if expected_records_by_stream: self._validate_expected_records( records=records, expected_records_by_stream=expected_records_by_stream, - flags=inputs.expect_records, + flags=expect_records_config, detailed_logger=detailed_logger, ) diff --git a/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/utils/__init__.py b/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/utils/__init__.py index 618c814dfc96..6e7535e99740 100644 --- a/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/utils/__init__.py +++ b/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/utils/__init__.py @@ -1,8 +1,17 @@ # -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. +# Copyright (c) 2022 Airbyte, Inc., all rights reserved. # from .asserts import verify_records_schema -from .common import SecretDict, filter_output, full_refresh_only_catalog, incremental_only_catalog, load_config, load_yaml_or_json_path +from .common import ( + SecretDict, + build_configured_catalog_from_custom_catalog, + build_configured_catalog_from_discovered_catalog_and_empty_streams, + filter_output, + full_refresh_only_catalog, + incremental_only_catalog, + load_config, + load_yaml_or_json_path, +) from .compare import diff_dicts, make_hashable from .connector_runner import ConnectorRunner from .json_schema_helper import JsonSchemaHelper @@ -19,4 +28,6 @@ "diff_dicts", "make_hashable", "verify_records_schema", + "build_configured_catalog_from_custom_catalog", + "build_configured_catalog_from_discovered_catalog_and_empty_streams", ] diff --git a/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/utils/common.py b/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/utils/common.py index 35fa082bea94..cdda3aa57e3b 100644 --- a/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/utils/common.py +++ b/airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/utils/common.py @@ -3,9 +3,10 @@ # import json +import logging from collections import UserDict from pathlib import Path -from typing import Iterable, List, Union +from typing import Iterable, List, MutableMapping, Set, Union import pytest from yaml import load @@ -15,8 +16,15 @@ except ImportError: from yaml import Loader -from airbyte_cdk.models import AirbyteMessage, ConfiguredAirbyteCatalog, SyncMode -from source_acceptance_test.config import Config +from airbyte_cdk.models import ( + AirbyteMessage, + AirbyteStream, + ConfiguredAirbyteCatalog, + ConfiguredAirbyteStream, + DestinationSyncMode, + SyncMode, +) +from source_acceptance_test.config import Config, EmptyStreamConfiguration def load_config(path: str) -> Config: @@ -111,3 +119,58 @@ def find_all_values_for_key_in_schema(schema: dict, searched_key: str): yield value if isinstance(value, dict) or isinstance(value, list): yield from find_all_values_for_key_in_schema(value, searched_key) + + +def build_configured_catalog_from_discovered_catalog_and_empty_streams( + discovered_catalog: MutableMapping[str, AirbyteStream], empty_streams: Set[EmptyStreamConfiguration] +): + """Build a configured catalog from the discovered catalog with empty streams removed. + + Args: + discovered_catalog (MutableMapping[str, AirbyteStream]): The discovered catalog. + empty_streams (Set[EmptyStreamConfiguration]): The set of empty streams declared in the test configuration. + + Returns: + ConfiguredAirbyteCatalog: a configured Airbyte catalog. + """ + empty_stream_names = [empty_stream.name for empty_stream in empty_streams] + streams = [ + ConfiguredAirbyteStream( + stream=stream, + sync_mode=stream.supported_sync_modes[0], + destination_sync_mode=DestinationSyncMode.append, + cursor_field=stream.default_cursor_field, + primary_key=stream.source_defined_primary_key, + ) + for _, stream in discovered_catalog.items() + if stream.name not in empty_stream_names + ] + if empty_stream_names: + logging.warning( + f"The configured catalog was built with the discovered catalog from which the following empty streams were removed: {', '.join(empty_stream_names)}." + ) + else: + logging.info("The configured catalog is built from a fully discovered catalog.") + return ConfiguredAirbyteCatalog(streams=streams) + + +def build_configured_catalog_from_custom_catalog(configured_catalog_path: str, discovered_catalog: MutableMapping[str, AirbyteStream]): + """Build a configured catalog from a local one stored in a JSON file. + + Args: + configured_catalog_path (str): Local path to a custom configured catalog path + discovered_catalog (MutableMapping[str, AirbyteStream]): The discovered catalog + + Returns: + ConfiguredAirbyteCatalog: a configured Airbyte catalog + """ + catalog = ConfiguredAirbyteCatalog.parse_file(configured_catalog_path) + for configured_stream in catalog.streams: + try: + configured_stream.stream = discovered_catalog[configured_stream.stream.name] + except KeyError: + pytest.fail( + f"The {configured_stream.stream.name} stream you have set in {configured_catalog_path} is not part of the discovered_catalog" + ) + logging.info("The configured catalog is built from a custom configured catalog.") + return catalog diff --git a/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_core.py b/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_core.py index 8082a6e02e27..291951688f26 100644 --- a/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_core.py +++ b/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_core.py @@ -20,9 +20,8 @@ TraceType, Type, ) -from source_acceptance_test.config import BasicReadTestConfig -from source_acceptance_test.tests.test_core import TestBasicRead as _TestBasicRead -from source_acceptance_test.tests.test_core import TestDiscovery as _TestDiscovery +from source_acceptance_test.config import BasicReadTestConfig, Config, ExpectedRecordsConfig +from source_acceptance_test.tests import test_core from .conftest import does_not_raise @@ -39,7 +38,7 @@ ], ) def test_discovery(schema, cursors, should_fail): - t = _TestDiscovery() + t = test_core.TestDiscovery() discovered_catalog = { "test_stream": AirbyteStream.parse_obj( { @@ -79,7 +78,7 @@ def test_discovery(schema, cursors, should_fail): ], ) def test_ref_in_discovery_schemas(schema, should_fail): - t = _TestDiscovery() + t = test_core.TestDiscovery() discovered_catalog = { "test_stream": AirbyteStream.parse_obj( {"name": "test_stream", "json_schema": schema, "supported_sync_modes": ["full_refresh", "incremental"]} @@ -123,7 +122,7 @@ def test_ref_in_discovery_schemas(schema, should_fail): ], ) def test_keyword_in_discovery_schemas(schema, keyword, should_fail): - t = _TestDiscovery() + t = test_core.TestDiscovery() discovered_catalog = { "test_stream": AirbyteStream.parse_obj( {"name": "test_stream", "json_schema": schema, "supported_sync_modes": ["full_refresh", "incremental"]} @@ -163,7 +162,7 @@ def test_keyword_in_discovery_schemas(schema, keyword, should_fail): ], ) def test_supported_sync_modes_in_stream(mocker, discovered_catalog, expectation): - t = _TestDiscovery() + t = test_core.TestDiscovery() with expectation: t.test_streams_has_sync_modes(discovered_catalog) @@ -230,11 +229,53 @@ def test_supported_sync_modes_in_stream(mocker, discovered_catalog, expectation) ], ) def test_additional_properties_is_true(discovered_catalog, expectation): - t = _TestDiscovery() + t = test_core.TestDiscovery() with expectation: t.test_additional_properties_is_true(discovered_catalog) +@pytest.mark.parametrize( + "test_strictness_level, configured_catalog_path", + [ + (Config.TestStrictnessLevel.high, None), + (Config.TestStrictnessLevel.high, "custom_configured_catalog_path"), + (Config.TestStrictnessLevel.low, None), + (Config.TestStrictnessLevel.low, "custom_configured_catalog_path"), + ], +) +def test_configured_catalog_fixture(mocker, test_strictness_level, configured_catalog_path): + mocker.patch.object(test_core, "build_configured_catalog_from_discovered_catalog_and_empty_streams") + mocker.patch.object(test_core, "build_configured_catalog_from_custom_catalog") + mocker.patch.object(test_core.pytest, "fail") + + mock_discovered_catalog = mocker.Mock() + mock_empty_streams = mocker.Mock() + t = test_core.TestBasicRead() + configured_catalog = test_core.TestBasicRead.configured_catalog_fixture.__wrapped__( + t, test_strictness_level, configured_catalog_path, mock_discovered_catalog, mock_empty_streams + ) + if test_strictness_level is Config.TestStrictnessLevel.high: + if configured_catalog_path: + test_core.pytest.fail.assert_called_once() + else: + test_core.build_configured_catalog_from_discovered_catalog_and_empty_streams.assert_called_once_with( + mock_discovered_catalog, mock_empty_streams + ) + test_core.build_configured_catalog_from_custom_catalog.assert_not_called() + assert configured_catalog == test_core.build_configured_catalog_from_discovered_catalog_and_empty_streams.return_value + else: + if configured_catalog_path is None: + test_core.build_configured_catalog_from_discovered_catalog_and_empty_streams.assert_called_once_with( + mock_discovered_catalog, mock_empty_streams + ) + test_core.build_configured_catalog_from_custom_catalog.assert_not_called() + assert configured_catalog == test_core.build_configured_catalog_from_discovered_catalog_and_empty_streams.return_value + else: + test_core.build_configured_catalog_from_custom_catalog.assert_called_once_with(configured_catalog_path, mock_discovered_catalog) + test_core.build_configured_catalog_from_discovered_catalog_and_empty_streams.assert_not_called() + assert configured_catalog == test_core.build_configured_catalog_from_custom_catalog.return_value + + @pytest.mark.parametrize( "schema, record, expectation", [ @@ -260,7 +301,7 @@ def test_additional_properties_is_true(discovered_catalog, expectation): ], ) def test_read(schema, record, expectation): - catalog = ConfiguredAirbyteCatalog( + configured_catalog = ConfiguredAirbyteCatalog( streams=[ ConfiguredAirbyteStream( stream=AirbyteStream.parse_obj({"name": "test_stream", "json_schema": schema, "supported_sync_modes": ["full_refresh"]}), @@ -269,14 +310,23 @@ def test_read(schema, record, expectation): ) ] ) - input_config = BasicReadTestConfig() docker_runner_mock = MagicMock() docker_runner_mock.call_read.return_value = [ AirbyteMessage(type=Type.RECORD, record=AirbyteRecordMessage(stream="test_stream", data=record, emitted_at=111)) ] - t = _TestBasicRead() + t = test_core.TestBasicRead() with expectation: - t.test_read(None, catalog, input_config, [], docker_runner_mock, MagicMock()) + t.test_read( + connector_config=None, + configured_catalog=configured_catalog, + expect_records_config=ExpectedRecordsConfig(path="foobar"), + should_validate_schema=True, + should_validate_data_points=False, + empty_streams=set(), + expected_records_by_stream={}, + docker_runner=docker_runner_mock, + detailed_logger=MagicMock(), + ) @pytest.mark.parametrize( @@ -355,7 +405,7 @@ def test_read(schema, record, expectation): ], ) def test_airbyte_trace_message_on_failure(output, expect_trace_message_on_failure, should_fail): - t = _TestBasicRead() + t = test_core.TestBasicRead() input_config = BasicReadTestConfig(expect_trace_message_on_failure=expect_trace_message_on_failure) docker_runner_mock = MagicMock() docker_runner_mock.call_read.return_value = output @@ -835,7 +885,7 @@ def test_airbyte_trace_message_on_failure(output, expect_trace_message_on_failur ], ) def test_validate_field_appears_at_least_once(records, configured_catalog, expected_error): - t = _TestBasicRead() + t = test_core.TestBasicRead() if expected_error: with pytest.raises(AssertionError, match=expected_error): t._validate_field_appears_at_least_once(records=records, configured_catalog=configured_catalog) diff --git a/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_global_fixtures.py b/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_global_fixtures.py index cdd8b006b3c6..9b1ecf07ab5f 100644 --- a/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_global_fixtures.py +++ b/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_global_fixtures.py @@ -158,10 +158,24 @@ def test_expected_records_by_stream_fixture( for record in expected_records: expected_records_file.write(json.dumps(record) + "\n") - inputs = BasicReadTestConfig(config_path="", empty_streams=empty_streams, expect_records=expected_records_config) - - conftest.expected_records_by_stream_fixture.__wrapped__(test_strictness_level, configured_catalog, empty_streams, inputs, base_path) + conftest.expected_records_by_stream_fixture.__wrapped__( + test_strictness_level, configured_catalog, empty_streams, expected_records_config, base_path + ) if should_fail: conftest.pytest.fail.assert_called_once() else: conftest.pytest.fail.assert_not_called() + + +@pytest.mark.parametrize("configured_catalog_path", [None, "my_path"]) +def test_configured_catalog_fixture(mocker, configured_catalog_path): + mock_discovered_catalog = mocker.Mock() + mocker.patch.object(conftest, "build_configured_catalog_from_custom_catalog") + mocker.patch.object(conftest, "build_configured_catalog_from_discovered_catalog_and_empty_streams") + configured_catalog = conftest.configured_catalog_fixture.__wrapped__(configured_catalog_path, mock_discovered_catalog) + if configured_catalog_path: + assert configured_catalog == conftest.build_configured_catalog_from_custom_catalog.return_value + conftest.build_configured_catalog_from_custom_catalog.assert_called_once_with(configured_catalog_path, mock_discovered_catalog) + else: + assert configured_catalog == conftest.build_configured_catalog_from_discovered_catalog_and_empty_streams.return_value + conftest.build_configured_catalog_from_discovered_catalog_and_empty_streams.assert_called_once_with(mock_discovered_catalog, set()) diff --git a/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_utils.py b/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_utils.py index 78ec12e89126..d4a0a3feda06 100644 --- a/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_utils.py +++ b/airbyte-integrations/bases/source-acceptance-test/unit_tests/test_utils.py @@ -15,8 +15,10 @@ import docker import pytest import yaml +from airbyte_cdk.models import AirbyteStream, ConfiguredAirbyteCatalog, ConfiguredAirbyteStream, DestinationSyncMode, SyncMode from docker.errors import ContainerError, NotFound -from source_acceptance_test.utils.common import find_all_values_for_key_in_schema, load_yaml_or_json_path +from source_acceptance_test.config import EmptyStreamConfiguration +from source_acceptance_test.utils import common from source_acceptance_test.utils.compare import make_hashable from source_acceptance_test.utils.connector_runner import ConnectorRunner @@ -332,20 +334,20 @@ def test_load_json(self): with tempfile.NamedTemporaryFile("w", suffix=".json") as f: f.write(json.dumps(self.VALID_SPEC)) f.flush() - actual = load_yaml_or_json_path(Path(f.name)) + actual = common.load_yaml_or_json_path(Path(f.name)) assert self.VALID_SPEC == actual def test_load_yaml(self): with tempfile.NamedTemporaryFile("w", suffix=".yaml") as f: f.write(yaml.dump(self.VALID_SPEC)) f.flush() - actual = load_yaml_or_json_path(Path(f.name)) + actual = common.load_yaml_or_json_path(Path(f.name)) assert self.VALID_SPEC == actual def test_load_other(self): with tempfile.NamedTemporaryFile("w", suffix=".txt") as f: with pytest.raises(RuntimeError): - load_yaml_or_json_path(Path(f.name)) + common.load_yaml_or_json_path(Path(f.name)) @pytest.mark.parametrize( @@ -375,4 +377,96 @@ def test_load_other(self): ], ) def test_find_all_values_for_key_in_schema(schema, searched_key, expected_values): - assert list(find_all_values_for_key_in_schema(schema, searched_key)) == expected_values + assert list(common.find_all_values_for_key_in_schema(schema, searched_key)) == expected_values + + +DUMMY_DISCOVERED_CATALOG = { + "stream_a": AirbyteStream( + name="stream_a", + json_schema={"a": {"type": "string"}}, + supported_sync_modes=[SyncMode.full_refresh], + ), + "stream_b": AirbyteStream( + name="stream_b", + json_schema={"a": {"type": "string"}}, + supported_sync_modes=[SyncMode.full_refresh], + ), +} + +DUMMY_CUSTOM_CATALOG = { + "stream_a": AirbyteStream( + name="stream_a", + json_schema={"a": {"type": "number"}}, + supported_sync_modes=[SyncMode.full_refresh], + ), + "stream_b": AirbyteStream( + name="stream_b", + json_schema={"a": {"type": "number"}}, + supported_sync_modes=[SyncMode.full_refresh], + ), +} + +DUMMY_CUSTOM_CATALOG_WITH_EXTRA_STREAM = { + "stream_a": AirbyteStream( + name="stream_a", + json_schema={"a": {"type": "number"}}, + supported_sync_modes=[SyncMode.full_refresh], + ), + "stream_b": AirbyteStream( + name="stream_b", + json_schema={"a": {"type": "number"}}, + supported_sync_modes=[SyncMode.full_refresh], + ), + "stream_c": AirbyteStream( + name="stream_c", + json_schema={"a": {"type": "number"}}, + supported_sync_modes=[SyncMode.full_refresh], + ), +} + + +@pytest.mark.parametrize( + "discovered_catalog, empty_streams", + [ + (DUMMY_DISCOVERED_CATALOG, set()), + (DUMMY_DISCOVERED_CATALOG, {EmptyStreamConfiguration(name="stream_b", bypass_reason="foobar")}), + ], +) +def test_build_configured_catalog_from_discovered_catalog_and_empty_streams(mocker, discovered_catalog, empty_streams): + mocker.patch.object(common, "logging") + configured_catalog = common.build_configured_catalog_from_discovered_catalog_and_empty_streams(discovered_catalog, empty_streams) + assert len(configured_catalog.streams) == len(DUMMY_DISCOVERED_CATALOG.values()) - len(empty_streams) + if empty_streams: + common.logging.warning.assert_called_once() + configured_stream_names = [configured_stream.stream.name for configured_stream in configured_catalog.streams] + for empty_stream in empty_streams: + assert empty_stream.name not in configured_stream_names + else: + common.logging.info.assert_called_once() + + +@pytest.mark.parametrize( + "custom_configured_catalog, expect_failure", [(DUMMY_CUSTOM_CATALOG, False), (DUMMY_CUSTOM_CATALOG_WITH_EXTRA_STREAM, True)] +) +def test_build_configured_catalog_from_custom_catalog(mocker, custom_configured_catalog, expect_failure): + mocker.patch.object(common, "logging") + mocker.patch.object(common.pytest, "fail") + + dummy_configured_catalog = ConfiguredAirbyteCatalog( + streams=[ + ConfiguredAirbyteStream(stream=stream, sync_mode=SyncMode.full_refresh, destination_sync_mode=DestinationSyncMode.append) + for stream in custom_configured_catalog.values() + ] + ) + mocker.patch.object(common.ConfiguredAirbyteCatalog, "parse_file", mocker.Mock(return_value=dummy_configured_catalog)) + + configured_catalog = common.build_configured_catalog_from_custom_catalog("path", DUMMY_DISCOVERED_CATALOG) + + if not expect_failure: + assert len(configured_catalog.streams) == len(dummy_configured_catalog.streams) + # Checking that the function under test retrieves the stream from the discovered catalog + assert configured_catalog.streams[0].stream == DUMMY_DISCOVERED_CATALOG["stream_a"] + assert configured_catalog.streams[0].stream != custom_configured_catalog["stream_a"] + common.logging.info.assert_called_once() + else: + common.pytest.fail.assert_called_once() diff --git a/airbyte-integrations/connectors/source-pokeapi/acceptance-test-config.yml b/airbyte-integrations/connectors/source-pokeapi/acceptance-test-config.yml index a98c1c1a9a9e..2f23c6db6c7f 100644 --- a/airbyte-integrations/connectors/source-pokeapi/acceptance-test-config.yml +++ b/airbyte-integrations/connectors/source-pokeapi/acceptance-test-config.yml @@ -13,7 +13,8 @@ acceptance_tests: basic_read: tests: - config_path: "integration_tests/config.json" - configured_catalog_path: "integration_tests/configured_catalog.json" + expect_records: + bypass_reason: "We should create an expected_records file" full_refresh: tests: - config_path: "integration_tests/config.json" diff --git a/docs/connector-development/testing-connectors/source-acceptance-tests-reference.md b/docs/connector-development/testing-connectors/source-acceptance-tests-reference.md index 0aa5db52f7e7..a716ec1bca90 100644 --- a/docs/connector-development/testing-connectors/source-acceptance-tests-reference.md +++ b/docs/connector-development/testing-connectors/source-acceptance-tests-reference.md @@ -272,7 +272,6 @@ acceptance_tests: basic_read: tests: - config_path: "integration_tests/config.json" - configured_catalog_path: "integration_tests/configured_catalog.json" full_refresh: tests: - config_path: "integration_tests/config.json" @@ -294,7 +293,6 @@ acceptance_tests: basic_read: tests: - config_path: secrets/config.json - configured_catalog_path: integration_tests/streams_with_output_records_catalog.json empty_streams: - name: collections bypass_reason: "This stream can't be seeded in our sandbox account" @@ -309,3 +307,23 @@ In `high` test strictness level we expect the `expect_records` subtest to be set If you can't create an `expected_records.json` with all the existing stream you need to declare the missing streams in the `empty_streams` section. If you can't get an `expected_records.json` file at all, you must fill in a `bypass_reason`. +#### Basic read: no `configured_catalog_path` can be set +In `high` test strictness level we want to run the `basic_read` test on a configured catalog created from the discovered catalog from which we remove declared empty streams. Declaring `configured_catalog_path` in the test configuration is not allowed. + + + +```yaml +connector_image: airbyte/source-recharge:dev +test_strictness_level: high +acceptance_tests: + basic_read: + tests: + - config_path: secrets/config.json + empty_streams: + - name: collections + bypass_reason: "This stream can't be seeded in our sandbox account" + - name: discounts + bypass_reason: "This stream can't be seeded in our sandbox account" + timeout_seconds: 1200 +... +``` \ No newline at end of file From 7164e1c70070043aac2c3f88527efd33f1bd001d Mon Sep 17 00:00:00 2001 From: Joey Marshment-Howell Date: Mon, 7 Nov 2022 13:21:00 +0100 Subject: [PATCH 73/73] =?UTF-8?q?=F0=9F=AA=9F=20=F0=9F=90=9B=20Fix=20wrong?= =?UTF-8?q?=20geography=20dropdown=20type=20#19021?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workspaces/DataResidencyView/DataResidencyView.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx b/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx index a24475b5e834..b2a83b27de98 100644 --- a/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx +++ b/airbyte-webapp/src/packages/cloud/views/workspaces/DataResidencyView/DataResidencyView.tsx @@ -18,11 +18,6 @@ import { links } from "utils/links"; import styles from "./DataResidencyView.module.scss"; -interface SelectGeographyOption { - label: Geography; - value: Geography; -} - interface DefaultDataResidencyFormValues { defaultGeography: Geography | undefined; } @@ -78,7 +73,7 @@ export const DataResidencyView: React.FC = () => { {({ isSubmitting, dirty, isValid, resetForm }) => (
    - {({ field, form }: FieldProps) => ( + {({ field, form }: FieldProps) => (

    (>tl+ClBt-aQ7L%}n&H9uUP(b#0UXAaQ- zNi)H?a8q?#ayupzoX)ZFw|1X$gEXd{Na9Pr1zqz>C>PM_D6d2jfzT0gW~r-Pu+(Pfx;eVwV#X0u8EYi>=n&hme&>h z)h_|)vd(L-GAZgkdGoJx>#xgj!;Yi=>K(b$JyiE^4xVBfigfOP)?44;|MM!!oLGQ6 zg?Yo0vj-XaoLj}Y(^rOarHh(yRO;2-Z^b!K=}78pNH-7eAnR$ktwfMoV-k;TiTdVK zje}Od`rUU2A`p(GP{-i@KJK92KXmW-xFXV&>8_ihaB;r=IM58adOJB#O^Yll;`weF zJSk~0u!iXF8$)8qtIH4KRxO_-1vdPs&tr9$d2p;{*!e2)-;1zbpIhWu?Tc^Y@U}NHd=>W6@fB4PLgb$;A0zcPlpM2w83X1OnC1AG3 zi~qXe+R=v63m`w=FDLG={Uok(;j$usPWuoZsoPr@t==ib)COrCBIQ23mTQh#TSCq~ z`5K5aP$;L~RX^MipRMISI+Krd8m0fiJ|tQYH5dYd1g%``dYVW!v*!gE8e_`5;ByNHFcbSDZg zf+S!T;|A43W-0n)WJDT#zRwGaeb9J8d9E9O7>K6lxavEhY+}ZzD#*(q!4YkjS}u?C zLw~m$lL0qboOB|i4k%V6@4iNh_wcCe=~2+ULf17o4~q|ctFM6sRcKpLZfO=T!|&Xw zC?o1K$$Je8^;nBA1!)roi+mfpZvrMXO;Q)9ku9 zcQyKs)6sF0KMEIS?Zy#l7~IcXgMU|zrN01v{U$aIV854x{NSljzN&e>`r*_F9b)c? z3uo{|pQdidTYBZ-BlXLVuNxi&;*=+xudPlF$_8M@wo@f%KkS>(MFSJWvMSVJy? zCbIb)&3l^Uc!aiA9Se%(|8g624s_`n@W{L7y7u#jS^ml_6^{xV)6sHjh;B{5)G?YF zLr7zAG4hE}1w7qgIhjziF^PXX%QB=_k?UFY8<5&u;hDYtTlKQbr>&+CAshk` z+qn21BUW8+snZ|ZCx_a!e5Mn3pVcjsQ;scaIP#%VQFK4TtrI&9I3n8TY{6%2lsnrn zhf@oPTpx%&XZ^eU;UyizC>C*)KQQG6Rqz2f{XAYNp94wTYM{RB%U5-X3ukMHA}^)m z2Ibc9&H7Y}gLrNUDuUq4q&T6!-YdsO#L&Qx{UPL6tB^Y68q<6}&kg@n2O4#Xa!dXU z%->1+dc$m~wAL+NSTo4$BBN|N|gex_T0iDE6Ntn3furV&VFV+{vs%0TzY*Dw?piX!D)Ne(95fM1V*G)Rfk@B=z1BSrFQ$mcBfAV|0K}U! zdMh3z44^8+NxwNt^6E$S^+Q+CCc0aqkJ3Y`R71dp1ytASZ}>RcW$ESm1TOKktOpUg zk``{HimJ&>=K36CV7{(BF!BCP@msX?htQ|rX~e}cvy1F&#Z7pSrZNL~`Vgt#gsZs( z;-`Jm1hjjnfs;;g!tc3*?5l_GAwq^n>rMTc3ba=Z5wbjImxRG@$$6~9V4k%M z*hAjthD+>&+;GpiHDo~Sf6NGBX;*qtw2ePhkAS>hyB?CW#XsywG*i60qGtoJe*_VB zFPdX4OgiazpB10&i7RavxSrHLfsNhQmt&y)GhY-q%k7TZGa6ZB1*v-Hkj5HqRnR+v zjV3jFtB9wkc_8x~%j}%n4CbhV`z?2jL0eNho@r!Xj7!l^dE8brZdf$ISs;l;bh2ZzD4J8s?2ix%JzjgJeLyWNwV84t{ta6CQu~W$Pv*|K#yf)ApS|5B z12}PW#b&qT>SER@Z_vD@TMwdMec;D?2d}-w;0wk-+$L*b*KLn!G**DYHdkuvpOiM2v` z$|b;RFQv8=>_we%r_3CBnJEW$*1>nE;LaY}OdQf1%HhG?83tS=q?RU&-31G~`xuo0?@RghDaa0bwRTlFW*Lq>bxh^%WbR~+MWu>P=@ts9 z!#O0W7&)KJoCdJTdo7t)eaKj&;2IL(>N*B!3d4A2I_;w#$%%<5$I*vxnH|6Pgi#({ zRDkdhd)%a(fHZ=5DcV;hPt_WqpUy6Px3->$DNDw{UyAr0K`|z6x4u#9FJlGHcRP{F z8mc0D5DaU}Th8}+P~Xn=l(|;jSLowsh!(^*jZh++M9ihjo4Osfb+_uW&znvs=S{L_ z>&~^wp09Rl|2uDb@+OCyGnC&qCKYGyJyGy=0*tsUozg;6e228EFD;&&jmH^78OG4> zCm%&~cI+?B zSeLAFc+Wg74m*|&KitZ~QE&iKn2SEB#It;`*`pwgwj|{3skBiI$=M&wp-Psp@+waw zlQvmBRB9<$xT)vqTlm!=cRh>FGEM%i*Iec7%}87PSHmu~OZaCZ@Kx(0=rhfO4%r!q z?4C75EVQ_-+BhMT<~wVZ_$8NZ242K?8hb*&F|RW4=9%PwNQu{GTA&=rtihWy@2N_| zr}~Duo4#H~L^hKDVcvPu_Hqldwwrw^1iL03(Z|+1zD{Hfdn|uQ`Xv|~KgEgv$6_yn zH}L^pcrI?>DW3K48E&?@82SooUz*@<9YQ}p)j^K^Y&$?1G()j%+J(#boTdP35$H6_ z|2PT3T|n_Uq7QaTHHoe~g!Y-cc=G^4Pnq;z*Lt$}4w!C^--9QI(YKT*$yJZ$iSo5a z6fNN@N~TmIWn@-L`>yRFwx)5?-Dl7b!Rxz385h7v2UdG~>yp*;<}U)6{Tr(3R`Lkh zd^RgyOSn7*Pd=9VQrmat$`j8~u>xmwLL*P244Hn^B13V_=VnkhdVB+yv9~-&`r;7caA?>uQ-wzKKv_4n zJqr+D_Dd_NMMod^5MQEZVjmwlf38Dr2jtvJAR zwC#0$nv7o;MW^=fjWbKRDA8%w;X5m?kO+z4B0YN zpz=$&|F_Y$UszcQQU9#_b}48E8FqY~tY?*bAeqwNf}YYzD1sRtE<{*;^YQWhd9a4^ z93{hLkoMcaQ2iV7L|AQ|^Oq21pgwH@mv))b^?hLri0BQ)kP5Tiw{SQ2&GxJTd1MIO zR4C-Kame+`Sx09VcK$!800ADE96)Vx30J8%55e=p2VO$ARvnTX{X3df}W$KI)hhaP;)^TUuvhNeMV4lk+6U#6cZ9T9M~8i<+N}PJbJO zHt4$T6kL6UrE9|Yy;Vp%is6lUxoOE}gZig?Iw)zR5h<|JbgNRo<_pPSLB#=7Q#O09<3b7<@vjom-9peI~89i?iq!9KUIsBm*=y;UlJLG!e z#GI6$neq@Ffw_Xi#z}e3o{Ssz9-x>jo#h|FaAHZ04;qfIYiPC#06o1W>uBWOlIZ5Y zupLFAw^7C6R#y+z$O|ON@AM&8=UZ!1w~CIYI&14qh;)v=!e>{6OD-~$dRDBz_OI7& z_R#QD-!AKebI#QhFd>nZpIaA}z4y_Dw^(Y7Hf4$7)JOD~u(hJ+pF$`}$ViT``$g(1 zyoJthLErCxzeqixKV4qcV@7H-S3tySRA|h0DGA8D2k)vqizplb1jlyIW+O0JW|G3C zgb7vdY0Hq9m{@8EtGTp#_ioUh?<`HIY*xqD>EuXMZK?splGJUa!A|mbed0ZtR8VB{ z-=uyYtWov{8hjW1l{%DQA%L*Q1gHpf7tuku-_KA6Uyqo^Sf57Cm%rQfIt+IM3WP#= zVrj+w#Vj+LpaPrbE6yLH`VFnhe!Xtf+g=^i4brc78fya^R>!8-%-Fz0bN z?Uk`qF67z^bjAg86{AfOIaRVU$#l)$2b~KeOT7>p{}b~D*$;0IE!!!b;@|`V4PWCl zOQ&hqdXQAP0*`}#Y2MN57@42@%`3XRBz8HA7kAVQzH;MzC@x7k`^?_m zJfX97==v2ix)f+S7YGezgzV~CpEj#L@Ujb*I_Y?=Lj`0NyQPpty0yL7RJa_kRAhxN9 zr@+d=5Ss1<#D)R6(^|X;mjfLOlEex{0dx#gmsaJ`!)&DYPXNo8BGapG)?65t+ zk* z$8NbZh6oL(#=)7F5WzBR)Ri?W*-IsqiQ(qvSzXbLig7TAouEQ?`PjRDB%Q!eUpJq& zk0&JS_=qmR`MLY!%3lnGgj4l9&e8cCD-uKq2b>DNbDKXU7^mA}a;vmIhxMZ-&eBfV z!21%d{{3L=jZ}ySS=5al^wys_gR>vm9eeGnu_QQFdnJ>EBZqHH+e2qP$e~P{<{vtl zfYI4uN6`B6&j2E3^t@CGpj$1Ei=|VFHshBdpPnABJl3{qp67}a5)qMk7^gVV6Y(Hz z?mEv&-xL1eew-xc>!CkU?wh6>5ZXwz?=T7Zb^F!ChyGvHR(0xy_|bs+(i+1PCJTX9 z_lUDv3mSG;y=1gW?$ZIb81%4Rm+S7KcP!DE!!1Ay%Ff zlLePH4^hnT=dxP*Rw-V60XfwqNxIRqim%ct^OFadKjT}U1E1ph*9FVZ z!tM_c6gXPP)WP0T9N5^RjW7^KpCS~%AS_j1k-NXRS78T!=J9*$jUUf@e1~4OzK1)} z2rY%3bD@2T2cRjCdHfGHC+kvWk%K7e&C4hRY7@75_1VA}>!x+&#ZKuEfxYroyp{vY*x4q0z3g z8;OQ%xHYomo&bvwa^e+{AC5kLhZ^_J$UqWqZcK8_Q5)&o4bVsF%S z;sA;7xV%pa7kOKH{d+Ll(eiP&Y85G;llP@hd!;rQY$m2e88H>0t^Y44_O3yhN-jSO zpPOGjDmS`=Zf8!_zvs{!?WJ98{f(Ju2MNXVUZ6^3m(nLpLnckHi8o;`d^-LT12(k~ ztP8FIh^4>q;y!|>r*Yw%91-=QloLnm9Tr3fV=D1K8r7f{51ZU$Bi%0a!lRVWmgRoy zdd^dsCQ{dV^5XuSjDyQ=Qg}F>eA^)U0!`K4gc3|z9;!>7H2T4eViq{*{S5?Rw9#$2 zn;32E)+IOa{LTYTSx)9aE$Hh96CZ|>a|+&^Rsti-B;kj?ASCmW{}XOCwoBzfnkV9L zC}j>VVOnfWV6Dz+mpZc)?X_tpk5tB$<&pqnW=Q`mFqkNY0i zBsK`b0+dp%;M_bGp53=h&L)IG`CO+7z)nFY*P`#UZS1&{D@FcXsQ4@rY1#&$(6C-o zJoS1-$#^WEbk4+qPHPDh*Y|M*UKXY(+48oOT2E&Y_un zGx}qA_UR$L4@f5N%ZopxCOGtLdNR1#{Ez(bo0j@gj%5?*ZoZA0A1{6^`g&G}YCX04 zmT|Dax!Hp<`waXV2-wLo8+m!90ex=NT`pRi&nv$u#Yt}b{ZabnGEmEy^88tqsL+Uo zkHab`4i|s?S3HMd+urB^S>_Zsk|QhU23>hrXVrvD!ZRr##M`#kbbzPl|NG_ydI0`~)?qiD8x>g#S5*t-|y%r4e6Jp0X@fL$ri= zUFT#pg{Z5y8b%%UOZ@iSZCI;U)QmnCKN8rAC>YJ>r51bl%CSzQ5kDc; zeJ|%<5k0`0Wpzh9h4QZ=nV7t_In?l^0MUGW%tc#lQ5t}2g7Rk#`w>;$Q8K6PjbwAxhP`xF7JO(cVKJ2b+3$nLn}3(cGtU>%278cV zO8Z%##rI8(6WC82nCXu(sLdC`I%wUn>lQJQ@^FH08>G28V zFTM>tSs&;3t=3gt$^D%_cW9#eK_Bt55Jz&dE$e*jHrPKr?N=b*=CWycCZJV!LO@s9 zcg_&Zt`UqRe;&mo)2aPg`Ju4MJlPJ}BE6gRb4;oDB!WM6B~Gp7yA1!c%}o2g{(