seeder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []