seed_dump_citus 1.0.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 589295ccb53fca1a66f410a15a6fce7c179be89a0ab6ce311967bd6a130b12e0
4
+ data.tar.gz: 6649359765019a7faf1ee7f1655565841fd011a8b98ad3714f2d23dd4ff2afed
5
+ SHA512:
6
+ metadata.gz: 3598300d5a6b4f61465ba26708ffc4ce24ac7088a32ff1c329ba3c15f292c80f9f01c80a3545d01b938affe83b826605cf36b40dd3b24a97511c2e0df4f1dda8
7
+ data.tar.gz: be3d6452a2ea1f69cbda6cd48f51d349d3f155d5787db34f4f7e7c6681abbf34d378372a76a762b45a496e051eaefd2fd26037976d34a8cc575674d626106ebe
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,20 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'activesupport', '>= 4'
4
+ gem 'activerecord', '>= 4'
5
+
6
+ group :development, :test do
7
+ gem 'byebug', '~> 2.0'
8
+ gem 'factory_bot', '~> 4.8.2'
9
+ gem 'activerecord-import', '~> 0.4'
10
+ end
11
+
12
+ group :development do
13
+ gem 'jeweler', '~> 2.0'
14
+ end
15
+
16
+ group :test do
17
+ gem 'rspec', '~> 3.7.0'
18
+ gem 'sqlite3', '~> 1.0'
19
+ gem 'database_cleaner', '~> 1.0'
20
+ end
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Ryan Oblak
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,131 @@
1
+ Seed Dump
2
+ ========
3
+
4
+ Seed Dump is a Rails 4 and 5 plugin that adds a rake task named `db:seed:dump`.
5
+
6
+ It allows you to create seed data files from the existing data in your database.
7
+
8
+ You can also use Seed Dump from the Rails console. See below for usage examples.
9
+
10
+ Note: if you want to use Seed Dump with Rails 3 or earlier, use [version 0.5.3](http://rubygems.org/gems/seed_dump/versions/0.5.3).
11
+
12
+ Installation
13
+ ------------
14
+
15
+ Add it to your Gemfile with:
16
+ ```ruby
17
+ gem 'seed_dump_citus'
18
+ ```
19
+ Or install it by hand:
20
+ ```sh
21
+ $ gem install seed_dump
22
+ ```
23
+ Examples
24
+ --------
25
+
26
+ ### Rake task
27
+
28
+ Dump all data directly to `db/seeds.rb`:
29
+ ```sh
30
+ $ rake db:seed:dump
31
+ ```
32
+ Result:
33
+ ```ruby
34
+ Product.create!([
35
+ { category_id: 1, description: "Long Sleeve Shirt", name: "Long Sleeve Shirt" },
36
+ { category_id: 3, description: "Plain White Tee Shirt", name: "Plain T-Shirt" }
37
+ ])
38
+ User.create!([
39
+ { password: "123456", username: "test_1" },
40
+ { password: "234567", username: "test_2" }
41
+ ])
42
+ ```
43
+
44
+ Dump only data from the users table and dump a maximum of 1 record:
45
+ ```sh
46
+ $ rake db:seed:dump MODELS=User LIMIT=1
47
+ ```
48
+
49
+ Result:
50
+ ```ruby
51
+ User.create!([
52
+ { password: "123456", username: "test_1" }
53
+ ])
54
+ ```
55
+
56
+ Append to `db/seeds.rb` instead of overwriting it:
57
+ ```sh
58
+ rake db:seed:dump APPEND=true
59
+ ```
60
+
61
+ Use another output file instead of `db/seeds.rb`:
62
+ ```sh
63
+ rake db:seed:dump FILE=db/seeds/users.rb
64
+ ```
65
+
66
+ Exclude `name` and `age` from the dump:
67
+ ```sh
68
+ rake db:seed:dump EXCLUDE=name,age
69
+ ```
70
+
71
+ There are more options that can be set— see below for all of them.
72
+
73
+ ### Console
74
+
75
+ Output a dump of all User records:
76
+ ```ruby
77
+ irb(main):001:0> puts SeedDump.dump(User)
78
+ User.create!([
79
+ { password: "123456", username: "test_1" },
80
+ { password: "234567", username: "test_2" }
81
+ ])
82
+ ```
83
+
84
+ Write the dump to a file:
85
+ ```ruby
86
+ irb(main):002:0> SeedDump.dump(User, file: 'db/seeds.rb')
87
+ ```
88
+
89
+ Append the dump to a file:
90
+ ```ruby
91
+ irb(main):003:0> SeedDump.dump(User, file: 'db/seeds.rb', append: true)
92
+ ```
93
+
94
+ Exclude `name` and `age` from the dump:
95
+ ```ruby
96
+ irb(main):004:0> SeedDump.dump(User, exclude: [:name, :age])
97
+ ```
98
+
99
+ Options are specified as a Hash for the second argument.
100
+
101
+ In the console, any relation of ActiveRecord rows can be dumped (not individual objects though)
102
+ ```ruby
103
+ irb(main):001:0> puts SeedDump.dump(User.where(is_admin: false))
104
+ User.create!([
105
+ { password: "123456", username: "test_1", is_admin: false },
106
+ { password: "234567", username: "test_2", is_admin: false }
107
+ ])
108
+ ```
109
+
110
+ Options
111
+ -------
112
+
113
+ Options are common to both the Rake task and the console, except where noted.
114
+
115
+ `append`: If set to `true`, append the data to the file instead of overwriting it. Default: `false`.
116
+
117
+ `batch_size`: Controls the number of records that are written to file at a given time. Default: 1000. If you're running out of memory when dumping, try decreasing this. If things are dumping too slow, trying increasing this.
118
+
119
+ `exclude`: Attributes to be excluded from the dump. Pass a comma-separated list to the Rake task (i.e. `name,age`) and an array on the console (i.e. `[:name, :age]`). Default: `[:id, :created_at, :updated_at]`.
120
+
121
+ `file`: Write to the specified output file. The Rake task default is `db/seeds.rb`. The console returns the dump as a string by default.
122
+
123
+ `import`: If `true`, output will be in the format needed by the [activerecord-import](https://github.com/zdennis/activerecord-import) gem, rather than the default format. Default: `false`.
124
+
125
+ `limit`: Dump no more than this amount of data. Default: no limit. Rake task only. In the console just pass in an ActiveRecord::Relation with the appropriate limit (e.g. `SeedDump.dump(User.limit(5))`).
126
+
127
+ `conditions`: Dump only specific records. In the console just pass in an ActiveRecord::Relation with the appropriate conditions (e.g. `SeedDump.dump(User.where(state: :active))`).
128
+
129
+ `model[s]`: Restrict the dump to the specified comma-separated list of models. Default: all models. If you are using a Rails engine you can dump a specific model by passing "EngineName::ModelName". Rake task only. Example: `rake db:seed:dump MODELS="User, Position, Function"`
130
+
131
+ `models_exclude`: Exclude the specified comma-separated list of models from the dump. Default: no models excluded. Rake task only. Example: `rake db:seed:dump MODELS_EXCLUDE="User"`
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "seed_dump_citus"
8
+ gem.summary = "{Seed Dumper for Rails}"
9
+ gem.description = %Q{Dump (parts) of your database to db/seeds.rb to get a headstart creating a meaningful seeds.rb file}
10
+ gem.email = 'rroblak@gmail.com'
11
+ gem.homepage = 'https://github.com/rroblak/seed_dump_citus'
12
+ gem.authors = ['Rob Halff', 'Ryan Oblak']
13
+ gem.license = 'MIT'
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
19
+
20
+ require 'rdoc/task'
21
+ Rake::RDocTask.new do |rdoc|
22
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
23
+
24
+ rdoc.rdoc_dir = 'rdoc'
25
+ rdoc.title = "seed_dump_citus #{version}"
26
+ rdoc.rdoc_files.include('README*')
27
+ rdoc.rdoc_files.include('lib/**/*.rb')
28
+ end
29
+
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec)
32
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 3.3.2
@@ -0,0 +1,11 @@
1
+ require 'ipaddr'
2
+ require 'seed_dump_citus/dump_methods/enumeration'
3
+ require 'seed_dump_citus/dump_methods'
4
+ require 'seed_dump_citus/environment'
5
+
6
+ class SeedDumpCitus
7
+ extend Environment
8
+ extend DumpMethods
9
+
10
+ require 'seed_dump_citus/railtie' if defined?(Rails)
11
+ end
@@ -0,0 +1,129 @@
1
+ class SeedDumpCitus
2
+ module DumpMethods
3
+ include Enumeration
4
+
5
+ def dump(records, options = {})
6
+ return nil if records.count == 0
7
+
8
+ io = open_io(options)
9
+
10
+ write_records_to_io(records, io, options)
11
+
12
+ ensure
13
+ io.close if io.present?
14
+ end
15
+
16
+ private
17
+
18
+ def dump_record(record, options)
19
+ attribute_strings = []
20
+
21
+ # We select only string attribute names to avoid conflict
22
+ # with the composite_primary_keys gem (it returns composite
23
+ # primary key attribute names as hashes).
24
+ record.attributes.select {|key| key.is_a?(String) || key.is_a?(Symbol) }.each do |attribute, value|
25
+ attribute_strings << dump_attribute_new(attribute, value, options) unless options[:exclude].include?(attribute.to_sym)
26
+ end
27
+
28
+ open_character, close_character = options[:import] ? ['[', ']'] : ['{', '}']
29
+
30
+ "#{open_character}#{attribute_strings.join(", ")}#{close_character}"
31
+ end
32
+
33
+ def dump_attribute_new(attribute, value, options)
34
+ options[:import] ? value_to_s(value) : "#{attribute}: #{value_to_s(value)}"
35
+ end
36
+
37
+ def value_to_s(value)
38
+ value = case value
39
+ when BigDecimal, IPAddr
40
+ value.to_s
41
+ when Date, Time, DateTime
42
+ value.to_s(:db)
43
+ when Range
44
+ range_to_string(value)
45
+ when ->(v) { v.class.ancestors.map(&:to_s).include?('RGeo::Feature::Instance') }
46
+ value.to_s
47
+ else
48
+ value
49
+ end
50
+
51
+ value.inspect
52
+ end
53
+
54
+ def range_to_string(object)
55
+ from = object.begin.respond_to?(:infinite?) && object.begin.infinite? ? '' : object.begin
56
+ to = object.end.respond_to?(:infinite?) && object.end.infinite? ? '' : object.end
57
+ "[#{from},#{to}#{object.exclude_end? ? ')' : ']'}"
58
+ end
59
+
60
+ def open_io(options)
61
+ if options[:file].present?
62
+ mode = options[:append] ? 'a+' : 'w+'
63
+
64
+ File.open(options[:file], mode)
65
+ else
66
+ StringIO.new('', 'w+')
67
+ end
68
+ end
69
+
70
+ def write_records_to_io(records, io, options)
71
+ options[:exclude] ||= [:id, :created_at, :updated_at]
72
+
73
+ method = options[:import] ? 'import' : 'create!'
74
+ io.write("#{model_for(records)}.#{method}(")
75
+ if options[:import]
76
+ io.write("[#{attribute_names(records, options).map {|name| name.to_sym.inspect}.join(', ')}], ")
77
+ end
78
+ io.write("[\n ")
79
+
80
+ enumeration_method = if records.is_a?(ActiveRecord::Relation) || records.is_a?(Class)
81
+ :active_record_enumeration
82
+ else
83
+ :enumerable_enumeration
84
+ end
85
+
86
+ send(enumeration_method, records, io, options) do |record_strings, last_batch|
87
+ io.write(record_strings.join(",\n "))
88
+
89
+ io.write(",\n ") unless last_batch
90
+ end
91
+
92
+ io.write("\n]#{active_record_import_options(options)})\n")
93
+
94
+ if options[:file].present?
95
+ nil
96
+ else
97
+ io.rewind
98
+ io.read
99
+ end
100
+ end
101
+
102
+ def active_record_import_options(options)
103
+ return unless options[:import] && options[:import].is_a?(Hash)
104
+
105
+ ', ' + options[:import].map { |key, value| "#{key}: #{value}" }.join(', ')
106
+ end
107
+
108
+ def attribute_names(records, options)
109
+ attribute_names = if records.is_a?(ActiveRecord::Relation) || records.is_a?(Class)
110
+ records.attribute_names
111
+ else
112
+ records[0].attribute_names
113
+ end
114
+
115
+ attribute_names.select {|name| !options[:exclude].include?(name.to_sym)}
116
+ end
117
+
118
+ def model_for(records)
119
+ if records.is_a?(Class)
120
+ records
121
+ elsif records.respond_to?(:model)
122
+ records.model
123
+ else
124
+ records[0].class
125
+ end
126
+ end
127
+
128
+ end
129
+ end
@@ -0,0 +1,78 @@
1
+ class SeedDumpCitus
2
+ module DumpMethods
3
+ module Enumeration
4
+ def active_record_enumeration(records, io, options)
5
+ # If the records don't already have an order,
6
+ # order them by primary key ascending.
7
+ if !records.respond_to?(:arel) || records.arel.orders.blank?
8
+ records.order("#{records.quoted_table_name}.#{records.quoted_primary_key} ASC")
9
+ end
10
+
11
+ num_of_batches, batch_size, last_batch_size = batch_params_from(records, options)
12
+
13
+ # Loop through each batch
14
+ TransactionAccessor.acceptable_non_sharded_read do
15
+
16
+ (1..num_of_batches).each do |batch_number|
17
+
18
+ record_strings = []
19
+
20
+ last_batch = (batch_number == num_of_batches)
21
+
22
+ cur_batch_size = if last_batch
23
+ last_batch_size
24
+ else
25
+ batch_size
26
+ end
27
+
28
+ # Loop through the records of the current batch
29
+ records.offset((batch_number - 1) * batch_size).limit(cur_batch_size).each do |record|
30
+ record_strings << dump_record(record, options)
31
+ end
32
+
33
+ yield record_strings, last_batch
34
+ end
35
+ end
36
+ end
37
+
38
+ def enumerable_enumeration(records, io, options)
39
+ num_of_batches, batch_size = batch_params_from(records, options)
40
+
41
+ record_strings = []
42
+
43
+ batch_number = 1
44
+
45
+ records.each_with_index do |record, i|
46
+ record_strings << dump_record(record, options)
47
+
48
+ last_batch = (i == records.length - 1)
49
+
50
+ if (record_strings.length == batch_size) || last_batch
51
+ yield record_strings, last_batch
52
+
53
+ record_strings = []
54
+ batch_number += 1
55
+ end
56
+ end
57
+ end
58
+
59
+ def batch_params_from(records, options)
60
+ batch_size = batch_size_from(records, options)
61
+
62
+ count = records.count
63
+
64
+ remainder = count % batch_size
65
+
66
+ [((count.to_f / batch_size).ceil), batch_size, (remainder == 0 ? batch_size : remainder)]
67
+ end
68
+
69
+ def batch_size_from(records, options)
70
+ if options[:batch_size].present?
71
+ options[:batch_size].to_i
72
+ else
73
+ 1000
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end