├── .dockerignore ├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ ├── lint.yml │ ├── main.yml │ ├── npm-publish.yaml │ ├── publish-slim-version.yaml │ ├── publish.yaml │ ├── script.js │ └── update-npm-packages.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .nvmrc ├── Dockerfile ├── LICENSE ├── README.md ├── apps └── velo-external-db │ ├── .eslintrc.json │ ├── .gitignore │ ├── .nvmrc │ ├── .travis.yml │ ├── Dockerfile │ ├── collection-level-roles-config.json │ ├── jest.config.ts │ ├── project.json │ ├── roles-config.json │ ├── src │ ├── app.ts │ ├── auth │ │ ├── auth_request_handlers.js │ │ └── auth_router.js │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── global.d.ts │ ├── main.ts │ └── storage │ │ ├── factory.ts │ │ └── stub-db │ │ ├── init.ts │ │ ├── providers.ts │ │ └── stub-connector.ts │ ├── test │ ├── drivers │ │ ├── app_info_config_test_support.ts │ │ ├── authorization_test_support.ts │ │ ├── data_api_rest_test_support.ts │ │ ├── data_provider_matchers.ts │ │ ├── hooks_test_support.ts │ │ ├── index_api_rest_matchers.ts │ │ ├── index_api_rest_test_support.ts │ │ ├── schema_api_rest_matchers.ts │ │ ├── schema_api_rest_test_support.ts │ │ ├── schema_provider_matchers.ts │ │ ├── wix_data_resources.ts │ │ └── wix_data_testkit.ts │ ├── e2e │ │ ├── app.e2e.spec.ts │ │ ├── app_auth.e2e.spec.ts │ │ ├── app_data.e2e.spec.ts │ │ ├── app_data_hooks.e2e.spec.ts │ │ ├── app_index.e2e.spec.ts │ │ ├── app_schema.e2e.spec.ts │ │ └── app_schema_hooks.e2e.spec.ts │ ├── env │ │ ├── ci_utils.ts │ │ ├── env.db.setup.js │ │ └── env.db.teardown.js │ ├── gen.ts │ ├── resources │ │ ├── docker-compose.yaml │ │ ├── e2e_resources.ts │ │ ├── engines │ │ │ └── init-mongo.js │ │ ├── operations_resources.ts │ │ ├── provider_resources.ts │ │ └── test_suite_definition.ts │ ├── storage │ │ ├── data_provider.spec.ts │ │ ├── database_operation.spec.ts │ │ └── schema_provider.spec.ts │ ├── types.ts │ └── utils │ │ └── eventually.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── jest.config.ts ├── jest.preset.js ├── libs ├── external-db-airtable │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── airtable_config_validator.ts │ │ ├── airtable_data_provider.ts │ │ ├── airtable_operations.ts │ │ ├── airtable_schema_provider.ts │ │ ├── airtable_utils.ts │ │ ├── connection_provider.ts │ │ ├── index.ts │ │ ├── sql_exception_translator.ts │ │ ├── sql_filter_transformer.spec.ts │ │ ├── sql_filter_transformer.ts │ │ ├── sql_schema_translator.spec.ts │ │ ├── sql_schema_translator.ts │ │ └── supported_operations.ts │ ├── tests │ │ ├── drivers │ │ │ ├── air_table_base.js │ │ │ ├── air_table_mock_utils.js │ │ │ ├── air_table_table.js │ │ │ ├── db_operations_test_support.ts │ │ │ ├── mock_air_table.js │ │ │ └── sql_filter_transformer_test_support.ts │ │ └── e2e-testkit │ │ │ └── airtable_resources.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-bigquery │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── bigquery_capabilities.ts │ │ ├── bigquery_config_validator.ts │ │ ├── bigquery_data_provider.ts │ │ ├── bigquery_operations.ts │ │ ├── bigquery_schema_provider.ts │ │ ├── bigquery_utils.spec.ts │ │ ├── bigquery_utils.ts │ │ ├── bigquery_utils_test_support.ts │ │ ├── connection_provider.ts │ │ ├── index.ts │ │ ├── sql_exception_translator.ts │ │ ├── sql_filter_transformer.spec.ts │ │ ├── sql_filter_transformer.ts │ │ ├── sql_schema_translator.spec.ts │ │ ├── sql_schema_translator.ts │ │ ├── supported_operations.ts │ │ └── types.ts │ ├── tests │ │ ├── drivers │ │ │ ├── db_operations_test_support.ts │ │ │ └── sql_filter_transformer_test_support.ts │ │ └── e2e-testkit │ │ │ └── bigquery_resources.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-config │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── factory.ts │ │ ├── index.ts │ │ ├── readers │ │ │ ├── auth-deprecated │ │ │ │ ├── aws_auth_config_reader.js │ │ │ │ ├── azure_auth_config_reader.js │ │ │ │ └── gcp_auth_config_reader.js │ │ │ ├── authorization_config_reader.ts │ │ │ ├── aws_authorization_config_reader.ts │ │ │ ├── aws_config_reader.ts │ │ │ ├── azure_config_reader.ts │ │ │ ├── common_config_reader.ts │ │ │ ├── gcp_config_reader.ts │ │ │ └── stub_config_reader.ts │ │ ├── service │ │ │ ├── config_reader.ts │ │ │ ├── config_validator.spec.ts │ │ │ └── config_validator_matchers.ts │ │ ├── types.ts │ │ ├── utils │ │ │ ├── config_utils.spec.ts │ │ │ └── config_utils.ts │ │ └── validators │ │ │ ├── authorization_config_validator.ts │ │ │ ├── common_config_validator.spec.ts │ │ │ ├── common_config_validator.ts │ │ │ └── config_validator.ts │ ├── test │ │ ├── drivers │ │ │ ├── aws_mongo_config_test_support.ts │ │ │ ├── aws_mysql_config_test_support.ts │ │ │ ├── azure_mysql_config_test_support.ts │ │ │ ├── common_config_test_support.ts │ │ │ ├── external_config_reader_e2e_test_support.ts │ │ │ ├── external_db_config_test_support.ts │ │ │ ├── gcp_firestore_config_test_support.ts │ │ │ ├── gcp_mysql_config_test_support.ts │ │ │ └── gcp_spanner_config_test_support.ts │ │ ├── e2e │ │ │ ├── external_db_config_client.e2e.spec.ts │ │ │ └── external_db_config_client_matcher.ts │ │ ├── gen.ts │ │ ├── provider │ │ │ └── config_reader_service.spec.ts │ │ ├── test_types.ts │ │ └── test_utils.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-dynamodb │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── connection_provider.ts │ │ ├── dynamo_capabilities.ts │ │ ├── dynamo_config_validator.ts │ │ ├── dynamo_data_provider.ts │ │ ├── dynamo_data_requests_utils.ts │ │ ├── dynamo_operations.ts │ │ ├── dynamo_schema_provider.ts │ │ ├── dynamo_schema_requests_utils.ts │ │ ├── dynamo_utils.spec.ts │ │ ├── dynamo_utils.ts │ │ ├── index.ts │ │ ├── sql_exception_translator.ts │ │ ├── sql_filter_transformer.spec.ts │ │ ├── sql_filter_transformer.ts │ │ ├── supported_operations.ts │ │ └── types.ts │ ├── tests │ │ ├── drivers │ │ │ ├── db_operations_test_support.ts │ │ │ └── sql_filter_transformer_test_support.ts │ │ ├── e2e-testkit │ │ │ ├── docker-compose.yaml │ │ │ └── dynamodb_resources.ts │ │ └── gen.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-firestore │ ├── .eslintrc.json │ ├── .gitignore │ ├── .nvmrc │ ├── README.md │ ├── jest.config.js │ ├── package.json │ ├── project.json │ ├── src │ │ ├── connection_provider.ts │ │ ├── firestore_capabilities.ts │ │ ├── firestore_config_validator.ts │ │ ├── firestore_data_provider.ts │ │ ├── firestore_operations.ts │ │ ├── firestore_schema_provider.ts │ │ ├── firestore_utils.ts │ │ ├── index.ts │ │ ├── sql_exception_translator.ts │ │ ├── sql_filter_transformer.spec.ts │ │ ├── sql_filter_transformer.ts │ │ ├── supported_operations.ts │ │ └── types.ts │ ├── tests │ │ ├── drivers │ │ │ ├── broken_creds.json │ │ │ ├── db_operations_test_support.ts │ │ │ └── sql_filter_transformer_test_support.ts │ │ ├── e2e-testkit │ │ │ ├── docker-compose.yaml │ │ │ └── firestore_resources.ts │ │ └── gen.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-google-sheets │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── connection_provider.ts │ │ ├── google_sheet_config_validator.ts │ │ ├── google_sheet_data_provider.ts │ │ ├── google_sheet_exception_translator.ts │ │ ├── google_sheet_operations.ts │ │ ├── google_sheet_schema_provider.ts │ │ ├── google_sheet_utils.ts │ │ ├── index.ts │ │ ├── supported_operations.ts │ │ └── types.ts │ ├── tests │ │ ├── drivers │ │ │ ├── db_operations_test_support.ts │ │ │ └── sql_filter_transformer_test_support.ts │ │ ├── e2e-testkit │ │ │ ├── google_sheets_resources.ts │ │ │ └── service_account_key.json │ │ ├── google_sheet_doc_class.js │ │ ├── google_sheet_sheet_class.js │ │ ├── google_sheets_test_utils.js │ │ ├── mock-server.js │ │ ├── mock_google_sheets_api.js │ │ ├── sql_filter_transformer_test_support.js │ │ └── templates.js │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-logger │ ├── .eslintrc.json │ ├── README.md │ ├── index.ts │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── logger.ts │ │ └── types.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-mongo │ ├── .eslintrc.json │ ├── .gitignore │ ├── .nvmrc │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── connection_provider.ts │ │ ├── exception_translator.ts │ │ ├── index.ts │ │ ├── mongo_capabilities.ts │ │ ├── mongo_config_validator.ts │ │ ├── mongo_data_provider.ts │ │ ├── mongo_operations.ts │ │ ├── mongo_schema_provider.ts │ │ ├── mongo_utils.spec.ts │ │ ├── mongo_utils.ts │ │ ├── sql_filter_transformer.spec.ts │ │ ├── sql_filter_transformer.ts │ │ ├── supported_operations.ts │ │ └── types.ts │ ├── tests │ │ ├── drivers │ │ │ ├── db_operations_test_support.ts │ │ │ └── sql_filter_transformer_test_support.ts │ │ └── e2e-testkit │ │ │ ├── docker-compose.yaml │ │ │ ├── init-mongo.js │ │ │ └── mongo_resources.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-mssql │ ├── .eslintrc.json │ ├── .gitignore │ ├── .nvmrc │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── connection_provider.ts │ │ ├── index.ts │ │ ├── mssql_capabilities.ts │ │ ├── mssql_config_validator.ts │ │ ├── mssql_data_provider.ts │ │ ├── mssql_operations.ts │ │ ├── mssql_schema_provider.ts │ │ ├── mssql_utils.spec.ts │ │ ├── mssql_utils.ts │ │ ├── sql_exception_translator.ts │ │ ├── sql_filter_transformer.spec.ts │ │ ├── sql_filter_transformer.ts │ │ ├── sql_schema_translator.spec.ts │ │ ├── sql_schema_translator.ts │ │ ├── supported_operations.ts │ │ └── types.ts │ ├── tests │ │ ├── drivers │ │ │ ├── db_operations_test_support.ts │ │ │ └── sql_filter_transformer_test_support.ts │ │ └── e2e-testkit │ │ │ ├── docker-compose.yaml │ │ │ └── mssql_resources.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-mysql │ ├── .eslintrc.json │ ├── .gitignore │ ├── .nvmrc │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── config_validator.spec.ts │ │ ├── connection_provider.ts │ │ ├── index.ts │ │ ├── mysql_capabilities.ts │ │ ├── mysql_config_validator.ts │ │ ├── mysql_data_provider.ts │ │ ├── mysql_index_provider.ts │ │ ├── mysql_operations.ts │ │ ├── mysql_schema_provider.ts │ │ ├── mysql_utils.spec.ts │ │ ├── mysql_utils.ts │ │ ├── sql_exception_translator.ts │ │ ├── sql_filter_transformer.spec.ts │ │ ├── sql_filter_transformer.ts │ │ ├── sql_schema_translator.spec.ts │ │ ├── sql_schema_translator.ts │ │ ├── supported_operations.ts │ │ └── types.ts │ ├── tests │ │ ├── drivers │ │ │ ├── db_operations_test_support.ts │ │ │ └── sql_filter_transformer_test_support.ts │ │ ├── e2e-testkit │ │ │ ├── docker-compose.yaml │ │ │ └── mysql_resources.ts │ │ └── gen.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-postgres │ ├── .eslintrc.json │ ├── .gitignore │ ├── .nvmrc │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── config_validator.spec.ts │ │ ├── connection_provider.ts │ │ ├── index.ts │ │ ├── postgres_capabilities.ts │ │ ├── postgres_config_validator.ts │ │ ├── postgres_data_provider.ts │ │ ├── postgres_index_provider.ts │ │ ├── postgres_operations.ts │ │ ├── postgres_schema_provider.ts │ │ ├── postgres_utils.spec.ts │ │ ├── postgres_utils.ts │ │ ├── sql_exception_translator.ts │ │ ├── sql_filter_transformer.spec.ts │ │ ├── sql_filter_transformer.ts │ │ ├── sql_schema_translator.spec.ts │ │ ├── sql_schema_translator.ts │ │ ├── supported_operations.ts │ │ └── types.ts │ ├── tests │ │ ├── drivers │ │ │ ├── db_operations_test_support.ts │ │ │ └── sql_filter_transformer_test_support.ts │ │ ├── e2e-testkit │ │ │ ├── docker-compose.yaml │ │ │ └── postgres_resources.ts │ │ └── gen.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-security │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── auth-providers │ │ │ ├── aws_auth_provider.js │ │ │ ├── azure_auth_provider.js │ │ │ ├── factory.js │ │ │ ├── gcp_auth_provider.js │ │ │ └── stub_auth_provider.js │ │ ├── index.ts │ │ ├── services │ │ │ ├── role_authorization.spec.ts │ │ │ └── role_authorization.ts │ │ └── test │ │ │ └── gen.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-spanner │ ├── .eslintrc.json │ ├── .gitignore │ ├── .nvmrc │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── connection_provider.ts │ │ ├── escaping.spec.ts │ │ ├── index.ts │ │ ├── spanner_capabilities.ts │ │ ├── spanner_config_validator.ts │ │ ├── spanner_data_provider.ts │ │ ├── spanner_operations.ts │ │ ├── spanner_schema_provider.ts │ │ ├── spanner_utils.spec.ts │ │ ├── spanner_utils.ts │ │ ├── sql_exception_translator.ts │ │ ├── sql_filter_transformer.spec.ts │ │ ├── sql_filter_transformer.ts │ │ ├── sql_schema_translator.spec.ts │ │ ├── sql_schema_translator.ts │ │ ├── supported_operations.ts │ │ └── types.ts │ ├── tests │ │ ├── drivers │ │ │ ├── db_operations_test_support.ts │ │ │ └── sql_filter_transformer_test_support.ts │ │ └── e2e-testkit │ │ │ ├── docker-compose.yaml │ │ │ └── spanner_resources.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── external-db-testkit │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── auth_test_support.ts │ │ │ ├── docker_support.js │ │ │ └── e2e_resources.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── test-commons │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── libs │ │ │ ├── auth-config.json │ │ │ ├── gen.ts │ │ │ └── test-commons.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── velo-external-db-commons │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── libs │ │ │ ├── config_commons.ts │ │ │ ├── data_commons.ts │ │ │ ├── db_connector.ts │ │ │ ├── errors.ts │ │ │ ├── schema_commons.ts │ │ │ └── types.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── velo-external-db-core │ ├── .eslintrc.json │ ├── .gitignore │ ├── .nvmrc │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── assets │ │ │ ├── cloud_bg.svg │ │ │ ├── cloudy-bg.svg │ │ │ ├── dark_bg.svg │ │ │ ├── lightbulb_icon.svg │ │ │ ├── sad-unicorn.svg │ │ │ ├── sad-wix.svg │ │ │ ├── stylesheets │ │ │ │ └── style.css │ │ │ └── wix-logo.svg │ │ ├── converters │ │ │ ├── aggregation_transformer.spec.ts │ │ │ ├── aggregation_transformer.ts │ │ │ ├── data_utils.spec.ts │ │ │ ├── data_utils.ts │ │ │ ├── filter_transformer.spec.ts │ │ │ ├── filter_transformer.ts │ │ │ ├── item_transformer.js │ │ │ ├── item_transformer.spec.ts │ │ │ ├── query_validator.spec.ts │ │ │ ├── query_validator.ts │ │ │ ├── query_validator_utils.spec.ts │ │ │ ├── query_validator_utils.ts │ │ │ └── utils.ts │ │ ├── data_hooks_utils.spec.ts │ │ ├── data_hooks_utils.ts │ │ ├── health │ │ │ ├── app_info.spec.ts │ │ │ └── app_info.ts │ │ ├── index.ts │ │ ├── roles-config.json │ │ ├── router.ts │ │ ├── schema_hooks_utils.spec.ts │ │ ├── schema_hooks_utils.ts │ │ ├── service │ │ │ ├── data.spec.ts │ │ │ ├── data.ts │ │ │ ├── indexing.spec.ts │ │ │ ├── indexing.ts │ │ │ ├── operation.spec.ts │ │ │ ├── operation.ts │ │ │ ├── schema.spec.ts │ │ │ ├── schema.ts │ │ │ ├── schema_aware_data.spec.ts │ │ │ ├── schema_aware_data.ts │ │ │ ├── schema_information.spec.ts │ │ │ └── schema_information.ts │ │ ├── spi-model │ │ │ ├── capabilities.ts │ │ │ ├── collection.ts │ │ │ ├── data_source.ts │ │ │ ├── errors.ts │ │ │ ├── filter.ts │ │ │ └── indexing.ts │ │ ├── types.ts │ │ ├── utils │ │ │ ├── base64_utils.ts │ │ │ ├── data_utils.ts │ │ │ ├── date_time_provider.js │ │ │ ├── router_utils.build.ts │ │ │ ├── router_utils.ts │ │ │ ├── schema_utils.spec.ts │ │ │ └── schema_utils.ts │ │ ├── views │ │ │ ├── error.ejs │ │ │ ├── index-without-data.ejs │ │ │ ├── index.ejs │ │ │ ├── login.ejs │ │ │ └── partials │ │ │ │ └── details.ejs │ │ └── web │ │ │ ├── auth-role-middleware.spec.ts │ │ │ ├── auth-role-middleware.ts │ │ │ ├── domain-to-spi-error-translator.ts │ │ │ ├── error-middleware.spec.ts │ │ │ ├── error-middleware.ts │ │ │ ├── jwt-verifier-decoder-middleware.spec.ts │ │ │ ├── jwt-verifier-decoder-middleware.ts │ │ │ ├── jwt-verifier-test-support.ts │ │ │ ├── jwt-verifier.spec.ts │ │ │ ├── jwt-verifier.ts │ │ │ ├── middleware-support.ts │ │ │ └── wix_data_facade.ts │ ├── test │ │ ├── drivers │ │ │ ├── aggregation_transformer_test_support.ts │ │ │ ├── app_info_test_support.ts │ │ │ ├── auth_middleware_test_support.ts │ │ │ ├── data_provider_test_support.ts │ │ │ ├── data_service_test_support.ts │ │ │ ├── date_time_provider_test_support.js │ │ │ ├── filter_transformer_test_support.ts │ │ │ ├── index_provider_test_support.ts │ │ │ ├── item_patcher_test_support.ts │ │ │ ├── operation_provider_test_support.ts │ │ │ ├── query_validator_test_support.ts │ │ │ ├── schema_information_test_support.ts │ │ │ ├── schema_matchers.ts │ │ │ └── schema_provider_test_support.ts │ │ └── gen.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json └── velo-external-db-types │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ ├── collection_types.ts │ ├── index.ts │ └── indexing_types.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── lint-staged.config.js ├── nx.json ├── package.json ├── scripts ├── data-tools │ ├── .gitignore │ ├── lib │ │ ├── adapter │ │ │ ├── data.js │ │ │ └── schema.js │ │ ├── cli │ │ │ ├── display.js │ │ │ └── user-input.js │ │ ├── core │ │ │ └── process.js │ │ ├── generator │ │ │ ├── data.js │ │ │ └── schema.js │ │ ├── index.js │ │ └── utils │ │ │ ├── request.js │ │ │ └── utils.js │ └── package.json ├── provision │ ├── .gitignore │ ├── README.MD │ ├── lib │ │ ├── auth │ │ │ └── default_credentials.js │ │ ├── cli │ │ │ ├── display.js │ │ │ ├── user-input.js │ │ │ └── validators.js │ │ ├── cloud-providers │ │ │ ├── aws │ │ │ │ ├── aws_adapter_provision.js │ │ │ │ ├── aws_config_writer.js │ │ │ │ ├── aws_db_provision.js │ │ │ │ ├── aws_network_provision.js │ │ │ │ ├── aws_permissions_provision.js │ │ │ │ ├── aws_ui_utils.js │ │ │ │ ├── db │ │ │ │ │ ├── factory.js │ │ │ │ │ ├── mssql_support.js │ │ │ │ │ ├── mysql_support.js │ │ │ │ │ └── postgres_support.js │ │ │ │ └── index.js │ │ │ ├── azure │ │ │ │ ├── azure_adapter_provision.js │ │ │ │ ├── azure_config_writer.js │ │ │ │ ├── azure_db_provision.js │ │ │ │ ├── azure_network.js │ │ │ │ ├── azure_permissions_provision.js │ │ │ │ ├── azure_ui_utils.js │ │ │ │ ├── db │ │ │ │ │ ├── factory.js │ │ │ │ │ ├── mysql_support.js │ │ │ │ │ └── postgres_support.js │ │ │ │ ├── index.js │ │ │ │ └── utils.js │ │ │ ├── factory.js │ │ │ └── gcp │ │ │ │ ├── gcp_adapter_provision.js │ │ │ │ ├── gcp_config_writer.js │ │ │ │ ├── gcp_db_provision.js │ │ │ │ ├── gcp_network_provision.js │ │ │ │ ├── gcp_permissions_provision.js │ │ │ │ ├── gcp_ui_utils.js │ │ │ │ └── index.js │ │ ├── core │ │ │ └── provision.js │ │ ├── index.js │ │ └── utils │ │ │ ├── password_utils.js │ │ │ └── utils.js │ └── package.json └── terraform │ ├── .gitignore │ ├── README.MD │ ├── azure │ ├── mysql │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ └── postgres │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── gcp │ ├── main.tf │ ├── outputs.tf │ └── variables.tf │ └── package.json ├── supported-operations-table.md ├── tools └── scripts │ ├── publish.mjs │ └── publishCi.mjs ├── tsconfig.base.json └── workspace.json /.dockerignore: -------------------------------------------------------------------------------- 1 | # FOLDERS 2 | 3 | node_modules 4 | .vscode 5 | .github 6 | .husky 7 | scripts 8 | tmp 9 | tools 10 | 11 | 12 | # FILES 13 | 14 | npm-debug.log 15 | Dockerfile* 16 | docker-compose* 17 | .dockerignore 18 | .git 19 | .gitignore 20 | README.md 21 | LICENSE 22 | .eslintcache 23 | .eslintrc.json 24 | .nvmrc -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/* 2 | **/node_modules/** -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: "*" 6 | 7 | workflow_dispatch: 8 | 9 | jobs: 10 | Lint: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Use Node.js 16 15 | uses: actions/setup-node@v2 16 | with: 17 | node-version: lts/* 18 | 19 | - name: Installing Dependencies 20 | run: npm install 21 | 22 | - name: Install dependencies of the homemade packages. 23 | run: npm run build:dev 24 | 25 | - name: Linting 26 | run: npm run lint 27 | 28 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish NPM packages 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | publish_npm_package: 8 | 9 | runs-on: ubuntu-latest 10 | env: 11 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 12 | 13 | steps: 14 | - name: Git checkout 15 | uses: actions/checkout@v3 16 | 17 | - uses: actions/setup-node@v3 18 | with: 19 | node-version: '16.x' 20 | registry-url: 'https://registry.npmjs.org' 21 | 22 | - name: Installing NX 23 | run: npm install -g nx 24 | 25 | - run: npm install 26 | 27 | - name: publish to npm 28 | run: | 29 | nx run-many --exclude=velo-external-db --target=publishCi --all 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /.github/workflows/script.js: -------------------------------------------------------------------------------- 1 | module.exports = async ({github, context, core}) => { 2 | const execSync = require('child_process').execSync 3 | 4 | const { version } = context.payload.inputs 5 | delete context.payload.inputs.version 6 | 7 | for (const [packageName, toUpdate] of Object.entries(context.payload.inputs)) { 8 | console.log({ [packageName]: toUpdate }) 9 | if (toUpdate == 'true') { 10 | const result = execSync(`nx run @${packageName}:publish --ver=${version}`).toString() 11 | console.log({ result }) 12 | } 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /.github/workflows/update-npm-packages.yml: -------------------------------------------------------------------------------- 1 | name: Update npm Packages and Create PR 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | update-dep: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - uses: actions/setup-node@v3 12 | with: 13 | node-version: '20.x' 14 | - name: Update dependencies 15 | run: | 16 | npx -p npm-check-updates ncu -u 17 | npm install 18 | - name: Create Pull Request 19 | uses: peter-evans/create-pull-request@v7 20 | with: 21 | commit-message: Update dependencies 22 | title: Update dependencies 23 | body: | 24 | - Dependency updates 25 | branch: update-dependencies 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | .vscode 9 | packages/.DS_Store 10 | .DS_Store 11 | .eslintcache 12 | .infracost 13 | 14 | # dependencies 15 | node_modules 16 | 17 | # compiled output 18 | /dist 19 | /tmp 20 | /out-tsc 21 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged --allow-empty 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Compile stage 2 | FROM node:20-slim 3 | WORKDIR /usr/lib/app 4 | 5 | # Copy the project dir 6 | COPY . . 7 | 8 | # Install NX and project dependencies 9 | RUN npm install -g nx 10 | RUN npm install 11 | 12 | # Build the JS files 13 | RUN nx run-many --target=build --all 14 | 15 | 16 | FROM node:20-alpine 17 | 18 | WORKDIR /usr/lib/app 19 | 20 | # Copy the compiled JS files from the compile stage 21 | COPY --from=0 /usr/lib/app/dist/apps/velo-external-db . 22 | 23 | # Install dependencies 24 | RUN npm install --production 25 | 26 | # Run the app 27 | CMD node ./main.js 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Wix.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /apps/velo-external-db/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/velo-external-db/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | -------------------------------------------------------------------------------- /apps/velo-external-db/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* -------------------------------------------------------------------------------- /apps/velo-external-db/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "14" -------------------------------------------------------------------------------- /apps/velo-external-db/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-alpine 2 | WORKDIR /app 3 | COPY ./dist/apps/velo-external-db . 4 | # ENV PORT=8080 5 | # EXPOSE ${PORT} 6 | RUN npm install --production 7 | # dependencies that nestjs needs 8 | # RUN npm install reflect-metadata tslib rxjs @nestjs/platform-express 9 | CMD node ./main.js -------------------------------------------------------------------------------- /apps/velo-external-db/collection-level-roles-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "collectionPermissions": [] 3 | } -------------------------------------------------------------------------------- /apps/velo-external-db/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'velo-external-db', 3 | preset: '../../jest.preset.js', 4 | clearMocks: true, 5 | verbose: true, 6 | roots: ['/src', '/test'], 7 | globals: { 8 | 'ts-jest': { 9 | tsconfig: '/tsconfig.spec.json', 10 | }, 11 | }, 12 | // testRegex: '(.*\\.spec\\.)js$', 13 | testEnvironment: 'node', 14 | transform: { 15 | '^.+\\.[tj]s$': 'ts-jest', 16 | }, 17 | globalSetup: './test/env/env.db.setup.js', 18 | globalTeardown: './test/env/env.db.teardown.js', 19 | testTimeout: 20000, 20 | moduleFileExtensions: ['ts', 'js', 'html'], 21 | setupFilesAfterEnv: ['jest-extended/all'], 22 | coverageDirectory: '../../coverage/apps/ex-db-template', 23 | maxWorkers: 1, 24 | } 25 | -------------------------------------------------------------------------------- /apps/velo-external-db/roles-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": [ 3 | { 4 | "pathPrefix": "/schemas/column", 5 | "roles": ["OWNER"] 6 | }, 7 | { 8 | "pathPrefix": "/schemas/create", 9 | "roles": ["OWNER"] 10 | }, 11 | { 12 | "pathPrefix": "/schemas/list", 13 | "roles": ["OWNER", "BACKEND_CODE", "MEMBER"] 14 | }, 15 | { 16 | "pathPrefix": "/schemas/find", 17 | "roles": ["OWNER", "BACKEND_CODE", "MEMBER", "VISITOR"] 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /apps/velo-external-db/src/auth/auth_request_handlers.js: -------------------------------------------------------------------------------- 1 | 2 | const passport = require('passport') 3 | 4 | const AuthName = 'external-db-authorization' 5 | const CallbackRedirectOptions = { 6 | successReturnToOrRedirect: '/', 7 | failureRedirect: '/auth/login' 8 | } 9 | 10 | const initAuthenticationFrameworkWith = (authProvider) => { 11 | passport.use(AuthName, authProvider) 12 | passport.serializeUser((user, done) => done(null, user)) 13 | passport.deserializeUser((obj, done) => done(null, obj)) 14 | } 15 | 16 | const userAuthenticationHandler = passport.authenticate(AuthName) 17 | 18 | const authenticatedUserHandler = passport.authenticate(AuthName, CallbackRedirectOptions) 19 | 20 | const logoutUserHandler = (req, res) => { 21 | req.logout() 22 | res.redirect('/') 23 | } 24 | 25 | module.exports = { 26 | initAuthenticationFrameworkWith, userAuthenticationHandler, authenticatedUserHandler, logoutUserHandler 27 | } 28 | -------------------------------------------------------------------------------- /apps/velo-external-db/src/auth/auth_router.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const auth = require('./auth_request_handlers') 3 | 4 | let authProvider 5 | 6 | const initAuthService = ( _authProvider ) => { 7 | authProvider = _authProvider 8 | } 9 | 10 | const createAuthRouter = () => { 11 | const router = express.Router() 12 | 13 | auth.initAuthenticationFrameworkWith(authProvider) 14 | 15 | router.get('/auth/login', auth.userAuthenticationHandler) 16 | 17 | router.get('/auth/callback', auth.authenticatedUserHandler) 18 | 19 | router.get('/auth/logout', auth.logoutUserHandler) 20 | 21 | return router 22 | 23 | } 24 | 25 | module.exports = { createAuthRouter, initAuthService } 26 | -------------------------------------------------------------------------------- /apps/velo-external-db/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | } 4 | -------------------------------------------------------------------------------- /apps/velo-external-db/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false, 3 | } 4 | -------------------------------------------------------------------------------- /apps/velo-external-db/src/global.d.ts: -------------------------------------------------------------------------------- 1 | import 'jest-extended' 2 | -------------------------------------------------------------------------------- /apps/velo-external-db/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from './app' 2 | 3 | createApp() 4 | -------------------------------------------------------------------------------- /apps/velo-external-db/src/storage/stub-db/init.ts: -------------------------------------------------------------------------------- 1 | import { StubDataProvider, StubDatabaseOperations, StubSchemaProvider } from './providers' 2 | 3 | export default (type: string) => ( 4 | { dataProvider: new StubDataProvider(), schemaProvider: new StubSchemaProvider(), databaseOperations: new StubDatabaseOperations(type), connection: {}, cleanup: {} } 5 | ) 6 | -------------------------------------------------------------------------------- /apps/velo-external-db/src/storage/stub-db/providers.ts: -------------------------------------------------------------------------------- 1 | import { checkRequiredKeys } from '@wix-velo/velo-external-db-commons' 2 | import { errors } from '@wix-velo/velo-external-db-commons' 3 | const { UnsupportedDatabase } = errors 4 | 5 | export class StubDataProvider {} 6 | 7 | export class StubConfigValidator { 8 | config: any 9 | constructor(config: any) { 10 | this.config = config 11 | } 12 | 13 | readConfig() { 14 | return this.config 15 | } 16 | 17 | validate() { 18 | return { 19 | missingRequiredSecretsKeys: checkRequiredKeys(this.config, []) 20 | } 21 | } 22 | } 23 | 24 | export class StubDatabaseOperations { 25 | type: any 26 | constructor(type: any) { 27 | this.type = type 28 | } 29 | 30 | validateConnection() { 31 | return { valid: false, error: new UnsupportedDatabase(`Unknown db type: ${this.type}`) } 32 | } 33 | } 34 | 35 | export class StubSchemaProvider { 36 | constructor() { 37 | } 38 | 39 | list() { 40 | return {} 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /apps/velo-external-db/src/storage/stub-db/stub-connector.ts: -------------------------------------------------------------------------------- 1 | import { DbConnector } from '@wix-velo/velo-external-db-commons' 2 | import init from './init' 3 | import { StubConfigValidator } from './providers' 4 | 5 | class StubConnector extends DbConnector { 6 | constructor(type: string) { 7 | // @ts-ignore - todo: fix this 8 | super(StubConfigValidator, init) 9 | this.type = type 10 | } 11 | } 12 | 13 | 14 | const stubFactory = async(type: string, config: any) => { 15 | const connector = new StubConnector(type) 16 | const { connection, cleanup, ...providers } = await connector.initialize(type, config) 17 | return { connector, connection, providers, cleanup } 18 | } 19 | 20 | 21 | module.exports = { StubConnector, stubFactory } 22 | -------------------------------------------------------------------------------- /apps/velo-external-db/test/drivers/app_info_config_test_support.ts: -------------------------------------------------------------------------------- 1 | import { dbTeardown, initApp } from '../resources/e2e_resources' 2 | 3 | export const givenHideAppInfoEnvIsTrue = async() => { 4 | await dbTeardown() 5 | process.env.HIDE_APP_INFO = 'true' 6 | await initApp() 7 | 8 | // Fix for tests running in Node 20. 9 | await new Promise(resolve => setTimeout(resolve, 5)) 10 | } 11 | -------------------------------------------------------------------------------- /apps/velo-external-db/test/drivers/authorization_test_support.ts: -------------------------------------------------------------------------------- 1 | import { VeloRole } from '@wix-velo/velo-external-db-types' 2 | import { dbTeardown, initApp } from '../resources/e2e_resources' 3 | 4 | const DefaultPolicies = ['Admin'] 5 | 6 | const authRoleConfig = (collectionName: string, read: VeloRole[], write: VeloRole[]) => { 7 | const config = { 8 | collectionPermissions: [ 9 | { 10 | id: collectionName, 11 | read: [...DefaultPolicies, ...read], 12 | write: [...DefaultPolicies, ...write] 13 | } 14 | ] 15 | } 16 | process.env.PERMISSIONS = JSON.stringify(config) 17 | } 18 | 19 | export const givenCollectionWithVisitorReadPolicy = async(collectionName: string) => { 20 | await dbTeardown() 21 | authRoleConfig(collectionName, ['Visitor'], []) 22 | await initApp() 23 | 24 | // Fix for tests running in Node 20. 25 | await new Promise(resolve => setTimeout(resolve, 5)) 26 | } 27 | -------------------------------------------------------------------------------- /apps/velo-external-db/test/drivers/data_provider_matchers.ts: -------------------------------------------------------------------------------- 1 | import { Item, ResponseField } from '@wix-velo/velo-external-db-types' 2 | 3 | export const entitiesWithOwnerFieldOnly = (entities: Item[]) => expect.arrayContaining(entities.map((e: Item) => ({ _owner: e._owner }))) 4 | 5 | export const entityWithObjectField = (entity: Item, entityFields: ResponseField[]) => { 6 | const { field: objectFieldName } = entityFields.find((f: { type: string }) => f.type === 'object') 7 | const stringifyObjectField = JSON.stringify(entity[objectFieldName]) 8 | 9 | return expect.arrayContaining([ 10 | expect.objectContaining({ 11 | ...entity, 12 | [objectFieldName]: expect.toBeOneOf([entity[objectFieldName], expect.toEqualIgnoringWhitespace(stringifyObjectField)]) 13 | }) 14 | ]) 15 | } 16 | -------------------------------------------------------------------------------- /apps/velo-external-db/test/drivers/wix_data_resources.ts: -------------------------------------------------------------------------------- 1 | import { Server } from 'http' 2 | import { app as mockServer } from './wix_data_testkit' 3 | 4 | let _server: Server 5 | const PORT = 9001 6 | 7 | export const initWixDataEnv = async() => { 8 | _server = mockServer.listen(PORT) 9 | } 10 | 11 | export const shutdownWixDataEnv = async() => { 12 | _server.close() 13 | } 14 | 15 | export const wixDataBaseUrl = () => { 16 | return `http://localhost:${PORT}` 17 | } 18 | -------------------------------------------------------------------------------- /apps/velo-external-db/test/drivers/wix_data_testkit.ts: -------------------------------------------------------------------------------- 1 | import { authConfig } from '@wix-velo/test-commons' 2 | import * as express from 'express' 3 | 4 | export const app = express() 5 | 6 | app.set('case sensitive routing', true) 7 | 8 | app.use(express.json()) 9 | 10 | app.get('/v1/external-databases/:externalDatabaseId/public-keys', (_req, res) => { 11 | res.json({ 12 | publicKeys: [ 13 | { id: authConfig.kid, publicKeyPem: authConfig.authPublicKey }, 14 | ] 15 | }) 16 | }) 17 | 18 | app.use((_req, res) => { 19 | res.status(404) 20 | res.json({ error: 'NOT_FOUND' }) 21 | }) 22 | 23 | app.use((err, _req, res, next) => { 24 | res.status(err.status) 25 | res.json({ 26 | error: { 27 | message: err.message, 28 | status: err.status, 29 | error: err.error 30 | } 31 | }) 32 | next() 33 | }) 34 | -------------------------------------------------------------------------------- /apps/velo-external-db/test/env/ci_utils.ts: -------------------------------------------------------------------------------- 1 | 2 | export const LocalDev = () => process.env.CI === undefined || process.env.CI === 'false' 3 | 4 | export const engineWithoutDocker = (engine: string) => (enginesWithoutDocker.includes(engine)) 5 | 6 | const enginesWithoutDocker = ['airtable', 'google-sheet'] 7 | -------------------------------------------------------------------------------- /apps/velo-external-db/test/resources/engines/init-mongo.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | db.createUser( 3 | { 4 | user: 'root', 5 | pwd: 'pass', 6 | roles: [ 7 | { 8 | role: 'dbOwner', 9 | db: 'testdb' 10 | } 11 | ] 12 | } 13 | ) 14 | -------------------------------------------------------------------------------- /apps/velo-external-db/test/resources/test_suite_definition.ts: -------------------------------------------------------------------------------- 1 | export const suiteDef = (name: string, setup: any, testResources: any) => ({ 2 | name, 3 | setup, 4 | supportedOperations: testResources.supportedOperations, 5 | capabilities: testResources.capabilities 6 | }) 7 | -------------------------------------------------------------------------------- /apps/velo-external-db/test/utils/eventually.ts: -------------------------------------------------------------------------------- 1 | import * as trier from 'trier-promise' 2 | 3 | const defaults = { 4 | timeout: 5000, 5 | interval: 200 6 | } 7 | 8 | export const eventually = async(fn: any, opts?: { timeout?: number; interval?: number }) => { 9 | return Promise.resolve().then(() => { 10 | let error = null 11 | const action = () => Promise.resolve().then(fn).catch(err => { 12 | error = err 13 | throw err 14 | }) 15 | const options = Object.assign({ action }, defaults, opts) 16 | 17 | return trier(options).catch(() => { 18 | if (error !== null) { 19 | error.message = `Timeout of ${options.timeout} ms with: ` + error.message 20 | } 21 | throw error 22 | }) 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /apps/velo-external-db/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["node", "express"] 7 | }, 8 | "exclude": [ 9 | "jest.config.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.ts", 12 | "**/*.spec.js", 13 | "**/*.test.js" 14 | ], 15 | "include": ["**/*.ts", "**/*.js"] 16 | } 17 | -------------------------------------------------------------------------------- /apps/velo-external-db/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "allowJs": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /apps/velo-external-db/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "**/*.test.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.tsx", 13 | "**/*.spec.tsx", 14 | "**/*.test.js", 15 | "**/*.spec.js", 16 | "**/*.test.jsx", 17 | "**/*.spec.jsx", 18 | "**/*.d.ts", 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { getJestProjects } from '@nrwl/jest' 2 | 3 | export default { 4 | projects: getJestProjects() 5 | } 6 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nrwl/jest/preset').default 2 | 3 | module.exports = { ...nxPreset } 4 | -------------------------------------------------------------------------------- /libs/external-db-airtable/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-airtable/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | -------------------------------------------------------------------------------- /libs/external-db-airtable/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-airtable/README.md -------------------------------------------------------------------------------- /libs/external-db-airtable/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-airtable', 3 | clearMocks: true, 4 | verbose: true, 5 | // roots: ['/src'], 6 | // testRegex: '(.*\\.spec\\.)js$', 7 | preset: '../../jest.preset.js', 8 | globals: { 9 | 'ts-jest': { 10 | tsconfig: '/tsconfig.spec.json', 11 | }, 12 | }, 13 | transform: { 14 | '^.+\\.[tj]s$': 'ts-jest', 15 | }, 16 | moduleFileExtensions: ['ts', 'js', 'html'], 17 | coverageDirectory: '../../coverage/libs/external-db-airtable', 18 | testEnvironment: 'node' 19 | } 20 | -------------------------------------------------------------------------------- /libs/external-db-airtable/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-airtable", 3 | "version": "1.2.0", 4 | "type": "commonjs" 5 | } -------------------------------------------------------------------------------- /libs/external-db-airtable/src/airtable_config_validator.ts: -------------------------------------------------------------------------------- 1 | import { IConfigValidator } from '@wix-velo/velo-external-db-types' 2 | import { checkRequiredKeys } from '@wix-velo/velo-external-db-commons' 3 | 4 | export class AirtableConfigValidator implements IConfigValidator { 5 | config: any 6 | constructor(config: any) { 7 | this.config = config 8 | } 9 | 10 | readConfig() { 11 | return this.config 12 | } 13 | 14 | validate() { 15 | return { 16 | missingRequiredSecretsKeys: checkRequiredKeys(this.config, ['AIRTABLE_API_KEY', 'META_API_KEY', 'BASE_ID']) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/external-db-airtable/src/airtable_operations.ts: -------------------------------------------------------------------------------- 1 | 2 | import { notThrowingTranslateErrorCodes } from './sql_exception_translator' 3 | import { Base as AirtableBase } from 'airtable' 4 | import { IDatabaseOperations, ValidateConnectionResult } from '@wix-velo/velo-external-db-types' 5 | 6 | export default class DatabaseOperations implements IDatabaseOperations { 7 | base: AirtableBase 8 | baseId: string 9 | constructor(base: any) { 10 | this.base = base 11 | this.baseId = base.getId() 12 | } 13 | 14 | async validateConnection(): Promise { 15 | try { 16 | await this.base('Table') 17 | .select({}) 18 | .firstPage() 19 | return { valid: true } 20 | } catch (e) { 21 | if (this.connectionSucceedTableDoesNotExist(e)) return { valid: true } 22 | return { valid: false, error: notThrowingTranslateErrorCodes(e) } 23 | } 24 | } 25 | 26 | connectionSucceedTableDoesNotExist(e: any) { 27 | return e.message === `Could not find table Table in application ${this.baseId}` 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libs/external-db-airtable/src/airtable_utils.ts: -------------------------------------------------------------------------------- 1 | export const minifyAndFixDates = (record: { _createdDate: string | number | Date; _updatedDate: string | number | Date }) => { 2 | if (record._createdDate && typeof record._createdDate === 'string') record._createdDate = new Date(record._createdDate) 3 | if (record._updatedDate && typeof record._updatedDate === 'string') record._updatedDate = new Date(record._updatedDate) 4 | return record 5 | } 6 | export const DEFAULT_MAX_RECORDS = 100 7 | 8 | export const EmptySort = { sort: [] } 9 | -------------------------------------------------------------------------------- /libs/external-db-airtable/src/sql_exception_translator.ts: -------------------------------------------------------------------------------- 1 | import { errors } from '@wix-velo/velo-external-db-commons' 2 | const { DbConnectionError } = errors 3 | 4 | export const notThrowingTranslateErrorCodes = (err: any) => { 5 | switch (err.error) { 6 | case 'NOT_FOUND': 7 | return new DbConnectionError(`Base does not exists: Airtable message : ${err.message}`) 8 | case 'AUTHENTICATION_REQUIRED': 9 | return new DbConnectionError(`Authentication failed: Airtable message: ${err.message}`) 10 | default: 11 | return new DbConnectionError(err.message) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /libs/external-db-airtable/src/supported_operations.ts: -------------------------------------------------------------------------------- 1 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 2 | 3 | const { List, ListHeaders, Create, Drop, AddColumn, Describe, NotOperator } = SchemaOperations 4 | 5 | export const supportedOperations = [ List, ListHeaders, Create, Drop, AddColumn, Describe, NotOperator ] 6 | -------------------------------------------------------------------------------- /libs/external-db-airtable/tests/drivers/air_table_base.js: -------------------------------------------------------------------------------- 1 | const { AirtableTable } = require('./air_table_table') 2 | const chance = require('chance')() 3 | 4 | class AirtableBase { 5 | constructor(id, name) { 6 | this.id = id 7 | this.name = name 8 | this.tables = [] 9 | } 10 | 11 | tablesList() { 12 | return { 13 | tables: this.tables.map(table => table.info()) 14 | } 15 | } 16 | 17 | getTable(tableName) { 18 | return this.tables.find(table => table.name === tableName) 19 | 20 | } 21 | 22 | createTable(tableName, columns) { 23 | this.tables.push(new AirtableTable(`tbl${chance.word({ length: 14 })}`, tableName)) 24 | const table = this.getTable(tableName) 25 | columns.forEach(column => { 26 | table.addColumn(column.name, column.type) 27 | }) 28 | } 29 | deleteTable(tableName) { 30 | this.tables = this.tables.filter(table => table.name !== tableName) 31 | } 32 | } 33 | module.exports = { AirtableBase } 34 | -------------------------------------------------------------------------------- /libs/external-db-airtable/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-airtable/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-airtable/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-bigquery/README.md -------------------------------------------------------------------------------- /libs/external-db-bigquery/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-bigquery', 3 | clearMocks: true, 4 | verbose: true, 5 | preset: '../../jest.preset.js', 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | }, 10 | }, 11 | transform: { 12 | '^.+\\.[tj]s$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'js', 'html'], 15 | coverageDirectory: '../../coverage/libs/external-db-bigquery', 16 | testEnvironment: 'node' 17 | } 18 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-bigquery", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } -------------------------------------------------------------------------------- /libs/external-db-bigquery/src/bigquery_config_validator.ts: -------------------------------------------------------------------------------- 1 | import { checkRequiredKeys } from '@wix-velo/velo-external-db-commons' 2 | 3 | export default class ConfigValidator { 4 | config: any 5 | requiredKeys: string[] 6 | 7 | constructor(config: any) { 8 | this.config = config 9 | this.requiredKeys = ['projectId', 'databaseId'] 10 | } 11 | 12 | readConfig() { 13 | return this.config 14 | } 15 | 16 | validate() { 17 | return { 18 | missingRequiredSecretsKeys: checkRequiredKeys(this.config, this.requiredKeys) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/src/bigquery_operations.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { Dataset } from '@google-cloud/bigquery' 4 | import { errors } from '@wix-velo/velo-external-db-commons' 5 | import { IDatabaseOperations, ValidateConnectionResult } from '@wix-velo/velo-external-db-types' 6 | const { DbConnectionError, UnauthorizedError } = errors 7 | 8 | const notThrowingTranslateErrorCodes = (err: any) => { 9 | switch (err.code) { 10 | case 404: 11 | return new DbConnectionError(err.message) 12 | default : 13 | return new UnauthorizedError(`${err.code} ${err.message}`) 14 | } 15 | } 16 | 17 | export default class DatabaseOperations implements IDatabaseOperations { 18 | pool: Dataset 19 | constructor(pool: Dataset) { 20 | this.pool = pool 21 | } 22 | 23 | async validateConnection(): Promise { 24 | try { 25 | await this.pool.getMetadata() 26 | return { valid: true } 27 | 28 | } catch (error) { 29 | return { valid: false, error: notThrowingTranslateErrorCodes(error) } 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/src/bigquery_utils_test_support.ts: -------------------------------------------------------------------------------- 1 | import { when } from 'jest-when' 2 | 3 | export const bigQueryItem: any = {} 4 | 5 | export const givenNullValueTo = ( propertyName: string ) => bigQueryItem[propertyName] = null 6 | 7 | 8 | export const givenNumberValueTo = (propertyName: string, number: number) => { 9 | bigQueryItem[propertyName] = { toNumber: jest.fn() } 10 | when(bigQueryItem[propertyName].toNumber).calledWith().mockReturnValue(number) 11 | } 12 | 13 | export const givenDateValueTo = (propertyName: string, date: Date) => { 14 | bigQueryItem[propertyName] = { value: date.toISOString() } 15 | } 16 | 17 | export const givenWrongFormatDateValueTo = (propertyName: string, date: Date) => { 18 | bigQueryItem[propertyName] = date.toISOString() 19 | } 20 | export const reset = () => { 21 | Object.keys(bigQueryItem).forEach(key => delete bigQueryItem[key]) 22 | } 23 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/src/connection_provider.ts: -------------------------------------------------------------------------------- 1 | import { BigQuery, Dataset } from '@google-cloud/bigquery' 2 | import FilterParser from './sql_filter_transformer' 3 | import DatabaseOperations from './bigquery_operations' 4 | import SchemaProvider from './bigquery_schema_provider' 5 | import DataProvider from './bigquery_data_provider' 6 | import { BigQueryConfig } from './types' 7 | import { DbProviders } from '@wix-velo/velo-external-db-types' 8 | 9 | export default ({ projectId, databaseId }: BigQueryConfig): DbProviders => { 10 | const bigquery = new BigQuery() 11 | const pool = bigquery.dataset(databaseId) 12 | 13 | const filterParser = new FilterParser() 14 | const databaseOperations = new DatabaseOperations(pool) 15 | const dataProvider = new DataProvider(pool, filterParser) 16 | const schemaProvider = new SchemaProvider(pool, { projectId, databaseId }) 17 | 18 | return { 19 | dataProvider, 20 | schemaProvider, 21 | databaseOperations, 22 | connection: pool, 23 | cleanup: async() => {} 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/src/supported_operations.ts: -------------------------------------------------------------------------------- 1 | import { AllSchemaOperations } from '@wix-velo/velo-external-db-commons' 2 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 3 | 4 | const notSupportedOperations = [ 5 | SchemaOperations.UpdateImmediately, 6 | SchemaOperations.DeleteImmediately, 7 | SchemaOperations.StartWithCaseInsensitive, 8 | SchemaOperations.PrimaryKey, 9 | SchemaOperations.ChangeColumnType, 10 | SchemaOperations.Indexing, 11 | ] 12 | 13 | export const supportedOperations = AllSchemaOperations.filter(op => !notSupportedOperations.includes(op)) 14 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface BigQueryConfig { 2 | projectId: string 3 | databaseId: string 4 | } 5 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/tests/drivers/db_operations_test_support.ts: -------------------------------------------------------------------------------- 1 | import DatabaseOperations from '../../src/bigquery_operations' 2 | import init from '../../src/connection_provider' 3 | 4 | const createPool = (modify: any) => { 5 | const config = {} 6 | const { connection, cleanup } = init({ ...config, ...modify }) 7 | return { connection, cleanup } 8 | } 9 | 10 | const dbOperationWithMisconfiguredDatabaseId = () => new DatabaseOperations(createPool({ databaseId: 'wrong' }).connection) 11 | 12 | export const dbOperationWithValidDB = () => { 13 | const { connection, cleanup } = createPool({ databaseId: 'testDB' }) 14 | const dbOperations = new DatabaseOperations(connection) 15 | return { dbOperations, cleanup } 16 | } 17 | 18 | export const misconfiguredDbOperationOptions = () => ([ ['pool connection with wrong databaseId', () => dbOperationWithMisconfiguredDatabaseId()]]) 19 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-bigquery/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-config/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-config/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | .vscode 9 | -------------------------------------------------------------------------------- /libs/external-db-config/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-config/README.md -------------------------------------------------------------------------------- /libs/external-db-config/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-config', 3 | preset: '../../jest.preset.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsconfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | transform: { 10 | '^.+\\.[tj]s$': 'ts-jest', 11 | }, 12 | moduleFileExtensions: ['ts', 'js', 'html'], 13 | coverageDirectory: '../../coverage/libs/velo-external-db-commons', 14 | clearMocks: true, 15 | verbose: true, 16 | // testRegex: '(.*\\.spec\\.)js$', 17 | } 18 | 19 | -------------------------------------------------------------------------------- /libs/external-db-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-config", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /libs/external-db-config/src/index.ts: -------------------------------------------------------------------------------- 1 | import CommonConfigReader from './readers/common_config_reader' 2 | 3 | export { create } from './factory' 4 | export { AuthorizationConfigValidator } from './validators/authorization_config_validator' 5 | export { CommonConfigValidator } from './validators/common_config_validator' 6 | export { ConfigValidator } from './validators/config_validator' 7 | export const readCommonConfig = () => new CommonConfigReader().readConfig() 8 | 9 | -------------------------------------------------------------------------------- /libs/external-db-config/src/readers/auth-deprecated/azure_auth_config_reader.js: -------------------------------------------------------------------------------- 1 | const { checkRequiredKeys } = require('../utils/config_utils') 2 | 3 | class AzureAuthConfigReader { 4 | constructor() { 5 | } 6 | 7 | async readConfig() { 8 | const { callbackUrl, clientId, clientSecret } = process.env 9 | return { callbackUrl, clientId, clientSecret } 10 | } 11 | 12 | validate() { 13 | return { 14 | missingRequiredSecretsKeys: checkRequiredKeys(process.env, ['callbackUrl', 'clientId', 'clientSecret']) 15 | } 16 | } 17 | } 18 | 19 | module.exports = { AzureAuthConfigReader } 20 | -------------------------------------------------------------------------------- /libs/external-db-config/src/readers/auth-deprecated/gcp_auth_config_reader.js: -------------------------------------------------------------------------------- 1 | const { checkRequiredKeys } = require('../utils/config_utils') 2 | 3 | class GcpAuthConfigReader { 4 | constructor() { 5 | } 6 | 7 | async readConfig() { 8 | const { callbackUrl, clientId, clientSecret } = process.env 9 | return { callbackUrl, clientId, clientSecret } 10 | } 11 | 12 | validate() { 13 | return { 14 | missingRequiredSecretsKeys: checkRequiredKeys(process.env, ['callbackUrl', 'clientId', 'clientSecret']) 15 | } 16 | } 17 | } 18 | 19 | module.exports = { GcpAuthConfigReader } 20 | -------------------------------------------------------------------------------- /libs/external-db-config/src/readers/authorization_config_reader.ts: -------------------------------------------------------------------------------- 1 | import { IConfigReader } from '../types' 2 | import { isJson, jsonParser } from '../utils/config_utils' 3 | 4 | export default class AuthorizationConfigReader implements IConfigReader { 5 | constructor() { 6 | } 7 | 8 | async readConfig() { 9 | const { PERMISSIONS: roleConfig } = process.env 10 | 11 | return isJson(roleConfig) ? jsonParser((roleConfig) as string) : roleConfig 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /libs/external-db-config/src/readers/azure_config_reader.ts: -------------------------------------------------------------------------------- 1 | import { IConfigReader } from '../types' 2 | 3 | export class AzureConfigReader implements IConfigReader { 4 | constructor() { 5 | } 6 | 7 | async readConfig() { 8 | const { HOST, USER, PASSWORD, DB, UNSECURED_ENV, DB_PORT, JWT_PUBLIC_KEY, APP_DEF_ID } = process.env 9 | return { host: HOST, user: USER, password: PASSWORD, db: DB, unsecuredEnv: UNSECURED_ENV, port: DB_PORT, 10 | jwtPublicKey: JWT_PUBLIC_KEY, appDefId: APP_DEF_ID } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /libs/external-db-config/src/readers/common_config_reader.ts: -------------------------------------------------------------------------------- 1 | import { IConfigReader } from '../types' 2 | 3 | export default class CommonConfigReader implements IConfigReader { 4 | constructor() { } 5 | 6 | readConfig() { 7 | const { CLOUD_VENDOR, TYPE, REGION, SECRET_NAME, HIDE_APP_INFO, READ_ONLY_SCHEMA } = process.env 8 | return { vendor: CLOUD_VENDOR, type: TYPE, region: REGION, secretId: SECRET_NAME, hideAppInfo: HIDE_APP_INFO ? HIDE_APP_INFO === 'true' : undefined, readOnlySchema: READ_ONLY_SCHEMA ? READ_ONLY_SCHEMA === 'true' : undefined } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/external-db-config/src/readers/stub_config_reader.ts: -------------------------------------------------------------------------------- 1 | import { IConfigReader } from '../types' 2 | 3 | export default class StubConfigReader implements IConfigReader { 4 | constructor() { 5 | } 6 | 7 | readConfig() { 8 | return {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/external-db-config/src/service/config_reader.ts: -------------------------------------------------------------------------------- 1 | import CommonConfigReader from '../readers/common_config_reader' 2 | import { IAuthorizationConfigReader, IConfigReader } from '../types' 3 | 4 | export default class ConfigReader { 5 | externalConfigReader: IConfigReader 6 | commonConfigReader: CommonConfigReader 7 | authorizationConfig: IAuthorizationConfigReader 8 | constructor(externalConfigReader: IConfigReader, commonConfigReader: CommonConfigReader, authorizationConfigReader: IAuthorizationConfigReader) { 9 | this.externalConfigReader = externalConfigReader 10 | this.commonConfigReader = commonConfigReader 11 | this.authorizationConfig = authorizationConfigReader 12 | } 13 | 14 | async readConfig() { 15 | const externalConfig = await this.externalConfigReader.readConfig() 16 | const authorizationConfig = await this.authorizationConfig.readConfig() 17 | return { ...externalConfig, authorization: authorizationConfig } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/external-db-config/src/types.ts: -------------------------------------------------------------------------------- 1 | import AuthorizationConfigReader from './readers/authorization_config_reader' 2 | import AwsAuthorizationConfigReader from './readers/aws_authorization_config_reader' 3 | import StubConfigReader from './readers/stub_config_reader' 4 | 5 | export interface IConfigReader { 6 | readConfig(): any 7 | readExternalAndLocalConfig?(): any 8 | readExternalConfig?(): any 9 | } 10 | 11 | export type IAuthorizationConfigReader = AuthorizationConfigReader | StubConfigReader | AwsAuthorizationConfigReader 12 | -------------------------------------------------------------------------------- /libs/external-db-config/test/drivers/common_config_test_support.ts: -------------------------------------------------------------------------------- 1 | import CommonConfigReader from '../../src/readers/common_config_reader' 2 | import * as Chance from 'chance' 3 | import { CommonConfig } from '../test_types' 4 | const chance = new Chance() 5 | 6 | export const defineValidConfig = (config: CommonConfig) => { 7 | if (config.vendor) { 8 | process.env['CLOUD_VENDOR'] = config.vendor 9 | } 10 | if (config.type) { 11 | process.env['TYPE'] = config.type 12 | } 13 | if (config.hideAppInfo !== undefined) { 14 | process.env['HIDE_APP_INFO'] = config.hideAppInfo.toString() 15 | } 16 | } 17 | 18 | export const validConfig = (): CommonConfig => ({ 19 | vendor: chance.word(), 20 | type: chance.word(), 21 | hideAppInfo: chance.bool(), 22 | }) 23 | 24 | export const ExpectedProperties = ['CLOUD_VENDOR', 'TYPE', 'HIDE_APP_INFO'] 25 | 26 | export const reset = () => ExpectedProperties.forEach(p => delete process.env[p]) 27 | export const hasReadErrors = false 28 | export const configReaderProvider = new CommonConfigReader() 29 | -------------------------------------------------------------------------------- /libs/external-db-config/test/e2e/external_db_config_client.e2e.spec.ts: -------------------------------------------------------------------------------- 1 | import { Uninitialized } from '@wix-velo/test-commons' 2 | import { env, initEnv, reset } from '../drivers/external_config_reader_e2e_test_support' 3 | const each = require('jest-each').default 4 | 5 | each( 6 | [ 7 | ['AZURE', ['mysql', 'postgres']], 8 | ['AWS', ['mysql', 'postgres', 'mongo']], 9 | ['GCP', ['mysql', 'postgres', 'spanner', 'firestore']] 10 | ] 11 | ).describe('Config Reader for %s', (vendor: string, engines: string) => { 12 | 13 | each(engines).describe('Engine %s', (engine: string) => { 14 | 15 | beforeAll(async() => { 16 | initEnv(vendor, engine) 17 | }) 18 | 19 | const ctx = { 20 | config: Uninitialized 21 | } 22 | 23 | beforeEach(async() => { 24 | reset() 25 | ctx.config = env.driver.validConfigWithAuthorization() 26 | }) 27 | 28 | 29 | test('read config', async() => { 30 | env.driver.defineValidConfig(ctx.config) 31 | 32 | await expect( env.configReader.readConfig() ).resolves.toEqual(ctx.config) 33 | }) 34 | }) 35 | 36 | }) 37 | 38 | -------------------------------------------------------------------------------- /libs/external-db-config/test/e2e/external_db_config_client_matcher.ts: -------------------------------------------------------------------------------- 1 | export const invalidConfigStatusResponse = () => expect.objectContaining({ 2 | message: expect.stringContaining('Missing props'), 3 | validConfig: false, 4 | validAuthorization: false, 5 | }) 6 | -------------------------------------------------------------------------------- /libs/external-db-config/test/gen.ts: -------------------------------------------------------------------------------- 1 | import * as Chance from 'chance' 2 | import { supportedVendors, supportedDBs } from '../src/utils/config_utils' 3 | const chance = Chance() 4 | 5 | export const randomConfig = () => ({ 6 | host: chance.url(), 7 | user: chance.first(), 8 | password: chance.guid(), 9 | db: chance.word(), 10 | }) 11 | 12 | export const randomCommonConfig = () => ({ 13 | jwtPublicKey: chance.guid(), 14 | appDefId: chance.guid(), 15 | }) 16 | 17 | export const randomExtendedCommonConfig = () => ({ 18 | jwtPublicKey: chance.guid(), 19 | appDefId: chance.guid(), 20 | vendor: chance.pickone(supportedVendors), 21 | type: chance.pickone(supportedDBs), 22 | }) 23 | -------------------------------------------------------------------------------- /libs/external-db-config/test/test_utils.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as Chance from 'chance' 3 | import { gen } from '@wix-velo/test-commons' 4 | 5 | const chance = new Chance() 6 | const { randomElementsFromArray } = gen 7 | 8 | export const validAuthorizationConfig = { 9 | collectionPermissions: [ 10 | { 11 | id: chance.word(), 12 | read: ['Admin'], 13 | write: ['Admin'], 14 | } 15 | ] 16 | } 17 | 18 | export const splitConfig = (config: {[key: string]: any}) => { 19 | const firstPart = randomElementsFromArray(Object.keys(config)).reduce((pV, cV) => ({ ...pV, [cV]: config[cV] }), {}) 20 | 21 | const secondPart = Object.keys(config).filter(k => firstPart[k] === undefined) 22 | .reduce((pV, cV) => ({ ...pV, [cV]: config[cV] }), {}) 23 | return { firstPart, secondPart } 24 | } 25 | 26 | export const extendedCommonConfigRequiredProperties = ['jwtPublicKey', 'appDefId', 'vendor', 'type'] 27 | -------------------------------------------------------------------------------- /libs/external-db-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-config/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-config/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-dynamodb/README.md -------------------------------------------------------------------------------- /libs/external-db-dynamodb/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-dynamodb', 3 | clearMocks: true, 4 | verbose: true, 5 | // roots: ['/src'], 6 | // testRegex: '(.*\\.spec\\.)js$', 7 | preset: '../../jest.preset.js', 8 | globals: { 9 | 'ts-jest': { 10 | tsconfig: '/tsconfig.spec.json', 11 | }, 12 | }, 13 | transform: { 14 | '^.+\\.[tj]s$': 'ts-jest', 15 | }, 16 | moduleFileExtensions: ['ts', 'js', 'html'], 17 | coverageDirectory: '../../coverage/libs/external-db-dynamodb', 18 | testEnvironment: 'node' 19 | } 20 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-dynamodb", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } -------------------------------------------------------------------------------- /libs/external-db-dynamodb/src/connection_provider.ts: -------------------------------------------------------------------------------- 1 | import SchemaProvider from'./dynamo_schema_provider' 2 | import DataProvider from './dynamo_data_provider' 3 | import FilterParser from './sql_filter_transformer' 4 | import DatabaseOperations from './dynamo_operations' 5 | import { DynamoDB } from '@aws-sdk/client-dynamodb' 6 | import { DynamoConfig } from './types' 7 | 8 | 9 | const extraOptions = (cfg: DynamoConfig) => { 10 | if (cfg.endpoint) 11 | return { endpoint: cfg.endpoint } 12 | return {} 13 | } 14 | 15 | 16 | export default (cfg: DynamoConfig, _cfgOptions?: {[x: string]: any}) => { 17 | const options = _cfgOptions || {} 18 | const client = new DynamoDB({ region: cfg.region, ...extraOptions(cfg), ...options, logger: undefined }) 19 | const databaseOperations = new DatabaseOperations(client) 20 | 21 | const filterParser = new FilterParser() 22 | const dataProvider = new DataProvider(client, filterParser) 23 | const schemaProvider = new SchemaProvider(client) 24 | 25 | return { dataProvider, schemaProvider, databaseOperations, connection: client, cleanup: () => {} } 26 | } 27 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/src/dynamo_config_validator.ts: -------------------------------------------------------------------------------- 1 | import { checkRequiredKeys } from '@wix-velo/velo-external-db-commons' 2 | import { IConfigValidator } from '@wix-velo/velo-external-db-types' 3 | 4 | export default class ConfigValidator implements IConfigValidator { 5 | config: any 6 | requiredKeys: string[] 7 | constructor(config: any) { 8 | this.config = config 9 | this.requiredKeys = ['region'] 10 | } 11 | 12 | readConfig() { 13 | return this.config 14 | } 15 | 16 | validate() { 17 | return { 18 | missingRequiredSecretsKeys: checkRequiredKeys(this.config, this.requiredKeys) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/src/dynamo_operations.ts: -------------------------------------------------------------------------------- 1 | import { IDatabaseOperations } from '@wix-velo/velo-external-db-types' 2 | import { notThrowingTranslateErrorCodes } from './sql_exception_translator' 3 | 4 | export default class DatabaseOperations implements IDatabaseOperations { 5 | client: any 6 | constructor(client: any) { 7 | this.client = client 8 | } 9 | 10 | async validateConnection() { 11 | return await this.client.listTables({}).then(() => { return { valid: true } }) 12 | .catch((e: any) => { return { valid: false, error: notThrowingTranslateErrorCodes(e) } }) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/src/dynamo_utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { errors } from '@wix-velo/velo-external-db-commons' 2 | import { validateTable } from './dynamo_utils' 3 | const { InvalidQuery } = errors 4 | 5 | describe('Dynamo Utils', () => { 6 | describe('validateTable', () => { 7 | test('validateTable will not allow systemTable', () => { 8 | expect(() => validateTable('_descriptor')).toThrow(InvalidQuery) 9 | }) 10 | 11 | test('validateTable will not allow variation of systemTable', () => { 12 | expect(() => validateTable('_dEscRiptoR')).toThrow() 13 | }) 14 | 15 | test('validateTable will not throw with valid table name', () => { 16 | expect(() => validateTable('someTable')).not.toThrow() 17 | }) 18 | }) 19 | 20 | }) 21 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SchemaProvider } from './dynamo_schema_provider' 2 | export { default as DataProvider } from './dynamo_data_provider' 3 | export { default as FilterParser } from './sql_filter_transformer' 4 | export { default as DatabaseOperations } from './dynamo_operations' 5 | export { default as init } from './connection_provider' 6 | export * as testResources from '../tests/e2e-testkit/dynamodb_resources' 7 | 8 | import init from './connection_provider' 9 | import { DbConnector } from '@wix-velo/velo-external-db-commons' 10 | import ConfigValidator from './dynamo_config_validator' 11 | 12 | export const driver = () => require('../tests/drivers/sql_filter_transformer_test_support') 13 | export const opsDriver = () => require('../tests/drivers/db_operations_test_support') 14 | 15 | export class DynamoDbConnector extends DbConnector { 16 | constructor() { 17 | super(ConfigValidator, init) 18 | this.type = 'dynamoDB' 19 | } 20 | } 21 | 22 | export const dynamoDbFactory = async(config: any, options: any) => { 23 | const connector = new DynamoDbConnector() 24 | const { connection, cleanup, ...providers } = await connector.initialize(config, options) 25 | return { connector, connection, providers, cleanup } 26 | } 27 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/src/supported_operations.ts: -------------------------------------------------------------------------------- 1 | import { AllSchemaOperations } from '@wix-velo/velo-external-db-commons' 2 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 3 | 4 | const notSupportedOperations = [ 5 | SchemaOperations.FindWithSort, 6 | SchemaOperations.Aggregate, 7 | SchemaOperations.StartWithCaseInsensitive, 8 | SchemaOperations.FindObject, 9 | SchemaOperations.IncludeOperator, 10 | SchemaOperations.Matches, 11 | SchemaOperations.NonAtomicBulkInsert, 12 | SchemaOperations.Indexing, 13 | ] 14 | 15 | 16 | 17 | export const supportedOperations = AllSchemaOperations.filter(op => !notSupportedOperations.includes(op)) 18 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/src/types.ts: -------------------------------------------------------------------------------- 1 | export type DynamoParsedFilter = { 2 | FilterExpression?: string, 3 | KeyConditionExpression?: string, 4 | ExpressionAttributeNames?: { [key: string]: string }, 5 | ExpressionAttributeValues?: { [key: string]: any } 6 | ProjectionExpression?: { [key: string]: string } 7 | } 8 | 9 | export interface DynamoConfig { 10 | region: string 11 | endpoint?: string 12 | [x: string]: any 13 | } 14 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/tests/e2e-testkit/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | dynamodb: 4 | image: amazon/dynamodb-local:latest 5 | restart: always 6 | ports: 7 | - 8000:8000 8 | environment: 9 | AWS_REGION: us-west-2 10 | AWS_ACCESS_KEY_ID: TestAccessKeyId 11 | AWS_SECRET_ACCESS_KEY: TestSecretAccessKey 12 | networks: 13 | - backend 14 | 15 | networks: 16 | backend: 17 | driver: bridge 18 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/tests/gen.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import * as Chance from 'chance' 4 | import { AdapterOperators } from '@wix-velo/velo-external-db-commons' 5 | const { eq, gt, gte, include, lt, lte, string_begins, string_ends, string_contains } = AdapterOperators 6 | 7 | const chance = Chance() 8 | 9 | const operatorsWithoutEqual = [lt, lte, gt, gte, include, string_contains, string_begins, string_ends] 10 | const randomOperatorWithoutEqual = () => ( chance.pickone(operatorsWithoutEqual) ) 11 | const randomAdapterOperator = () => ( chance.pickone([...operatorsWithoutEqual, eq]) ) 12 | 13 | 14 | export const idFilter = ({ withoutEqual }: {withoutEqual: boolean} = { withoutEqual: false }) => { 15 | const operator = withoutEqual ? randomOperatorWithoutEqual() : randomAdapterOperator() 16 | const value = operator === '$hasSome' ? [chance.word(), chance.word(), chance.word(), chance.word(), chance.word()] : chance.word() 17 | return { 18 | fieldName: '_id', 19 | operator, 20 | value 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-dynamodb/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-firestore/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-firestore/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | -------------------------------------------------------------------------------- /libs/external-db-firestore/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* -------------------------------------------------------------------------------- /libs/external-db-firestore/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-firestore/README.md -------------------------------------------------------------------------------- /libs/external-db-firestore/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'external-db-firestore', 3 | clearMocks: true, 4 | verbose: true, 5 | preset: '../../jest.preset.js', 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | }, 10 | }, 11 | transform: { 12 | '^.+\\.[tj]s$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'js', 'html'], 15 | coverageDirectory: '../../coverage/libs/external-db-firestore', 16 | testEnvironment: 'node' 17 | } 18 | -------------------------------------------------------------------------------- /libs/external-db-firestore/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-firestore", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } -------------------------------------------------------------------------------- /libs/external-db-firestore/src/connection_provider.ts: -------------------------------------------------------------------------------- 1 | import SchemaProvider from './firestore_schema_provider' 2 | import DataProvider from './firestore_data_provider' 3 | import FilterParser from './sql_filter_transformer' 4 | import DatabaseOperations from './firestore_operations' 5 | import { Firestore } from '@google-cloud/firestore' 6 | import { firestoreConfig } from './types' 7 | import { DbProviders } from '@wix-velo/velo-external-db-types' 8 | 9 | export default ({ projectId }: firestoreConfig): DbProviders => { 10 | const firestore = new Firestore({ 11 | projectId, 12 | ignoreUndefinedProperties: true 13 | }) 14 | 15 | const databaseOperations = new DatabaseOperations(firestore) 16 | const filterParser = new FilterParser() 17 | const dataProvider = new DataProvider(firestore, filterParser) 18 | const schemaProvider = new SchemaProvider(firestore) 19 | 20 | return { 21 | dataProvider, 22 | schemaProvider, 23 | databaseOperations, 24 | connection: firestore, 25 | cleanup: async() => await firestore.terminate() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /libs/external-db-firestore/src/firestore_config_validator.ts: -------------------------------------------------------------------------------- 1 | import { checkRequiredKeys } from '@wix-velo/velo-external-db-commons' 2 | import { IConfigValidator } from '@wix-velo/velo-external-db-types' 3 | 4 | export class ConfigValidator implements IConfigValidator { 5 | requiredKeys: string[] 6 | config: any 7 | 8 | constructor(config: any) { 9 | this.requiredKeys = ['projectId'] 10 | this.config = config 11 | } 12 | 13 | readConfig() { 14 | return this.config 15 | } 16 | 17 | validate() { 18 | return { 19 | missingRequiredSecretsKeys: checkRequiredKeys(this.config, this.requiredKeys) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libs/external-db-firestore/src/firestore_operations.ts: -------------------------------------------------------------------------------- 1 | import { Firestore } from '@google-cloud/firestore' 2 | import { IDatabaseOperations, ValidateConnectionResult } from '@wix-velo/velo-external-db-types' 3 | import { notThrowingTranslateErrorCodes } from './sql_exception_translator' 4 | 5 | export default class DatabaseOperations implements IDatabaseOperations { 6 | database: Firestore 7 | 8 | public constructor(database: Firestore) { 9 | this.database = database 10 | } 11 | 12 | async validateConnection(): Promise { 13 | try { 14 | await this.database.listCollections() 15 | return { valid: true } 16 | } catch (error) { 17 | return { valid: false, error: notThrowingTranslateErrorCodes(error) } 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /libs/external-db-firestore/src/firestore_utils.ts: -------------------------------------------------------------------------------- 1 | import { Timestamp, DocumentData, QueryDocumentSnapshot } from '@google-cloud/firestore' 2 | 3 | export const LastLetterCoder = String.fromCharCode(65535) 4 | 5 | export const fixDates = (value : any) => { 6 | if (value instanceof Timestamp) { 7 | return value.toDate() 8 | } 9 | return value 10 | } 11 | 12 | 13 | export const asEntity = (docEntity: QueryDocumentSnapshot) => { 14 | const doc = docEntity.data() 15 | return Object.keys(doc) 16 | .reduce(function(obj: { [key: string]: any}, key: any) { 17 | return { ...obj, [key]: fixDates(doc[key]) } 18 | }.bind(this), {}) 19 | } 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /libs/external-db-firestore/src/index.ts: -------------------------------------------------------------------------------- 1 | import { DbConnector } from '@wix-velo/velo-external-db-commons' 2 | import { ConfigValidator } from './firestore_config_validator' 3 | export { default as SchemaProvider } from './firestore_schema_provider' 4 | export { default as DataProvider } from './firestore_data_provider' 5 | export { default as FilterParser } from './sql_filter_transformer' 6 | export { default as DatabaseOperations } from './firestore_operations' 7 | import init from './connection_provider' 8 | export { default as init } from './connection_provider' 9 | export * as testResources from '../tests/e2e-testkit/firestore_resources' 10 | 11 | export const driver = () => require('../tests/drivers/sql_filter_transformer_test_support') 12 | export const opsDriver = () => require('../tests/drivers/db_operations_test_support') 13 | 14 | export class FirestoreConnector extends DbConnector { 15 | constructor() { 16 | super(ConfigValidator, init) 17 | this.type = 'firestore' 18 | } 19 | } 20 | 21 | export const firestoreFactory = async(config: any, options: any) => { 22 | const connector = new FirestoreConnector() 23 | const { connection, cleanup, ...providers } = await connector.initialize(config, options) 24 | return { connector, connection, providers, cleanup } 25 | } 26 | -------------------------------------------------------------------------------- /libs/external-db-firestore/src/supported_operations.ts: -------------------------------------------------------------------------------- 1 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 2 | const { List, ListHeaders, Create, Drop, AddColumn, RemoveColumn, Describe, BulkDelete, Truncate, DeleteImmediately, UpdateImmediately, StartWithCaseSensitive, FindObject, IncludeOperator, FilterByEveryField, QueryNestedFields } = SchemaOperations 3 | 4 | export const supportedOperations = [ List, ListHeaders, Create, Drop, AddColumn, RemoveColumn, Describe, BulkDelete, Truncate, DeleteImmediately, UpdateImmediately, StartWithCaseSensitive, FindObject, IncludeOperator, FilterByEveryField, QueryNestedFields ] 5 | 6 | -------------------------------------------------------------------------------- /libs/external-db-firestore/src/types.ts: -------------------------------------------------------------------------------- 1 | import { WhereFilterOp } from '@google-cloud/firestore' 2 | 3 | export type firestoreConfig = { 4 | projectId: string 5 | } 6 | 7 | export type table = { 8 | table_name: string, 9 | fields: string, 10 | type: string, 11 | } 12 | 13 | 14 | export type queryFilter = { fieldName: string, opStr: WhereFilterOp, value: any } 15 | -------------------------------------------------------------------------------- /libs/external-db-firestore/tests/drivers/broken_creds.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "service_account", 3 | "project_id": "wrong-project-id", 4 | "private_key_id": "wrong-private-key-id", 5 | "private_key": "wrong-private-key", 6 | "client_email": "wrong-email", 7 | "client_id": "0", 8 | "auth_uri": "https://accounts.google.com/o/oauth2/auth", 9 | "token_uri": "https://oauth2.googleapis.com/token", 10 | "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", 11 | "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/broken.iam.gserviceaccount.com" 12 | } 13 | -------------------------------------------------------------------------------- /libs/external-db-firestore/tests/drivers/db_operations_test_support.ts: -------------------------------------------------------------------------------- 1 | import init from '../../src/connection_provider' 2 | 3 | const createPool = (modify: any) => { 4 | const config = { 5 | projectId: 'test-project', 6 | } 7 | 8 | return init({ ...config, ...modify }) 9 | } 10 | 11 | const unplugEmulator = () => delete process.env['FIRESTORE_EMULATOR_HOST'] 12 | 13 | const setWrongCredentials = () => process.env['GOOGLE_APPLICATION_CREDENTIALS'] ='./libs/external-db-firestore/tests/drivers/broken_creds.json' 14 | 15 | const dbOperationWithMisconfiguredProjectId = () => { 16 | unplugEmulator() 17 | setWrongCredentials() 18 | return createPool({ projectId: 'wrong' }).databaseOperations 19 | } 20 | 21 | export const dbOperationWithValidDB = () => { 22 | process.env['FIRESTORE_EMULATOR_HOST'] = 'localhost:8082' 23 | const { databaseOperations, cleanup } = createPool({ }) 24 | return { dbOperations: databaseOperations, cleanup } 25 | } 26 | 27 | export const misconfiguredDbOperationOptions = () => ([['pool connection with wrong projectId.', () => dbOperationWithMisconfiguredProjectId()]]) 28 | -------------------------------------------------------------------------------- /libs/external-db-firestore/tests/e2e-testkit/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | firestore: 4 | image: groovex/firestore-emulator:latest 5 | ports: 6 | - 8082:8082 7 | build: 8 | args: 9 | GCLOUD_SDK_VERSION: 360.0.0 10 | context: . 11 | networks: 12 | - backend 13 | 14 | networks: 15 | backend: 16 | driver: bridge -------------------------------------------------------------------------------- /libs/external-db-firestore/tests/gen.ts: -------------------------------------------------------------------------------- 1 | import * as Chance from 'chance' 2 | import { AdapterOperators } from '@wix-velo/velo-external-db-commons' 3 | const chance = Chance() 4 | const { eq, gt, gte, include, lt, lte, ne } = AdapterOperators 5 | 6 | export const randomSupportedFilter = () => { 7 | const operator = chance.pickone([ne, lt, lte, gt, gte, include, eq]) 8 | const fieldName = chance.word() 9 | const value = operator === include ? [chance.word(), chance.word(), chance.word(), chance.word(), chance.word()] : chance.word() 10 | return { 11 | fieldName, 12 | operator, 13 | value 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-firestore/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-firestore/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-firestore/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/.gitignore: -------------------------------------------------------------------------------- 1 | keys.json 2 | package-lock.json 3 | node_modules 4 | config.json 5 | schemas.json 6 | .gcloudignore 7 | .eslint 8 | .idea 9 | tests/e2e-testkit/service_account_key.json 10 | 11 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-google-sheets/README.md -------------------------------------------------------------------------------- /libs/external-db-google-sheets/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'external-db-google-sheets', 4 | clearMocks: true, 5 | verbose: true, 6 | preset: '../../jest.preset.js', 7 | globals: { 8 | 'ts-jest': { 9 | tsconfig: '/tsconfig.spec.json', 10 | }, 11 | }, 12 | transform: { 13 | '^.+\\.[tj]s$': 'ts-jest', 14 | }, 15 | moduleFileExtensions: ['ts', 'js', 'html'], 16 | coverageDirectory: '../../coverage/libs/external-db-google-sheets', 17 | testEnvironment: 'node' 18 | } -------------------------------------------------------------------------------- /libs/external-db-google-sheets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-google-sheets", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } -------------------------------------------------------------------------------- /libs/external-db-google-sheets/src/connection_provider.ts: -------------------------------------------------------------------------------- 1 | import { GoogleSpreadsheet } from 'google-spreadsheet' 2 | import { loadSheets, docAuthSetup } from './google_sheet_utils' 3 | import SchemaProvider from './google_sheet_schema_provider' 4 | import DataProvider from './google_sheet_data_provider' 5 | import DatabaseOperations from './google_sheet_operations' 6 | import { DbProviders } from '@wix-velo/velo-external-db-types' 7 | import { GoogleSheetsConfig } from './types' 8 | 9 | export default async(config: GoogleSheetsConfig): Promise> => { 10 | const doc = new GoogleSpreadsheet(config.sheetId) 11 | await docAuthSetup(config, doc) 12 | await loadSheets(doc) 13 | 14 | const databaseOperations = new DatabaseOperations(doc) 15 | const dataProvider = new DataProvider(doc) 16 | const schemaProvider = new SchemaProvider(doc) 17 | 18 | const cleanup = async() => { 19 | await Promise.allSettled(doc.sheetsByIndex.map(sheet => sheet.delete())) 20 | return 21 | } 22 | 23 | return { 24 | dataProvider, 25 | schemaProvider, 26 | databaseOperations, 27 | connection: doc, 28 | cleanup 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/src/google_sheet_config_validator.ts: -------------------------------------------------------------------------------- 1 | import { checkRequiredKeys } from '@wix-velo/velo-external-db-commons' 2 | import { IConfigValidator } from '@wix-velo/velo-external-db-types' 3 | 4 | export default class ConfigValidator implements IConfigValidator { 5 | requiredKeys: string[] 6 | config: any 7 | 8 | constructor(config: any) { 9 | this.requiredKeys = ['clientEmail', 'apiPrivateKey', 'sheetId'] 10 | this.config = config 11 | } 12 | 13 | readConfig() { 14 | return this.config 15 | } 16 | 17 | validate() { 18 | return { 19 | missingRequiredSecretsKeys: checkRequiredKeys(this.config, this.requiredKeys) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/src/google_sheet_exception_translator.ts: -------------------------------------------------------------------------------- 1 | import { errors } from '@wix-velo/velo-external-db-commons' 2 | const { FieldAlreadyExists, UnrecognizedError, DbConnectionError } = errors 3 | 4 | export const notThrowingTranslateErrorCodes = (err: any) => { 5 | 6 | if (!err.code) { 7 | if (err.message.includes('entity was not found')) 8 | return new DbConnectionError('Sheet ID is invalid') 9 | } 10 | 11 | switch (err.code) { 12 | case 'ERR_OSSL_PEM_BAD_BASE64_DECODE': 13 | case 'ERR_OSSL_PEM_NO_START_LINE': 14 | case 'ERR_OSSL_PEM_BAD_END_LINE': 15 | case 'ERR_OSSL_UNSUPPORTED': 16 | return new DbConnectionError(`API key is invalid: ${err.message}`) 17 | case '400': 18 | return new DbConnectionError('Client email is invalid') 19 | default : 20 | return new UnrecognizedError(`${err.message}`) 21 | } 22 | } 23 | 24 | export const translateErrorCodes = (err: any) => { 25 | 26 | if (err.message.includes('Duplicate header detected')) { 27 | return new FieldAlreadyExists(err) 28 | } 29 | 30 | return new UnrecognizedError(`${err.errors[0].message}`) 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/src/google_sheet_operations.ts: -------------------------------------------------------------------------------- 1 | import { GoogleSpreadsheet } from 'google-spreadsheet' 2 | import { IDatabaseOperations, ValidateConnectionResult } from '@wix-velo/velo-external-db-types' 3 | import { notThrowingTranslateErrorCodes } from './google_sheet_exception_translator' 4 | 5 | export default class DatabaseOperations implements IDatabaseOperations { 6 | doc: GoogleSpreadsheet 7 | 8 | constructor(doc: GoogleSpreadsheet) { 9 | this.doc = doc 10 | } 11 | 12 | async validateConnection(): Promise { 13 | try { 14 | await this.doc.loadInfo() 15 | return { valid: true } 16 | } catch (error) { 17 | return { valid: false, error: notThrowingTranslateErrorCodes(error) } 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/src/supported_operations.ts: -------------------------------------------------------------------------------- 1 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 2 | 3 | const { List, ListHeaders, Create, Drop, AddColumn, Describe, Projection } = SchemaOperations 4 | 5 | export const supportedOperations = [ List, ListHeaders, Create, Drop, AddColumn, Describe, Projection ] 6 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/src/types.ts: -------------------------------------------------------------------------------- 1 | export type GoogleSheetsConfig = { 2 | sheetId: string, 3 | clientEmail?: string, 4 | apiPrivateKey?: string 5 | } 6 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/tests/e2e-testkit/service_account_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "", 3 | "project_id": "", 4 | "private_key_id": "", 5 | "private_key": "", 6 | "client_email": "", 7 | "client_id": "", 8 | "auth_uri": "", 9 | "token_uri": "", 10 | "auth_provider_x509_cert_url": "", 11 | "client_x509_cert_url": "" 12 | } 13 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/tests/mock-server.js: -------------------------------------------------------------------------------- 1 | const { app } = require('./mock_google_sheets_api') 2 | 3 | const PORT = 1502 4 | 5 | app.listen(PORT, () => console.log(`google-sheets mock server is running on port ${PORT}`)) 6 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-google-sheets/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-logger/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx"], 7 | "rules": {} 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /libs/external-db-logger/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-logger/README.md -------------------------------------------------------------------------------- /libs/external-db-logger/index.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from './src/logger' 2 | 3 | 4 | export * from './src/types' 5 | export { Logger } 6 | 7 | -------------------------------------------------------------------------------- /libs/external-db-logger/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'external-db-logger', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | transform: { 11 | '^.+\\.[tj]s$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'js', 'html'], 14 | coverageDirectory: '../../coverage/libs/external-db-logger', 15 | verbose: true, 16 | }; 17 | -------------------------------------------------------------------------------- /libs/external-db-logger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-logger", 3 | "version": "1.0.0", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /libs/external-db-logger/src/logger.ts: -------------------------------------------------------------------------------- 1 | import pino from 'pino' 2 | import { ILogger, LogLevel, Data, LoggerError } from './types' 3 | 4 | export class Logger implements ILogger { 5 | private logLevel: LogLevel 6 | private logger: pino.Logger 7 | 8 | constructor() { 9 | this.logLevel = process.env['LOG_LEVEL']?.toLocaleLowerCase() as LogLevel || LogLevel.INFO 10 | this.logger = pino({ 11 | base: {}, 12 | timestamp: false, 13 | level: this.logLevel, 14 | messageKey: 'message', 15 | formatters: { 16 | level: (label) => ({ 17 | severity: label.toUpperCase(), 18 | }), 19 | }, 20 | }) 21 | } 22 | 23 | debug(message: string, data?: Data): void { 24 | this.logger.debug({ data }, message) 25 | } 26 | 27 | info(message: string, data?: Data): void { 28 | this.logger.info({ data }, message) 29 | } 30 | 31 | warn(message: string, data?: Data): void { 32 | this.logger.warn({ data }, message) 33 | } 34 | 35 | error(message: string, error?: LoggerError, data?: Data): void { 36 | this.logger.error(error, message, data) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libs/external-db-logger/src/types.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export type LoggerError = any; 4 | 5 | export type Data = Record | undefined; 6 | 7 | export enum LogLevel { 8 | DEBUG = 'debug', 9 | INFO = 'info', 10 | WARN = 'warn', 11 | ERROR = 'error', 12 | } 13 | 14 | export interface ILogger { 15 | debug(message: string, data?: Data): void; 16 | info(message: string, data?: Data): void; 17 | warn(message: string, data?: Data): void; 18 | error(message: string, error: LoggerError, data?: Data): void; 19 | } 20 | -------------------------------------------------------------------------------- /libs/external-db-logger/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-logger/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-logger/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-mongo/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-mongo/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | -------------------------------------------------------------------------------- /libs/external-db-mongo/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* -------------------------------------------------------------------------------- /libs/external-db-mongo/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-mongo/README.md -------------------------------------------------------------------------------- /libs/external-db-mongo/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-mongo', 3 | clearMocks: true, 4 | verbose: true, 5 | preset: '../../jest.preset.js', 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | }, 10 | }, 11 | transform: { 12 | '^.+\\.[tj]s$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'js', 'html'], 15 | coverageDirectory: '../../coverage/libs/external-db-mongo', 16 | testEnvironment: 'node' 17 | } 18 | -------------------------------------------------------------------------------- /libs/external-db-mongo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-mongo", 3 | "version": "2.0.0", 4 | "type": "commonjs", 5 | "devDependencies": { 6 | "@types/chance": "^1.1.3" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /libs/external-db-mongo/src/exception_translator.ts: -------------------------------------------------------------------------------- 1 | import { errors } from '@wix-velo/velo-external-db-commons' 2 | const { ItemAlreadyExists } = errors 3 | 4 | const extractItemIdFromError = (err: any) => err.message.split('"')[1] 5 | 6 | const notThrowingTranslateErrorCodes = (err: any, collectionName: string) => { 7 | switch (err.code) { 8 | case 11000: 9 | return new ItemAlreadyExists(`Item already exists: ${err.message}`, collectionName, extractItemIdFromError(err)) 10 | default: 11 | return new Error (`default ${err.message}`) 12 | } 13 | } 14 | 15 | export const translateErrorCodes = (err: any, collectionName: string) => { 16 | throw notThrowingTranslateErrorCodes(err, collectionName) 17 | } 18 | -------------------------------------------------------------------------------- /libs/external-db-mongo/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SchemaProvider } from './mongo_schema_provider' 2 | export { default as DataProvider } from './mongo_data_provider' 3 | export { default as FilterParser } from './sql_filter_transformer' 4 | export { default as DatabaseOperations } from './mongo_operations' 5 | export { default as init } from './connection_provider' 6 | export * as testResources from '../tests/e2e-testkit/mongo_resources' 7 | 8 | import init from './connection_provider' 9 | import { MongoConfigValidator } from './mongo_config_validator' 10 | import { DbConnector } from '@wix-velo/velo-external-db-commons' 11 | 12 | export const driver = () => require('../tests/drivers/sql_filter_transformer_test_support') 13 | export const opsDriver = () => require('../tests/drivers/db_operations_test_support') 14 | 15 | export class MongoConnector extends DbConnector { 16 | constructor() { 17 | super(MongoConfigValidator, init) 18 | this.type = 'mongo' 19 | } 20 | } 21 | 22 | export const mongoFactory = async(config: any, options: any) => { 23 | const connector = new MongoConnector() 24 | const { connection, cleanup, ...providers } = await connector.initialize(config, options) 25 | return { connector, connection, providers, cleanup } 26 | } 27 | -------------------------------------------------------------------------------- /libs/external-db-mongo/src/mongo_config_validator.ts: -------------------------------------------------------------------------------- 1 | import { checkRequiredKeys } from '@wix-velo/velo-external-db-commons' 2 | import { IConfigValidator } from '@wix-velo/velo-external-db-types' 3 | 4 | export class MongoConfigValidator implements IConfigValidator { 5 | config: any 6 | constructor(config: any) { 7 | this.config = config 8 | } 9 | 10 | readConfig() { 11 | return this.config 12 | } 13 | 14 | validate() { 15 | return { 16 | missingRequiredSecretsKeys: checkRequiredKeys(this.config, ['connectionUri']) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/external-db-mongo/src/mongo_operations.ts: -------------------------------------------------------------------------------- 1 | import { errors } from '@wix-velo/velo-external-db-commons' 2 | const { DbConnectionError } = errors 3 | import { isConnected } from './mongo_utils' 4 | import { IDatabaseOperations, ValidateConnectionResult } from '@wix-velo/velo-external-db-types' 5 | 6 | export default class DatabaseOperations implements IDatabaseOperations { 7 | client: any 8 | constructor(client: any) { 9 | this.client = client 10 | } 11 | 12 | async validateConnection(): Promise { 13 | try { 14 | if (isConnected(this.client)) 15 | return { valid: true } 16 | else { 17 | await this.client.connect() 18 | return isConnected(this.client) ? { valid: true } : { valid: false, error: new DbConnectionError('Connection to database failed') } 19 | } 20 | } catch (err: any) { 21 | return { valid: false, error: new DbConnectionError(err.message) } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /libs/external-db-mongo/src/supported_operations.ts: -------------------------------------------------------------------------------- 1 | import { AllSchemaOperations } from '@wix-velo/velo-external-db-commons' 2 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 3 | const notSupportedOperations = [ 4 | SchemaOperations.AtomicBulkInsert, 5 | SchemaOperations.Indexing, 6 | ] 7 | 8 | export const supportedOperations = AllSchemaOperations.filter(op => !notSupportedOperations.includes(op)) 9 | -------------------------------------------------------------------------------- /libs/external-db-mongo/src/types.ts: -------------------------------------------------------------------------------- 1 | import { AnyFixMe } from '@wix-velo/velo-external-db-types' 2 | 3 | export type MongoFilter = { 4 | [key: string]: AnyFixMe 5 | } 6 | 7 | export type MongoAggregation = { 8 | fieldsStatement: AnyFixMe, 9 | havingFilter: { $match: MongoFilter } 10 | } 11 | 12 | export type MongoFieldSort = [string, 'asc' | 'desc'] 13 | 14 | export type MongoSort = { sort: MongoFieldSort[] } 15 | 16 | export type MongoProjection = { 17 | [key: string]: 1 | 0 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-mongo/tests/e2e-testkit/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | mongo: 4 | image: mongo:5 5 | environment: 6 | MONGO_INITDB_DATABASE: testdb 7 | MONGO_INITDB_ROOT_USERNAME: root 8 | MONGO_INITDB_ROOT_PASSWORD: pass 9 | restart: always 10 | ports: 11 | - 27017:27017 12 | volumes: 13 | - ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro 14 | networks: 15 | - backend 16 | 17 | networks: 18 | backend: 19 | driver: bridge 20 | -------------------------------------------------------------------------------- /libs/external-db-mongo/tests/e2e-testkit/init-mongo.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | db.createUser( 3 | { 4 | user: 'root', 5 | pwd: 'pass', 6 | roles: [ 7 | { 8 | role: 'dbOwner', 9 | db: 'testdb' 10 | } 11 | ] 12 | } 13 | ) 14 | -------------------------------------------------------------------------------- /libs/external-db-mongo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-mongo/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-mongo/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-mssql/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-mssql/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | -------------------------------------------------------------------------------- /libs/external-db-mssql/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* -------------------------------------------------------------------------------- /libs/external-db-mssql/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-mssql/README.md -------------------------------------------------------------------------------- /libs/external-db-mssql/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-mssql', 3 | clearMocks: true, 4 | verbose: true, 5 | // roots: ['/src'], 6 | // testRegex: '(.*\\.spec\\.)js$', 7 | preset: '../../jest.preset.js', 8 | globals: { 9 | 'ts-jest': { 10 | tsconfig: '/tsconfig.spec.json', 11 | }, 12 | }, 13 | transform: { 14 | '^.+\\.[tj]s$': 'ts-jest', 15 | }, 16 | moduleFileExtensions: ['ts', 'js', 'html'], 17 | coverageDirectory: '../../coverage/libs/external-db-mssql', 18 | testEnvironment: 'node' 19 | } 20 | -------------------------------------------------------------------------------- /libs/external-db-mssql/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-mssql", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } -------------------------------------------------------------------------------- /libs/external-db-mssql/src/mssql_config_validator.ts: -------------------------------------------------------------------------------- 1 | import { checkRequiredKeys, checkThatHasAtLestOneRequiredKeys } from '@wix-velo/velo-external-db-commons' 2 | import { IConfigValidator } from '@wix-velo/velo-external-db-types' 3 | 4 | export class MSSQLConfigValidator implements IConfigValidator { 5 | config: any 6 | requiredKeys: string[] 7 | hostKeyOptions: string[] 8 | constructor(config: any) { 9 | this.requiredKeys = ['user', 'password', 'db'] 10 | this.hostKeyOptions = ['host', 'cloudSqlConnectionName'] 11 | this.config = config 12 | } 13 | 14 | readConfig() { 15 | return this.config 16 | } 17 | 18 | validate() { 19 | const missingRequiredKeys = checkRequiredKeys(this.config, this.requiredKeys) 20 | const missingRequiredHostKey = checkThatHasAtLestOneRequiredKeys(this.config, this.hostKeyOptions) 21 | return { 22 | missingRequiredSecretsKeys: [...missingRequiredKeys, ...missingRequiredHostKey ] 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /libs/external-db-mssql/src/mssql_operations.ts: -------------------------------------------------------------------------------- 1 | import { IDatabaseOperations } from '@wix-velo/velo-external-db-types' 2 | import { notThrowingTranslateErrorCodes } from './sql_exception_translator' 3 | 4 | export default class DatabaseOperations implements IDatabaseOperations { 5 | sql: any 6 | constructor(pool: any) { 7 | this.sql = pool 8 | } 9 | 10 | async validateConnection() { 11 | const sql = await this.sql 12 | if (sql._connected) { 13 | return await sql.query('SELECT 1') 14 | .then(() => { return { valid: true } }) 15 | .catch((e: any) => { return { valid: false, error: notThrowingTranslateErrorCodes(e) } }) 16 | } 17 | return await sql.connect() 18 | .then(() => { return { valid: true } }) 19 | .catch((e: any) => { return { valid: false, error: notThrowingTranslateErrorCodes(e) } }) 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libs/external-db-mssql/src/mssql_utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { errors } from '@wix-velo/velo-external-db-commons' 2 | import { escapeTable, escapeId } from './mssql_utils' 3 | const { InvalidQuery } = errors 4 | 5 | describe('Sql Server Utils', () => { 6 | test('escape collection id will not allow dots', () => { 7 | expect( () => escapeTable('db.table') ).toThrow(InvalidQuery) 8 | }) 9 | 10 | test('escape collection id', () => { 11 | expect( escapeTable('some_table_name') ).toEqual(escapeId('some_table_name')) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /libs/external-db-mssql/src/supported_operations.ts: -------------------------------------------------------------------------------- 1 | import { AllSchemaOperations } from '@wix-velo/velo-external-db-commons' 2 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 3 | const notSupportedOperations = [ 4 | SchemaOperations.QueryNestedFields, 5 | SchemaOperations.FindObject, 6 | SchemaOperations.NonAtomicBulkInsert, 7 | SchemaOperations.Indexing, 8 | ] 9 | 10 | export const supportedOperations = AllSchemaOperations.filter(op => !notSupportedOperations.includes(op)) 11 | -------------------------------------------------------------------------------- /libs/external-db-mssql/src/types.ts: -------------------------------------------------------------------------------- 1 | export type MSSQLParsedFilter = { 2 | filterExpr: string, 3 | parameters: any 4 | } 5 | 6 | export type MSSQLParsedAggregation = { 7 | fieldsStatement: string 8 | groupByColumns: string[] 9 | havingFilter: string, 10 | parameters: any[] 11 | } 12 | 13 | 14 | export interface MSSQLConfig { 15 | user: string 16 | password: string 17 | db: string 18 | host: string 19 | unsecuredEnv?: any 20 | port?: number 21 | [key: string]: any 22 | } 23 | -------------------------------------------------------------------------------- /libs/external-db-mssql/tests/e2e-testkit/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | mssql: 4 | image: mcr.microsoft.com/mssql/server:2019-latest 5 | ports: 6 | - 1433:1433 7 | environment: 8 | SA_PASSWORD: "t9D4:EHfU6Xgccs-" 9 | ACCEPT_EULA: "Y" 10 | networks: 11 | - backend 12 | command: 13 | - /bin/bash 14 | - -c 15 | - | 16 | /opt/mssql/bin/sqlservr 17 | curl -s https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh | bash /dev/stdin localhost:1433 18 | 19 | 20 | networks: 21 | backend: 22 | driver: bridge -------------------------------------------------------------------------------- /libs/external-db-mssql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "lib": [ 13 | "es2019" 14 | ] 15 | }, 16 | "files": [], 17 | "include": [], 18 | "references": [ 19 | { 20 | "path": "./tsconfig.lib.json" 21 | }, 22 | { 23 | "path": "./tsconfig.spec.json" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /libs/external-db-mssql/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-mssql/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-mysql/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-mysql/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | -------------------------------------------------------------------------------- /libs/external-db-mysql/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* -------------------------------------------------------------------------------- /libs/external-db-mysql/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-mysql/README.md -------------------------------------------------------------------------------- /libs/external-db-mysql/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-mysql', 3 | clearMocks: true, 4 | verbose: true, 5 | // roots: ['/src'], 6 | preset: '../../jest.preset.js', 7 | globals: { 8 | 'ts-jest': { 9 | tsconfig: '/tsconfig.spec.json', 10 | }, 11 | }, 12 | transform: { 13 | '^.+\\.[tj]s$': 'ts-jest', 14 | }, 15 | moduleFileExtensions: ['ts', 'js', 'html'], 16 | coverageDirectory: '../../coverage/libs/external-db-mysql', 17 | testEnvironment: 'node' 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-mysql/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-mysql", 3 | "version": "2.0.1", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /libs/external-db-mysql/src/mysql_config_validator.ts: -------------------------------------------------------------------------------- 1 | import { checkRequiredKeys, checkThatHasAtLestOneRequiredKeys } from '@wix-velo/velo-external-db-commons' 2 | import { IConfigValidator } from '@wix-velo/velo-external-db-types' 3 | 4 | export class MySqlConfigValidator implements IConfigValidator { 5 | requiredKeys: string[] 6 | hostKeyOptions: string[] 7 | config: any 8 | constructor(config: any) { 9 | this.requiredKeys = ['user', 'password', 'db'] 10 | this.hostKeyOptions = ['host', 'cloudSqlConnectionName'] 11 | this.config = config 12 | } 13 | 14 | readConfig() { 15 | return this.config 16 | } 17 | 18 | validate() { 19 | const missingRequiredKeys = checkRequiredKeys(this.config, this.requiredKeys) 20 | const missingRequiredHostKey = checkThatHasAtLestOneRequiredKeys(this.config, this.hostKeyOptions) 21 | return { 22 | missingRequiredSecretsKeys: [...missingRequiredKeys, ...missingRequiredHostKey ] 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /libs/external-db-mysql/src/mysql_operations.ts: -------------------------------------------------------------------------------- 1 | import { IDatabaseOperations } from '@wix-velo/velo-external-db-types' 2 | import { promisify } from 'util' 3 | import { notThrowingTranslateErrorCodes } from './sql_exception_translator' 4 | import { Pool as MysqlPool } from 'mysql' 5 | 6 | export default class DatabaseOperations implements IDatabaseOperations { 7 | pool: MysqlPool 8 | query: any 9 | constructor(pool: any) { 10 | this.pool = pool 11 | this.query = promisify(this.pool.query).bind(this.pool) 12 | } 13 | 14 | async validateConnection() { 15 | return await this.query('SELECT 1').then(() => { return { valid: true } }) 16 | .catch((e: any) => { return { valid: false, error: notThrowingTranslateErrorCodes(e, '') } }) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-mysql/src/mysql_utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { escapeTable, escapeId, } from './mysql_utils' 2 | import { errors } from '@wix-velo/velo-external-db-commons' 3 | const { InvalidQuery } = errors 4 | // const { eq, ne, string_contains, string_begins, string_ends, gt, gte, lt, lte, include } = AdapterOperators 5 | 6 | describe('Mysql Utils', () => { 7 | test('escape collection id will not allow dots', () => { 8 | expect( () => escapeTable('db.table') ).toThrow(InvalidQuery) 9 | }) 10 | 11 | test('escape collection id', () => { 12 | expect( escapeTable('some_table_name') ).toEqual(escapeId('some_table_name')) 13 | }) 14 | 15 | }) 16 | -------------------------------------------------------------------------------- /libs/external-db-mysql/src/mysql_utils.ts: -------------------------------------------------------------------------------- 1 | import { escapeId } from 'mysql' 2 | import { errors, patchDateTime } from '@wix-velo/velo-external-db-commons' 3 | import { Item } from '@wix-velo/velo-external-db-types' 4 | 5 | export const wildCardWith = (n: number, char: string) => Array(n).fill(char, 0, n).join(', ') 6 | 7 | export const escapeTable = (t: string) => { 8 | if(t && t.indexOf('.') !== -1) { 9 | throw new errors.InvalidQuery('Illegal table name') 10 | } 11 | return escapeId(t) 12 | } 13 | 14 | const escapeIdField = (f: string) => f === '*' ? '*' : escapeId(f) 15 | 16 | const patchObjectField = (item: Item) => Object.entries(item).reduce((acc: {[key:string]: any}, [key, value]) => { 17 | acc[key] = (typeof value === 'object' && value !== null) ? JSON.stringify(value) : value 18 | return acc 19 | }, {}) 20 | 21 | 22 | export const patchItem = (item: Item) => { 23 | const itemWithPatchedDateTime = patchDateTime(item) 24 | const itemWithPatchedObject = patchObjectField(itemWithPatchedDateTime) 25 | 26 | return itemWithPatchedObject 27 | } 28 | 29 | export { escapeIdField as escapeId } 30 | -------------------------------------------------------------------------------- /libs/external-db-mysql/src/supported_operations.ts: -------------------------------------------------------------------------------- 1 | import { AllSchemaOperations } from '@wix-velo/velo-external-db-commons' 2 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 3 | const notSupportedOperations = [SchemaOperations.NonAtomicBulkInsert] 4 | 5 | export const supportedOperations = AllSchemaOperations.filter(op => !notSupportedOperations.includes(op)) 6 | -------------------------------------------------------------------------------- /libs/external-db-mysql/src/types.ts: -------------------------------------------------------------------------------- 1 | export type MySqlParsedFilter = { 2 | filterExpr: string 3 | parameters: any[] 4 | } 5 | 6 | export type MySqlParsedAggregation = { 7 | fieldsStatement: string 8 | groupByColumns: string[] 9 | havingFilter: string, 10 | parameters: any[] 11 | } 12 | 13 | export interface MySqlConfig { 14 | host?: string 15 | user: string 16 | password: string 17 | db: string 18 | cloudSqlConnectionName?: string 19 | port?: number 20 | } 21 | 22 | export type MySqlQuery = (sql: string, values?: any) => Promise 23 | -------------------------------------------------------------------------------- /libs/external-db-mysql/tests/e2e-testkit/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | mysql: 4 | image: mysql:8.0 5 | command: --default-authentication-plugin=mysql_native_password 6 | restart: always 7 | environment: 8 | MYSQL_USER: test-user 9 | MYSQL_PASSWORD: password 10 | MYSQL_DATABASE: test-db 11 | MYSQL_ALLOW_EMPTY_PASSWORD: "yes" 12 | ports: 13 | - 3306:3306 14 | networks: 15 | - backend 16 | 17 | networks: 18 | backend: 19 | driver: bridge -------------------------------------------------------------------------------- /libs/external-db-mysql/tests/gen.ts: -------------------------------------------------------------------------------- 1 | import * as Chance from 'chance' 2 | const chance = Chance() 3 | 4 | export const validConfig = () => ({ 5 | host: chance.word(), 6 | password: chance.word(), 7 | db: chance.word(), 8 | user: chance.word() 9 | }) 10 | 11 | export const validGCPConfig = () => ({ 12 | cloudSqlConnectionName: chance.word(), 13 | password: chance.word(), 14 | db: chance.word(), 15 | user: chance.word() 16 | }) 17 | 18 | export const configWithInvalidHost = () => ({ 19 | ... validConfig(), 20 | host: chance.natural() 21 | }) 22 | -------------------------------------------------------------------------------- /libs/external-db-mysql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "lib": [ 13 | "es2019" 14 | ], 15 | }, 16 | "files": [], 17 | "include": [], 18 | "references": [ 19 | { 20 | "path": "./tsconfig.lib.json" 21 | }, 22 | { 23 | "path": "./tsconfig.spec.json" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /libs/external-db-mysql/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-mysql/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-postgres/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-postgres/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | -------------------------------------------------------------------------------- /libs/external-db-postgres/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* -------------------------------------------------------------------------------- /libs/external-db-postgres/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-postgres/README.md -------------------------------------------------------------------------------- /libs/external-db-postgres/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-postgres', 3 | clearMocks: true, 4 | verbose: true, 5 | preset: '../../jest.preset.js', 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | }, 10 | }, 11 | transform: { 12 | '^.+\\.[tj]s$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'js', 'html'], 15 | coverageDirectory: '../../coverage/libs/external-db-postgres', 16 | testEnvironment: 'node' 17 | } 18 | -------------------------------------------------------------------------------- /libs/external-db-postgres/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-postgres", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } -------------------------------------------------------------------------------- /libs/external-db-postgres/src/postgres_config_validator.ts: -------------------------------------------------------------------------------- 1 | import { IConfigValidator } from '@wix-velo/velo-external-db-types' 2 | import { checkRequiredKeys, checkThatHasAtLestOneRequiredKeys } from '@wix-velo/velo-external-db-commons' 3 | 4 | 5 | export class PostgresConfigValidator implements IConfigValidator { 6 | requiredKeys: string[] 7 | hostKeyOptions: string[] 8 | config: any 9 | 10 | public constructor(config: any) { 11 | this.requiredKeys = ['user', 'password', 'db'] 12 | this.hostKeyOptions = ['host', 'cloudSqlConnectionName'] 13 | this.config = config 14 | } 15 | 16 | readConfig() { 17 | return this.config 18 | } 19 | 20 | validate() { 21 | const missingRequiredKeys = checkRequiredKeys(this.config, this.requiredKeys) 22 | const missingRequiredHostKey = checkThatHasAtLestOneRequiredKeys(this.config, this.hostKeyOptions) 23 | return { 24 | missingRequiredSecretsKeys: [...missingRequiredKeys, ...missingRequiredHostKey ] 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /libs/external-db-postgres/src/postgres_operations.ts: -------------------------------------------------------------------------------- 1 | import { Pool } from 'pg' 2 | import { IDatabaseOperations } from '@wix-velo/velo-external-db-types' 3 | import { notThrowingTranslateErrorCodes } from './sql_exception_translator' 4 | 5 | export default class DatabaseOperations implements IDatabaseOperations { 6 | pool: Pool 7 | 8 | public constructor(pool: Pool) { 9 | this.pool = pool 10 | } 11 | 12 | // @ts-ignore 13 | async validateConnection() { 14 | return await this.pool.query('SELECT 1').then(() => { return { valid: true } }) 15 | .catch((e) => { return { valid: false, error: notThrowingTranslateErrorCodes(e, '') } }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/external-db-postgres/src/supported_operations.ts: -------------------------------------------------------------------------------- 1 | import { AllSchemaOperations } from '@wix-velo/velo-external-db-commons' 2 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 3 | const notSupportedOperations = [SchemaOperations.NonAtomicBulkInsert] 4 | 5 | export const supportedOperations = AllSchemaOperations.filter(op => !notSupportedOperations.includes(op)) 6 | -------------------------------------------------------------------------------- /libs/external-db-postgres/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface PostgresConfig { 2 | host?: string 3 | cloudSqlConnectionName?: string 4 | user: string 5 | password: string 6 | db: string 7 | port?: number 8 | } 9 | 10 | export interface postgresPoolOptions { 11 | [x:string]: any 12 | } 13 | 14 | export type ParsedFilter = { 15 | filterExpr?: string, 16 | filterColumns: [], 17 | parameters: any[], 18 | offset: number, 19 | } 20 | 21 | -------------------------------------------------------------------------------- /libs/external-db-postgres/tests/e2e-testkit/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | postgres: 4 | image: postgres:latest 5 | restart: always 6 | ports: 7 | - 5432:5432 8 | environment: 9 | POSTGRES_USER: test-user 10 | POSTGRES_PASSWORD: password 11 | POSTGRES_DB: test-db 12 | 13 | networks: 14 | backend: 15 | driver: bridge -------------------------------------------------------------------------------- /libs/external-db-postgres/tests/gen.ts: -------------------------------------------------------------------------------- 1 | import * as Chance from 'chance' 2 | const chance = Chance() 3 | 4 | export const validConfig = () => ({ 5 | host: chance.word(), 6 | password: chance.word(), 7 | db: chance.word(), 8 | user: chance.word() 9 | }) 10 | 11 | export const validGCPConfig = () => ({ 12 | cloudSqlConnectionName: chance.word(), 13 | password: chance.word(), 14 | db: chance.word(), 15 | user: chance.word() 16 | }) 17 | 18 | export const configWithInvalidHost = () => ({ 19 | ... validConfig(), 20 | host: chance.natural() 21 | }) 22 | 23 | -------------------------------------------------------------------------------- /libs/external-db-postgres/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-postgres/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-postgres/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-security/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-security/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | .env -------------------------------------------------------------------------------- /libs/external-db-security/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-security/README.md -------------------------------------------------------------------------------- /libs/external-db-security/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-security', 3 | clearMocks: true, 4 | verbose: true, 5 | preset: '../../jest.preset.js', 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | }, 10 | }, 11 | transform: { 12 | '^.+\\.[tj]s$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'js', 'html'], 15 | coverageDirectory: '../../coverage/libs/external-db-security', 16 | // testRegex: '(.*\\.spec\\.)js$', 17 | // roots: ['/src'], 18 | // testRegex: '(.*\\.spec\\.)js$', 19 | // testEnvironment: 'node', 20 | } 21 | 22 | -------------------------------------------------------------------------------- /libs/external-db-security/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-security", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /libs/external-db-security/src/auth-providers/azure_auth_provider.js: -------------------------------------------------------------------------------- 1 | const AzureAdOAuth2Strategy = require('passport-azure-ad-oauth2') 2 | 3 | class AzureAuthProvider { 4 | constructor({ clientId, clientSecret, callbackUrl }) { 5 | this.options = { 6 | clientID: clientId, 7 | clientSecret, 8 | callbackURL: callbackUrl, 9 | } 10 | 11 | return new AzureAdOAuth2Strategy(this.options, this.verify) 12 | } 13 | 14 | verify(accessToken, tokenSecret, profile, done) { 15 | done(null, profile) 16 | } 17 | 18 | } 19 | 20 | module.exports = { AzureAuthProvider } 21 | -------------------------------------------------------------------------------- /libs/external-db-security/src/auth-providers/gcp_auth_provider.js: -------------------------------------------------------------------------------- 1 | const GoogleStrategy = require('passport-google-oauth20').Strategy 2 | 3 | class GcpAuthProvider { 4 | constructor({ clientId, clientSecret, callbackUrl }) { 5 | this.options = { 6 | clientID: clientId, 7 | clientSecret, 8 | callbackURL: callbackUrl, 9 | scope: ['email', 'profile'] 10 | } 11 | 12 | return new GoogleStrategy(this.options, this.verify) 13 | } 14 | 15 | verify(accessToken, tokenSecret, profile, done) { 16 | done(null, profile) 17 | } 18 | 19 | } 20 | 21 | module.exports = { GcpAuthProvider } 22 | -------------------------------------------------------------------------------- /libs/external-db-security/src/auth-providers/stub_auth_provider.js: -------------------------------------------------------------------------------- 1 | const localStrategy = require('passport-local') 2 | 3 | class StubAuthProvider { 4 | constructor() { 5 | return new localStrategy(this.verify) 6 | } 7 | 8 | verify(accessToken, tokenSecret, profile, done) { 9 | done(null, profile) 10 | } 11 | 12 | } 13 | 14 | module.exports = { StubAuthProvider } 15 | -------------------------------------------------------------------------------- /libs/external-db-security/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as RoleAuthorizationService } from './services/role_authorization' 2 | -------------------------------------------------------------------------------- /libs/external-db-security/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-security/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-security/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-spanner/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-spanner/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | -------------------------------------------------------------------------------- /libs/external-db-spanner/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* -------------------------------------------------------------------------------- /libs/external-db-spanner/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-spanner/README.md -------------------------------------------------------------------------------- /libs/external-db-spanner/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-spanner', 3 | clearMocks: true, 4 | verbose: true, 5 | preset: '../../jest.preset.js', 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | }, 10 | }, 11 | transform: { 12 | '^.+\\.[tj]s$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'js', 'html'], 15 | coverageDirectory: '../../coverage/libs/external-db-spanner', 16 | testEnvironment: 'node' 17 | } 18 | -------------------------------------------------------------------------------- /libs/external-db-spanner/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-spanner", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } -------------------------------------------------------------------------------- /libs/external-db-spanner/src/connection_provider.ts: -------------------------------------------------------------------------------- 1 | import SchemaProvider from './spanner_schema_provider' 2 | import DataProvider from './spanner_data_provider' 3 | import FilterParser from './sql_filter_transformer' 4 | import DatabaseOperations from './spanner_operations' 5 | import { Spanner, Database as SpannerDb } from '@google-cloud/spanner' 6 | import { DbProviders } from '@wix-velo/velo-external-db-types' 7 | 8 | 9 | export interface SpannerConfig { 10 | projectId: any 11 | instanceId: string 12 | databaseId: string 13 | } 14 | 15 | export default (cfg: SpannerConfig, _poolOptions?: {[x:string]: any}): DbProviders => { 16 | const spanner = new Spanner({ projectId: cfg.projectId }) 17 | const instance = spanner.instance(cfg.instanceId) 18 | 19 | const poolOptions = _poolOptions || { } 20 | 21 | const database = instance.database(cfg.databaseId, poolOptions) 22 | 23 | const databaseOperations = new DatabaseOperations(database) 24 | 25 | const filterParser = new FilterParser() 26 | const dataProvider = new DataProvider(database, filterParser) 27 | const schemaProvider = new SchemaProvider(database) 28 | 29 | return { dataProvider, schemaProvider, databaseOperations, connection: database, cleanup: async() => { await database.close() } } 30 | } 31 | -------------------------------------------------------------------------------- /libs/external-db-spanner/src/spanner_config_validator.ts: -------------------------------------------------------------------------------- 1 | import { checkRequiredKeys } from '@wix-velo/velo-external-db-commons' 2 | import { IConfigValidator } from '@wix-velo/velo-external-db-types' 3 | 4 | export class ConfigValidator implements IConfigValidator { 5 | requiredKeys: string[] 6 | config: any 7 | constructor(config: any) { 8 | this.requiredKeys = ['projectId', 'instanceId', 'databaseId'] 9 | this.config = config 10 | } 11 | 12 | readConfig() { 13 | return this.config 14 | } 15 | 16 | validate() { 17 | return { missingRequiredSecretsKeys: checkRequiredKeys(this.config, this.requiredKeys) } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/external-db-spanner/src/spanner_operations.ts: -------------------------------------------------------------------------------- 1 | import { IDatabaseOperations } from '@wix-velo/velo-external-db-types' 2 | import { notThrowingTranslateErrorCodes } from './sql_exception_translator' 3 | 4 | export default class DatabaseOperations implements IDatabaseOperations { 5 | database: any 6 | constructor(database: any) { 7 | this.database = database 8 | } 9 | 10 | async validateConnection() { 11 | return await this.database.run({ sql: 'SELECT 1' }) 12 | .then(() => { return { valid: true } }) 13 | .catch((e: any) => { return { valid: false, error: notThrowingTranslateErrorCodes(e) } }) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-spanner/src/supported_operations.ts: -------------------------------------------------------------------------------- 1 | import { AllSchemaOperations } from '@wix-velo/velo-external-db-commons' 2 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 3 | //change column types - https://cloud.google.com/spanner/docs/schema-updates#supported_schema_updates 4 | const notSupportedOperations = [ 5 | SchemaOperations.ChangeColumnType, 6 | SchemaOperations.NonAtomicBulkInsert, 7 | SchemaOperations.FindObject, 8 | SchemaOperations.Indexing, 9 | ] 10 | 11 | export const supportedOperations = AllSchemaOperations.filter(op => !notSupportedOperations.includes(op)) 12 | -------------------------------------------------------------------------------- /libs/external-db-spanner/src/types.ts: -------------------------------------------------------------------------------- 1 | export type SpannerParsedFilter = { 2 | filterExpr: string, 3 | parameters: any 4 | } 5 | 6 | export type SpannerParsedAggregation = { 7 | fieldsStatement: string 8 | groupByColumns: string[] 9 | havingFilter: string, 10 | parameters: any[] 11 | } 12 | -------------------------------------------------------------------------------- /libs/external-db-spanner/tests/e2e-testkit/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | spanner: 4 | image: roryq/spanner-emulator:latest 5 | ports: 6 | - 9010:9010 7 | - 9020:9020 8 | environment: 9 | SPANNER_DATABASE_ID: test-database 10 | SPANNER_INSTANCE_ID: test-instance 11 | SPANNER_PROJECT_ID: test-project 12 | networks: 13 | - backend 14 | 15 | networks: 16 | backend: 17 | driver: bridge -------------------------------------------------------------------------------- /libs/external-db-spanner/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-spanner/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ], 15 | "noImplicitAny": true, 16 | } 17 | -------------------------------------------------------------------------------- /libs/external-db-spanner/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/external-db-testkit/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/external-db-testkit/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/external-db-testkit/README.md -------------------------------------------------------------------------------- /libs/external-db-testkit/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'external-db-testkit', 3 | clearMocks: true, 4 | verbose: true, 5 | preset: '../../jest.preset.js', 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | }, 10 | }, 11 | transform: { 12 | '^.+\\.[tj]s$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'js', 'html'], 15 | coverageDirectory: '../../coverage/libs/external-db-testkit', 16 | testEnvironment: 'node' 17 | } 18 | -------------------------------------------------------------------------------- /libs/external-db-testkit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/external-db-testkit", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } -------------------------------------------------------------------------------- /libs/external-db-testkit/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as E2EResources } from './lib/e2e_resources' 2 | export * from './lib/auth_test_support' 3 | -------------------------------------------------------------------------------- /libs/external-db-testkit/src/lib/docker_support.js: -------------------------------------------------------------------------------- 1 | const compose = require('docker-compose') 2 | 3 | const runImage = async(image, showLogs) => { 4 | await compose.upOne(image, { cwd: __dirname, log: true, commandOptions: [['--force-recreate', '--remove-orphans']] }) 5 | if (showLogs) { 6 | await compose.logs(image, { cwd: __dirname, log: true }) 7 | } 8 | } 9 | const stopImage = async(image) => await compose.stopOne(image, { cwd: __dirname, log: true }) 10 | 11 | module.exports = { runImage, stopImage } 12 | -------------------------------------------------------------------------------- /libs/external-db-testkit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/external-db-testkit/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/external-db-testkit/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/test-commons/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx"], 7 | "rules": {} 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /libs/test-commons/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/test-commons/README.md -------------------------------------------------------------------------------- /libs/test-commons/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'test-commons', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | transform: { 11 | '^.+\\.[tj]s$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'js', 'html'], 14 | coverageDirectory: '../../coverage/libs/test-commons', 15 | verbose: true, 16 | }; 17 | -------------------------------------------------------------------------------- /libs/test-commons/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/test-commons", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /libs/test-commons/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './libs/test-commons' 2 | export * as gen from './libs/gen' 3 | export { authConfig } from './libs/auth-config.json' 4 | -------------------------------------------------------------------------------- /libs/test-commons/src/libs/auth-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authConfig": { 3 | "kid": "7968bd02-7c7d-446e-83c5-5c993c20a140", 4 | "authPublicKey": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdnP+fQMJYtljus9pnpEWT02T0uqF\nUacdoxL19vmQdii4DAj+S0pbJ/owcc7HsPvNwhJvIwFtk/4Cm+OYp7fXSQ==\n-----END PUBLIC KEY-----", 5 | "authPrivateKey": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEINoWtnYgw8ZcsZkgWDBxAcJF0ziCI4SOVuK17DrQFCWYoAoGCCqGSM49\nAwEHoUQDQgAEdnP+fQMJYtljus9pnpEWT02T0uqFUacdoxL19vmQdii4DAj+S0pb\nJ/owcc7HsPvNwhJvIwFtk/4Cm+OYp7fXSQ==\n-----END EC PRIVATE KEY-----", 6 | "otherAuthPublicKey": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC0QSOeblgUZjrKzxsLwJ/gcTFV+/\nTIhuEDxhpNaAnY1AvqFuANfCJ++aCWMjmhp1Fy9BZ6pi/lxVJAF4fpMqtw==\n-----END PUBLIC KEY-----", 7 | "otherAuthPrivateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIBOQIBAAJAbcyXwdpGC435MK3+YrondHjQgU6ev6IIi0BUxstX2N0kWSIjZveu\nv7yrpLHmE5kiFmIK2QQJJB2fBgvFe1rREQIDAQABAkA+BAjTHQ3jCNVugVflO299\ngZ+C6X0Qj9xzimpXvhJoEgF2h46MymRdxhIBjFdk27RiNbCcxSO+/9ihXgpRFJYB\nAiEAuAyC3I9deFYhivwDyY8SylXtJM6amrM9VDYfWe6VqOkCIQCYuTkNRYgOoYZv\nx56c+ssbLsPi+wvegXMUFcGEEOZN6QIhAJSGxDRqHew21errZcMLCwbuQOorMOkX\nLK8A3lwdBfnBAh9YSryw74G486jE9qK8HkFNdbvJfVlfSXc+JVW7BAohAiEArZNb\nPzT+UboIuTYSyPElaCV8wLmJ88m5t+NwlNSfsqs=\n-----END RSA PRIVATE KEY-----" 8 | } 9 | } -------------------------------------------------------------------------------- /libs/test-commons/src/libs/test-commons.ts: -------------------------------------------------------------------------------- 1 | import { isObject } from '@wix-velo/velo-external-db-commons' 2 | import { SchemaOperations } from '@wix-velo/velo-external-db-types' 3 | 4 | export const Uninitialized: any = null 5 | 6 | export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) 7 | 8 | export const shouldNotRunOn = (impl: string[], current: string) => !impl.includes(current) 9 | 10 | export const shouldRunOnlyOn = (impl: string[], current: string) => impl.includes(current) 11 | 12 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 13 | //@ts-ignore 14 | export const testIfSupportedOperationsIncludes = (supportedOperations: SchemaOperations[], operation: string[]): any => operation.every((o: any) => supportedOperations.includes(o)) ? test : test.skip 15 | 16 | export const testSupportedOperations = (supportedOperations: SchemaOperations[], arrayTable: any[][]): string[][] => { 17 | return arrayTable.filter(i => { 18 | const lastItem = i[i.length - 1] 19 | return !isObject(lastItem) || lastItem['neededOperations'].every((i: any) => supportedOperations.includes(i)) 20 | }) 21 | } 22 | 23 | -------------------------------------------------------------------------------- /libs/test-commons/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/test-commons/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/test-commons/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/velo-external-db-commons/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.ts", "*.tsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/velo-external-db-commons/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/velo-external-db-commons/README.md -------------------------------------------------------------------------------- /libs/velo-external-db-commons/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'velo-external-db-commons', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | transform: { 11 | '^.+\\.[tj]s$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'js', 'html'], 14 | coverageDirectory: '../../coverage/libs/velo-external-db-commons', 15 | verbose: true, 16 | }; 17 | -------------------------------------------------------------------------------- /libs/velo-external-db-commons/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/velo-external-db-commons", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /libs/velo-external-db-commons/src/index.ts: -------------------------------------------------------------------------------- 1 | export * as errors from './libs/errors' 2 | export * from './libs/schema_commons' 3 | export * from './libs/data_commons' 4 | export * from './libs/config_commons' 5 | export * from './libs/types' 6 | export { default as DbConnector } from './libs/db_connector' 7 | -------------------------------------------------------------------------------- /libs/velo-external-db-commons/src/libs/config_commons.ts: -------------------------------------------------------------------------------- 1 | const objectContainsKey = (obj: { [x: string]: string | any[] }, key: string ) => typeof obj[key] === 'string' && obj[key].length > 0 2 | 3 | export const checkRequiredKeys = (obj: { [x: string]: string | any[] }, requiredKeys: string[]) => requiredKeys.filter((key: string) => !objectContainsKey(obj, key)) 4 | 5 | export const checkThatHasAtLestOneRequiredKeys = (obj: { [x: string]: string | any[] }, keys: any[]) => keys.some((key: any) => objectContainsKey(obj, key)) ? [] : [keys.join('/')] 6 | -------------------------------------------------------------------------------- /libs/velo-external-db-commons/src/libs/types.ts: -------------------------------------------------------------------------------- 1 | import { ConnectionCleanUp, IDatabaseOperations, IDataProvider, ISchemaProvider } from '@wix-velo/velo-external-db-types' 2 | import DbConnector from './db_connector' 3 | 4 | export type Field = { 5 | field: string, 6 | type: string, 7 | subtype?: string, 8 | precision?: number, 9 | isPrimary?: boolean, 10 | } 11 | 12 | export type DatabaseFactoryResponse = { 13 | connector: DbConnector 14 | providers: { 15 | dataProvider: IDataProvider; 16 | schemaProvider: ISchemaProvider; 17 | databaseOperations: IDatabaseOperations; 18 | } 19 | cleanup: ConnectionCleanUp 20 | connection: any 21 | } 22 | -------------------------------------------------------------------------------- /libs/velo-external-db-commons/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/velo-external-db-commons/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/velo-external-db-commons/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | config.json 4 | schemas.json 5 | .gcloudignore 6 | .eslint 7 | .idea 8 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* -------------------------------------------------------------------------------- /libs/velo-external-db-core/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wix/velo-external-db/0704e83591b429e97e7752bd61a1f8c09bf84f3f/libs/velo-external-db-core/README.md -------------------------------------------------------------------------------- /libs/velo-external-db-core/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'velo-external-db-core', 3 | clearMocks: true, 4 | verbose: true, 5 | roots: ['/src'], 6 | testEnvironment: 'node', 7 | preset: '../../jest.preset.js', 8 | globals: { 9 | 'ts-jest': { 10 | tsconfig: '/tsconfig.spec.json', 11 | }, 12 | }, 13 | transform: { 14 | '^.+\\.[tj]s$': 'ts-jest', 15 | }, 16 | moduleFileExtensions: ['ts', 'js', 'html'], 17 | coverageDirectory: '../../coverage/libs/velo-external-db-core', 18 | setupFilesAfterEnv: ['jest-extended/all'], 19 | } 20 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/velo-external-db-core", 3 | "version": "2.0.2", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/converters/data_utils.ts: -------------------------------------------------------------------------------- 1 | import { isDate } from '@wix-velo/velo-external-db-commons' 2 | import { Item, ItemWithId } from '@wix-velo/velo-external-db-types' 3 | import * as crypto from 'crypto' 4 | 5 | 6 | export const asWixData = (item: Item) => { 7 | return generateIdsIfNeeded(packDates(item)) 8 | } 9 | 10 | export const asWixDataItem = (item: Item) => { 11 | return { item: asWixData(item) } 12 | } 13 | 14 | const replaceNonAlphanumeric = (str: string) => { 15 | // Replace non-alphanumeric characters with dashes 16 | return str.replace(/[^a-zA-Z0-9]/g, '-') 17 | } 18 | 19 | export const generateIdsIfNeeded = (item: Item): ItemWithId => { 20 | if ('_id' in item) 21 | return item as ItemWithId 22 | const sha = crypto.createHash('sha1') 23 | const fieldsConcat = Object.values(item).join('') 24 | const base64Digest = sha.update(fieldsConcat).digest('base64') 25 | const validId = replaceNonAlphanumeric(base64Digest) 26 | return { ...item, _id: validId } 27 | } 28 | 29 | const packDates = (item: Item) => Object.entries(item) 30 | .reduce((o, [k, v]) => ({ ...o, [k]: isDate(v) ? { $date: new Date(v).toISOString() } : v }), {}) 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/converters/query_validator_utils.ts: -------------------------------------------------------------------------------- 1 | import { QueryOperatorsByFieldType } from '@wix-velo/velo-external-db-commons' 2 | import { AdapterFilter, AdapterOperator, NotEmptyAdapterFilter } from '@wix-velo/velo-external-db-types' 3 | import FilterTransformer from '../converters/filter_transformer' 4 | import { EmptyFilter } from '../converters/utils' 5 | const WixOperatorToAdapterOperator = new FilterTransformer().wixOperatorToAdapterOperatorString 6 | 7 | export const queryAdapterOperatorsFor = (type: string) => ( (QueryOperatorsByFieldType as any)[type].map((op: any) => WixOperatorToAdapterOperator(`$${op}`)) ) 8 | 9 | export const extractFieldsAndOperators = (_filter: AdapterFilter): { name: string, operator: AdapterOperator }[] => { 10 | if (_filter === EmptyFilter) return [] 11 | const filter = _filter as NotEmptyAdapterFilter 12 | if (filter.fieldName) return [{ name: filter.fieldName.split('.')[0], operator: filter.operator as AdapterOperator }] 13 | return filter.value.map((filter: any) => extractFieldsAndOperators(filter)).flat() 14 | } 15 | 16 | export const isBlank = (str: string) => (!str || /^\s*$/.test(str)) 17 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/converters/utils.ts: -------------------------------------------------------------------------------- 1 | import { AdapterFunctions } from '@wix-velo/velo-external-db-types' 2 | 3 | export const EmptyFilter = {} 4 | 5 | export const projectionFieldFor = (fieldName: any, fieldAlias?: string) => { 6 | const field = { name: fieldName.substring(1) } 7 | return fieldAlias ? { ...field, ...{ alias: fieldAlias } } : field 8 | } 9 | 10 | export const projectionFunctionFor = (fieldName: string | number, fieldAlias: any, func: any) => { 11 | if (func === AdapterFunctions.count) 12 | return { alias: fieldAlias, function: AdapterFunctions.count, name: '*' } 13 | 14 | return { name: fieldName as string, alias: fieldAlias || fieldName as string, function: func } 15 | } 16 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/health/app_info.ts: -------------------------------------------------------------------------------- 1 | import { AnyFixMe } from '@wix-velo/velo-external-db-types' 2 | 3 | export const maskSensitiveData = (cfg: {[key: string]: any}) => { 4 | const config = { ...cfg } 5 | if (config['password']) config['password'] = '*********' 6 | if (config['secretKey']) config['secretKey'] = '*********' 7 | return config 8 | } 9 | 10 | // 1. fix config reader config client when moving configReader to ts 11 | // 2. operation service - when declaring it as OperationService, there's a problem with mock and tests, create interface? 12 | export const appInfoFor = async(operationService: AnyFixMe, configReaderClient: AnyFixMe, hideAppInfo?:boolean) => { 13 | const connectionStatus = await operationService.connectionStatus() 14 | const { message: configReaderStatus, authorizationMessage: authorizationConfigStatus } = await configReaderClient.configStatus() 15 | 16 | const config = hideAppInfo ? {} : maskSensitiveData (await configReaderClient.readConfig()) 17 | 18 | 19 | return { 20 | configReaderStatus, 21 | authorizationConfigStatus, 22 | config, 23 | dbConnectionStatus: connectionStatus.error || connectionStatus.status, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/roles-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": [ 3 | { 4 | "pathPrefix": "/schemas/column", 5 | "roles": ["OWNER"] 6 | }, 7 | { 8 | "pathPrefix": "/schemas/create", 9 | "roles": ["OWNER"] 10 | }, 11 | { 12 | "pathPrefix": "/schemas/list", 13 | "roles": ["OWNER", "BACKEND_CODE", "MEMBER"] 14 | }, 15 | { 16 | "pathPrefix": "/schemas/find", 17 | "roles": ["OWNER", "BACKEND_CODE", "MEMBER", "VISITOR"] 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/service/operation.ts: -------------------------------------------------------------------------------- 1 | import { IDatabaseOperations, ValidateConnectionResult, connectionStatusResult } from '@wix-velo/velo-external-db-types' 2 | 3 | export interface IOperationService { 4 | validateConnection(): Promise 5 | connectionStatus(): Promise 6 | } 7 | 8 | export default class OperationService implements IOperationService { 9 | databaseOperation: IDatabaseOperations 10 | constructor(databaseOperation: any) { 11 | this.databaseOperation = databaseOperation 12 | } 13 | 14 | async validateConnection() { 15 | return await this.databaseOperation.validateConnection() 16 | } 17 | 18 | async connectionStatus() { 19 | const connectionStatus = await this.databaseOperation.validateConnection() 20 | if (connectionStatus.valid) { 21 | return { 22 | status: 'Connected to database successfully' 23 | } 24 | } 25 | return { 26 | error: (connectionStatus as any).error.message //todo: fix this hack 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/spi-model/capabilities.ts: -------------------------------------------------------------------------------- 1 | export interface GetCapabilitiesRequest {} 2 | 3 | // Global capabilities that datasource supports. 4 | export interface GetCapabilitiesResponse { 5 | capabilities: Capabilities 6 | } 7 | 8 | export interface Capabilities { 9 | // Defines which collection operations is supported. 10 | collection: CollectionCapability[] 11 | } 12 | 13 | export enum CollectionCapability { 14 | // Supports creating new collections. 15 | CREATE = 'CREATE' 16 | } 17 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/spi-model/filter.ts: -------------------------------------------------------------------------------- 1 | 2 | // type PrimitveType = number | string | boolean 3 | // type PrimitveTypeArray = PrimitveType[] 4 | 5 | // interface Filter { 6 | // root: And 7 | // } 8 | 9 | 10 | // interface ToAdapterType { 11 | // toAdapter(): void 12 | // } 13 | 14 | // type Comperator = Eq | Ne | Lt 15 | 16 | // interface FieldComperator { 17 | // [fieldName: string]: Comperator | PrimitveType | PrimitveTypeArray 18 | // } 19 | 20 | // interface Eq { 21 | // $eq: PrimitveType 22 | // } 23 | 24 | // interface Ne { 25 | // $ne: PrimitveType 26 | // } 27 | 28 | // interface Lt { 29 | // $lt: number 30 | // } 31 | 32 | // interface And { 33 | // $and: Array 34 | // } 35 | 36 | // interface Or { 37 | // $or: Array 38 | // } 39 | 40 | // interface Not { 41 | // $not: FieldComperator | And | Or | Not 42 | // } 43 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/utils/base64_utils.ts: -------------------------------------------------------------------------------- 1 | 2 | export function decodeBase64(data: string): string { 3 | const buff = Buffer.from(data, 'base64') 4 | return buff.toString('ascii') 5 | } 6 | export function encodeBase64(data: string): string { 7 | const buff = Buffer.from(data, 'utf-8') 8 | return buff.toString('base64') 9 | } 10 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/utils/data_utils.ts: -------------------------------------------------------------------------------- 1 | import { AdapterOperators } from '@wix-velo/velo-external-db-commons' 2 | import { AdapterFilter, AdapterOperator } from '@wix-velo/velo-external-db-types' 3 | 4 | export const getByIdFilterFor = (itemId: string): AdapterFilter => ({ 5 | fieldName: '_id', 6 | operator: AdapterOperators.eq as AdapterOperator, 7 | value: itemId 8 | }) 9 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/utils/date_time_provider.js: -------------------------------------------------------------------------------- 1 | const dateTime = { 2 | currentDateTime: () => new Date(), 3 | } 4 | 5 | module.exports = dateTime 6 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/utils/router_utils.build.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path' 2 | import * as ejs from 'ejs' 3 | import { AnyFixMe } from '@wix-velo/velo-external-db-types' 4 | const fs = require('fs').promises 5 | 6 | const getAppInfoTemplate = async(hideAppInfo: boolean) => { 7 | const fileName = hideAppInfo ? 'index-without-data.ejs' : 'index.ejs' 8 | return await fs.readFile(path.join( __dirname, 'views', fileName), 'utf8') 9 | } 10 | 11 | export const getAppInfoPage = async(appInfo: AnyFixMe, hideAppInfo: boolean) => { 12 | const appInfoTemplate = await getAppInfoTemplate(hideAppInfo) 13 | const appInfoPage = ejs.render(appInfoTemplate, appInfo) 14 | return appInfoPage 15 | } 16 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/utils/router_utils.ts: -------------------------------------------------------------------------------- 1 | import path = require('path') 2 | import ejs = require('ejs') 3 | import { promises as fs } from 'fs' 4 | 5 | const getAppInfoTemplate = async(hideAppInfo?: boolean) => { // TODO: fix this hack! 6 | const fileName = hideAppInfo ? 'index-without-data.ejs' : 'index.ejs' 7 | try { 8 | return await fs.readFile(path.join( __dirname, '..', 'views', fileName), 'utf8') 9 | } catch (err) { 10 | return await fs.readFile(path.join( __dirname, 'views', fileName), 'utf8') 11 | } 12 | 13 | 14 | } 15 | 16 | export const getAppInfoPage = async(appInfo: any, hideAppInfo?: boolean) => { 17 | const appInfoTemplate = await getAppInfoTemplate(hideAppInfo) 18 | const appInfoPage = ejs.render(appInfoTemplate, appInfo) 19 | return appInfoPage 20 | } 21 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/views/error.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%- include("partials/header.ejs") %> 4 | 5 | 6 |
7 |
8 |
9 | 10 | 12 | sad-unicorn 13 | 14 |
15 | 16 |
17 |

Something went wrong...

18 |
19 |
20 |
21 |

Error:

22 |

23 | <%= error %> 24 |

25 |
26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/web/auth-role-middleware.ts: -------------------------------------------------------------------------------- 1 | import { errors } from '@wix-velo/velo-external-db-commons' 2 | import { Request } from 'express' 3 | import { property } from './middleware-support' 4 | const { UnauthorizedError } = errors 5 | 6 | export const extractRole = (body: any) => property('requestContext.role', body) 7 | 8 | const authorizeRole = (req: Request, roles: string | any[]) => { 9 | const role = extractRole(req.body) 10 | if (!roles.includes(role)) { 11 | throw new UnauthorizedError('You are not authorized') 12 | } 13 | } 14 | 15 | export function authRoleMiddleware( { roles }: { roles: string | any[] } ) { 16 | return (req: any, res: any, next: () => void) => { 17 | authorizeRole(req, roles) 18 | next() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/web/error-middleware.ts: -------------------------------------------------------------------------------- 1 | import { NextFunction, Response } from 'express' 2 | import { domainToSpiErrorTranslator } from './domain-to-spi-error-translator' 3 | import { ILogger } from '@wix-velo/external-db-logger' 4 | 5 | export const errorMiddleware = (logger?: ILogger) => (err: any, _req: any, res: Response, _next?: NextFunction) => { 6 | if (process.env['NODE_ENV'] !== 'test') { 7 | logger?.error(err.message, err) 8 | } 9 | 10 | const error = domainToSpiErrorTranslator(err) 11 | res.status(error.httpCode).send({ 12 | data: error.data, 13 | errorCode: error.errorCode, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/web/jwt-verifier-decoder-middleware.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from 'express' 2 | import { JWTVerifier } from './jwt-verifier' 3 | 4 | export class JWTVerifierDecoderMiddleware { 5 | private jwtVerifier: JWTVerifier 6 | 7 | constructor(jwtVerifier: any) { 8 | this.jwtVerifier = jwtVerifier 9 | } 10 | 11 | verifyAndDecodeMiddleware() { 12 | return (req: Request, res: Response, next: NextFunction) => { 13 | try { 14 | const { request, metadata } = this.jwtVerifier.verifyAndDecode(req.body) 15 | req.body = request 16 | req.body.metadata = metadata 17 | next() 18 | } 19 | catch (error) { 20 | next(error) 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/web/jwt-verifier-test-support.ts: -------------------------------------------------------------------------------- 1 | import { when } from 'jest-when' 2 | import { errors } from '@wix-velo/velo-external-db-commons' 3 | 4 | const { UnauthorizedError } = errors 5 | export const jwtVerifier = { 6 | verifyAndDecode: jest.fn(), 7 | } 8 | 9 | export const givenValidToken = (token: string, decodedToken: any) => { 10 | when(jwtVerifier.verifyAndDecode).calledWith(token).mockReturnValue(decodedToken) 11 | } 12 | 13 | export const givenInvalidToken = (token: string, errorMsgFromVerifier: string) => { 14 | when(jwtVerifier.verifyAndDecode).calledWith(token).mockImplementation(() => { throw new UnauthorizedError(errorMsgFromVerifier) }) 15 | } 16 | 17 | export const reset = () => { 18 | jwtVerifier.verifyAndDecode.mockClear() 19 | } 20 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/src/web/middleware-support.ts: -------------------------------------------------------------------------------- 1 | import { errors } from '@wix-velo/velo-external-db-commons' 2 | import { NextFunction, Request, Response } from 'express' 3 | import { has, get } from 'nested-property' 4 | const { UnauthorizedError } = errors 5 | 6 | export const unless = function(path: string | any[], middleware: any) { 7 | return function(req: Request, res: Response, next: NextFunction) { 8 | if (path.includes(req.path)) { 9 | return next() 10 | } else { 11 | return middleware(req, res, next) 12 | } 13 | } 14 | } 15 | 16 | export const includes = function(path: any[], middleware: any) { 17 | return function(req: Request, res: Response, next: NextFunction) { 18 | if (path.some((p: any) => req.path.startsWith(p))) { 19 | return middleware(req, res, next) 20 | } else { 21 | return next() 22 | } 23 | } 24 | } 25 | 26 | export const property = (prop: any, body: any) => { 27 | if (!has(body, prop)) { 28 | throw new UnauthorizedError('You are not authorized') 29 | } 30 | return get(body, prop) 31 | } 32 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/test/drivers/aggregation_transformer_test_support.ts: -------------------------------------------------------------------------------- 1 | import { when } from 'jest-when' 2 | 3 | export const aggregationTransformer = { 4 | transform: jest.fn(), 5 | } 6 | 7 | export const givenTransformTo = (aggregation: any, transformedAggregation: any) => { 8 | when(aggregationTransformer.transform).calledWith(aggregation) 9 | .mockReturnValue(transformedAggregation) 10 | } 11 | 12 | export const reset = () => { 13 | aggregationTransformer.transform.mockClear() 14 | } 15 | 16 | const transform = aggregationTransformer.transform 17 | export { transform } 18 | 19 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/test/drivers/date_time_provider_test_support.js: -------------------------------------------------------------------------------- 1 | const current = new Date() 2 | 3 | const dateTime = { 4 | currentDateTime: () => current, 5 | } 6 | 7 | module.exports = dateTime 8 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/test/drivers/index_provider_test_support.ts: -------------------------------------------------------------------------------- 1 | import { DomainIndex } from '@wix-velo/velo-external-db-types' 2 | import { when } from 'jest-when' 3 | 4 | export const indexProvider = { 5 | list: jest.fn(), 6 | create: jest.fn(), 7 | remove: jest.fn(), 8 | } 9 | 10 | export const givenListResult = (indexes: DomainIndex[], collectionName: string) => { 11 | when(indexProvider.list).calledWith(collectionName).mockResolvedValue(indexes) 12 | } 13 | 14 | export const givenCreateResult = (index: DomainIndex, collectionName: string) => { 15 | const { status, ...indexWithoutStatus } = index 16 | when(indexProvider.create).calledWith(collectionName, indexWithoutStatus).mockResolvedValue(index) 17 | } 18 | 19 | export const reset = () => { 20 | indexProvider.list.mockReset() 21 | indexProvider.create.mockReset() 22 | indexProvider.remove.mockReset() 23 | } 24 | 25 | 26 | export function givenRemoveResult(collectionName: string, name: string) { 27 | when(indexProvider.remove).calledWith(collectionName, name).mockResolvedValue({}) 28 | } 29 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/test/drivers/operation_provider_test_support.ts: -------------------------------------------------------------------------------- 1 | export const dataOperation = { 2 | validateConnection: jest.fn() 3 | } 4 | 5 | export const givenValidPool = () => 6 | dataOperation.validateConnection.mockResolvedValue({ valid: true }) 7 | 8 | export const givenInvalidPool = (error: any) => 9 | dataOperation.validateConnection.mockImplementation(() => { return { valid: false, error } }) 10 | 11 | export const reset = () => { 12 | dataOperation.validateConnection.mockClear() 13 | } 14 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/velo-external-db-core/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/velo-external-db-types/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx"], 7 | "rules": {} 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /libs/velo-external-db-types/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'velo-external-db-types', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | transform: { 11 | '^.+\\.[tj]s$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'js', 'html'], 14 | coverageDirectory: '../../coverage/libs/velo-external-db-types', 15 | verbose: true, 16 | }; 17 | -------------------------------------------------------------------------------- /libs/velo-external-db-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wix-velo/velo-external-db-types", 3 | "version": "2.0.0", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /libs/velo-external-db-types/src/indexing_types.ts: -------------------------------------------------------------------------------- 1 | export interface IIndexProvider { 2 | list(collectionName: string): Promise 3 | create(collectionName: string, index: DomainIndex): Promise 4 | remove(collectionName: string, indexName: string): Promise 5 | } 6 | 7 | 8 | export interface DomainIndex { 9 | name: string 10 | columns: string[] 11 | isUnique: boolean 12 | caseInsensitive: boolean 13 | order : 'ASC' | 'DESC' 14 | status?: DomainIndexStatus 15 | error?: any 16 | } 17 | 18 | export enum DomainIndexStatus { 19 | ACTIVE = 'ACTIVE', 20 | BUILDING = 'BUILDING', 21 | FAILED = 'FAILED' 22 | } 23 | -------------------------------------------------------------------------------- /libs/velo-external-db-types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "allowJs": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/velo-external-db-types/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": [] 7 | }, 8 | "include": ["**/*.ts", "**/*.js"], 9 | "exclude": [ 10 | "jest.config.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.ts", 13 | "**/*.test.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/velo-external-db-types/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '*.{ts,js}': [ 3 | 'nx affected --target lint --uncommitted --fix --quiet true', 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/nx/schemas/nx-schema.json", 3 | "tasksRunnerOptions": { 4 | "default": { 5 | "runner": "nx/tasks-runners/default", 6 | "options": { 7 | "cacheableOperations": [ "build", "test", "lint", "package", "prepare" ] 8 | } 9 | } 10 | }, 11 | "targetDependencies": { 12 | "build": [ 13 | { 14 | "target": "build", 15 | "projects": "dependencies" 16 | } 17 | ], 18 | "prepare": [ 19 | { 20 | "target": "prepare", 21 | "projects": "dependencies" 22 | } 23 | ], 24 | "package": [ 25 | { 26 | "target": "package", 27 | "projects": "dependencies" 28 | } 29 | ] 30 | }, 31 | "affected": { 32 | "defaultBase": "master" 33 | }, 34 | "defaultProject": "velo-external-db" 35 | } 36 | -------------------------------------------------------------------------------- /scripts/data-tools/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | .credentials.json 4 | -------------------------------------------------------------------------------- /scripts/data-tools/lib/adapter/data.js: -------------------------------------------------------------------------------- 1 | const { randomEntity } = require('../generator/data') 2 | 3 | const insert = async(items, collectionName, axios) => { 4 | await axios.post('/data/insert/bulk', { collectionName, items }) 5 | .catch(error => console.log(`Error adding chunk: ${error.message}`)) 6 | } 7 | 8 | const insertChunk = async(count, columns, collectionName, axios) => { 9 | const items = [...Array(count)].map(() => randomEntity(columns)) 10 | await insert(items, collectionName, axios) 11 | } 12 | 13 | module.exports = { insertChunk } 14 | -------------------------------------------------------------------------------- /scripts/data-tools/lib/adapter/schema.js: -------------------------------------------------------------------------------- 1 | 2 | const create = async(collectionName, axios) => await axios.post('/schemas/create', { collectionName }) 3 | const createCollection = async(collectionName, axios) => await create(collectionName, axios) 4 | 5 | const addColumn = async(collectionName, column, axios) => { 6 | try{ 7 | return await axios.post('/schemas/column/add', { collectionName, column }) 8 | }catch(e) {console.log(e)} 9 | } 10 | 11 | const addColumnsToCollection = async(collectionName, newColumns, axios) => { 12 | for (const c of newColumns) { 13 | await addColumn(collectionName, c, axios) 14 | } 15 | } 16 | 17 | const truncate = (collectionName, axios) => axios.post('/data/truncate', { collectionName }) 18 | 19 | module.exports = { addColumnsToCollection, createCollection, truncate } 20 | -------------------------------------------------------------------------------- /scripts/data-tools/lib/generator/data.js: -------------------------------------------------------------------------------- 1 | const Chance = require('chance') 2 | const chance = Chance() 3 | 4 | 5 | const newDate = () => { 6 | const d = new Date() 7 | d.setMilliseconds(0) 8 | return d 9 | } 10 | 11 | const veloDate = () => ( { $date: newDate().toISOString() } ) 12 | 13 | const randomEntity = (columns) => { 14 | const entity = { 15 | _id: chance.guid(), 16 | _createdDate: veloDate(), 17 | _updatedDate: veloDate(), 18 | _owner: chance.guid(), 19 | } 20 | 21 | const _columns = columns || [] 22 | 23 | for (const column of _columns) { 24 | entity[column.name] = chance.word() 25 | } 26 | return entity 27 | } 28 | 29 | module.exports = { randomEntity } 30 | -------------------------------------------------------------------------------- /scripts/data-tools/lib/generator/schema.js: -------------------------------------------------------------------------------- 1 | const generateColumns = columnsCount => [...Array(parseInt(columnsCount))].map((e, i) => ({ name: `column_${i}`, type: 'text', subtype: 'string', precision: '256', isPrimary: false })) 2 | 3 | module.exports = { generateColumns } 4 | -------------------------------------------------------------------------------- /scripts/data-tools/lib/index.js: -------------------------------------------------------------------------------- 1 | const { askForUserInput } = require('./cli/user-input') 2 | const { main } = require('./core/process') 3 | const { blankLine, header } = require('./cli/display') 4 | 5 | const process = async() => { 6 | await header() 7 | const userInput = await askForUserInput() 8 | blankLine() 9 | blankLine() 10 | await main(userInput) 11 | } 12 | 13 | process() 14 | -------------------------------------------------------------------------------- /scripts/data-tools/lib/utils/request.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | 3 | const appendSecretKeyRoleToRequest = (data, secretKey) => ({ 4 | ...data, 5 | requestContext: { 6 | role: 'OWNER', 7 | settings: { secretKey } 8 | } 9 | }) 10 | 11 | const axiosFor = ({ adapterUrl, secretKey }) => { 12 | return axios.create({ 13 | baseURL: adapterUrl, 14 | transformRequest: [ 15 | // eslint-disable-next-line no-unused-vars 16 | (data, _headers) => appendSecretKeyRoleToRequest(data, secretKey), 17 | ...axios.defaults.transformRequest] 18 | }) 19 | } 20 | 21 | module.exports = { axiosFor } 22 | -------------------------------------------------------------------------------- /scripts/data-tools/lib/utils/utils.js: -------------------------------------------------------------------------------- 1 | 2 | const nonEmpty = input => !(!input || input.trim() === '') 3 | const isNumber = input => Number.isInteger(parseInt(input)) 4 | 5 | module.exports = { nonEmpty, isNumber } 6 | -------------------------------------------------------------------------------- /scripts/data-tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "data-import", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "test": "", 8 | "start": "node lib/index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/wix/velo-external-db.git" 13 | }, 14 | "author": "noama@wix.com", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/wix/velo-external-db/issues" 18 | }, 19 | "homepage": "https://github.com/wix/velo-external-db#readme", 20 | "dependencies": { 21 | "axios": "^0.26.0", 22 | "chalk": "^4.1.2", 23 | "chance": "^1.1.8", 24 | "cli-progress": "^3.9.1", 25 | "cli-spinner": "^0.2.10", 26 | "inquirer": "^8.2.0", 27 | "node-banner": "^1.4.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scripts/provision/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | .credentials.json 4 | -------------------------------------------------------------------------------- /scripts/provision/README.MD: -------------------------------------------------------------------------------- 1 | # Wix Velo External Database Adapter Generator 2 | 3 | 4 | - [Wix Velo External Database Adapter Generator](#wix-velo-external-database-adapter-generator) 5 | - [Introduction](#introduction) 6 | - [Prerequisites](#prerequisites) 7 | - [Google Cloud Platform](#google-cloud-platform) 8 | - [Azure](#azure) 9 | 10 | 11 | ## Introduction 12 | 13 | Wix Velo External Database Adapter Generator was created to autogenerate Velo External Database Adapter for a variety of cloud services 14 | 15 | ## Prerequisites 16 | 17 | ### Google Cloud Platform 18 | To get started, you'll need: 19 | 1. An active gcp client email, and private key 20 | 2. Enable the following apis: 21 | 1. Identity and Access Management (IAM) API 22 | 2. Cloud Resource Manager API 23 | 24 | ### Azure 25 | To get started, you'll need: 26 | 1. install azure cli 27 | 2. type 'az login' and log in your azure user. 28 | 3. get your user object id by the command ' az ad signed-in-user show | grep "objectId" ' and copy the value 29 | 4. get the subscription id by the command ' az account show | grep "id" ' and copy the value 30 | -------------------------------------------------------------------------------- /scripts/provision/lib/auth/default_credentials.js: -------------------------------------------------------------------------------- 1 | const AwsEmptyCredentials = { accessKeyId: '', secretAccessKey: '' } 2 | 3 | const credentialsFor = (impl) => { 4 | try { 5 | return require('../../.credentials.json') 6 | } catch (e) { 7 | switch (impl) { 8 | case 'aws': 9 | return AwsEmptyCredentials 10 | default: 11 | return { } 12 | } 13 | } 14 | } 15 | 16 | module.exports = { credentialsFor } 17 | -------------------------------------------------------------------------------- /scripts/provision/lib/cli/validators.js: -------------------------------------------------------------------------------- 1 | const nonEmpty = input => !(!input || input.trim() === '') 2 | 3 | module.exports = { nonEmpty } 4 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/aws/aws_config_writer.js: -------------------------------------------------------------------------------- 1 | const { SecretsManagerClient, CreateSecretCommand } = require('@aws-sdk/client-secrets-manager') 2 | 3 | class ConfigWriter { 4 | constructor({ awsAccessKeyId, awsSecretAccessKey }, region) { 5 | this.client = new SecretsManagerClient({ region, credentials: { accessKeyId: awsAccessKeyId, secretAccessKey: awsSecretAccessKey } }) 6 | } 7 | 8 | async writeConfig({ secretId, dbCredentials, host, db, secretKey }) { 9 | const config = { host, username: dbCredentials.user, password: dbCredentials.passwd, DB: db, SECRET_KEY: secretKey } 10 | await this.client.send(new CreateSecretCommand({ Name: secretId, SecretString: JSON.stringify(config) } ) ) 11 | } 12 | } 13 | 14 | module.exports = ConfigWriter 15 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/aws/aws_permissions_provision.js: -------------------------------------------------------------------------------- 1 | 2 | class PermissionsProvision { 3 | constructor() { 4 | } 5 | 6 | async createServiceAccount() { 7 | } 8 | 9 | async grantPermission() { 10 | } 11 | } 12 | 13 | module.exports = PermissionsProvision 14 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/aws/db/factory.js: -------------------------------------------------------------------------------- 1 | const clientFor = engine => { 2 | switch (engine) { 3 | case 'mysql': 4 | return require('./mysql_support') 5 | case 'postgres': 6 | return require('./postgres_support') 7 | case 'mssql': 8 | return require('./mssql_support') 9 | } 10 | } 11 | 12 | const portFor = engine => { 13 | switch (engine) { 14 | case 'mysql': 15 | return 3306 16 | case 'postgres': 17 | return 5432 18 | case 'mssql': 19 | return 1443 20 | } 21 | } 22 | 23 | const createCmdPatchFor = (engine) => { 24 | switch (engine) { 25 | case 'mssql': 26 | return { Engine: 'sqlserver-ex', DBInstanceClass: 'db.t3.small', LicenseModel: 'license-included' } 27 | default: 28 | return { } 29 | 30 | } 31 | } 32 | 33 | module.exports = { clientFor, portFor, createCmdPatchFor } 34 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/aws/db/mssql_support.js: -------------------------------------------------------------------------------- 1 | const sql = require('mssql') 2 | 3 | const createDatabase = async(dbName, host, credentials) => { 4 | const config = { 5 | user: credentials.user, 6 | password: credentials.password, 7 | server: host, 8 | port: 1433, 9 | options: { 10 | encrypt: false, 11 | trustServerCertificate: true 12 | } 13 | 14 | } 15 | 16 | try { 17 | await sql.connect(config) 18 | await sql.query(`CREATE DATABASE ${dbName}`) 19 | } catch (err) { 20 | console.error(err) 21 | } finally { 22 | await sql.close() 23 | } 24 | } 25 | 26 | module.exports = { createDatabase } 27 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/aws/db/mysql_support.js: -------------------------------------------------------------------------------- 1 | const mysql = require('mysql') 2 | 3 | 4 | const createDatabase = async(dbName, host, credentials) => { 5 | let connection 6 | 7 | try { 8 | connection = mysql.createConnection({ 9 | host, 10 | user: credentials.user, 11 | password: credentials.passwd, 12 | }) 13 | connection.connect() 14 | connection.query(`CREATE DATABASE ${dbName}`) 15 | } catch (err) { 16 | console.error(err) 17 | } finally { 18 | if (connection) { 19 | connection.end() 20 | } 21 | } 22 | } 23 | 24 | module.exports = { createDatabase } 25 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/aws/db/postgres_support.js: -------------------------------------------------------------------------------- 1 | const { Client } = require('pg') 2 | 3 | 4 | const createDatabase = async(dbName, host, credentials) => { 5 | const client = new Client({ 6 | host, 7 | user: credentials.user, 8 | password: credentials.passwd, 9 | database: 'postgres', 10 | port: 5432, 11 | }) 12 | try { 13 | await client.connect() 14 | await client.query(`CREATE DATABASE ${dbName}`) 15 | } catch (err) { 16 | console.log('failed to create db') 17 | } finally { 18 | await client.end() 19 | } 20 | } 21 | 22 | module.exports = { createDatabase } 23 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/aws/index.js: -------------------------------------------------------------------------------- 1 | const DbProvision = require('./aws_db_provision') 2 | const ConfigWriter = require('./aws_config_writer') 3 | const AdapterProvision = require('./aws_adapter_provision') 4 | const NetworkProvision = require('./aws_network_provision') 5 | const PermissionsProvision = require('./aws_permissions_provision') 6 | const uiUtils = require('./aws_ui_utils') 7 | 8 | 9 | module.exports = { DbProvision, ConfigWriter, AdapterProvision, NetworkProvision, PermissionsProvision, ...uiUtils } 10 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/azure/azure_permissions_provision.js: -------------------------------------------------------------------------------- 1 | 2 | class PermissionsProvision { 3 | constructor() { 4 | } 5 | 6 | async createServiceAccount() { 7 | } 8 | 9 | async grantPermission() { 10 | } 11 | } 12 | 13 | module.exports = PermissionsProvision 14 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/azure/azure_ui_utils.js: -------------------------------------------------------------------------------- 1 | const inquirer = require('inquirer') 2 | const { nonEmpty } = require('../../cli/validators') 3 | const { SubscriptionClient } = require('@azure/arm-subscriptions') 4 | const { DefaultAzureCredential } = require('@azure/identity') 5 | 6 | const credentials = async() => inquirer.prompt([ 7 | { 8 | type: 'input', 9 | name: 'subscriptionId', 10 | message: 'Subscription Id', 11 | validate: nonEmpty 12 | }, 13 | { 14 | type: 'input', 15 | name: 'userObjectId', 16 | message: 'User Object Id', 17 | validate: nonEmpty 18 | } 19 | ]) 20 | 21 | const region = async(credentials) => inquirer.prompt([ 22 | { 23 | type: 'list', 24 | name: 'region', 25 | message: 'Region availability', 26 | choices: async() => await regionList(credentials.subscriptionId) 27 | } 28 | ]) 29 | 30 | 31 | const regionList =async(subscriptionId) => { 32 | const client = new SubscriptionClient(new DefaultAzureCredential()) 33 | const regions = await client.subscriptions.listLocations(subscriptionId) 34 | return regions.map(region => ({ name: region.displayName, value: region.name })) 35 | } 36 | 37 | module.exports = { credentials, region } 38 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/azure/db/factory.js: -------------------------------------------------------------------------------- 1 | const clientFor = engine => { 2 | switch (engine) { 3 | case 'mysql': 4 | return require('./mysql_support') 5 | case 'postgres': 6 | return require ('./postgres_support') 7 | } 8 | } 9 | 10 | module.exports = { clientFor } 11 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/azure/index.js: -------------------------------------------------------------------------------- 1 | const DbProvision = require('./azure_db_provision') 2 | const ConfigWriter = require('./azure_config_writer') 3 | const AdapterProvision = require('./azure_adapter_provision') 4 | const PermissionsProvision = require('./azure_permissions_provision') 5 | const { provisionVariables } = require('./utils') 6 | const uiUtils = require('./azure_ui_utils') 7 | 8 | module.exports = { DbProvision, ConfigWriter, AdapterProvision, PermissionsProvision, provisionVariables, ...uiUtils } 9 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/azure/utils.js: -------------------------------------------------------------------------------- 1 | const { randomInt } = require('../../utils/utils') 2 | 3 | const random = randomInt() 4 | 5 | const provisionVariables = { 6 | resourceGroupName: `velo-resource-group-${random}`, 7 | virtualNetworkName: `velo-vnet-${random}`, 8 | subnetName: `velo-subnet-${random}`, 9 | appServicePlanName: `plan${random}`, 10 | keyVaultName: `key-vault-${random}` 11 | } 12 | 13 | const refFromKeyVault = (keyVaultName, secretName) => `@Microsoft.KeyVault(VaultName=${keyVaultName};SecretName=${secretName})` 14 | 15 | const DockerImage = 'DOCKER|veloex/velo-external-db:latest' 16 | 17 | module.exports = { provisionVariables, refFromKeyVault, DockerImage } 18 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/factory.js: -------------------------------------------------------------------------------- 1 | 2 | const providerFor = (vendor) => { 3 | switch (vendor) { 4 | case 'gcp': 5 | return require('./gcp') 6 | case 'aws': 7 | return require('./aws') 8 | case 'azure': 9 | return require ('./azure') 10 | } 11 | } 12 | 13 | module.exports = { providerFor } 14 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/gcp/gcp_network_provision.js: -------------------------------------------------------------------------------- 1 | 2 | class NetworkProvision { 3 | constructor() { 4 | } 5 | 6 | async addSecurityRule() { 7 | } 8 | 9 | } 10 | 11 | module.exports = NetworkProvision 12 | -------------------------------------------------------------------------------- /scripts/provision/lib/cloud-providers/gcp/index.js: -------------------------------------------------------------------------------- 1 | const DbProvision = require('./gcp_db_provision') 2 | const ConfigWriter = require('./gcp_config_writer') 3 | const AdapterProvision = require('./gcp_adapter_provision') 4 | const NetworkProvision = require('./gcp_network_provision') 5 | const PermissionsProvision = require('./gcp_permissions_provision') 6 | const uiUtils = require('./gcp_ui_utils') 7 | 8 | 9 | module.exports = { DbProvision, ConfigWriter, AdapterProvision, NetworkProvision, PermissionsProvision, ...uiUtils } 10 | -------------------------------------------------------------------------------- /scripts/provision/lib/index.js: -------------------------------------------------------------------------------- 1 | const { askForUserInput } = require('./cli/user-input') 2 | const { header } = require('./cli/display') 3 | const { main } = require('./core/provision') 4 | 5 | const process = async() => { 6 | await header() 7 | const userInput = await askForUserInput() 8 | await main(userInput) 9 | } 10 | 11 | process() 12 | -------------------------------------------------------------------------------- /scripts/provision/lib/utils/password_utils.js: -------------------------------------------------------------------------------- 1 | const passwdGen = require('generate-password') 2 | 3 | const shuffle = array => array.sort(() => Math.random() - 0.5) 4 | 5 | 6 | const randomPassword = () => { 7 | const passwds = passwdGen.generateMultiple(10, { length: 30, numbers: true/*, symbols: true*/ }) 8 | return shuffle(passwds)[0] 9 | } 10 | 11 | const randomSecretKey = () => { 12 | const passwds = passwdGen.generateMultiple(10, { length: 30, numbers: true, symbols: true }) 13 | return shuffle(passwds)[0] 14 | } 15 | 16 | 17 | const randomCredentials = () => ({ user: 'velo_user', passwd: randomPassword() }) 18 | 19 | module.exports = { randomCredentials, randomSecretKey } 20 | -------------------------------------------------------------------------------- /scripts/provision/lib/utils/utils.js: -------------------------------------------------------------------------------- 1 | const { waitFor } = require('poll-until-promise') 2 | 3 | const blockUntil = async f => waitFor( 4 | async() => { 5 | const response = await f() 6 | 7 | if (!response) { 8 | throw new Error('try again') 9 | } 10 | }, { 11 | interval: 100, 12 | timeout: 20 * 60 * 1000, 13 | message: 'Waiting for time to pass :)', 14 | } 15 | ) 16 | 17 | const randomInt = () => Math.floor(Math.random() * 10000) 18 | const randomWithPrefix = prefix => `${prefix}-${randomInt()}` 19 | 20 | 21 | module.exports = { blockUntil, randomWithPrefix, randomInt } 22 | -------------------------------------------------------------------------------- /scripts/terraform/.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | **/.terraform* 4 | 5 | # .tfstate files 6 | *.tfstate 7 | *.tfstate.* 8 | 9 | # Crash log files 10 | crash.log 11 | crash.*.log 12 | 13 | # Ignore CLI configuration files 14 | .terraformrc 15 | terraform.rc 16 | 17 | # Ignored Terraform files 18 | *gitignore*.tf -------------------------------------------------------------------------------- /scripts/terraform/README.MD: -------------------------------------------------------------------------------- 1 | # Wix Velo External Database Adaptor Terraform provision 2 | 3 | 4 | - [Wix Velo External Database Adaptor Terraform provision](#wix-velo-external-database-adaptor-terraform-provision) 5 | - [Introduction](#introduction) 6 | - [Prerequisites](#prerequisites) 7 | - [Azure](#azure) 8 | - [GCP](#gcp) 9 | 10 | 11 | ## Introduction 12 | 13 | Using Terraform to provision the adaptor in Azure/ GCP / AWS. 14 | 15 | ## Prerequisites 16 | 17 | * You must have [Terraform](https://www.terraform.io/) installed on your computer. 18 | 19 | 20 | ### Azure 21 | To get started, you'll need: 22 | 1. Install [azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) 23 | 2. Authenticate with Azure: Run ``` az login ``` and log in your azure user. 24 | 25 | **MySql** 26 | - Run ``` npm run start:azure-mysql ``` 27 | 28 | **Postgres** 29 | - Run ``` npm run start:azure-postgres ``` 30 | 31 | ### GCP 32 | To get started, you'll need: 33 | 1. Install [gcloud CLI](https://cloud.google.com/sdk/docs/install) 34 | 2. Authenticate with GCP, The easiest way to do this is to run ``` gcloud auth application-default login. ``` 35 | 3. Run ``` npm start:gcp ``` 36 | 37 | -------------------------------------------------------------------------------- /scripts/terraform/azure/mysql/outputs.tf: -------------------------------------------------------------------------------- 1 | output "adapterUrl" { 2 | value = azurerm_app_service.veloAppService.default_site_hostname 3 | description = "The URL on which the deployed service is available" 4 | } 5 | -------------------------------------------------------------------------------- /scripts/terraform/azure/mysql/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | description = "Velo External DB adapter service deployment region" 3 | type = string 4 | default = "eastus" 5 | } 6 | 7 | variable "resourceGroupName" { 8 | description = "Velo External DB adapter service deployment resource group name" 9 | type = string 10 | default = "velo-external-db-adapter-rg" 11 | } 12 | 13 | variable "databaseName" { 14 | description = "Database name for Velo External DB adapter service (must be unique)" 15 | type = string 16 | } 17 | 18 | variable "databaseUserName" { 19 | description = "Database user name for Velo External DB adapter service" 20 | type = string 21 | } 22 | 23 | variable "databasePassword" { 24 | description = "Database password for Velo External DB adapter service" 25 | type = string 26 | sensitive = true 27 | } 28 | 29 | variable "adapterName" { 30 | description = "The name of the Velo External DB adapter service to create (must be unique)" 31 | type = string 32 | } 33 | 34 | variable "secretKey" { 35 | description = "Secret Key for Velo External DB adapter service" 36 | type = string 37 | sensitive = true 38 | } -------------------------------------------------------------------------------- /scripts/terraform/azure/postgres/outputs.tf: -------------------------------------------------------------------------------- 1 | output "adapterUrl" { 2 | value = azurerm_app_service.veloAppService.default_site_hostname 3 | description = "The URL on which the deployed service is available" 4 | } 5 | -------------------------------------------------------------------------------- /scripts/terraform/azure/postgres/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | description = "Velo External DB adapter service deployment region" 3 | type = string 4 | default = "eastus" 5 | } 6 | 7 | variable "resourceGroupName" { 8 | description = "Velo External DB adapter service deployment resource group name" 9 | type = string 10 | default = "velo-external-db-adapter-rg" 11 | } 12 | 13 | variable "databaseName" { 14 | description = "Database name for Velo External DB adapter service (must be unique)" 15 | type = string 16 | } 17 | 18 | variable "databaseUserName" { 19 | description = "Database user name for Velo External DB adapter service" 20 | type = string 21 | } 22 | 23 | variable "databasePassword" { 24 | description = "Database password for Velo External DB adapter service" 25 | type = string 26 | sensitive = true 27 | } 28 | 29 | variable "adapterName" { 30 | description = "The name of the Velo External DB adapter service to create (must be unique)" 31 | type = string 32 | } 33 | 34 | variable "secretKey" { 35 | description = "Secret Key for Velo External DB adapter service" 36 | type = string 37 | sensitive = true 38 | } -------------------------------------------------------------------------------- /scripts/terraform/gcp/outputs.tf: -------------------------------------------------------------------------------- 1 | output "service_name" { 2 | value = google_cloud_run_service.run_service.name 3 | description = "Name of the created service" 4 | } 5 | 6 | output "service_url" { 7 | value = google_cloud_run_service.run_service.status[0].url 8 | description = "The URL on which the deployed service is available" 9 | } 10 | -------------------------------------------------------------------------------- /scripts/terraform/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "terraform", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start:azure-mysql": "terraform -chdir=./azure/mysql init && terraform -chdir=./azure/mysql apply", 7 | "start:azure-postgres": "terraform -chdir=./azure/postgres init && terraform -chdir=./azure/postgres apply", 8 | "start:gcp": "terraform -chdir=./gcp init && terraform -chdir=./gcp apply", 9 | "test": "" 10 | }, 11 | "author": "", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /workspace.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "projects": { 4 | "@wix-velo/external-db-config": "libs/external-db-config", 5 | "@wix-velo/external-db-postgres": "libs/external-db-postgres", 6 | "@wix-velo/external-db-mysql": "libs/external-db-mysql", 7 | "@wix-velo/external-db-mssql": "libs/external-db-mssql", 8 | "@wix-velo/external-db-spanner": "libs/external-db-spanner", 9 | "@wix-velo/external-db-firestore": "libs/external-db-firestore", 10 | "@wix-velo/external-db-dynamodb": "libs/external-db-dynamodb", 11 | "@wix-velo/external-db-bigquery": "libs/external-db-bigquery", 12 | "@wix-velo/external-db-security": "libs/external-db-security", 13 | "@wix-velo/test-commons": "libs/test-commons", 14 | "@wix-velo/velo-external-db-commons": "libs/velo-external-db-commons", 15 | "@wix-velo/external-db-mongo": "libs/external-db-mongo", 16 | "@wix-velo/velo-external-db-core": "libs/velo-external-db-core", 17 | "@wix-velo/velo-external-db-types": "libs/velo-external-db-types", 18 | "@wix-velo/external-db-testkit": "libs/external-db-testkit", 19 | "@wix-velo/external-db-logger": "libs/external-db-logger", 20 | "velo-external-db": "apps/velo-external-db" 21 | } 22 | } 23 | --------------------------------------------------------------------------------