rmap 0.3.0 → 0.4.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/Gemfile CHANGED
@@ -7,3 +7,5 @@ gem 'mysql2', "~> 0"
7
7
  gem 'json', "~> 1"
8
8
  gem 'ripl', "~> 0"
9
9
  gem 'ripl-multi_line', "~> 0"
10
+ gem 'powerline', "~> 0"
11
+ gem 'gengin', "~> 0"
data/bin/rmap CHANGED
@@ -1,18 +1,5 @@
1
1
 
2
2
  require 'rmap'
3
- require 'ripl'
4
- require 'ripl/multi_line'
5
-
6
- db = Rmap::Database.new
7
-
8
- current = Dir::getwd
9
- while current != '/'
10
- if ::File.file? "#{current}/conf.rmap.rb"
11
- db.run("#{current}/conf.rmap.rb")
12
- break
13
- end
14
- current = ::File.expand_path('../', current)
15
- end
16
-
17
- Ripl.start :binding => db.bindings
3
+ require 'powerline'
18
4
 
5
+ Powerline.new Rmap::Commands
@@ -1,10 +1,20 @@
1
1
 
2
- require 'mysql2'
2
+
3
+ module Rmap
4
+ current = Dir::getwd
5
+ while current != '/'
6
+ if ::File.file? "#{current}/conf.rmap.rb"
7
+ CONF_ROOT = current
8
+ break
9
+ end
10
+ current = ::File.expand_path('../', current)
11
+ end
12
+ end
3
13
 
4
14
  require 'rmap/version'
5
15
  require 'rmap/database'
6
16
  require 'rmap/table'
7
17
  require 'rmap/row'
18
+ require 'rmap/migration'
19
+ require 'rmap/commands'
8
20
 
9
- module Rmap
10
- end
@@ -0,0 +1,169 @@
1
+
2
+ require 'ripl'
3
+ require 'ripl/multi_line'
4
+ require 'gengin'
5
+
6
+ module Rmap
7
+ module Commands
8
+
9
+ def self.console
10
+ db = Rmap::Database.new
11
+
12
+ if Rmap.const_defined? :CONF_ROOT
13
+ db.run("#{Rmap::CONF_ROOT}/conf.rmap.rb")
14
+ end
15
+
16
+ Ripl.start :binding => db.bindings
17
+ end
18
+
19
+ def self.current_migration(options)
20
+ if !db.table? :rmap_vars
21
+ db.create :rmap_vars
22
+ db.rmap_vars.add :key, :string
23
+ db.rmap_vars.add :value, :binary
24
+ end
25
+
26
+ if db.rmap_vars.key_eq(:current_migration).count == 0
27
+ db.rmap_vars.insert(:key => :current_migration, :value => 0)
28
+ current_migration = 0
29
+ else
30
+ current_migration = db.rmap_vars.key_eq(:current_migration).first.value.to_i
31
+ end
32
+
33
+ if options[:echo] != false
34
+ puts current_migration
35
+ end
36
+
37
+ current_migration
38
+ end
39
+
40
+ module Generate
41
+
42
+ def self.conf(database, options={})
43
+ Gengin.new do
44
+ source_root File.expand_path("../generator_templates/", __FILE__)
45
+ @database = database
46
+ copy "conf.rmap.rb", :erb => true
47
+ end
48
+ end
49
+
50
+ def self.migration(name, *columns, options)
51
+ if !Rmap.const_defined? :CONF_ROOT
52
+ raise "Could not find a conf.rmap.rb file in your path."
53
+ end
54
+
55
+ Gengin.new do
56
+ source_root File.expand_path("../generator_templates/", __FILE__)
57
+ destination_root "#{Rmap::CONF_ROOT}/migrations"
58
+ @name = name
59
+ @columns = columns
60
+
61
+ up_code_buf = []
62
+ down_code_buf = []
63
+
64
+ if name.match(/\Aadd_.*_to_(.*?)\Z/)
65
+ table_name = $1
66
+ @columns.each do |column|
67
+ (column_name, type) = column.split(/:/)
68
+ up_code_buf << " #{table_name}.add :#{column_name}, :#{type}"
69
+ down_code_buf << " #{table_name}.remove :#{column_name}"
70
+ end
71
+ end
72
+
73
+ if name.match(/\Aremove_.*_from_(.*?)\Z/)
74
+ table_name = $1
75
+ @columns.each do |column|
76
+ (column_name, type) = column.split(/:/)
77
+ up_code_buf << " #{table_name}.remove :#{column_name}"
78
+ down_code_buf << " #{table_name}.add :#{column_name}, :#{type}"
79
+ end
80
+ end
81
+
82
+ @up_code = up_code_buf.join("\n")
83
+ @down_code = down_code_buf.join("\n")
84
+
85
+ copy "migration.rmap.rb", "#{Time.new.to_i}_#{name.downcase.strip.gsub(/\W+/, "_")}.migration.rmap.rb", :erb => true
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+
93
+
94
+ def self.migrate(options = {})
95
+ db = Rmap::Commands::db
96
+
97
+ current_migration = Rmap::Commands::current_migration(:echo => false)
98
+
99
+ migrations = Dir.new("#{Rmap::CONF_ROOT}/migrations/").to_a.find_all{|file| ::File.file? "#{Rmap::CONF_ROOT}/migrations/#{file}" }.map{ |file| Rmap::Migration.new("#{Rmap::CONF_ROOT}/migrations/#{file}") }.sort {|l,r| l.schema_version <=> r.schema_version}
100
+
101
+ if !options[:to].nil?
102
+ to = options[:to].to_i
103
+ found = false
104
+ migrations.each do |migration|
105
+ if migration.schema_version == to
106
+ found = true
107
+ break
108
+ end
109
+ end
110
+
111
+ if !found
112
+ raise "No such migration '#{to}' exists"
113
+ end
114
+
115
+ if to > current_migration
116
+ migrations.each do |migration|
117
+ if migration.schema_version <= current_migration
118
+ next
119
+ end
120
+
121
+ if migration.schema_version <= to
122
+ puts "up: #{migration.schema_version}"
123
+ db.run &migration.up_block
124
+ else
125
+ break
126
+ end
127
+ end
128
+ db.rmap_vars.key_eq(:current_migration).value = to.to_s
129
+ elsif to < current_migration
130
+ migrations.reverse.each do |migration|
131
+ if migration.schema_version > current_migration
132
+ next
133
+ end
134
+ if migration.schema_version > to
135
+ puts "down: #{migration.schema_version}"
136
+ db.run &migration.down_block
137
+ else
138
+ break
139
+ end
140
+ end
141
+ db.rmap_vars.key_eq(:current_migration).value = to
142
+ else
143
+ raise "already at migration #{to}"
144
+ end
145
+
146
+ elsif migrations.count > 0
147
+ migrations.each do |migration|
148
+ if migration.schema_version > current_migration
149
+ puts "up: #{migration.schema_version}"
150
+ db.run &migration.up_block
151
+ end
152
+ end
153
+ db.rmap_vars.key_eq(:current_migration).value = migrations.last.schema_version
154
+ end
155
+
156
+ end
157
+
158
+ private
159
+
160
+ def self.db
161
+ db = Rmap::Database.new
162
+ if Rmap.const_defined? :CONF_ROOT
163
+ db.run("#{Rmap::CONF_ROOT}/conf.rmap.rb")
164
+ end
165
+ db
166
+ end
167
+
168
+ end
169
+ end
@@ -1,43 +1,35 @@
1
1
 
2
+ require 'mysql2'
3
+
2
4
  module Rmap
3
5
  class Database
4
6
 
5
- def initialize(conf={:username => 'root'}, &block)
6
- @conf = conf
7
+ def initialize(connection={}, &block)
8
+ self.connection = connection
7
9
  if !block.nil?
8
10
  instance_eval(&block)
9
11
  end
12
+ @scopes = {}
13
+ end
14
+
15
+ def connection=(connection)
16
+ @connection = {:host => "localhost", :username => "root", :password => ""}.merge connection
17
+ close
18
+ @table_names = nil
10
19
  end
11
20
 
12
21
  def client
13
22
  if @client.nil?
14
- @client = Mysql2::Client.new(@conf)
23
+ @client = Mysql2::Client.new(@connection)
15
24
  end
16
25
  @client
17
26
  end
18
27
 
19
- def host(host)
20
- @client = nil
21
- @table_names = nil
22
- @conf[:host] = host
23
- end
24
-
25
- def username(username)
26
- @client = nil
27
- @table_names = nil
28
- @conf[:username] = username
29
- end
30
-
31
- def password(password)
32
- @client = nil
33
- @table_names = nil
34
- @conf[:password] = password
35
- end
36
-
37
- def database(database)
28
+ def close
29
+ if !@client.nil?
30
+ @client.close
31
+ end
38
32
  @client = nil
39
- @table_names = nil
40
- @conf[:database] = database
41
33
  end
42
34
 
43
35
  def bindings
@@ -58,16 +50,12 @@ module Rmap
58
50
  end
59
51
 
60
52
  def method_missing name, *args
61
- if table_names.include? name.to_s
62
- Table.new(self, name)
63
- else
64
- super(name, *args)
65
- end
53
+ Table.new(self, name)
66
54
  end
67
55
 
68
56
  def create(name)
69
57
  @table_names = nil
70
- client.query("create table `#{name}`(id int unsigned not null auto_increment primary key)")
58
+ client.query("create table `#{name}`(id int unsigned not null auto_increment primary key) engine = InnoDB")
71
59
  end
72
60
 
73
61
  def table_names
@@ -77,5 +65,17 @@ module Rmap
77
65
  @table_names
78
66
  end
79
67
 
68
+ def start_transaction
69
+ client.query("start transaction")
70
+ end
71
+
72
+ def commit_transaction
73
+ client.query("commit")
74
+ end
75
+
76
+ def rollback_transaction
77
+ client.query("rollback")
78
+ end
79
+
80
80
  end
81
81
  end
@@ -0,0 +1,5 @@
1
+
2
+ #host "localhost"
3
+ #username "root"
4
+ #password ""
5
+ database "<%= @database %>"
@@ -0,0 +1,8 @@
1
+
2
+ up do
3
+ <%= @up_code %>
4
+ end
5
+
6
+ down do
7
+ <%= @down_code %>
8
+ end
@@ -0,0 +1,21 @@
1
+
2
+ module Rmap
3
+ class Migration
4
+
5
+ attr_accessor :schema_version, :up_block, :down_block
6
+
7
+ def initialize(file_path)
8
+ @schema_version = file_path.sub(/\A.*?(\d+)[^\/]*\Z/, "\\1").to_i
9
+ instance_eval(::File.open(file_path).read, file_path)
10
+ end
11
+
12
+ def up(&block)
13
+ @up_block = block
14
+ end
15
+
16
+ def down(&block)
17
+ @down_block = block
18
+ end
19
+
20
+ end
21
+ end
@@ -17,7 +17,7 @@ module Rmap
17
17
  end
18
18
 
19
19
  def update(hash)
20
- @database.client.query("update `#{@table_name}` set #{(hash.map{|k,v| "`#{k}`='#{@database.client.escape(v)}'"}).join(', ')} where id = '#{id}'")
20
+ @database.client.query("update `#{@table_name}` set #{(hash.map{|k,v| "`#{k}`='#{@database.client.escape(v.to_s)}'"}).join(', ')} where id = '#{id}'")
21
21
  end
22
22
 
23
23
  def delete
@@ -36,8 +36,12 @@ module Rmap
36
36
  end
37
37
  end
38
38
 
39
+ def to_hash
40
+ @database.client.query("select * from `#{@table_name}` where id = '#{id}'", :as => :hash).first
41
+ end
42
+
39
43
  def to_s
40
- @database.client.query("select * from `#{@table_name}` where id = '#{id}'", :as => :hash).first.to_json
44
+ to_hash.to_json
41
45
  end
42
46
 
43
47
  end
@@ -9,8 +9,8 @@ module Rmap
9
9
  'le' => lambda {|left,right| "#{left} <= #{right}"},
10
10
  'ge' => lambda {|left,right| "#{left} >= #{right}"},
11
11
  'contains' => lambda {|left,right| "#{left} like concat('%', #{right}, '%')"},
12
- 'begins_with' => lambda {|left,right| "#{left} like concat('%', #{right})"},
13
- 'ends_with' => lambda {|left,right| "#{left} like concat(#{right}, '%')"},
12
+ 'ends_with' => lambda {|left,right| "#{left} like concat('%', #{right})"},
13
+ 'begins_with' => lambda {|left,right| "#{left} like concat(#{right}, '%')"},
14
14
  'year_eq' => lambda {|left,right| "year(#{left}) = #{right}"},
15
15
  'year_ne' => lambda {|left,right| "year(#{left}) != #{right}"},
16
16
  'year_lt' => lambda {|left,right| "year(#{left}) < #{right}"},
@@ -82,6 +82,7 @@ module Rmap
82
82
  end
83
83
 
84
84
  def method_missing name, *args
85
+ table = self
85
86
  if @database.table? name
86
87
  Table.new(@database, name).join(self, *args)
87
88
  elsif column? name
@@ -91,6 +92,9 @@ module Rmap
91
92
  elsif name.match /\A(.*?)_(#{BINARY_FILTER_METHODS.keys.join('|')})\Z/
92
93
  @binary_filter_methods_args[$2].push([$1.split(/_or_/),args[0]])
93
94
  self
95
+ elsif @database.instance_eval{!@scopes[table.name].nil? && !@scopes[table.name][name].nil?}
96
+ instance_exec *args, &@database.instance_eval{@scopes[table.name][name]}
97
+ self
94
98
  else
95
99
  super
96
100
  end
@@ -172,7 +176,7 @@ module Rmap
172
176
  end
173
177
  else
174
178
  if table2.column? "#{to_singular(table1.name)}_id"
175
- "#{table1.name}.id = #{to_singular(table2.name)}.#{table1.name}_id"
179
+ "#{table1.name}.id = #{table2.name}.#{to_singular(table1.name)}_id"
176
180
  else
177
181
  "#{table1.name}.#{to_singular(table2.name)}_id = #{table2.name}.id"
178
182
  end
@@ -237,22 +241,38 @@ module Rmap
237
241
  out
238
242
  end
239
243
 
240
- def generate_select_sql(expression_list_sql, limit = nil)
241
- if !limit.nil?
242
- limit_sql = "limit #{limit}"
244
+ def generate_limit_sql
245
+ if !@limit_row_count.nil?
246
+ "limit #{@limit_offset}, #{@limit_row_count}"
243
247
  else
244
- limit_sql = ''
248
+ ""
245
249
  end
246
- "select #{format_sql(expression_list_sql)} #{generate_from_sql} #{generate_where_sql} #{generate_group_by_sql} #{generate_order_by_sql} #{limit_sql}"
247
250
  end
248
251
 
249
- def count(limit = nil)
250
- @database.client.query(generate_select_sql('id', limit)).count
252
+ def generate_select_sql(expression_list_sql, without_limit_sql = false)
253
+ "select #{format_sql(expression_list_sql)} #{generate_from_sql} #{generate_where_sql} #{generate_group_by_sql} #{generate_order_by_sql} #{without_limit_sql ? "" : generate_limit_sql}"
254
+ end
255
+
256
+ def explain
257
+ generate_select_sql('id').strip
258
+ end
259
+
260
+ def count
261
+ @database.client.query(generate_select_sql('id')).count
262
+ end
263
+
264
+ def page_count
265
+ count_without_limit = @database.client.query(generate_select_sql('id', true)).count
266
+ if count_without_limit > 0
267
+ @page_size.nil? ? 1 : (count_with_limit.to_f / @page_size).ceil
268
+ else
269
+ 0
270
+ end
251
271
  end
252
272
 
253
- def all(limit = nil)
273
+ def all
254
274
  out = []
255
- @database.client.query(generate_select_sql('id', limit), :as => :hash).each do |row|
275
+ @database.client.query(generate_select_sql('id'), :as => :hash).each do |row|
256
276
  out.push(Row.new(@database, @name, row['id']))
257
277
  end
258
278
  out
@@ -264,7 +284,7 @@ module Rmap
264
284
  end
265
285
 
266
286
  def first
267
- all(1).first
287
+ all.first
268
288
  end
269
289
 
270
290
  def update(hash)
@@ -277,11 +297,12 @@ module Rmap
277
297
 
278
298
  def insert(hash)
279
299
  @database.client.query("insert into `#{@name}`(#{(hash.map{|k,v| "`#{k}`"}).join(', ')}) values(#{(hash.map{|k,v| quote(v)}).join(', ')})")
300
+ @database.client.last_id
280
301
  end
281
302
 
282
- def sum(sql_expression, limit = nil)
303
+ def sum(sql_expression)
283
304
  out = 0
284
- @database.client.query(generate_select_sql("sum(#{sql_expression})", limit), :as => :array).each{|row| out += row.first}
305
+ @database.client.query(generate_select_sql("sum(#{sql_expression})"), :as => :array).each{|row| out += row.first}
285
306
  out
286
307
  end
287
308
 
@@ -291,6 +312,11 @@ module Rmap
291
312
  end
292
313
 
293
314
  def add(name, type, options = {})
315
+
316
+ if !@database.table? @name
317
+ @database.create @name
318
+ end
319
+
294
320
  case type
295
321
  when :string
296
322
  @database.client.query("alter table `#{@name}` add `#{name}` varchar(255) not null")
@@ -326,6 +352,22 @@ module Rmap
326
352
  all.to_s
327
353
  end
328
354
 
355
+ def define_scope(name, &block)
356
+ table = self
357
+ @database.instance_eval do
358
+ if @scopes[table.name].nil?
359
+ @scopes[table.name] = {}
360
+ end
361
+ @scopes[table.name][name.to_sym] = block
362
+ end
363
+ end
364
+
365
+ def paginate(page, page_size = 10)
366
+ @limit_row_count = page_size
367
+ @limit_offset = (page - 1) * page_size
368
+ self
369
+ end
370
+
329
371
  private
330
372
 
331
373
  def to_singular(value)
@@ -1,3 +1,3 @@
1
1
  module Rmap
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -21,5 +21,7 @@ Gem::Specification.new do |s|
21
21
  s.add_dependency "json", "~> 1"
22
22
  s.add_dependency "ripl", "~> 0"
23
23
  s.add_dependency "ripl-multi_line", "~> 0"
24
+ s.add_dependency "powerline", "~> 0"
25
+ s.add_dependency "gengin", "~> 0"
24
26
 
25
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-14 00:00:00.000000000Z
12
+ date: 2012-08-16 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mysql2
16
- requirement: &82061450 !ruby/object:Gem::Requirement
16
+ requirement: &83687640 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *82061450
24
+ version_requirements: *83687640
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: json
27
- requirement: &82061200 !ruby/object:Gem::Requirement
27
+ requirement: &83684760 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '1'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *82061200
35
+ version_requirements: *83684760
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: ripl
38
- requirement: &82060970 !ruby/object:Gem::Requirement
38
+ requirement: &83684030 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *82060970
46
+ version_requirements: *83684030
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: ripl-multi_line
49
- requirement: &82060740 !ruby/object:Gem::Requirement
49
+ requirement: &83683360 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,7 +54,29 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *82060740
57
+ version_requirements: *83683360
58
+ - !ruby/object:Gem::Dependency
59
+ name: powerline
60
+ requirement: &83682550 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *83682550
69
+ - !ruby/object:Gem::Dependency
70
+ name: gengin
71
+ requirement: &83681920 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *83681920
58
80
  description:
59
81
  email:
60
82
  - jody@jodysalt.com
@@ -69,7 +91,11 @@ files:
69
91
  - Rakefile
70
92
  - bin/rmap
71
93
  - lib/rmap.rb
94
+ - lib/rmap/commands.rb
72
95
  - lib/rmap/database.rb
96
+ - lib/rmap/generator_templates/conf.rmap.rb
97
+ - lib/rmap/generator_templates/migration.rmap.rb
98
+ - lib/rmap/migration.rb
73
99
  - lib/rmap/row.rb
74
100
  - lib/rmap/table.rb
75
101
  - lib/rmap/version.rb