breathing 0.0.2 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b0a34aef932a21f7369a766114261c484fcc68cdb32ec50e81c721da2f13d0a
4
- data.tar.gz: eb6c8c5370a13e422674c9256032eeb650a4a58e018eed78f33c234a7a9cbc41
3
+ metadata.gz: 1e0db4001a0d83c74be3f2adcf49f754ea0c39837ecb17c13e2fbf016dc73ad8
4
+ data.tar.gz: 31cc6bd7ad4391573b64c909ea713dea43260a5b1e379405396e24f8bf29da18
5
5
  SHA512:
6
- metadata.gz: 91a00104ce4496d7250df3664624cd3cd5fb1b6af4d48f57445fbd7f0e798a4e4dd2003d0a2cfc3b1bc1e31d4729971abcfc0086701208a37b1a1975522527da
7
- data.tar.gz: 4dc36063b0e355d5f245660136b2c439bacf16bf2da61fe899ee05b19a51f17c09e2036e1f6aa4505671c1f89cd4f4c637f0f58baf1adf0d1776bf6379594ccf
6
+ metadata.gz: 802fb8542d7b310d40c8ca066c603416a5976f6729d4d4e6bcd4942b383a517ee75500c99503093b2d70226592d7fbc83aab14bd92930d84183255e7a1319b92
7
+ data.tar.gz: 783595b5a3faa2d5934ba2cfe1b5baa95c37c6d1131ffadcbaf54cb3ba120642c5c93d9932081916710a5e48ef2e002ba2c7e1e7fff046d8a198e3bb43dbb30c
@@ -6,8 +6,7 @@ executors:
6
6
  docker:
7
7
  - image: circleci/ruby:2.6
8
8
  environment:
9
- DB_USER: 'root'
10
- DB_PASS: 'root'
9
+ DB_USER: root
11
10
  DB_HOST: '127.0.0.1'
12
11
  - image: circleci/mysql:8-ram
13
12
  environment:
@@ -15,6 +14,10 @@ executors:
15
14
  MYSQL_ROOT_PASSWORD: root
16
15
  MYSQL_DATABASE: breathing_test
17
16
  command: [--default-authentication-plugin=mysql_native_password]
17
+ - image: circleci/postgres:10.6-alpine-ram
18
+ environment:
19
+ POSTGRES_USER: root
20
+ POSTGRES_DB: breathing_test
18
21
 
19
22
  commands:
20
23
  setup_bundle:
@@ -35,6 +38,9 @@ commands:
35
38
  - run:
36
39
  name: Wait for DB
37
40
  command: dockerize -wait tcp://127.0.0.1:3306 -timeout 1m
41
+ - run:
42
+ name: Wait for DB
43
+ command: dockerize -wait tcp://127.0.0.1:5432 -timeout 1m
38
44
 
39
45
  jobs:
40
46
  test:
@@ -43,7 +49,8 @@ jobs:
43
49
  - checkout
44
50
  - setup_bundle
45
51
  - wait_for_db
46
- - run: bundle exec rspec ./spec
52
+ - run: DB=mysql DB_PASS=root bundle exec rspec ./spec
53
+ - run: DB=pg bundle exec rspec ./spec
47
54
 
48
55
  workflows:
49
56
  version: 2
data/README.md CHANGED
@@ -5,15 +5,8 @@ Logging mechanism using database triggers to store the old and new row states in
5
5
 
6
6
  ## Install
7
7
 
8
- Put this line in your Gemfile:
9
-
10
8
  ```
11
- gem 'breathing'
12
- ```
13
-
14
- Then bundle:
15
- ```
16
- % bundle
9
+ gem install breathing
17
10
  ```
18
11
 
19
12
  ## Usage
@@ -24,6 +17,8 @@ Just run the following command.
24
17
 
25
18
  ```
26
19
  % DATABASE_URL="mysql2://user:pass@host:port/database" breathing install
20
+ or
21
+ % DATABASE_URL="postgres://user:pass@host:port/database" breathing install
27
22
  ```
28
23
 
29
24
  - Create table `change_logs`
@@ -46,12 +41,44 @@ Cleanup command.
46
41
  - change_logs_update_{table_name}
47
42
  - change_logs_delete_{table_name}
48
43
 
49
- ### export
44
+ ### Export
50
45
 
51
46
  ```
52
47
  % DATABASE_URL="mysql2://user:pass@host:port/database" breathing export
53
48
  ```
54
49
 
50
+ - Output file `breathing.xlsx`
51
+
52
+ ### out
53
+
54
+ ```
55
+ % DATABASE_URL="mysql2://user:pass@host:port/database" breathing out --table users --id 1
56
+ ```
57
+
58
+ ```
59
+ +----------------+------------------------+--------+----+-----+------+----------------------------+----------------------------+
60
+ | users |
61
+ +----------------+------------------------+--------+----+-----+------+----------------------------+----------------------------+
62
+ | change_logs.id | change_logs.created_at | action | id | age | name | created_at | updated_at |
63
+ +----------------+------------------------+--------+----+-----+------+----------------------------+----------------------------+
64
+ | 1 | 2020-12-18 22:43:32 | INSERT | 10 | 20 | a | 2020-12-18 13:43:32.316923 | 2020-12-18 13:43:32.316923 |
65
+ | 2 | 2020-12-18 22:43:32 | UPDATE | 10 | 21 | a | 2020-12-18 13:43:32.316923 | 2020-12-18 13:43:32.319706 |
66
+ | 3 | 2020-12-18 22:43:32 | DELETE | 10 | 21 | a | 2020-12-18 13:43:32.316923 | 2020-12-18 13:43:32.319706 |
67
+ +----------------+------------------------+--------+----+-----+------+----------------------------+----------------------------+
68
+ ```
69
+
70
+ ### tail
71
+
72
+ ```
73
+ % DATABASE_URL="mysql2://user:pass@host:port/database" breathing tail --table users --id 1
74
+ ```
75
+
76
+ ## Compatibility
77
+
78
+ - Ruby 2.3.0+
79
+ - MySQL 5.7.0+
80
+ - PostgreSQL 8.0+
81
+
55
82
  ## Copyright
56
83
 
57
84
  Copyright (c) 2020 Akira Kusumoto. See MIT-LICENSE file for further details.
@@ -2,7 +2,7 @@ $:.push File.expand_path('lib', __dir__)
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'breathing'
5
- s.version = '0.0.2'
5
+ s.version = '0.0.7'
6
6
  s.platform = Gem::Platform::RUBY
7
7
  s.authors = ['Akira Kusumoto']
8
8
  s.email = ['akirakusumo10@gmail.com']
@@ -21,8 +21,11 @@ Gem::Specification.new do |s|
21
21
  s.add_runtime_dependency 'thor'
22
22
 
23
23
  s.add_dependency 'activerecord', ['>= 5.0.0']
24
+ s.add_dependency 'hairtrigger'
25
+ s.add_dependency 'mysql2'
26
+ s.add_dependency 'pg'
27
+ s.add_dependency 'terminal-table'
24
28
  s.add_dependency 'rubyXL', ['>= 3.4.0']
25
- s.add_development_dependency 'mysql2'
26
29
  s.add_development_dependency 'pry-byebug'
27
30
  s.add_development_dependency 'rspec', '~> 3.9'
28
31
  end
@@ -1,35 +1,52 @@
1
1
  require 'active_record'
2
+ require 'hairtrigger'
2
3
  require 'breathing/installer'
3
4
  require 'breathing/trigger'
4
5
  require 'breathing/change_log'
5
6
  require 'breathing/excel'
7
+ require 'breathing/terminal_table'
6
8
 
7
9
  module Breathing
8
10
  VERSION = Gem.loaded_specs['breathing'].version.to_s
9
11
 
10
12
  class << self
11
13
  def install
12
- establish_connection
14
+ ActiveRecord::Base.establish_connection
13
15
  Breathing::Installer.new.install
14
16
  end
15
17
 
16
18
  def uninstall
17
- establish_connection
19
+ ActiveRecord::Base.establish_connection
18
20
  Breathing::Installer.new.uninstall
19
21
  end
20
22
 
21
23
  def clear
22
- establish_connection
24
+ ActiveRecord::Base.establish_connection
23
25
  Breathing::ChangeLog.delete_all
24
26
  end
25
27
 
26
28
  def export
27
- establish_connection
29
+ ActiveRecord::Base.establish_connection
28
30
  Breathing::Excel.new.create
29
31
  end
30
32
 
31
- def establish_connection
32
- ActiveRecord::Base.establish_connection(url: ENV['DATABASE_URL'])
33
+ def render_terminal_table(table_name:, id: 1)
34
+ ActiveRecord::Base.establish_connection
35
+ puts Breathing::TerminalTable.new(table_name).render(id: id)
36
+ end
37
+
38
+ def tail_f(table_name:, id: 1)
39
+ ActiveRecord::Base.establish_connection
40
+ table = Breathing::TerminalTable.new(table_name)
41
+
42
+ loop do
43
+ text = table.render(id: id)
44
+ if text.present?
45
+ puts text
46
+ id = table.last_id + 1
47
+ end
48
+ sleep 5
49
+ end
33
50
  end
34
51
  end
35
52
  end
@@ -12,5 +12,18 @@ module Breathing
12
12
  names = before_data.keys.present? ? before_data.keys : after_data.keys
13
13
  names.reject { |name| name == 'id' }
14
14
  end
15
+
16
+ def data
17
+ action == 'DELETE' ? before_data : after_data
18
+ end
19
+
20
+ def data_attributes
21
+ data_column_names.each.with_object("change_logs.id" => id,
22
+ "change_logs.created_at" => created_at.to_s(:db),
23
+ "action" => action,
24
+ "id" => transaction_id) do |name, hash|
25
+ hash[name] = data[name]
26
+ end
27
+ end
15
28
  end
16
29
  end
@@ -1,31 +1,57 @@
1
+ # frozen_string_literal: true
1
2
  require 'thor'
2
3
  require 'breathing'
3
4
 
4
5
  module Breathing
5
6
  class Cli < Thor
6
- default_command :install
7
+ default_command :export
7
8
 
8
9
  desc 'install', 'Create table change_logs and create triggers'
10
+
9
11
  def install
10
12
  Breathing.install
11
13
  end
12
14
 
13
15
  desc 'uninstall', 'Drop table change_logs and drop triggers'
16
+
14
17
  def uninstall
15
18
  Breathing.uninstall
16
19
  end
17
20
 
18
21
  desc 'clear', 'Delete all records in change_logs table'
22
+
19
23
  def clear
20
24
  Breathing.clear
21
25
  end
22
26
 
23
27
  desc 'export', 'output xlsx'
28
+
24
29
  def export
25
30
  Breathing.export
26
31
  end
27
32
 
33
+ desc 'out', 'output stdout'
34
+ method_option :type, aliases: '-t', default: 'terminal_table', type: :string
35
+ method_option :table, type: :string, required: true
36
+ method_option :id, default: 1, type: :numeric
37
+ def out
38
+ if options[:table] == 'terminal_table'
39
+ Breathing.render_terminal_table(table_name: options[:table], id: options[:id].to_i)
40
+ else
41
+ # TODO
42
+ # Breathing.export(table_name: options[:table], id: options[:id].to_i)
43
+ end
44
+ end
45
+
46
+ desc 'tail', 'tail terminal_table'
47
+ method_option :table, type: :string, required: true
48
+ method_option :id, default: 1, type: :numeric
49
+ def tail
50
+ Breathing.tail_f(table_name: options[:table], id: options[:id].to_i)
51
+ end
52
+
28
53
  desc 'version', 'Show Version'
54
+
29
55
  def version
30
56
  say "Version: #{Breathing::VERSION}"
31
57
  end
@@ -18,12 +18,16 @@ module Breathing
18
18
  sheet = @workbook.add_worksheet(table_name)
19
19
  end
20
20
 
21
- rows = Breathing::ChangeLog.where(table_name: table_name).where('id >= ?', id).order(:id)
21
+ rows = Breathing::ChangeLog.where(table_name: table_name).where('id >= ?', id).order(:id)
22
+ column_widths = []
22
23
 
23
24
  if first_row = rows.first
24
- add_header_row(sheet, first_row)
25
+ add_header_row(sheet, first_row, column_widths)
25
26
  end
26
- add_body_rows(sheet, rows)
27
+ add_body_rows(sheet, rows, column_widths)
28
+
29
+ column_widths.each.with_index { |size, i| sheet.change_column_width(i, size + 2) }
30
+
27
31
  add_style(sheet)
28
32
  end
29
33
 
@@ -32,28 +36,28 @@ module Breathing
32
36
 
33
37
  private
34
38
 
35
- def add_header_row(sheet, row)
36
- sheet.add_cell(0, 0, 'change_logs.id').change_font_bold(true)
37
- sheet.add_cell(0, 1, 'action').change_font_bold(true)
38
- sheet.add_cell(0, 2, 'id').change_font_bold(true)
39
- row.data_column_names.each.with_index(3) do |column_name, i|
40
- sheet.add_cell(0, i, column_name).change_font_bold(true)
39
+ def add_header_row(sheet, row, column_widths)
40
+ header_color = 'ddedf3' # blue
41
+ row.data_attributes.keys.each.with_index do |header_column, column_index|
42
+ cell = sheet.add_cell(0, column_index, header_column)
43
+ cell.change_font_bold(true)
44
+ cell.change_fill(header_color)
45
+
46
+ column_widths << header_column.size
41
47
  end
42
48
  end
43
49
 
44
- def add_body_rows(sheet, rows)
45
- rows.each.with_index(1) do |row, i|
46
- sheet.add_cell(i, 0, row.id)
47
- sheet.add_cell(i, 1, row.action)
48
- sheet.add_cell(i, 2, row.transaction_id)
49
- row.data_column_names.each.with_index(3) do |column_name, j|
50
- data = row.action == 'DELETE' ? row.before_data : row.after_data
51
- cell_object = sheet.add_cell(i, j, data[column_name])
50
+ def add_body_rows(sheet, rows, column_widths)
51
+ rows.each.with_index(1) do |row, row_number|
52
+ row.data_attributes.each.with_index do |(column_name, value), column_index|
53
+ cell = sheet.add_cell(row_number, column_index, value)
52
54
  if row.action == 'UPDATE' && column_name != 'updated_at' && row.changed_attribute_columns.include?(column_name)
53
- cell_object.change_fill('ffff00') # color: yellow
55
+ cell.change_fill('ffff00') # color: yellow
54
56
  elsif row.action == 'DELETE'
55
- cell_object.change_fill('d9d9d9') # color: grey
57
+ cell.change_fill('d9d9d9') # color: grey
56
58
  end
59
+
60
+ column_widths[column_index] = value.to_s.size if column_widths[column_index] < value.to_s.size
57
61
  end
58
62
  end
59
63
  end
@@ -65,7 +69,7 @@ module Breathing
65
69
  cell.change_border(direction, 'thin')
66
70
  end
67
71
 
68
- cell.change_border(:bottom, 'medium') if i.zero?
72
+ cell.change_border(:bottom, 'double') if i.zero?
69
73
  end
70
74
  end
71
75
  sheet.change_row_horizontal_alignment(0, 'center')
@@ -4,8 +4,12 @@ require 'breathing/trigger'
4
4
  require 'breathing/change_log'
5
5
 
6
6
  module Breathing
7
+ class UnsupportedError < StandardError; end
8
+
7
9
  class Installer
8
10
  def install
11
+ raise Breathing::UnsupportedError, "Version MySQL 5.6 is not supported." unless database_version_valid?
12
+
9
13
  create_log_table unless log_table_exists?
10
14
 
11
15
  models.each do |model|
@@ -24,6 +28,11 @@ module Breathing
24
28
 
25
29
  private
26
30
 
31
+ def database_version_valid?
32
+ connection = ActiveRecord::Base.connection
33
+ connection.adapter_name == "PostgreSQL" || (connection.adapter_name == 'Mysql2' && connection.raw_connection.info[:version].to_f >= 5.7)
34
+ end
35
+
27
36
  def log_table_name
28
37
  Breathing::ChangeLog.table_name
29
38
  end
@@ -0,0 +1,30 @@
1
+ require 'breathing'
2
+ require 'terminal-table'
3
+
4
+ module Breathing
5
+ class TerminalTable
6
+ attr_reader :last_id
7
+
8
+ def initialize(table_name)
9
+ @last_id = 1
10
+ @table_name = table_name
11
+ end
12
+
13
+ def render(id: 1)
14
+ rows = Breathing::ChangeLog.where(table_name: @table_name).where("id >= ? ", id).order(:id)
15
+
16
+ return if rows.size.zero?
17
+
18
+ @table = Terminal::Table.new(title: rows.first.table_name,
19
+ headings: rows.first.data_attributes.keys,
20
+ rows: rows.map { |row| row.data_attributes.values })
21
+
22
+ @last_id = rows.last.id
23
+ @table.to_s
24
+ end
25
+
26
+ def rows
27
+ @table.rows
28
+ end
29
+ end
30
+ end
@@ -12,69 +12,61 @@ module Breathing
12
12
 
13
13
  def create
14
14
  trigger_name = "#{log_table_name}_insert_#{model.table_name}"
15
+
15
16
  unless exists?(trigger_name)
16
17
  puts "CREATE TRIGGER #{trigger_name}"
17
- ActiveRecord::Base.connection.execute <<-SQL
18
- CREATE TRIGGER #{trigger_name}
19
- AFTER INSERT
20
- ON #{model.table_name}
21
- FOR EACH ROW
22
- BEGIN
23
- INSERT INTO #{log_table_name} (`action`, `table_name`, `transaction_id`, `before_data`, `after_data`, `created_at`)
18
+
19
+ ActiveRecord::Base.connection.create_trigger(trigger_name).on(model.table_name).after(:insert) do
20
+ <<-SQL
21
+ INSERT INTO #{log_table_name} (action, table_name, transaction_id, before_data, after_data, created_at)
24
22
  VALUES ('INSERT', '#{model.table_name}', NEW.id,
25
- JSON_OBJECT(),
26
- JSON_OBJECT(#{json_object_values(model.columns, 'NEW')}),
23
+ '{}',
24
+ #{row_to_json(model.columns, 'NEW')},
27
25
  CURRENT_TIMESTAMP);
28
- END;
29
- SQL
26
+ SQL
27
+ end
30
28
  end
31
29
 
32
30
  trigger_name = "#{log_table_name}_update_#{model.table_name}"
33
31
  unless exists?(trigger_name)
34
32
  puts "CREATE TRIGGER #{trigger_name}"
35
- ActiveRecord::Base.connection.execute <<-SQL
36
- CREATE TRIGGER #{trigger_name}
37
- BEFORE UPDATE
38
- ON #{model.table_name}
39
- FOR EACH ROW
40
- BEGIN
41
- IF (OLD.updated_at != NEW.updated_at) THEN
42
- INSERT INTO #{log_table_name} (`action`, `table_name`, `transaction_id`, `before_data`, `after_data`, `created_at`)
33
+
34
+ ActiveRecord::Base.connection.create_trigger(trigger_name).on(model.table_name).before(:update).of(:updated_at) do
35
+ <<-SQL
36
+ INSERT INTO #{log_table_name} (action, table_name, transaction_id, before_data, after_data, created_at)
43
37
  VALUES ('UPDATE', '#{model.table_name}', NEW.id,
44
- JSON_OBJECT(#{json_object_values(model.columns, 'OLD')}),
45
- JSON_OBJECT(#{json_object_values(model.columns, 'NEW')}),
38
+ #{row_to_json(model.columns, 'OLD')},
39
+ #{row_to_json(model.columns, 'NEW')},
46
40
  CURRENT_TIMESTAMP);
47
- end if;
48
- END;
49
- SQL
41
+ SQL
42
+ end
50
43
  end
51
44
 
52
45
  trigger_name = "#{log_table_name}_delete_#{model.table_name}"
53
46
  unless exists?(trigger_name)
54
47
  puts "CREATE TRIGGER #{trigger_name}"
55
- ActiveRecord::Base.connection.execute <<-SQL
56
- CREATE TRIGGER #{trigger_name}
57
- AFTER DELETE
58
- ON #{model.table_name}
59
- FOR EACH ROW
60
- BEGIN
61
- INSERT INTO #{log_table_name} (`action`, `table_name`, `transaction_id`, `before_data`, `after_data`, `created_at`)
62
- VALUES ('DELETE', '#{model.table_name}', OLD.id,
63
- JSON_OBJECT(#{json_object_values(model.columns, 'OLD')}),
64
- JSON_OBJECT(),
48
+ ActiveRecord::Base.connection.create_trigger(trigger_name).on(model.table_name).after(:delete) do
49
+ <<-SQL
50
+ INSERT INTO #{log_table_name} (action, table_name, transaction_id, before_data, after_data, created_at)
51
+ VALUES ('DELETE', '#{model.table_name}', OLD.id,
52
+ #{row_to_json(model.columns, 'OLD')},
53
+ '{}',
65
54
  CURRENT_TIMESTAMP);
66
- END;
67
- SQL
55
+ SQL
56
+ end
68
57
  end
69
58
  end
70
59
 
71
60
  def drop
72
61
  %w[insert update delete].each do |action|
73
62
  trigger_name = "#{log_table_name}_#{action}_#{model.table_name}"
74
- next unless exists?(trigger_name)
75
63
 
76
64
  begin
77
- sql = "DROP TRIGGER #{trigger_name}"
65
+ sql = "DROP TRIGGER IF EXISTS #{trigger_name}"
66
+ if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
67
+ sql << " ON #{model.table_name} CASCADE;"
68
+ sql << " DROP FUNCTION IF EXISTS #{trigger_name} CASCADE;"
69
+ end
78
70
  puts sql
79
71
  ActiveRecord::Base.connection.execute(sql)
80
72
  rescue StandardError => e
@@ -86,15 +78,19 @@ module Breathing
86
78
  private
87
79
 
88
80
  def exists?(trigger_name)
89
- @trigger_names ||= ActiveRecord::Base.connection.select_rows('SHOW TRIGGERS').map { |row| row.first }
90
- @trigger_names.include?(trigger_name)
81
+ ActiveRecord::Base.connection.triggers.keys.include?(trigger_name)
91
82
  end
92
83
 
93
- def json_object_values(columns, state)
94
- columns.each.with_object([]) do |column, array|
95
- array << "'#{column.name}'"
96
- array << "#{state}.#{column.name}"
97
- end.join(',')
84
+ def row_to_json(columns, state)
85
+ if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
86
+ "row_to_json(#{state}.*)"
87
+ else
88
+ json_object_values = columns.each.with_object([]) do |column, array|
89
+ array << "'#{column.name}'"
90
+ array << "#{state}.#{column.name}"
91
+ end
92
+ "JSON_OBJECT(#{json_object_values.join(',')})"
93
+ end
98
94
  end
99
95
  end
100
96
  end
@@ -2,7 +2,7 @@ require 'active_record'
2
2
  require 'breathing'
3
3
 
4
4
  ActiveRecord::Base.establish_connection(
5
- YAML.load(ERB.new(File.read('spec/database.yml')).result)['test']
5
+ YAML.load(ERB.new(File.read('spec/database.yml')).result)["test_#{ENV['DB'] || 'mysql'}"]
6
6
  )
7
7
 
8
8
  ActiveRecord::Schema.define version: 0 do
@@ -3,7 +3,9 @@ require 'spec_helper'
3
3
  describe Breathing::Excel do
4
4
  describe '#create' do
5
5
  before { Breathing::Installer.new.install }
6
- after { Breathing::Installer.new.uninstall }
6
+ after do
7
+ Breathing::Installer.new.uninstall if ActiveRecord::Base.connection.adapter_name == "Mysql2"
8
+ end
7
9
 
8
10
  it do
9
11
  user = User.create!(name: 'a', age: 20)
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Breathing::TerminalTable do
4
+ describe '#render' do
5
+ before { Breathing::Installer.new.install }
6
+ after do
7
+ Breathing::Installer.new.uninstall if ActiveRecord::Base.connection.adapter_name == "Mysql2"
8
+ end
9
+
10
+ it do
11
+ user = User.create!(name: 'a', age: 20)
12
+ user.update!(age: 21)
13
+ user.destroy!
14
+ expect(Breathing::ChangeLog.count).to eq(3)
15
+
16
+ table = Breathing::TerminalTable.new(:users)
17
+ puts table.render(id: 1)
18
+
19
+ expect(table.rows.size).to eq(3)
20
+ end
21
+ end
22
+ end
@@ -5,36 +5,41 @@ describe Breathing do
5
5
  expect(Breathing::VERSION).not_to be nil
6
6
  end
7
7
 
8
- before { Breathing::Installer.new.install }
9
- after { Breathing::Installer.new.uninstall }
10
-
11
- it do
12
- expect(Breathing::ChangeLog.count).to eq(0)
13
-
14
- # INSERT
15
- user = User.create!(name: 'a', age: 20)
16
- expect(Breathing::ChangeLog.count).to eq(1)
17
-
18
- log = Breathing::ChangeLog.where(table_name: user.class.table_name, transaction_id: user.id).last
19
- expect(log.before_data).to eq({})
20
- expect(log.after_data['name']).to eq('a')
21
- expect(log.after_data['age']).to eq(20)
22
-
23
- # UPDATE
24
- user.update!(age: 21)
25
- expect(Breathing::ChangeLog.count).to eq(2)
26
-
27
- log = Breathing::ChangeLog.where(table_name: user.class.table_name, transaction_id: user.id).last
28
- expect(log.before_data['age']).to eq(20)
29
- expect(log.after_data['age']).to eq(21)
30
- expect(log.before_data['name']).to eq(log.after_data['name'])
31
- expect(log.changed_attribute_columns).to eq(%w[age updated_at])
32
-
33
- # DELETE
34
- user.destroy!
35
- expect(Breathing::ChangeLog.count).to eq(3)
36
- log = Breathing::ChangeLog.where(table_name: user.class.table_name, transaction_id: user.id).last
37
- expect(log.before_data['name']).to eq('a')
38
- expect(log.after_data).to eq({})
8
+ describe 'change_logs' do
9
+ before { Breathing::Installer.new.install }
10
+
11
+ after do
12
+ Breathing::Installer.new.uninstall if ActiveRecord::Base.connection.adapter_name == "Mysql2"
13
+ end
14
+
15
+ it do
16
+ expect(Breathing::ChangeLog.count).to eq(0)
17
+
18
+ # INSERT
19
+ user = User.create!(name: 'a', age: 20)
20
+ expect(Breathing::ChangeLog.count).to eq(1)
21
+
22
+ log = Breathing::ChangeLog.where(table_name: user.class.table_name, transaction_id: user.id).last
23
+ expect(log.before_data).to eq({})
24
+ expect(log.after_data['name']).to eq('a')
25
+ expect(log.after_data['age']).to eq(20)
26
+
27
+ # UPDATE
28
+ user.update!(age: 21)
29
+ expect(Breathing::ChangeLog.count).to eq(2)
30
+
31
+ log = Breathing::ChangeLog.where(table_name: user.class.table_name, transaction_id: user.id).last
32
+ expect(log.before_data['age']).to eq(20)
33
+ expect(log.after_data['age']).to eq(21)
34
+ expect(log.before_data['name']).to eq(log.after_data['name'])
35
+ expect(log.changed_attribute_columns).to eq(%w[age updated_at])
36
+
37
+ # DELETE
38
+ user.destroy!
39
+ expect(Breathing::ChangeLog.count).to eq(3)
40
+ log = Breathing::ChangeLog.where(table_name: user.class.table_name, transaction_id: user.id).last
41
+ expect(log.before_data['name']).to eq('a')
42
+ expect(log.after_data).to eq({})
43
+ end
39
44
  end
40
45
  end
@@ -1,11 +1,18 @@
1
- test:
1
+ test_mysql:
2
2
  adapter: mysql2
3
3
  encoding: utf8mb4
4
4
  charset: utf8mb4
5
5
  collation: utf8mb4_general_ci
6
- pool: 5
7
6
  username: <%= ENV.fetch("DB_USER") { 'root' } %>
8
7
  password: <%= ENV.fetch("DB_PASS") { '' } %>
9
8
  host: <%= ENV.fetch("DB_HOST") { '127.0.0.1' } %>
10
9
  socket: /tmp/mysql.sock
11
- database: breathing_test
10
+ database: breathing_test
11
+
12
+ test_pg:
13
+ adapter: postgresql
14
+ encoding: unicode
15
+ username: <%= ENV.fetch("DB_USER") { 'root' } %>
16
+ password: <%= ENV.fetch("DB_PASS") { '' } %>
17
+ host: <%= ENV.fetch("DB_HOST") { '127.0.0.1' } %>
18
+ database: breathing_test
@@ -4,6 +4,8 @@ require 'active_record'
4
4
  require 'breathing'
5
5
  require_relative 'app'
6
6
 
7
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
8
+
7
9
  RSpec.configure do |config|
8
10
  config.around do |example|
9
11
  ActiveRecord::Base.transaction do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: breathing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Akira Kusumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-10 00:00:00.000000000 Z
11
+ date: 2020-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -39,19 +39,19 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: 5.0.0
41
41
  - !ruby/object:Gem::Dependency
42
- name: rubyXL
42
+ name: hairtrigger
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 3.4.0
47
+ version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 3.4.0
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: mysql2
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -59,13 +59,55 @@ dependencies:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
- type: :development
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pg
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - ">="
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: terminal-table
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubyXL
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 3.4.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 3.4.0
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: pry-byebug
71
113
  requirement: !ruby/object:Gem::Requirement
@@ -115,9 +157,11 @@ files:
115
157
  - lib/breathing/cli.rb
116
158
  - lib/breathing/excel.rb
117
159
  - lib/breathing/installer.rb
160
+ - lib/breathing/terminal_table.rb
118
161
  - lib/breathing/trigger.rb
119
162
  - spec/app.rb
120
163
  - spec/breathing/excel_spec.rb
164
+ - spec/breathing/terminal_table_spec.rb
121
165
  - spec/breathing_spec.rb
122
166
  - spec/database.yml
123
167
  - spec/spec_helper.rb
@@ -147,6 +191,7 @@ summary: Audit logging for database
147
191
  test_files:
148
192
  - spec/app.rb
149
193
  - spec/breathing/excel_spec.rb
194
+ - spec/breathing/terminal_table_spec.rb
150
195
  - spec/breathing_spec.rb
151
196
  - spec/database.yml
152
197
  - spec/spec_helper.rb