chronicle-etl 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d9be4b073385d9758a8b709bb6726d8dae648b8c4dbef474343840c011d1178
4
- data.tar.gz: 0d95395407d37f7e322287a0920bba60e1b4f81eb8649190d021e13580604a2d
3
+ metadata.gz: e1c08bc4f71c807525090abbf1701be19ab72cce08a99cc3bbec9b0db7150a02
4
+ data.tar.gz: 172a5d7e7ba7a9424ef7b5ab4da2b8c44defdb4e0a34c833248ff1b63f40407e
5
5
  SHA512:
6
- metadata.gz: 386c96518aa2d2810ae2a93bbe3af5bb08e26e132608b4e6ed8a278da076783e453854a2120c5016b6d02cd5dea406146d10ef3c7c1e77d854acd8ff2608eaf7
7
- data.tar.gz: eb14402be5d6db44a6f06e6ec930acc5103b36e5c2e5a13e89137c9ee45f5f11c1e9e6ab13d4d44e6ee06bd9b02309e02ac33e81256645ef71d5b431c97eb199
6
+ metadata.gz: 0f671c00928b15f9c0f6fa159ac106ff9c4f65a8bd16048e5d0cab82d680945317f7680e7796e98c665bb5cc757e0657f1a36d773d89e3e1587d9eebc12abdd8
7
+ data.tar.gz: 449d1368e0054f39006c7903218300b9b97ca839d6eff43b6b7bd659e5146d443a31c53325c4769ae7a56db9d42417020ccde17362ae024c01aca2ed63029044
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- chronicle-etl (0.2.1)
4
+ chronicle-etl (0.2.2)
5
5
  colorize (~> 0.8.1)
6
6
  thor (~> 0.20)
7
7
  tty-progressbar (~> 0.17)
@@ -1,5 +1,6 @@
1
1
  require_relative 'etl/catalog'
2
2
  require_relative 'etl/config'
3
+ require_relative 'etl/exceptions'
3
4
  require_relative 'etl/extractors/extractor'
4
5
  require_relative 'etl/loaders/loader'
5
6
  require_relative 'etl/runner'
@@ -4,6 +4,11 @@ module Chronicle
4
4
  # Loader connector classes are available to chronicle-etl
5
5
  module Catalog
6
6
  PLUGINS = ['email', 'bash']
7
+ BUILTIN = {
8
+ extractor: ['stdin', 'json', 'csv', 'file'],
9
+ transformer: ['null'],
10
+ loader: ['stdout', 'csv', 'table', 'rest']
11
+ }.freeze
7
12
 
8
13
  # Return which ETL connectors are available, both built in and externally-defined
9
14
  def self.available_classes
@@ -15,7 +20,7 @@ module Chronicle
15
20
  PLUGINS.each do |plugin|
16
21
  require "chronicle/#{plugin}"
17
22
  rescue LoadError
18
- # this will happen if the gem isn't available globally
23
+ # this will happen if the gem isn't available globally
19
24
  end
20
25
 
21
26
  parent_klasses = [
@@ -38,6 +43,18 @@ module Chronicle
38
43
  end
39
44
  end
40
45
 
46
+ # For a given connector identifier, return the class (either builtin, or from a
47
+ # external chronicle gem)
48
+ def self.identifier_to_klass(identifier:, phase:)
49
+ if BUILTIN[phase].include? identifier
50
+ load_builtin_klass(name: identifier, phase: phase)
51
+ else
52
+ provider, name = identifier.split(':')
53
+ name ||= ''
54
+ load_provider_klass(provider: provider, name: name, phase: phase)
55
+ end
56
+ end
57
+
41
58
  # Returns whether a class is an Extractor, Transformer, or Loader
42
59
  def phase
43
60
  ancestors = self.ancestors
@@ -57,6 +74,29 @@ module Chronicle
57
74
  def built_in?
58
75
  to_s.include? 'Chronicle::ETL'
59
76
  end
77
+
78
+ private
79
+
80
+ def self.load_builtin_klass(name:, phase:)
81
+ klass_str = "Chronicle::ETL::#{name.capitalize}#{phase.capitalize}"
82
+ begin
83
+ Object.const_get(klass_str)
84
+ rescue NameError => e
85
+ raise ConnectorNotAvailableError.new("Connector not found", name: name)
86
+ end
87
+ end
88
+
89
+ def self.load_provider_klass(name: '', phase:, provider:)
90
+ begin
91
+ require "chronicle/#{provider}"
92
+ klass_str = "Chronicle::#{provider.capitalize}::#{name.capitalize}#{phase.capitalize}"
93
+ Object.const_get(klass_str)
94
+ rescue LoadError => e
95
+ raise ProviderNotAvailableError.new("Provider '#{provider.capitalize}' could not be loaded", provider: provider)
96
+ rescue NameError => e
97
+ raise ProviderConnectorNotAvailableError.new("Connector '#{name}' in '#{provider}' could not be found", provider: provider, name: name)
98
+ end
99
+ end
60
100
  end
61
101
  end
62
102
  end
@@ -1,5 +1,4 @@
1
1
  require 'pp'
2
- require 'pry'
3
2
 
4
3
  module Chronicle
5
4
  module ETL
@@ -0,0 +1,17 @@
1
+ module Chronicle
2
+ module ETL
3
+ class Error < StandardError; end;
4
+
5
+ class ConnectorNotAvailableError < Error
6
+ def initialize(message, provider: nil, name: nil)
7
+ super(message)
8
+ @provider = provider
9
+ @name = name
10
+ end
11
+ attr_reader :name, :provider
12
+ end
13
+
14
+ class ProviderNotAvailableError < ConnectorNotAvailableError; end
15
+ class ProviderConnectorNotAvailableError < ConnectorNotAvailableError; end
16
+ end
17
+ end
@@ -1,59 +1,46 @@
1
- class Chronicle::ETL::Runner
2
- BUILTIN = {
3
- extractor: ['stdin', 'json', 'csv', 'file'],
4
- transformer: ['null'],
5
- loader: ['stdout', 'csv', 'table']
6
- }.freeze
1
+ require 'colorize'
7
2
 
8
- def initialize(options)
3
+ class Chronicle::ETL::Runner
4
+ def initialize(options = {})
9
5
  @options = options
10
-
11
- instantiate_etl_classes
12
6
  end
13
7
 
14
8
  def run!
15
- total = @extractor.results_count
9
+ extractor = instantiate_klass(:extractor)
10
+ loader = instantiate_klass(:loader)
11
+
12
+ total = extractor.results_count
16
13
  progress_bar = Chronicle::ETL::Utils::ProgressBar.new(title: 'Running job', total: total)
17
- count = 0
18
14
 
19
- @loader.start
15
+ loader.start
20
16
 
21
- @extractor.extract do |data, metadata|
22
- transformed_data = @transformer.transform(data)
23
- @loader.load(transformed_data)
17
+ extractor.extract do |data, metadata|
18
+ transformer = instantiate_klass(:transformer, data)
19
+ transformed_data = transformer.transform
24
20
 
21
+ loader.load(transformed_data)
25
22
  progress_bar.increment
26
- count += 1
27
23
  end
28
24
 
29
25
  progress_bar.finish
30
- @loader.finish
26
+ loader.finish
31
27
  end
32
28
 
33
29
  private
34
30
 
35
- def instantiate_etl_classes
36
- @extractor = load_etl_class(:extractor, @options[:extractor][:name]).new(@options[:extractor][:options])
37
- @transformer = load_etl_class(:transformer, @options[:transformer][:name]).new(@options[:transformer][:options])
38
- @loader = load_etl_class(:loader, @options[:loader][:name]).new(@options[:loader][:options])
31
+ def instantiate_klass(phase, *args)
32
+ klass = load_etl_class(phase, @options[phase][:name])
33
+ klass.new(@options[phase][:options], *args)
39
34
  end
40
35
 
41
- def load_etl_class(phase, x)
42
- if BUILTIN[phase].include? x
43
- klass_name = "Chronicle::ETL::#{x.capitalize}#{phase.to_s.capitalize}"
44
- else
45
- # TODO: come up with syntax for specifying a particular extractor in a provider library
46
- provider, name = x.split(":")
47
- provider = x unless provider
48
- begin
49
- require "chronicle/#{provider}"
50
- rescue LoadError => e
51
- warn("Error loading #{phase} '#{provider}'".red)
52
- warn(" Perhaps you haven't installed it yet: `$ gem install chronicle-#{provider}`")
53
- exit(false)
54
- end
55
- klass_name = "Chronicle::#{provider.capitalize}::#{name&.capitalize}#{phase.capitalize}"
56
- end
57
- Object.const_get(klass_name)
36
+ def load_etl_class(phase, identifier)
37
+ Chronicle::ETL::Catalog.identifier_to_klass(phase: phase, identifier: identifier)
38
+ rescue Chronicle::ETL::ProviderNotAvailableError => e
39
+ warn(e.message.red)
40
+ warn(" Perhaps you haven't installed it yet: `$ gem install chronicle-#{e.provider}`")
41
+ exit(false)
42
+ rescue Chronicle::ETL::ConnectorNotAvailableError => e
43
+ warn(e.message.red)
44
+ exit(false)
58
45
  end
59
46
  end
@@ -1,8 +1,8 @@
1
1
  module Chronicle
2
2
  module ETL
3
3
  class NullTransformer < Chronicle::ETL::Transformer
4
- def transform data
5
- return data
4
+ def transform
5
+ return @data
6
6
  end
7
7
  end
8
8
 
@@ -8,12 +8,13 @@ module Chronicle
8
8
  # == Paramters:
9
9
  # options::
10
10
  # Options for configuring this Transformer
11
- def initialize(options = {})
11
+ def initialize(options = {}, data)
12
12
  @options = options
13
+ @data = data
13
14
  end
14
15
 
15
16
  # The main entrypoint for transforming a record. Called by a Runner on each extracted record
16
- def transform data
17
+ def transform
17
18
  raise NotImplementedError
18
19
  end
19
20
 
@@ -1,5 +1,5 @@
1
1
  module Chronicle
2
2
  module ETL
3
- VERSION = "0.2.1"
3
+ VERSION = "0.2.2"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronicle-etl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Louis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-27 00:00:00.000000000 Z
11
+ date: 2020-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -183,6 +183,7 @@ files:
183
183
  - lib/chronicle/etl/cli/main.rb
184
184
  - lib/chronicle/etl/cli/subcommand_base.rb
185
185
  - lib/chronicle/etl/config.rb
186
+ - lib/chronicle/etl/exceptions.rb
186
187
  - lib/chronicle/etl/extractors/csv_extractor.rb
187
188
  - lib/chronicle/etl/extractors/extractor.rb
188
189
  - lib/chronicle/etl/extractors/file_extractor.rb