momomoto 0.1.13 → 0.1.14

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.
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