162 lines
4.7 KiB
Ruby
162 lines
4.7 KiB
Ruby
|
require_relative 'connector/fdw_support'
|
||
|
require_relative 'connector/errors'
|
||
|
require_relative 'connector/providers'
|
||
|
require_relative 'connector/parameters'
|
||
|
require_relative 'connector/context'
|
||
|
|
||
|
module Carto
|
||
|
# This class provides remote database connection services based on FDW
|
||
|
class Connector
|
||
|
|
||
|
attr_reader :provider_name
|
||
|
|
||
|
def initialize(parameters, context)
|
||
|
@connector_context = Context.cast(context)
|
||
|
|
||
|
@params = Parameters.new(parameters)
|
||
|
|
||
|
@provider_name = @params[:provider]
|
||
|
@provider_name ||= DEFAULT_PROVIDER
|
||
|
|
||
|
raise InvalidParametersError.new(message: "Provider not defined") if @provider_name.blank?
|
||
|
@provider = Connector.provider_class(@provider_name).try :new, @connector_context, @params
|
||
|
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)
|
||
|
information = Connector.information(provider)
|
||
|
information[:features][:list_tables]
|
||
|
end
|
||
|
|
||
|
def list_tables(limit = nil)
|
||
|
@provider.list_tables(limits: limits.merge(max_listed_tables: limit))
|
||
|
end
|
||
|
|
||
|
def check_connection
|
||
|
@provider.check_connection
|
||
|
end
|
||
|
|
||
|
def remote_data_updated?
|
||
|
@provider.remote_data_updated?
|
||
|
end
|
||
|
|
||
|
def remote_table_name
|
||
|
@provider.table_name
|
||
|
end
|
||
|
|
||
|
# General availabillity check
|
||
|
def self.check_availability!(user)
|
||
|
unless user.has_feature_flag?('carto-connectors')
|
||
|
raise ConnectorsDisabledError.new(user: user)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def self.available?(user)
|
||
|
user.has_feature_flag?('carto-connectors')
|
||
|
end
|
||
|
|
||
|
# Check availability for a user and provider
|
||
|
def check_availability!
|
||
|
Connector.check_availability!(@connector_context.user)
|
||
|
if !enabled?
|
||
|
raise ConnectorsDisabledError.new(user: @connector_context.user, provider: @provider_name)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Limits for the user/provider
|
||
|
def limits
|
||
|
Connector.limits provider_name: @provider_name, user: @connector_context.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
|
||
|
|
||
|
private
|
||
|
|
||
|
# 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)
|
||
|
@connector_context.log message, truncate
|
||
|
end
|
||
|
end
|
||
|
end
|