datamappify 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 [name of plugin creator]
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,118 @@
1
+ # Datamappify
2
+
3
+ ## Introduction
4
+
5
+ ActiveRecord is without doubt the *de facto* ORM library for Rails and many Ruby web frameworks. Many developers however, do not like database migrations and prefer to use DSL for data mapping. Datamappify is created with the sole purpose of getting rid of the DB migration headaches.
6
+
7
+ Brought to you by [Envato](http://envato.com) and [Wuit](http://wuit.com).
8
+
9
+ ## Disclaimer
10
+
11
+ **This plugin is NOT production-ready yet!** Use with caution.
12
+
13
+ ### Todo
14
+
15
+ * Add tests
16
+ * Remove the dependency of the `auto_migrate` plugin
17
+ * Possibly refactor `add_index` to be part of the `property` definition (as seen in the [DataMapper](http://datamapper.org/) library)
18
+
19
+ ## Why?
20
+
21
+ ### Why Not DB Migrations?
22
+
23
+ Well, depending on your specific project, DB migrations might create more trouble than it's worth. Besides, your code is already version controlled, so why create a separate version control for your DB schema?
24
+
25
+ ### Why Not Use DataMapper, Sequel, etc?
26
+
27
+ As stated in the introduction, ActiveRecord is the most popular ORM in the rails community, it is actively developed and battle-tested. If your only grief with ActiveRecord is the DB migrations, why not just eliminate it be happy? ;)
28
+
29
+ ## How?
30
+
31
+ How does this plugin work?
32
+
33
+ Basically, it -
34
+
35
+ 1. Uses a DSL similar to DataMapper's for defining model properties (DB mapping).
36
+ 2. `schema.rb` is automatically updated according to the model properties.
37
+ 3. Automatically 'migrates' the database according to the updated schema file.
38
+
39
+ ## Dependencies
40
+
41
+ To use Datamappify, you will need the following libraries.
42
+
43
+ * ActiveRecord
44
+ * [auto_migrations](http://github.com/pjhyett/auto_migrations)
45
+
46
+ ## Usages
47
+
48
+ Here's an example to get you started:
49
+
50
+ class User < ActiveRecord::Base
51
+ include Datamappify::Resource
52
+
53
+ property :email, :string
54
+ property :password, :string, :limit => 40
55
+ property :first_name, :string, :limit => 50
56
+ property :last_name, :string, :limit => 50
57
+ property :payment_email, :string
58
+ property :timestamps
59
+ add_index :email
60
+ add_index :payment_email
61
+ add_index :role_id
62
+
63
+ belongs_to :role
64
+ end
65
+
66
+ It will create the following schema:
67
+
68
+ create_table "users", :force => true do |t|
69
+ t.string :email, :limit => nil
70
+ t.string :password, :limit => nil
71
+ t.string :first_name, :limit => nil
72
+ t.string :last_name, :limit => nil
73
+ t.string :payment_email, :limit => nil
74
+ t.integer :role_id, :limit => nil
75
+ t.datetime :created_at
76
+ t.datetime :updated_at
77
+ end
78
+
79
+ add_index "users", :email
80
+ add_index "users", :payment_email
81
+ add_index "users", :role_id
82
+
83
+ #### property()
84
+
85
+ Use `property` to define and map DB columns. It accepts a number of arguments:
86
+
87
+ 1. Name of the column.
88
+ 2. SQL type of the column, same as the ones provided by ActiveRecord migrations.
89
+ 3. Column options, same as the ones provided by ActiveRecord migrations.
90
+
91
+ #### add_index()
92
+
93
+ Use `add_index` to add DB indexes. It accepts a number of arguments:
94
+
95
+ 1. The column(s) to index on, can be just one column or a number of columns in an array.
96
+ 3. Index options such as `name`, `unique` and `length`.
97
+
98
+ ### Rake Tasks
99
+
100
+ To set up your database for the first time, please run:
101
+
102
+ rake db:schema:update
103
+ rake db:setup
104
+
105
+ Later on, to only update the `schema.rb` file, run:
106
+
107
+ rake db:schema:update
108
+
109
+ To update `schema.rb` and to 'migrate' the updated database structure, run:
110
+
111
+ rake db:schema:auto_migrate
112
+
113
+ ## Author
114
+
115
+ Copyright (c) 2010 Fred Wu (<http://fredwu.me>), released under the MIT license
116
+
117
+ * Envato - <http://envato.com>
118
+ * Wuit - <http://wuit.com>
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |s|
6
+ s.name = "datamappify"
7
+ s.version = "0.1.0"
8
+ s.summary = "Turn ActiveRecord into DataMapper (sort of)!"
9
+ s.description = "ActiveRecord is without doubt the de facto ORM library for Rails and many Ruby web frameworks. Many developers however, do not like database migrations and prefer to use DSL for data mapping. Datamappify is created with the sole purpose of getting rid of the DB migration headaches."
10
+ s.email = "ifredwu@gmail.com"
11
+ s.homepage = "http://github.com/fredwu/datamappify"
12
+ s.authors = ["Fred Wu"]
13
+ s.add_dependency("activerecord")
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler not available. Install it with: gem install jeweler"
18
+ end
@@ -0,0 +1,53 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{datamappify}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Fred Wu"]
12
+ s.date = %q{2010-08-04}
13
+ s.description = %q{ActiveRecord is without doubt the de facto ORM library for Rails and many Ruby web frameworks. Many developers however, do not like database migrations and prefer to use DSL for data mapping. Datamappify is created with the sole purpose of getting rid of the DB migration headaches.}
14
+ s.email = %q{ifredwu@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "MIT-LICENSE",
21
+ "README.md",
22
+ "Rakefile",
23
+ "datamappify.gemspec",
24
+ "lib/datamappify.rb",
25
+ "lib/datamappify/associations.rb",
26
+ "lib/datamappify/collection.rb",
27
+ "lib/datamappify/fake/column.rb",
28
+ "lib/datamappify/fake/connection.rb",
29
+ "lib/datamappify/fake/index.rb",
30
+ "lib/datamappify/resource.rb",
31
+ "lib/datamappify/schema_dumper.rb",
32
+ "lib/tasks/datamappify.rake"
33
+ ]
34
+ s.homepage = %q{http://github.com/fredwu/datamappify}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.7}
38
+ s.summary = %q{Turn ActiveRecord into DataMapper (sort of)!}
39
+
40
+ if s.respond_to? :specification_version then
41
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
42
+ s.specification_version = 3
43
+
44
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
45
+ s.add_runtime_dependency(%q<activerecord>, [">= 0"])
46
+ else
47
+ s.add_dependency(%q<activerecord>, [">= 0"])
48
+ end
49
+ else
50
+ s.add_dependency(%q<activerecord>, [">= 0"])
51
+ end
52
+ end
53
+
@@ -0,0 +1,16 @@
1
+ raise "Please install the AutoMigrations plugin from http://github.com/pjhyett/auto_migrations" unless defined?(AutoMigrations.run)
2
+
3
+ require 'datamappify/associations'
4
+ require 'datamappify/collection'
5
+ require 'datamappify/fake/column'
6
+ require 'datamappify/fake/connection'
7
+ require 'datamappify/fake/index'
8
+ require 'datamappify/resource'
9
+ require 'datamappify/schema_dumper'
10
+
11
+ module Datamappify
12
+ def self.run
13
+ Datamappify::SchemaDumper.dump_to_file
14
+ AutoMigrations.run
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module Datamappify
2
+ module Associations
3
+ mattr_accessor :join_tables
4
+
5
+ @@join_tables = {}
6
+
7
+ module ClassMethods
8
+ def belongs_to(association_id, options = {})
9
+ super
10
+ foreign_key = options.include?(:foreign_key) ? options[:foreign_key] : association_id.to_s.foreign_key
11
+ property(foreign_key.to_sym, :integer)
12
+ end
13
+
14
+ def has_and_belongs_to_many(association_id, options = {}, &extension)
15
+ super
16
+ reflection = self.send :create_has_and_belongs_to_many_reflection, association_id, options
17
+ Associations.join_tables[reflection.options[:join_table]] = [reflection.association_foreign_key, reflection.primary_key_name]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,46 @@
1
+ module Datamappify
2
+ class Collection
3
+ def self.get
4
+ collection = []
5
+
6
+ Dir.glob(Rails.root.join('app', 'models', '**', '*.rb')).each do |file|
7
+ name = file[/.*\/(.*)\.rb/, 1]
8
+ klass = name.camelize.constantize
9
+
10
+ next unless klass.included_modules.include?(Datamappify::Resource) and klass.respond_to?(:properties)
11
+
12
+ collection << {
13
+ :name => name,
14
+ :table_name => klass.table_name,
15
+ :properties => klass.properties,
16
+ :indexes => klass.indexes,
17
+ }
18
+ end
19
+
20
+ Associations.join_tables.each do |table_name, ids|
21
+ collection << {
22
+ :name => table_name,
23
+ :table_name => table_name,
24
+ :properties => [{
25
+ :name => ids[0],
26
+ :sql_type => :integer,
27
+ :options => {},
28
+ }, {
29
+ :name => ids[1],
30
+ :sql_type => :integer,
31
+ :options => {},
32
+ }],
33
+ :indexes => [{
34
+ :columns => ids[0],
35
+ :options => {},
36
+ }, {
37
+ :columns => ids[1],
38
+ :options => {},
39
+ }],
40
+ }
41
+ end
42
+
43
+ collection
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ module Datamappify
2
+ module Fake
3
+ class Column < ActiveRecord::ConnectionAdapters::Column
4
+ def initialize(property)
5
+ allow_null = property[:options].include?(:null) ? property[:options][:null] : true
6
+
7
+ super(property[:name], property[:options][:default], property[:sql_type], allow_null)
8
+
9
+ @limit = property[:options][:limit]
10
+ @precision = property[:options][:precision]
11
+ @scale = property[:options][:scale]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,77 @@
1
+ module Datamappify
2
+ module Fake
3
+ class Connection
4
+ def columns(table)
5
+ @primary_key = "id"
6
+ resource = get_resource(table)
7
+ columns = []
8
+
9
+ # manually add the primary key property (without the :primary_key option)
10
+ # as ActiveRecord ignores the primary_key column
11
+ add_primary_key_to(resource) unless is_a_join_table?(table)
12
+
13
+ resource[:properties].map do |property|
14
+ if (property[:name] == :timestamps)
15
+ create_timestamps_for(resource)
16
+ else
17
+ columns << Column.new(property)
18
+ end
19
+ end
20
+
21
+ columns
22
+ end
23
+
24
+ def primary_key(table)
25
+ resource = get_resource(table)
26
+ primary_key_for(resource)
27
+ end
28
+
29
+ def indexes(table)
30
+ resource = get_resource(table)
31
+ resource[:indexes].map do |index|
32
+ Index.new(resource, index)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def get_resource(table)
39
+ Collection.get.select do |r|
40
+ r[:table_name].to_s == table.to_s
41
+ end[0]
42
+ end
43
+
44
+ def create_timestamps_for(resource)
45
+ resource[:properties] << {
46
+ :name => :created_at,
47
+ :sql_type => :datetime,
48
+ :options => {},
49
+ }
50
+ resource[:properties] << {
51
+ :name => :updated_at,
52
+ :sql_type => :datetime,
53
+ :options => {},
54
+ }
55
+ end
56
+
57
+ def primary_key_for(resource)
58
+ resource[:properties].select do |property|
59
+ return property[:name].to_s if property[:options][:primary_key]
60
+ end
61
+ "id"
62
+ end
63
+
64
+ def add_primary_key_to(resource)
65
+ resource[:properties] << {
66
+ :name => primary_key_for(resource),
67
+ :sql_type => :datetime,
68
+ :options => {},
69
+ }
70
+ end
71
+
72
+ def is_a_join_table?(table)
73
+ Associations.join_tables.key?(table)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,32 @@
1
+ module Datamappify
2
+ module Fake
3
+ class Index
4
+ include ActiveRecord::ConnectionAdapters::SchemaStatements
5
+
6
+ def initialize(resource, index)
7
+ @resource = resource
8
+ @index = index
9
+ end
10
+
11
+ def table
12
+ @resource[:table_name]
13
+ end
14
+
15
+ def name
16
+ @index[:options].include?(:name) ? @index[:options][:name].to_s : index_name(table, :column => @index[:columns])
17
+ end
18
+
19
+ def columns
20
+ @index[:columns]
21
+ end
22
+
23
+ def unique
24
+ @index[:options][:unique] if @index[:options].include?(:unique)
25
+ end
26
+
27
+ def lengths
28
+ @index[:options][:length] if @index[:options].include?(:length)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ module Datamappify
2
+ module Resource
3
+ def self.included(model)
4
+ model.send :cattr_accessor, :properties
5
+ model.send :cattr_accessor, :indexes
6
+
7
+ model.extend Resource::ClassMethods
8
+ model.extend Associations::ClassMethods
9
+ end
10
+
11
+ module ClassMethods
12
+ def self.extended(model)
13
+ @@model = model
14
+
15
+ @@model.properties = []
16
+ @@model.indexes = []
17
+ end
18
+
19
+ def property(name, sql_type=nil, options={})
20
+ @@model.properties << {
21
+ :name => name,
22
+ :sql_type => sql_type,
23
+ :options => options,
24
+ }
25
+ end
26
+
27
+ def add_index(columns, options={})
28
+ @@model.indexes << {
29
+ :columns => columns,
30
+ :options => options,
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ module Datamappify
2
+ class SchemaDumper < ActiveRecord::SchemaDumper
3
+ def self.dump_to_file
4
+ File.open(ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb", "w") do |file|
5
+ Datamappify::SchemaDumper.dump(ActiveRecord::Base.connection, file)
6
+ end
7
+ end
8
+
9
+ def initialize(connection)
10
+ super(connection)
11
+ @connection = Datamappify::Fake::Connection.new
12
+ end
13
+
14
+ def tables(stream)
15
+ Datamappify::Collection.get.each do |entry|
16
+ tbl = entry[:table_name] or entry[:resource].pluralize
17
+ table(tbl, stream)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ namespace :db do
2
+ namespace :schema do
3
+ desc "Update schema.rb with Datamappfiy"
4
+ task :update => :environment do
5
+ Datamappify::SchemaDumper.dump_to_file
6
+ Rake::Task["db:schema:update"].reenable
7
+ end
8
+
9
+ desc "Auto-migrate via schema.rb"
10
+ task :auto_migrate => :environment do
11
+ Rake::Task["db:schema:update"].invoke
12
+ Rake::Task["db:auto:migrate"].invoke
13
+ end
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: datamappify
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Fred Wu
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-08-04 00:00:00 +10:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activerecord
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ description: ActiveRecord is without doubt the de facto ORM library for Rails and many Ruby web frameworks. Many developers however, do not like database migrations and prefer to use DSL for data mapping. Datamappify is created with the sole purpose of getting rid of the DB migration headaches.
34
+ email: ifredwu@gmail.com
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files:
40
+ - README.md
41
+ files:
42
+ - .gitignore
43
+ - MIT-LICENSE
44
+ - README.md
45
+ - Rakefile
46
+ - datamappify.gemspec
47
+ - lib/datamappify.rb
48
+ - lib/datamappify/associations.rb
49
+ - lib/datamappify/collection.rb
50
+ - lib/datamappify/fake/column.rb
51
+ - lib/datamappify/fake/connection.rb
52
+ - lib/datamappify/fake/index.rb
53
+ - lib/datamappify/resource.rb
54
+ - lib/datamappify/schema_dumper.rb
55
+ - lib/tasks/datamappify.rake
56
+ has_rdoc: true
57
+ homepage: http://github.com/fredwu/datamappify
58
+ licenses: []
59
+
60
+ post_install_message:
61
+ rdoc_options:
62
+ - --charset=UTF-8
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.7
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Turn ActiveRecord into DataMapper (sort of)!
88
+ test_files: []
89
+