momomoto 0.1.13 → 0.1.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/Rakefile +15 -0
  2. data/lib/momomoto/base.rb +77 -12
  3. data/lib/momomoto/database.rb +16 -4
  4. data/lib/momomoto/datatype/base.rb +49 -8
  5. data/lib/momomoto/datatype/bigint.rb +2 -1
  6. data/lib/momomoto/datatype/boolean.rb +9 -0
  7. data/lib/momomoto/datatype/bytea.rb +4 -0
  8. data/lib/momomoto/datatype/character.rb +2 -0
  9. data/lib/momomoto/datatype/character_varying.rb +2 -0
  10. data/lib/momomoto/datatype/date.rb +5 -0
  11. data/lib/momomoto/datatype/inet.rb +4 -0
  12. data/lib/momomoto/datatype/integer.rb +5 -0
  13. data/lib/momomoto/datatype/interval.rb +14 -1
  14. data/lib/momomoto/datatype/numeric.rb +5 -0
  15. data/lib/momomoto/datatype/real.rb +2 -0
  16. data/lib/momomoto/datatype/smallint.rb +2 -0
  17. data/lib/momomoto/datatype/text.rb +14 -0
  18. data/lib/momomoto/datatype/time_with_time_zone.rb +3 -1
  19. data/lib/momomoto/datatype/time_without_time_zone.rb +10 -0
  20. data/lib/momomoto/datatype/timestamp_with_time_zone.rb +2 -0
  21. data/lib/momomoto/datatype/timestamp_without_time_zone.rb +5 -0
  22. data/lib/momomoto/information_schema/columns.rb +8 -0
  23. data/lib/momomoto/information_schema/fetch_procedure_columns.rb +2 -0
  24. data/lib/momomoto/information_schema/fetch_procedure_parameters.rb +2 -0
  25. data/lib/momomoto/information_schema/key_column_usage.rb +5 -0
  26. data/lib/momomoto/information_schema/routines.rb +4 -0
  27. data/lib/momomoto/information_schema/table_constraints.rb +5 -0
  28. data/lib/momomoto/order.rb +61 -0
  29. data/lib/momomoto/procedure.rb +14 -14
  30. data/lib/momomoto/row.rb +41 -4
  31. data/lib/momomoto/table.rb +106 -20
  32. data/lib/timeinterval.rb +90 -16
  33. data/test/test_datatype.rb +1 -1
  34. metadata +2 -2
data/Rakefile CHANGED
@@ -28,11 +28,26 @@ begin
28
28
  rescue LoadError
29
29
  end
30
30
 
31
+ desc "check documentation coverage"
32
+ task :dcov do
33
+ sh "find lib -name '*.rb' | xargs dcov"
34
+ end
35
+
31
36
  desc "create documentation for ri"
32
37
  task :doc do
33
38
  sh "rdoc -r lib"
34
39
  end
35
40
 
41
+ desc "create html documentation"
42
+ task :html do
43
+ sh "rdoc --template jamis --main Momomoto::Table --inline-source --force-update --webcvs 'http://trac.c3d2.de/momomoto/browser/trunk/%s' lib"
44
+ end
45
+
46
+ desc "update html documentation on momomoto.rubyforge.org"
47
+ task :update_html do
48
+ sh "scp -r doc rubyforge:/var/www/gforge-projects/momomoto"
49
+ end
50
+
36
51
  desc "run benchmark"
37
52
  task( :bench ) do | t |
38
53
  sh "ruby benchmark.rb"
data/lib/momomoto/base.rb CHANGED
@@ -4,30 +4,70 @@ module Momomoto
4
4
 
5
5
  class << self
6
6
 
7
+ # Getter and setter for debugging.
8
+ # If +debug+ evaluates to +true+ then all SQL queries to the database
9
+ # are printed to STDOUT.
7
10
  attr_accessor :debug
8
11
 
12
+ # Returns an instance of Order::Lower where +args+ is either a single
13
+ # or array of +Symbol+ representing columns.
14
+ #
15
+ # Eases the use of class Order::Lower. You can use it whenever selecting
16
+ # rows or in #default_order.
17
+ #
18
+ # order_lower = Momomoto.lower( :person )
19
+ # => #<Momomoto::Order::Lower:0x5184131c @fields=[:person]>
20
+ # Table.select( {}, {:order => order} )
21
+ # => returns Table's rows ordered case-insensitively by column person
9
22
  def lower( *args )
10
23
  Momomoto::Order::Lower.new( *args )
11
24
  end
12
25
 
26
+ # Returns an instance of Order::Asc where +args+ is either a single
27
+ # or array of +Symbol+ representing columns.
28
+ #
29
+ # Eases the use of class Order::Asc. You can use it whenever selecting
30
+ # rows or in #default_order.
31
+ #
32
+ # order_lower = Momomoto.asc( :person )
33
+ # => #<Momomoto::Order::Asc:0x5184131c @fields=[:person]>
34
+ # Table.select( {}, {:order => order} )
35
+ # => returns Table's rows ordered asc by column person
13
36
  def asc( *args )
14
37
  Momomoto::Order::Asc.new( *args )
15
38
  end
16
39
 
40
+ # Returns an instance of Order::Asc where +args+ is either a single
41
+ # or array of +Symbol+ representing columns.
42
+ #
43
+ # Eases the use of class Order::Desc. You can use it whenever selecting
44
+ # rows or in #default_order.
45
+ #
46
+ # order_lower = Momomoto.lower( :person )
47
+ # => #<Momomoto::Order::Desc:0x5184131c @fields=[:person]>
48
+ # Table.select( {}, {:order => order} )
49
+ # => returns Table's rows ordered desc by column person
17
50
  def desc( *args )
18
51
  Momomoto::Order::Desc.new( *args )
19
52
  end
20
53
 
21
54
  end
22
55
 
23
- ## base exception for all exceptions thrown by Momomoto
56
+ # Base exception for all exceptions thrown by Momomoto
24
57
  class Error < StandardError; end
25
58
 
26
- # thrown when datatype conversion fails
59
+ # Thrown when datatype conversion fails and if a +block+ given to
60
+ # Table#select_or_new does not act on all primary keys.
27
61
  class ConversionError < Error; end
28
- class CriticalError < Error; end
29
62
 
63
+ # Thrown when a critical error occurs.
64
+ class CriticalError < Error; end
65
+
66
+ # Thrown when multiple values are found in Table#select_or_new or
67
+ # Table#select_single.
30
68
  class Too_many_records < Error; end
69
+
70
+ # Thrown when no row was found in Table#select_single.
31
71
  class Nothing_found < Error; end
32
72
 
33
73
 
@@ -36,9 +76,13 @@ module Momomoto
36
76
 
37
77
  class << self
38
78
 
79
+ # Getter for logical operator. This is used in #compile_where.
80
+ # See Table#select for usage of logical operators.
39
81
  attr_reader :logical_operator
40
82
 
41
- # set the default logical operator for constraints
83
+ # Set the default logical operator for constraints. AND and OR are
84
+ # supported.
85
+ # See Table#select for usage of logical operators.
42
86
  def logical_operator=( value )
43
87
  @logical_operator = case value
44
88
  when /and/i then "AND"
@@ -47,12 +91,14 @@ module Momomoto
47
91
  end
48
92
  end
49
93
 
50
- # set the schema name of the table this class operates on
94
+ # Set the schema name of the table this class operates on.
51
95
  def schema_name=( schema_name )
52
96
  @schema_name = schema_name
53
97
  end
54
98
 
55
- # get the schema name of the table this class operates on
99
+ # Get the schema name of the table this class operates on. Invokes
100
+ # #schema_name= if +schema_name+ is given as parameter. Returns
101
+ # +@schema_name+
56
102
  def schema_name( schema_name = nil )
57
103
  return self.schema_name=( schema_name ) if schema_name
58
104
  if not instance_variable_defined?( :@schema_name )
@@ -63,9 +109,10 @@ module Momomoto
63
109
 
64
110
  protected
65
111
 
112
+ # Getter and setter used for marking tables as initialized.
66
113
  attr_accessor :initialized
67
114
 
68
- # guesses the schema name of the table this class works on
115
+ # Guesses the schema name of the table this class works on.
69
116
  def construct_schema_name( classname )
70
117
  # Uncomment these lines to derive the schema from the enclosing namespace of the class
71
118
  #schema = classname.split('::')[-2]
@@ -73,7 +120,7 @@ module Momomoto
73
120
  'public'
74
121
  end
75
122
 
76
- # get the database connection
123
+ # Get the database connection.
77
124
  def database # :nodoc:
78
125
  Momomoto::Database.instance
79
126
  end
@@ -85,6 +132,7 @@ module Momomoto
85
132
  where.empty? ? '' : " WHERE #{where}"
86
133
  end
87
134
 
135
+ # compiles subexpressions of the where-clause
88
136
  def compile_expression( conditions, operator )
89
137
  where = []
90
138
  case conditions
@@ -110,7 +158,10 @@ module Momomoto
110
158
  end
111
159
 
112
160
 
113
- # compiles the sql statement defining the limit
161
+ # Compiles the sql statement defining the limit
162
+ #
163
+ # #selects five feeds
164
+ # five_feeds = Feeds.select( {},{:limit => 5} )
114
165
  def compile_limit( limit )
115
166
  " LIMIT #{Integer(limit)}"
116
167
  rescue => e
@@ -118,6 +169,9 @@ module Momomoto
118
169
  end
119
170
 
120
171
  # compiles the sql statement defining the offset
172
+ #
173
+ # #selects five feeds ommitting the first 23 rows
174
+ # five_feeds = Feeds.select( {}, {:offset => 23, :limit => 5} )
121
175
  def compile_offset( offset )
122
176
  " OFFSET #{Integer(offset)}"
123
177
  rescue => e
@@ -140,7 +194,18 @@ module Momomoto
140
194
  " ORDER BY #{order.join(',')}"
141
195
  end
142
196
 
143
- # construct the Row class for the table
197
+ # Constructs the Row class for the given table or procedure +table+.
198
+ # If +columns+ is given as parameter to this method all setter and getter
199
+ # for the fields which are not included in columns will be removed.
200
+ #
201
+ # See Table#select for how this can be useful when only some columns are
202
+ # needed.
203
+ #
204
+ # module Methods can be used to modify setter and getter methods for columns.
205
+ # Methods is included to the row class after StandardMethods which holds all
206
+ # default accessors. That's why you can define your own accessors in Methods.
207
+ #
208
+ # See Row#set_column and Row#get_column for more information on this.
144
209
  def initialize_row( row, table, columns = table.columns )
145
210
 
146
211
  const_set( :Methods, Module.new ) if not const_defined?( :Methods )
@@ -173,8 +238,8 @@ module Momomoto
173
238
 
174
239
  end
175
240
 
176
- # defines row setter and getter in the module StandardMethods which
177
- # is later included in the Row class
241
+ # Defines row setter and getter in the module StandardMethods which
242
+ # is later included in the Row class.
178
243
  def define_row_accessors( method_module, table, columns )
179
244
  columns.each_with_index do | ( field_name, data_type ), index |
180
245
  method_module.instance_eval do
@@ -36,6 +36,7 @@ module Momomoto
36
36
  @config = config
37
37
  end
38
38
 
39
+ # Eases the use of #config.
39
40
  def self.config( conf )
40
41
  instance.config( conf )
41
42
  end
@@ -45,6 +46,10 @@ module Momomoto
45
46
  @connection = nil
46
47
  end
47
48
 
49
+ # Connects to database
50
+ # Momomoto::Database.config( :database=>:test, :username => 'test' )
51
+ # Momomoto::Database.connect
52
+ # # configure and connect
48
53
  def connect
49
54
  @connection.close if @connection
50
55
  @transaction_active = false
@@ -56,6 +61,11 @@ module Momomoto
56
61
  raise CriticalError, "Connection to database failed: #{e}"
57
62
  end
58
63
 
64
+ # Eases the use of #connect.
65
+ #
66
+ # Momomoto::Database.config( :database=>:test, :username => 'test' )
67
+ # Momomoto::Database.connect
68
+ # # configure and connect
59
69
  def self.connect
60
70
  instance.connect
61
71
  end
@@ -115,7 +125,7 @@ module Momomoto
115
125
  columns
116
126
  end
117
127
 
118
- # fetches the parameter of a stored procedure
128
+ # fetches parameters of a stored procedure
119
129
  def fetch_procedure_parameters( procedure_name, schema_name = nil ) # :nodoc:
120
130
  p = []
121
131
  conditions = { :procedure_name => procedure_name }
@@ -125,14 +135,14 @@ module Momomoto
125
135
  end
126
136
  # mark parameters of strict procedures as not null
127
137
  if Information_schema::Routines.select_single(:routine_name=>procedure_name).is_null_call == 'YES'
128
- p.each do | param |
129
- param[param.keys.first].instance_variable_set(:@not_null,true)
138
+ p.each do | param |
139
+ param[param.keys.first].instance_variable_set(:@not_null,true)
130
140
  end
131
141
  end
132
142
  p
133
143
  end
134
144
 
135
- # fetches the resultset columns of a stored procedure
145
+ # fetches the result set columns of a stored procedure
136
146
  def fetch_procedure_columns( procedure_name, schema_name = nil ) # :nodoc:
137
147
  c = {}
138
148
  conditions = { :procedure_name => procedure_name }
@@ -177,10 +187,12 @@ module Momomoto
177
187
  @transaction_active = false
178
188
  end
179
189
 
190
+ # escapes the given string +input+
180
191
  def self.escape_string( input )
181
192
  PGconn.escape( input )
182
193
  end
183
194
 
195
+ # escapes the given binary data +input+
184
196
  def self.escape_bytea( input )
185
197
  PGconn.escape_bytea( input )
186
198
  end
@@ -1,39 +1,61 @@
1
1
 
2
2
  module Momomoto
3
3
 
4
+ # This module encapsulates all supported data types, i.e.:
5
+ # Numeric, Integer, Bigint, Smallint, Real,
6
+ # Timestamp_with_time_zone, Timestamp_without_time_zone,
7
+ # Time_with_time_zone, Time_without_time_zone, Date, Interval,
8
+ # Character, Character_varying, Bytea, Text, Inet and Boolean.
9
+ #
10
+ # Refer to http://www.postgresql.org/docs/8.2/static/datatype.html
11
+ # for more information on the specific data types.
4
12
  module Datatype
5
- # base class for all datatypes
13
+
14
+ # Every data type class (see #Datatype) is derived from this class.
6
15
  class Base
7
- # get the default value for this column
8
- # returns false if none exists
16
+
17
+ # Gets the default value for this column or returns nil if none
18
+ # exists.
9
19
  def default
10
20
  @default
11
21
  end
12
22
 
13
- # is this column a not null column
23
+ # Returns true if this column can be NULL otherwise false.
14
24
  def not_null?
15
25
  @not_null
16
26
  end
17
27
 
28
+ # Creates a new instance of the special data type, setting +not_null+
29
+ # and +default+ according to the values from Information Schema.
18
30
  def initialize( row = nil )
19
- @not_null = row.respond_to?(:is_nullable) && row.is_nullable == "NO"
20
- @default = row.respond_to?( :column_default) && row.column_default
31
+ @not_null = row.respond_to?(:is_nullable) && row.is_nullable == "NO" ? true : false
32
+ @default = row.respond_to?(:column_default) ? row.column_default : nil
21
33
  end
22
34
 
23
- # values are filtered by this function when being set
35
+ # Values are filtered by this function when being set. See the
36
+ # method in the appropriate derived data type class for allowed
37
+ # values.
24
38
  def filter_set( value ) # :nodoc:
25
39
  value
26
40
  end
27
41
 
42
+ # Compares two values and return true if equal or false otherwise.
43
+ # It is used to check if a row field has been changed so that only
44
+ # changed fields are written to database.
28
45
  def equal( a, b )
29
46
  a == b
30
47
  end
31
48
 
49
+ # Escapes +input+ to be saved in database.
50
+ # If +input+ equals nil, NULL is returned, otherwise Database#escape_string
51
+ # is called.
52
+ # This method is overwritten to get data type-specific escaping rules.
32
53
  def escape( input )
33
54
  input.nil? ? "NULL" : "'" + Database.escape_string( input.to_s ) + "'"
34
55
  end
35
56
 
36
- # this functions is used for compiling the where clause
57
+ # This method is used when compiling the where clause. No need
58
+ # for direct use.
37
59
  def compile_rule( field_name, value ) # :nodoc:
38
60
  case value
39
61
  when nil then
@@ -66,6 +88,25 @@ module Momomoto
66
88
  end
67
89
  end
68
90
 
91
+ # These are operators supported by all data types. In your select
92
+ # statement use something like:
93
+ #
94
+ # one_day_ago = Time.now - (3600*24)
95
+ # Feeds.select( :date => {:ge => one_day_ago.to_s} )
96
+ #
97
+ # This will select all rows from Feeds that are newer than 24 hours.
98
+ # Same with Momomoto's TimeInterval:
99
+ #
100
+ # one_day_ago = Time.now + TimeInterval.new({:hour => -24})
101
+ # Feeds.select( :date => {:ge => one_day_ago.to_s} )
102
+ #
103
+ # In case of data type Text also +:like+ and +:ilike+ are supported.
104
+ # For +:like+ and +:ilike+ operators you may use _ as placeholder for
105
+ # a single character or % as placeholder for multiple characters.
106
+ #
107
+ # # Selects all posts having "surveillance" in their content field
108
+ # # while ignoring case.
109
+ # Posts.select( :content => {:ilike => 'surveillance'} )
69
110
  def self.operator_sign( op )
70
111
  case op
71
112
  when :le then '<='
@@ -1,8 +1,9 @@
1
1
  module Momomoto
2
2
  module Datatype
3
3
 
4
+ # Represents values of type Bigint derived from Integer
4
5
  class Bigint < Integer
5
-
6
+
6
7
  end
7
8
 
8
9
  end
@@ -1,7 +1,14 @@
1
1
  module Momomoto
2
2
  module Datatype
3
+
4
+ # This class represents values of boolean type.
3
5
  class Boolean < Base
4
6
 
7
+ # Values are filtered by this method when being set.
8
+ # Returns true or false.
9
+ # If the given +value+ cannot be converted to true or false
10
+ # and NULL is not allowed, than again return false. Otherwise
11
+ # return +nil+.
5
12
  def filter_set( value )
6
13
  case value
7
14
  when true, 1, 't', 'true', 'on' then true
@@ -10,6 +17,8 @@ module Momomoto
10
17
  end
11
18
  end
12
19
 
20
+ # Converts the given +input+ to true or false if possible.
21
+ # Otherwise returns NULL.
13
22
  def escape( input )
14
23
  case input
15
24
  when true, 1, 't', 'true', 'on' then "'t'"
@@ -1,8 +1,12 @@
1
1
 
2
2
  module Momomoto
3
3
  module Datatype
4
+
5
+ # This class is used for Binary Data (Byte Array).
4
6
  class Bytea < Base
5
7
 
8
+ # Escapes +input+ using Database#escape_bytea or returns NULL if
9
+ # +input+ is nil.
6
10
  def escape( input )
7
11
  input.nil? ? "NULL" : "E'" + Database.escape_bytea( input ) + "'"
8
12
  end
@@ -1,5 +1,7 @@
1
1
  module Momomoto
2
2
  module Datatype
3
+
4
+ # Represents character data type.
3
5
  class Character < Text
4
6
 
5
7
  end
@@ -1,5 +1,7 @@
1
1
  module Momomoto
2
2
  module Datatype
3
+
4
+ # Represents the Character Varying data type.
3
5
  class Character_varying < Text
4
6
 
5
7
  end
@@ -3,8 +3,13 @@ require 'date'
3
3
 
4
4
  module Momomoto
5
5
  module Datatype
6
+
7
+ # Represents the data type Date.
6
8
  class Date < Base
7
9
 
10
+ # Values are filtered by this function when being set.
11
+ # Returns ruby's Date or tries to build a Date from a String.
12
+ # Raises ConversionError if the given +value+ cannot be parsed.
8
13
  def filter_set( value )
9
14
  case value
10
15
  when nil,'' then nil