seeder 0.1.0

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.
data/CHANGELOG.txt ADDED
@@ -0,0 +1,2 @@
1
+ == 0.1.0
2
+ * Initial release, no tests, MySQL-only
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT LICENSE
2
+
3
+ Copyright (c) 2011 Wegowise Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ Description
2
+ ===========
3
+
4
+ Seeder provides a way for your app to plant seed data in its database.
5
+ It respects unique keys in your database, so that it does the equivalent of
6
+ MySQL's "on duplicate key update" (but this is database agnostic)
7
+
8
+
9
+ Install
10
+ =======
11
+
12
+ $ gem install seeder
13
+
14
+ Usage
15
+ =====
16
+
17
+ Suppose you have a `User` model
18
+
19
+ And suppose that user model has fields "name", "age", "address", "gender"
20
+
21
+ Finally, suppose you've set up your database to have a unique key on the fields
22
+ "name" and "address" (so two people can have the same name or live at the
23
+ same address, but not both)
24
+
25
+ If you wanted to seed your data with a couple users you could do the following:
26
+
27
+ ```ruby
28
+ seed_users = [
29
+ {
30
+ :name => "J'onn J'onzz",
31
+ :age => 94,
32
+ :address => 'Mars',
33
+ :gender => 'Male'
34
+ },
35
+ {
36
+ :name => "Barbara Gordon",
37
+ :age => 35,
38
+ :address => '14 Gotham Heights',
39
+ :gender => 'Female'
40
+ }
41
+ ]
42
+
43
+ SeedData.create {'User' => seed_users}, [:name, :address], User
44
+ ```
45
+
46
+ License
47
+ =======
48
+
49
+ See LICENSE.txt
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ require 'rake'
2
+ require 'fileutils'
3
+
4
+ def gemspec_name
5
+ @gemspec_name ||= Dir['*.gemspec'][0]
6
+ end
7
+
8
+ def gemspec
9
+ @gemspec ||= eval(File.read(gemspec_name), binding, gemspec_name)
10
+ end
11
+
12
+ desc "Build the gem"
13
+ task :gem=>:gemspec do
14
+ sh "gem build #{gemspec_name}"
15
+ FileUtils.mkdir_p 'pkg'
16
+ FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", 'pkg'
17
+ end
18
+
19
+ desc "Install the gem locally"
20
+ task :install => :gem do
21
+ sh %{gem install pkg/#{gemspec.name}-#{gemspec.version}}
22
+ end
23
+
24
+ desc "Generate the gemspec"
25
+ task :generate do
26
+ puts gemspec.to_ruby
27
+ end
28
+
29
+ desc "Validate the gemspec"
30
+ task :gemspec do
31
+ gemspec.validate
32
+ end
33
+
34
+ desc 'Run tests'
35
+ task :test do |t|
36
+ sh 'rspec spec'
37
+ end
38
+
39
+ task :default => :test
data/lib/seeder.rb ADDED
@@ -0,0 +1,62 @@
1
+ class Seeder
2
+
3
+ class << self
4
+
5
+ def existing_data_keys(ar_model)
6
+ keys = @primary_keys[ar_model.name]
7
+ ar_model.all.map{|item| item.attributes.symbolize_keys.values_at(*keys) }
8
+ end
9
+
10
+ def seed_data_keys(ar_model)
11
+ keys = @primary_keys[ar_model.name]
12
+ @data[ar_model.name].collect{|attributes| attributes.values_at(*keys) }
13
+ end
14
+
15
+ def items_to_delete(ar_model)
16
+ existing_data_keys(ar_model) - seed_data_keys(ar_model)
17
+ end
18
+
19
+ def value_to_sql(value)
20
+ if value.nil? then 'NULL'
21
+ elsif value.is_a?(String) then "'#{value}'"
22
+ elsif value == false then 0
23
+ elsif value == true then 1
24
+ else value
25
+ end
26
+ end
27
+
28
+ def add_new_or_changed_data(ar_model)
29
+ keys = @primary_keys[ar_model.name]
30
+ find_method = "find_by_#{keys.join('_and_')}"
31
+ @data[ar_model.name].collect do |attributes|
32
+ relevant_keys = attributes.keys & ar_model.column_names.map(&:to_sym)
33
+ existing = ar_model.send(find_method, *attributes.values_at(*keys))
34
+ next if existing && attributes.values_at(*relevant_keys) == existing.attributes.symbolize_keys.values_at(*relevant_keys)
35
+ values = attributes.values_at(*relevant_keys)
36
+ %{
37
+ INSERT INTO #{ar_model.table_name} (#{relevant_keys.map{|col| "`#{col}`"}.join(', ')}) VALUES (#{values.map{|val| value_to_sql(val)}.join(', ')}) ON DUPLICATE KEY UPDATE #{relevant_keys.map{|col| "`#{col}` = VALUES(`#{col}`)"}.join(', ')}
38
+ }
39
+ end.compact
40
+ end
41
+
42
+ def delete_outdated_data(ar_model)
43
+ keys = @primary_keys[ar_model.name]
44
+ items_to_delete(ar_model).collect do |field_to_delete|
45
+ conditions = field_to_delete.to_enum.with_index.collect{|value, index| "#{keys[index]} = '#{value}'"}.join(' AND ')
46
+ %{ DELETE FROM #{ar_model.table_name} WHERE #{conditions} }
47
+ end.compact
48
+ end
49
+
50
+ def create(data, keys, models)
51
+ @data, @primary_keys = data, keys
52
+ models.each {|model|
53
+ delete_outdated_data(model).each{|query| sql(query)}
54
+ add_new_or_changed_data(model).each{|query| sql(query)}
55
+ }
56
+ end
57
+
58
+ def sql(sql_command)
59
+ ActiveRecord::Base.connection.execute(sql_command)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ class Seeder
2
+ VERSION = '0.1.0'
3
+ end
data/seeder.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'rubygems' unless defined? Gem
3
+ require File.dirname(__FILE__) + "/lib/seeder/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "seeder"
7
+ s.version = Seeder::VERSION
8
+ s.authors = ["Barun Singh", "Gabriel Horner"]
9
+ s.email = "bsingh@wegowise.com"
10
+ s.homepage = "http://github.com/wegowise/seeder"
11
+ s.summary = "Seed your data"
12
+ s.description = "Keep your app's seed data in one file and update it easily, while respecting key constraints"
13
+ s.required_rubygems_version = ">= 1.3.6"
14
+ s.files = Dir.glob(%w[{lib,spec}/**/*.rb [A-Z]*.{txt,rdoc,md} *.gemspec]) + %w{Rakefile}
15
+ s.extra_rdoc_files = ["README.md", "LICENSE.txt"]
16
+ s.license = 'MIT'
17
+ s.add_development_dependency 'rspec', '~> 2.6.0'
18
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seeder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Barun Singh
9
+ - Gabriel Horner
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-09-02 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: &2152871700 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 2.6.0
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2152871700
26
+ description: Keep your app's seed data in one file and update it easily, while respecting
27
+ key constraints
28
+ email: bsingh@wegowise.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files:
32
+ - README.md
33
+ - LICENSE.txt
34
+ files:
35
+ - lib/seeder/version.rb
36
+ - lib/seeder.rb
37
+ - CHANGELOG.txt
38
+ - LICENSE.txt
39
+ - README.md
40
+ - seeder.gemspec
41
+ - Rakefile
42
+ homepage: http://github.com/wegowise/seeder
43
+ licenses:
44
+ - MIT
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: 1.3.6
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 1.8.6
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Seed your data
67
+ test_files: []