db_blaster 0.1.4 → 0.1.8

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: 9313d3abe0bd4dcaa756dab6b07b1d65eb6438b435c914d18f9d38964f08a29d
4
- data.tar.gz: c694940facb41fb3656d011baba720ffb5f66cf124472f945d7de45661ba90b5
3
+ metadata.gz: 548f2aefb696e0417a36de5169343570ca93d4d02fe04bdf13806f48be794d05
4
+ data.tar.gz: ac6a6829cfaa8523b7151b585a4037b602faeb87d6166f021679ab863a8c986b
5
5
  SHA512:
6
- metadata.gz: c045adce6f5a4fb70be59194f6f4630879761011be805dbed09c9be225a415a807ffe60a2b33ccf5361e49ce595b87250f8b0e67f370c29d867254928a36e41f
7
- data.tar.gz: 4b509898ced3205b588248700a75a375ddc6c614611298f0af347ef1a45b35f4c3d1adc9ae0a70d357c56050f47a7225d454564c22a350a21cec45da0effe322
6
+ metadata.gz: fff1f7224220a29d7318f8d9dd793a72e3696db4f61c7829de45d4e90ab431863893ac41abbf7f779cdcc5eab9e8ef17ab4128115ad4e327d8441fdb737035e3
7
+ data.tar.gz: c4bb757b9123e612ae42768a892b7a8cd2444f322ff3eb41d33b16ecd877fcdef9e33d3f7f6cd92fda72339207accb7f2ea2eb6d74f4d24a661cfe28c4c80343
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Adding last_published_id to avoid dupes in selecting sourcetables
4
+ class AddLastPublishedId < ActiveRecord::Migration[6.1]
5
+ def change
6
+ add_column :db_blaster_source_tables, :last_published_id, :string, default: '0'
7
+ end
8
+ end
@@ -8,6 +8,8 @@ module DbBlaster
8
8
  DEFAULT_MAX_MESSAGE_SIZE_IN_KILOBYTES = 256 # max size allowed by AWS SNS
9
9
  DEFAULT_S3_KEY = '<batch_date>/<batch_time>/db_blaster/<table_name>/<uuid>.json'
10
10
  DEFAULT_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%LZ'
11
+ ATTRIBUTE_S3_META_FORMAT = 'attribute' # { meta: {your: :value}, records: [] }
12
+ INLINE_S3_META_FORMAT = 'inline' # records.collect{|record| record.merge(meta) }
11
13
 
12
14
  # The required configuration fields
13
15
  REQUIRED_FIELDS = %i[aws_access_key aws_access_secret aws_region].freeze
@@ -32,15 +34,22 @@ module DbBlaster
32
34
  # Applicable only when `s3_bucket' is set
33
35
  # The value set here will be included in every payload pushed to S3
34
36
  # example: config.s3_meta = {'infra_id' => '061', 'source_app' => 'kcp-api'}}
35
- # The resulting JSON:
36
- # {"meta" : {"infra_id" : "061", "src_app" : "kcp-api", "src_table" : "the-table"}, "records" : [] }
37
37
  attr_accessor :s3_meta
38
38
 
39
+ # Optional
40
+ # Options: ['attribute', 'inline']
41
+ # Defaults to 'attribute'
42
+ # 'attribute' payload: { meta: `s3_meta`, records: [source_table_records] }
43
+ # 'inline' payload: records.collect{|record| record.merge(meta) }
44
+ attr_accessor :s3_meta_format
45
+
39
46
  # Optional
40
47
  # Applicable only when `s3_bucket` is set
41
48
  # The S3 key. The following values will get substituted:
42
- # <batch_timestamp> - a timestamp signifying the beginning of the batch processing
43
- # <timestamp> - the current time
49
+ # <batch_date_time> - date time when batch started
50
+ # <batch_date> - date when batch started
51
+ # <batch_time - time when batch started
52
+ # <date_time> - the datetime just before pushing to S3
44
53
  # <table_name> - the name of the table associated with the S3 body
45
54
  # <uuid> - a universal identifier
46
55
  # '<batch_timestamp>/kcp-api/001/<table_name>/<uuid>.json'
@@ -17,16 +17,26 @@ module DbBlaster
17
17
  "SELECT * FROM #{source_table.name} #{where} ORDER BY updated_at ASC LIMIT #{source_table.batch_size}"
18
18
  end
19
19
 
20
+ # if we just use updated_at > from_updated_at, it's possible to miss records
21
+ # that share the same `updated_at`
22
+ # if we use updated_at >= from_updated_at, we'll get redundant records on every run
23
+ # settled on the approach below
20
24
  def where
21
25
  return '' unless from_updated_at
22
26
 
23
27
  ActiveRecord::Base.sanitize_sql_for_conditions(
24
- ['WHERE updated_at >= :updated_at', { updated_at: from_updated_at.to_s(:db) }]
28
+ ['WHERE updated_at > :updated_at OR (updated_at = :updated_at AND id <> :updated_id)',
29
+ { updated_at: from_updated_at,
30
+ updated_id: last_published_id }]
25
31
  )
26
32
  end
27
33
 
28
34
  def from_updated_at
29
35
  @from_updated_at ||= source_table.last_published_updated_at
30
36
  end
37
+
38
+ def last_published_id
39
+ @last_published_id ||= source_table.last_published_id
40
+ end
31
41
  end
32
42
  end
@@ -22,7 +22,8 @@ module DbBlaster
22
22
  source_table.with_lock do
23
23
  Finder.find(source_table) do |records|
24
24
  BasePublisher.publish(source_table: source_table, records: records, batch_start_time: batch_start_time)
25
- source_table.update(last_published_updated_at: records.last['updated_at'])
25
+ source_table.update(last_published_updated_at: records.last['updated_at'],
26
+ last_published_id: records.last['id'])
26
27
  end
27
28
  end
28
29
  self
@@ -23,10 +23,12 @@ module DbBlaster
23
23
  end
24
24
 
25
25
  def substitutions
26
+ date_time = DateTime.now.utc.strftime(DbBlaster::Configuration::DEFAULT_DATETIME_FORMAT)
26
27
  date, time = batch_start_time.split('T')
27
28
  { '<batch_date_time>' => batch_start_time,
28
29
  '<batch_date>' => date,
29
30
  '<batch_time>' => time,
31
+ '<date_time>' => date_time,
30
32
  '<uuid>' => SecureRandom.uuid,
31
33
  '<table_name>' => source_table_name }
32
34
  end
@@ -14,6 +14,8 @@ module DbBlaster
14
14
  end
15
15
 
16
16
  def content
17
+ return meta_records if DbBlaster.configuration.s3_meta_format == Configuration::INLINE_S3_META_FORMAT
18
+
17
19
  { meta: meta,
18
20
  records: records }
19
21
  end
@@ -28,7 +30,11 @@ module DbBlaster
28
30
  end
29
31
 
30
32
  def meta
31
- (DbBlaster.configuration.s3_meta.presence || {}).merge(source_table: source_table.name)
33
+ @meta ||= (DbBlaster.configuration.s3_meta.presence || {}).merge(source_table: source_table.name)
34
+ end
35
+
36
+ def meta_records
37
+ records.collect { |record| record.merge(meta) }
32
38
  end
33
39
 
34
40
  def client
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DbBlaster
4
+ # Builds an array of tables and their columns
5
+ class SourceTablesSchemaBuilder
6
+ def self.build_schema
7
+ new.build_schema
8
+ end
9
+
10
+ def build_schema
11
+ ActiveRecord::Base.connection.tables.each_with_object({}) do |table_name, hash|
12
+ unless AvailableTables::SYSTEM_TABLES.include?(table_name)
13
+ hash[table_name] = build_columns_from_table_name(table_name)
14
+ end
15
+ end
16
+ end
17
+
18
+ def build_columns_from_table_name(table_name)
19
+ ActiveRecord::Base.connection.columns(table_name).collect do |column|
20
+ next if ignored_column?(column.name)
21
+
22
+ { name: column.name,
23
+ type: column.type,
24
+ limit: column.limit }
25
+ end.compact
26
+ end
27
+
28
+ def ignored_column?(column)
29
+ (DbBlaster.configuration.ignored_column_names || []).include?(column)
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DbBlaster
4
- VERSION = '0.1.4'
4
+ VERSION = '0.1.8'
5
5
  end
data/lib/db_blaster.rb CHANGED
@@ -15,6 +15,7 @@ require 'db_blaster/publish_source_table'
15
15
  require 'db_blaster/chunker'
16
16
  require 'db_blaster/finder_sql'
17
17
  require 'db_blaster/finder'
18
+ require 'db_blaster/source_tables_schema_builder'
18
19
 
19
20
  # Top-level module that serves as an entry point
20
21
  # into the engine gem
@@ -22,8 +22,7 @@ DbBlaster.configure do |config|
22
22
  # The S3 key path. The following values will get substituted:
23
23
  # <batch_date_time> - a timestamp signifying the beginning of the batch processing
24
24
  # <batch_date> - a date signifying the beginning of the batch processing
25
- # <batch_time> - a time signifying the beginning of the batch processing
26
- # <timestamp> - the current time
25
+ # <date_time> - the datetime just before pushing to S3
27
26
  # <table_name> - the name of the table associated with the S3 body
28
27
  # <uuid> - a universal identifier
29
28
  # config.s3_key = '<batch_timestamp>/kcp-api/001/<table_name>/<uuid>.json'
@@ -32,8 +31,7 @@ DbBlaster.configure do |config|
32
31
  # Applicable only when `s3_bucket' is set
33
32
  # Extra meta values sent along with each payload
34
33
  # example: config.s3_meta = {'infra_id' => '061'}
35
- # The resulting JSON:
36
- # {"meta" : {"infra_id" : "061", "source_app" : "kcp-api", "src_table" : "the-table"}, "records" : [] }
34
+ # The resulting JSON will include the `meta` merged into every record.
37
35
  # config.s3_meta = {'infra_id' => '061'}
38
36
 
39
37
  # Optional
@@ -1,5 +1,14 @@
1
1
  # frozen_string_literal: true
2
- # desc "Explaining what the task does"
3
- # task :db_blaster do
4
- # # Task goes here
5
- # end
2
+
3
+ require 'db_blaster'
4
+
5
+ namespace :db_blaster do
6
+ desc 'generate table schema'
7
+ task generate_table_schema: :environment do
8
+ schema_name = 'kcp-api-schema.json'
9
+ puts "Generating #{schema_name}......."
10
+ built = DbBlaster::SourceTablesSchemaBuilder.build_schema
11
+ File.open(schema_name, 'w') { |f| f << built.to_json }
12
+ puts 'Success!'
13
+ end
14
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: db_blaster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Perry Hertler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-02 00:00:00.000000000 Z
11
+ date: 2021-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-s3
@@ -131,6 +131,7 @@ files:
131
131
  - config/brakeman.ignore
132
132
  - config/routes.rb
133
133
  - db/migrate/20210727222252_create_source_tables.rb
134
+ - db/migrate/20210908214439_add_last_published_id.rb
134
135
  - lib/db_blaster.rb
135
136
  - lib/db_blaster/available_tables.rb
136
137
  - lib/db_blaster/base_publisher.rb
@@ -147,6 +148,7 @@ files:
147
148
  - lib/db_blaster/sns_publisher.rb
148
149
  - lib/db_blaster/source_table_configuration.rb
149
150
  - lib/db_blaster/source_table_configuration_builder.rb
151
+ - lib/db_blaster/source_tables_schema_builder.rb
150
152
  - lib/db_blaster/version.rb
151
153
  - lib/generators/db_blaster/install/install_generator.rb
152
154
  - lib/generators/db_blaster/install/templates/db_blaster_config.rb
@@ -173,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
175
  - !ruby/object:Gem::Version
174
176
  version: '0'
175
177
  requirements: []
176
- rubygems_version: 3.1.6
178
+ rubygems_version: 3.1.4
177
179
  signing_key:
178
180
  specification_version: 4
179
181
  summary: Push db changes to AWS SNS.