215 lines
6.0 KiB
Ruby
215 lines
6.0 KiB
Ruby
require_relative 'connector/errors'
|
|
require_relative 'connector/providers'
|
|
require_relative 'connector/parameters'
|
|
|
|
module Carto
|
|
# This class provides remote database connection services
|
|
class Connector
|
|
|
|
attr_reader :provider_name
|
|
|
|
def initialize(parameters:, user:, **args)
|
|
@params = Parameters.new(parameters)
|
|
|
|
@provider_name = @params[:provider]
|
|
@provider_name ||= DEFAULT_PROVIDER
|
|
|
|
@user = user
|
|
|
|
raise InvalidParametersError.new(message: "Provider not defined") if @provider_name.blank?
|
|
@provider = Connector.provider_class(@provider_name).try :new, parameters: @params, user: @user, **args
|
|
raise InvalidParametersError.new(message: "Invalid provider", provider: @provider_name) if @provider.blank?
|
|
end
|
|
|
|
def copy_table(schema_name:, table_name:)
|
|
@provider.copy_table(schema_name: schema_name, table_name: table_name, limits: limits)
|
|
end
|
|
|
|
def self.list_tables?(provider)
|
|
has_feature? provider, :list_tables
|
|
end
|
|
|
|
def self.list_projects?(provider)
|
|
has_feature? provider, :list_projects
|
|
end
|
|
|
|
def self.dry_run?(provider)
|
|
has_feature? provider, :dry_run
|
|
end
|
|
|
|
def list_tables(limit = nil)
|
|
@provider.list_tables(limits: limits.merge(max_listed_tables: limit))
|
|
end
|
|
|
|
def list_projects
|
|
@provider.list_projects
|
|
end
|
|
|
|
def list_project_datasets(project_id)
|
|
@provider.list_project_datasets(project_id)
|
|
end
|
|
|
|
def list_project_dataset_tables(project_id, dataset_id)
|
|
@provider.list_project_dataset_tables(project_id, dataset_id)
|
|
end
|
|
|
|
def check_connection
|
|
@provider.check_connection
|
|
end
|
|
|
|
def dry_run
|
|
@provider.dry_run
|
|
end
|
|
|
|
def remote_data_updated?
|
|
@provider.remote_data_updated?
|
|
end
|
|
|
|
def last_modified
|
|
@provider.last_modified
|
|
end
|
|
|
|
def table_name
|
|
@provider.table_name
|
|
end
|
|
|
|
# Availabillity check: checks general availability for user,
|
|
# and specific provider availability if provider_name is not nil
|
|
def self.check_availability!(user, provider_name=nil)
|
|
return false if user.nil?
|
|
return user.do_enabled? if provider_name == 'do-v2'
|
|
# check general availability
|
|
unless user.has_feature_flag?('carto-connectors')
|
|
raise ConnectorsDisabledError.new(user: user)
|
|
end
|
|
if provider_name
|
|
# check the provider is enabled for the user
|
|
limits = Connector.limits provider_name: provider_name, user: user
|
|
if !limits || !limits[:enabled]
|
|
raise ConnectorsDisabledError.new(user: user, provider: provider_name)
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.available?(user)
|
|
user.has_feature_flag?('carto-connectors')
|
|
end
|
|
|
|
def self.provider_available?(provider, user)
|
|
Carto::Connector.check_availability! user, provider
|
|
true
|
|
rescue ConnectorsDisabledError
|
|
false
|
|
end
|
|
|
|
# Check availability for a user and provider
|
|
def check_availability!
|
|
Connector.check_availability!(@user, @provider_name)
|
|
end
|
|
|
|
# Limits for the user/provider
|
|
def limits
|
|
Connector.limits provider_name: @provider_name, user: @user
|
|
end
|
|
|
|
# Availability for the user/provider
|
|
def enabled?
|
|
limits[:enabled]
|
|
end
|
|
|
|
def self.limits(provider_name:, user:)
|
|
if configuration = user.connector_configuration(provider_name)
|
|
{ enabled: configuration.enabled?, max_rows: configuration.max_rows }
|
|
else
|
|
{}
|
|
end
|
|
end
|
|
|
|
# Information about a connector's features and parameters.
|
|
#
|
|
# Example:
|
|
# {
|
|
# 'mysql' => {
|
|
# features: {
|
|
# "sql_queries": true,
|
|
# "list_databases": false,
|
|
# "list_tables": true,
|
|
# "preview_table": false
|
|
# },
|
|
# parameters: {
|
|
# connection: {
|
|
# server: { required: true, description: "..." },
|
|
# ...
|
|
# },
|
|
# table: { required: true, description: "..." },
|
|
# ...
|
|
# }
|
|
# }, ...
|
|
# }
|
|
def self.information(provider_name)
|
|
provider = provider_class(provider_name)
|
|
raise InvalidParametersError.new(message: "Invalid provider", provider: provider_name) if provider.blank?
|
|
provider.information
|
|
end
|
|
|
|
# Available providers information.
|
|
#
|
|
# Example:
|
|
# {
|
|
# 'mysql' => { name: 'MySQL', description: '...', enabled: true },
|
|
# ...
|
|
# }
|
|
#
|
|
# By default only `public` providers are returned; use `all: true` to return all of them.
|
|
# If a `user:` argument is provided, the `enabled` key will indicate if the provider is
|
|
# enabled for the user; otherwise it indicates if it is enabled by default.
|
|
#
|
|
def self.providers(user: nil, all: false)
|
|
providers_info = {}
|
|
provider_ids.each do |id|
|
|
next unless all || provider_public?(id)
|
|
# TODO: load description template for provider id
|
|
description = nil
|
|
enabled = if user
|
|
Connector.limits(user: user, provider_name: id)[:enabled]
|
|
else
|
|
provider = ConnectorProvider.find_by_name(id)
|
|
ConnectorConfiguration.default(provider).enabled if provider
|
|
end
|
|
providers_info[id] = {
|
|
name: provider_name(id),
|
|
description: description,
|
|
enabled: enabled
|
|
}
|
|
end
|
|
providers_info
|
|
end
|
|
|
|
def get_service(service)
|
|
if @provider.respond_to?(service)
|
|
@provider.send(service)
|
|
else
|
|
raise Carto::Connector::InvalidParametersError.new("Invalid connector service: #{service}")
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def self.has_feature?(provider, feature)
|
|
information = Connector.information(provider)
|
|
information[:features][feature]
|
|
end
|
|
|
|
# Validate parameters.
|
|
# An array of parameter names to validate can be passed via :only.
|
|
# By default all parameters are validated
|
|
def validate!(only: nil)
|
|
@provider.validate!(only: only)
|
|
end
|
|
|
|
def log(message, truncate = true)
|
|
@provider.log message, truncate
|
|
end
|
|
end
|
|
end
|