exwiw 0.1.3 → 0.1.5

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: 83fdfcea806c556f4eace82d26f2c5fcd08b05c37ee1396b14e3752110e17b73
4
- data.tar.gz: 38fc8c299154dab02fd23d1c39d09453ebeaf66be611127453b46908bbe70986
3
+ metadata.gz: 2f9fb9e57ed24338ac642aa9f0aa200980d8b57fd2d73851249467f9ec9e251b
4
+ data.tar.gz: 2cb68bd84f67b9a683116d83daacab6a96b65e4802f8b67afb81ef97ebccf3c7
5
5
  SHA512:
6
- metadata.gz: 2192f38b947c07a5118defa2160316411c5e60f77398b2859d9b31b59079fbabcd2ecb7436071d2ec79629073bdd7339bdc71def16cb709955e8728d363c91dd
7
- data.tar.gz: da4fd038b0b21ff9255f5f5d72ad5dbe1b4a42c9d28a4c0e60af19f700c8a82c45226091bad43bdaecda49d5bbc07fb4a7bc8337ffecd793ce4509abd1955b9d
6
+ metadata.gz: 59bc123c523bf1f97dd97b6c18aa93972926366f121dda9dad9105cf651a783a77b38d7547fad99b7ab1c9509452123bf1c8423203cb0757cf3161d64d296c84
7
+ data.tar.gz: 6ea7278185d5f92bea6b43d3fb164bb23ae6557ce5d1f3d27e2a86a5147e665a7228ae848e2340c41fd1c5d43ccbdb81decf71804c4d68283de3c61b17be701c
data/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ### Added
6
+
7
+ - Add `bulk_insert_chunk_size` table config to split the generated `INSERT` statement into chunks of the specified size. ([#8](https://github.com/riseshia/exwiw/pull/8))
8
+
9
+ ### Changed
10
+
11
+ - Bump minimum required Ruby version to 3.3.0 and drop Ruby 3.2 from the CI matrix (3.2 reached EOL on 2026-03-31).
12
+
13
+ ### Fixed
14
+
15
+ - Fix MySQL host access for local rspec runs and switch local dev scripts to inject the password via `MYSQL_PWD` env on `docker compose exec` instead of the `-p` CLI flag. ([#5](https://github.com/riseshia/exwiw/pull/5))
16
+ - Expand `~` in path arguments and validate the existence of `--config-dir`. ([#6](https://github.com/riseshia/exwiw/pull/6))
17
+ - Fix incorrect left-side table in `JOIN ... ON` clause for join chains with 3+ hops, which caused `no such column` / `column does not exist` errors at execute time. ([#7](https://github.com/riseshia/exwiw/pull/7))
18
+
19
+ ## [0.1.4] - 2026-04-04
20
+
21
+ ### Fixed
22
+
23
+ - Skip models whose table does not exist in `exwiw:schema:generate` task.
24
+ - Add trailing newline to generated schema files.
25
+ - Fixed foreign key constraint errors when exporting child tables with filters on intermediate tables. Filters from intermediate tables are now correctly included in JOIN clauses. ([#3](https://github.com/riseshia/exwiw/pull/3))
26
+
5
27
  ## [0.1.3] - 2025-04-02
6
28
 
7
29
  ### Fixed
data/README.md CHANGED
@@ -98,6 +98,7 @@ This is an example of the one table schema:
98
98
  "name": "users",
99
99
  "primary_key": "id",
100
100
  "filter": "users.id > 0",
101
+ "bulk_insert_chunk_size": 1000,
101
102
  "belongs_to": [{
102
103
  "name": "companies",
103
104
  "foreign_key": "company_id"
@@ -115,6 +116,12 @@ This is an example of the one table schema:
115
116
 
116
117
  `--config-dir` will use all json files in the specified directory.
117
118
 
119
+ ### Bulk insert chunk size
120
+
121
+ `bulk_insert_chunk_size` splits the generated `INSERT` statement into multiple statements, each containing at most the specified number of rows. This is useful when the number of records per table is large enough to hit limits like MySQL's `max_allowed_packet`.
122
+
123
+ If omitted, all records for a table are emitted as a single `INSERT` statement.
124
+
118
125
  ### Filter
119
126
 
120
127
  Some case, you don't need full records related to target. e.g. dump user access logs only for the last year.
@@ -79,7 +79,7 @@ module Exwiw
79
79
  sql += " FROM #{query_ast.from_table_name}"
80
80
 
81
81
  query_ast.join_clauses.each do |join|
82
- sql += " JOIN #{join.join_table_name} ON #{query_ast.from_table_name}.#{join.foreign_key} = #{join.join_table_name}.#{join.primary_key}"
82
+ sql += " JOIN #{join.join_table_name} ON #{join.base_table_name}.#{join.foreign_key} = #{join.join_table_name}.#{join.primary_key}"
83
83
 
84
84
  join.where_clauses.each do |where|
85
85
  compiled_where_condition = compile_where_condition(where, join.join_table_name)
@@ -79,7 +79,7 @@ module Exwiw
79
79
  sql += " FROM #{query_ast.from_table_name}"
80
80
 
81
81
  query_ast.join_clauses.each do |join|
82
- sql += " JOIN #{join.join_table_name} ON #{query_ast.from_table_name}.#{join.foreign_key} = #{join.join_table_name}.#{join.primary_key}"
82
+ sql += " JOIN #{join.join_table_name} ON #{join.base_table_name}.#{join.foreign_key} = #{join.join_table_name}.#{join.primary_key}"
83
83
 
84
84
  join.where_clauses.each do |where|
85
85
  compiled_where_condition = compile_where_condition(where, join.join_table_name)
@@ -79,7 +79,7 @@ module Exwiw
79
79
  sql += " FROM #{query_ast.from_table_name}"
80
80
 
81
81
  query_ast.join_clauses.each do |join|
82
- sql += " JOIN #{join.join_table_name} ON #{query_ast.from_table_name}.#{join.foreign_key} = #{join.join_table_name}.#{join.primary_key}"
82
+ sql += " JOIN #{join.join_table_name} ON #{join.base_table_name}.#{join.foreign_key} = #{join.join_table_name}.#{join.primary_key}"
83
83
 
84
84
  join.where_clauses.each do |where|
85
85
  compiled_where_condition = compile_where_condition(where, join.join_table_name)
@@ -157,7 +157,7 @@ module Exwiw
157
157
  @connection ||=
158
158
  begin
159
159
  require 'sqlite3'
160
- SQLite3::Database.new(@connection_config.database_name)
160
+ SQLite3::Database.new(File.expand_path(@connection_config.database_name))
161
161
  end
162
162
  end
163
163
  end
data/lib/exwiw/cli.rb CHANGED
@@ -79,10 +79,6 @@ module Exwiw
79
79
  end
80
80
  end
81
81
 
82
- if @config_dir.nil?
83
- $stderr.puts "Config dir is required"
84
- end
85
-
86
82
  if @database_password.nil? || @database_password.empty?
87
83
  $stderr.puts "environment variable 'DATABASE_PASSWORD' is required"
88
84
  exit 1
@@ -95,6 +91,21 @@ module Exwiw
95
91
  exit 1
96
92
  end
97
93
 
94
+ if @config_dir.nil?
95
+ $stderr.puts "Config dir is required"
96
+ exit 1
97
+ end
98
+
99
+ unless Dir.exist?(@config_dir)
100
+ $stderr.puts "Config dir does not exist: #{@config_dir}"
101
+ exit 1
102
+ end
103
+
104
+ if Dir.glob(File.join(@config_dir, "*.json")).empty?
105
+ $stderr.puts "Config dir contains no .json files: #{@config_dir}"
106
+ exit 1
107
+ end
108
+
98
109
  if @target_table_name.nil? || @target_table_name.empty?
99
110
  $stderr.puts "Target table is required"
100
111
  exit 1
@@ -130,10 +141,12 @@ module Exwiw
130
141
  opts.on("-p", "--port=PORT", "Target database port") { |v| @database_port = v }
131
142
  opts.on("-u", "--user=USERNAME", "Target database user") { |v| @database_user = v }
132
143
  opts.on("-o", "--output-dir=[DUMP_DIR_PATH]", "Output file path. default is dump/") do |v|
133
- @output_dir = v.end_with?("/") ? v[0..-2] : v
144
+ v = v.end_with?("/") ? v[0..-2] : v
145
+ @output_dir = File.expand_path(v)
134
146
  end
135
147
  opts.on("-c", "--config-dir=CONFIG_DIR_PATH", "Config dir path.") do |v|
136
- @config_dir = v.end_with?("/") ? v[0..-2] : v
148
+ v = v.end_with?("/") ? v[0..-2] : v
149
+ @config_dir = File.expand_path(v)
137
150
  end
138
151
  opts.on("-a", "--adapter=ADAPTER", "Database adapter") { |v| @database_adapter = v }
139
152
  opts.on("--database=DATABASE", "Target database name") { |v| @database_name = v }
@@ -20,7 +20,9 @@ module Exwiw
20
20
  join_table_name: join_table_name,
21
21
  primary_key: primary_key,
22
22
  }
23
- hash[:where_clauses] = where_clauses.map(&:to_h) if where_clauses.size.positive?
23
+ if where_clauses.size.positive?
24
+ hash[:where_clauses] = where_clauses.map { |wc| wc.is_a?(String) ? wc : wc.to_h }
25
+ end
24
26
  hash
25
27
  end
26
28
  end
@@ -61,6 +61,11 @@ module Exwiw
61
61
  )
62
62
  end
63
63
 
64
+ # Add filter from intermediate table to join clause
65
+ if to_table.filter
66
+ join_clause.where_clauses.push to_table.filter
67
+ end
68
+
64
69
  join_clauses.push(join_clause)
65
70
  end
66
71
 
data/lib/exwiw/runner.rb CHANGED
@@ -46,9 +46,11 @@ module Exwiw
46
46
  end
47
47
  @logger.debug(" Generate INSERT SQL...")
48
48
 
49
- insert_sql = adapter.to_bulk_insert(results, table)
49
+ chunk_size = table.bulk_insert_chunk_size
50
+ chunks = chunk_size ? results.each_slice(chunk_size).to_a : [results]
51
+ insert_sql = chunks.map { |chunk_rows| adapter.to_bulk_insert(chunk_rows, table) }.join("\n")
50
52
 
51
- @logger.info(" Generated INSERT SQL for #{record_num} records.")
53
+ @logger.info(" Generated INSERT SQL for #{record_num} records (#{chunks.size} statement(s)).")
52
54
  insert_idx = (idx + 1).to_s.rjust(3, '0')
53
55
  File.open(File.join(@output_dir, "insert-#{insert_idx}-#{table_name}.sql"), 'w') do |file|
54
56
  file.puts(insert_sql)
@@ -9,6 +9,7 @@ module Exwiw
9
9
  attribute :filter, optional(String), skip_serializing_if_nil: true
10
10
  attribute :belongs_tos, array(BelongsTo)
11
11
  attribute :columns, array(TableColumn)
12
+ attribute :bulk_insert_chunk_size, optional(Integer), skip_serializing_if_nil: true
12
13
 
13
14
  def self.from_symbol_keys(hash)
14
15
  from(JSON.parse(hash.to_json))
@@ -74,6 +75,7 @@ module Exwiw
74
75
  merged_table.primary_key = passed_table.primary_key
75
76
  merged_table.filter = filter
76
77
  merged_table.belongs_tos = passed_table.belongs_tos
78
+ merged_table.bulk_insert_chunk_size = passed_table.bulk_insert_chunk_size
77
79
 
78
80
  receiver_column_by_name = columns.each_with_object({}) { |column, hash| hash[column.name] = column }
79
81
 
data/lib/exwiw/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Exwiw
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.5"
5
5
  end
data/lib/tasks/exwiw.rake CHANGED
@@ -14,6 +14,7 @@ namespace :exwiw do
14
14
 
15
15
  ActiveRecord::Base.descendants.each do |model|
16
16
  next if model.abstract_class?
17
+ next unless model.table_exists?
17
18
  next if table_by_name[model.table_name]
18
19
 
19
20
  belongs_tos = model.reflect_on_all_associations(:belongs_to).map do |assoc|
@@ -51,9 +52,9 @@ namespace :exwiw do
51
52
  if File.exist?(path)
52
53
  current_config = Exwiw::TableConfig.from(JSON.parse(File.read(path)))
53
54
  merged_config = current_config.merge(table)
54
- File.write(path, JSON.pretty_generate(merged_config.to_hash))
55
+ File.write(path, JSON.pretty_generate(merged_config.to_hash) + "\n")
55
56
  else
56
- File.write(path, JSON.pretty_generate(table.to_hash))
57
+ File.write(path, JSON.pretty_generate(table.to_hash) + "\n")
57
58
  end
58
59
  end
59
60
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exwiw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shia
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-02 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: serdes
@@ -66,14 +66,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 3.2.0
69
+ version: 3.3.0
70
70
  required_rubygems_version: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  requirements: []
76
- rubygems_version: 3.6.2
76
+ rubygems_version: 3.6.9
77
77
  specification_version: 4
78
78
  summary: Ruby gem that allows you to export records from a database to a dump file.
79
79
  test_files: []