momomoto 0.1.0 → 0.1.1
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/lib/momomoto/base.rb +25 -13
- data/lib/momomoto/database.rb +9 -2
- data/lib/momomoto/datatype/bytea.rb +1 -1
- data/lib/momomoto/datatype/text.rb +1 -1
- data/lib/momomoto/row.rb +26 -0
- data/lib/momomoto/table.rb +45 -3
- data/test/test.sql +68 -0
- data/test/test_base.rb +3 -3
- data/test/test_functions.sql +25 -0
- data/test/test_information_schema.rb +1 -3
- data/test/test_table.rb +28 -6
- metadata +4 -2
data/lib/momomoto/base.rb
CHANGED
@@ -114,30 +114,43 @@ module Momomoto
|
|
114
114
|
# construct the Row class for the table
|
115
115
|
def initialize_row( row, table ) # :nodoc:
|
116
116
|
|
117
|
+
const_set( :Methods, Module.new ) if not const_defined?( :Methods )
|
118
|
+
const_set( :StandardMethods, Module.new ) if not const_defined?( :StandardMethods )
|
119
|
+
|
117
120
|
if not row.ancestors.member?( Momomoto::Row )
|
118
121
|
raise CriticalError, "Row is not inherited from Momomoto::Row"
|
119
122
|
end
|
120
123
|
|
121
124
|
row.instance_eval do class_variable_set( :@@table, table ) end
|
122
125
|
|
126
|
+
define_row_accessors( table )
|
127
|
+
|
128
|
+
row.instance_eval do
|
129
|
+
include table.const_get( :StandardMethods )
|
130
|
+
include table.const_get( :Methods )
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
# defines row setter and getter in the module StandardMethods which
|
136
|
+
# is later included in the Row class
|
137
|
+
def define_row_accessors( table ) #:nodoc:
|
138
|
+
method_module = const_get( :StandardMethods )
|
123
139
|
columns.each_with_index do | ( field_name, data_type ), index |
|
124
|
-
|
140
|
+
method_module.instance_eval do
|
125
141
|
# define getter for row class
|
126
|
-
if
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
instance_variable_get(:@data)[index]
|
134
|
-
end
|
142
|
+
if data_type.respond_to?( :filter_get )
|
143
|
+
define_method( field_name ) do
|
144
|
+
data_type.filter_get( instance_variable_get(:@data)[index] )
|
145
|
+
end
|
146
|
+
else
|
147
|
+
define_method( field_name ) do
|
148
|
+
instance_variable_get(:@data)[index]
|
135
149
|
end
|
136
150
|
end
|
137
151
|
|
138
152
|
# define setter for row class
|
139
|
-
|
140
|
-
define_method( setter_name ) do | value |
|
153
|
+
define_method( "#{field_name}=" ) do | value |
|
141
154
|
if not new_record? and table.primary_keys.member?( field_name )
|
142
155
|
raise Error, "Setting primary keys(#{field_name}) is only allowed for new records"
|
143
156
|
end
|
@@ -151,7 +164,6 @@ module Momomoto
|
|
151
164
|
|
152
165
|
end
|
153
166
|
end
|
154
|
-
|
155
167
|
end
|
156
168
|
|
157
169
|
end
|
data/lib/momomoto/database.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
|
2
2
|
begin
|
3
3
|
require 'rubygems'
|
4
|
-
|
4
|
+
gem 'ruby-postgres', '>= 0.7.1.2006.04.06'
|
5
|
+
require 'postgres'
|
5
6
|
rescue LoadError
|
6
7
|
require 'postgres'
|
7
8
|
end
|
@@ -63,7 +64,7 @@ module Momomoto
|
|
63
64
|
def disconnect
|
64
65
|
@connection.close
|
65
66
|
@connection = nil
|
66
|
-
@transaction_active =
|
67
|
+
@transaction_active = false
|
67
68
|
end
|
68
69
|
|
69
70
|
# execute a query
|
@@ -71,6 +72,12 @@ module Momomoto
|
|
71
72
|
puts sql if Momomoto.debug
|
72
73
|
@connection.query( sql )
|
73
74
|
rescue => e
|
75
|
+
if @connection.status == PGconn::CONNECTION_BAD
|
76
|
+
begin
|
77
|
+
connect
|
78
|
+
rescue
|
79
|
+
end
|
80
|
+
end
|
74
81
|
raise CriticalError, "#{e}: #{sql}"
|
75
82
|
end
|
76
83
|
|
data/lib/momomoto/row.rb
CHANGED
@@ -50,6 +50,7 @@ module Momomoto
|
|
50
50
|
self.class.table.delete( self )
|
51
51
|
end
|
52
52
|
|
53
|
+
# convert row to hash
|
53
54
|
def to_hash
|
54
55
|
hash = {}
|
55
56
|
self.class.table.columns.keys.each do | key |
|
@@ -58,6 +59,31 @@ module Momomoto
|
|
58
59
|
hash
|
59
60
|
end
|
60
61
|
|
62
|
+
# generic setter for column values
|
63
|
+
def set_column( column, value )
|
64
|
+
table = self.class.table
|
65
|
+
if not new_record? and table.primary_keys.member?( column.to_sym )
|
66
|
+
raise Error, "Setting primary keys(#{column}) is only allowed for new records"
|
67
|
+
end
|
68
|
+
value = table.columns[column.to_sym].filter_set( value )
|
69
|
+
index = table.column_order.index( column.to_sym )
|
70
|
+
if @data[index] != value
|
71
|
+
@dirty = true
|
72
|
+
@data[index] = value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# generic getter for column values
|
77
|
+
def get_column( column )
|
78
|
+
table = self.class.table
|
79
|
+
index = table.column_order.index( column.to_sym )
|
80
|
+
if table.columns[column.to_sym].respond_to?( :filter_get )
|
81
|
+
table.columns[column.to_sym].filter_get( @data[index] )
|
82
|
+
else
|
83
|
+
@data[index]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
61
87
|
end
|
62
88
|
|
63
89
|
end
|
data/lib/momomoto/table.rb
CHANGED
@@ -9,18 +9,31 @@ module Momomoto
|
|
9
9
|
|
10
10
|
# set the default order for selects
|
11
11
|
def default_order=( order )
|
12
|
-
|
12
|
+
class_variable_set( :@@default_order, order )
|
13
13
|
end
|
14
14
|
|
15
|
-
# get
|
15
|
+
# get the columns of the table this class operates on
|
16
16
|
def default_order( order = nil )
|
17
17
|
return self.default_order=( order ) if order
|
18
|
-
|
18
|
+
begin
|
19
|
+
class_variable_get( :@@default_order )
|
20
|
+
rescue NameError
|
21
|
+
class_variable_set( :@@default_order, nil )
|
22
|
+
end
|
19
23
|
end
|
20
24
|
|
21
25
|
# set the columns of the table this class operates on
|
22
26
|
def columns=( columns )
|
23
27
|
class_variable_set( :@@columns, columns)
|
28
|
+
# we store the order separate because it's quite important
|
29
|
+
# that it's constant otherwise get_colum and set_column
|
30
|
+
# on the row class might stop working
|
31
|
+
class_variable_set( :@@column_order, columns.keys )
|
32
|
+
end
|
33
|
+
|
34
|
+
# get the columns of this table
|
35
|
+
def column_order
|
36
|
+
class_variable_get( :@@column_order )
|
24
37
|
end
|
25
38
|
|
26
39
|
# get the columns of the table this class operates on
|
@@ -117,6 +130,35 @@ module Momomoto
|
|
117
130
|
data
|
118
131
|
end
|
119
132
|
|
133
|
+
## Searches for records and returns an array containing the records
|
134
|
+
def select_with_join( conditions = {}, options = {} )
|
135
|
+
initialize_table unless class_variables.member?('@@initialized')
|
136
|
+
join_table = options[:join]
|
137
|
+
fields = columns.keys.map{|field| full_name+'."'+field.to_s+'"'}
|
138
|
+
fields += join_table.columns.keys.map{|field| join_table.full_name+'."'+field.to_s+'"'}
|
139
|
+
|
140
|
+
sql = "SELECT " + fields.join( "," ) + " FROM "
|
141
|
+
sql += full_name
|
142
|
+
sql += " LEFT OUTER JOIN " + join_table.full_name + " USING(#{join_columns(join_table).join(',')})"
|
143
|
+
sql += compile_where( conditions )
|
144
|
+
sql += compile_order( options[:order] ) if options[:order]
|
145
|
+
sql += compile_limit( options[:limit] ) if options[:limit]
|
146
|
+
sql += compile_offset( options[:offset] ) if options[:offset]
|
147
|
+
data = []
|
148
|
+
database.execute( sql ).each do | row |
|
149
|
+
new_row = const_get(:Row).new( row[0, columns.keys.length] )
|
150
|
+
join_row = join_table.const_get(:Row).new( row[columns.keys.length,join_table.columns.keys.length] )
|
151
|
+
new_row.instance_variable_set(:@join, join_row)
|
152
|
+
new_row.send( :instance_eval ) { class << self; self; end }.send(:define_method, join_table.table_name ) do join_row end
|
153
|
+
data << new_row
|
154
|
+
end
|
155
|
+
data
|
156
|
+
end
|
157
|
+
|
158
|
+
def join_columns( join_table )
|
159
|
+
join_table.primary_keys.select{|f| columns.key?(f)}
|
160
|
+
end
|
161
|
+
|
120
162
|
## constructor for a record in this table accepts a hash with presets for the fields of the record
|
121
163
|
def new( fields = {} )
|
122
164
|
initialize_table unless class_variables.member?('@@initialized')
|
data/test/test.sql
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
CREATE TABLE conference (
|
3
|
+
conference_id SERIAL,
|
4
|
+
acronym TEXT NOT NULL UNIQUE,
|
5
|
+
title TEXT NOT NULL,
|
6
|
+
subtitle TEXT,
|
7
|
+
description TEXT,
|
8
|
+
start_date DATE NOT NULL,
|
9
|
+
timeslot_duration INTERVAL NOT NULL DEFAULT '0:30:00',
|
10
|
+
default_timeslots INTEGER NOT NULL DEFAULT 1,
|
11
|
+
max_timeslots_per_event INTEGER NOT NULL DEFAULT 10,
|
12
|
+
day_change TIME WITHOUT TIME ZONE NOT NULL DEFAULT '0:00:00',
|
13
|
+
feedback_enabled BOOL NOT NULL DEFAULT FALSE,
|
14
|
+
submission_enabled BOOL NOT NULL DEFAULT FALSE,
|
15
|
+
visitor_enabled BOOL NOT NULL DEFAULT FALSE,
|
16
|
+
reconfirmation_enabled BOOL NOT NULL DEFAULT FALSE,
|
17
|
+
PRIMARY KEY(conference_id)
|
18
|
+
);
|
19
|
+
|
20
|
+
CREATE TABLE person (
|
21
|
+
person_id SERIAL,
|
22
|
+
first_name TEXT,
|
23
|
+
last_name TEXT,
|
24
|
+
nick_name TEXT,
|
25
|
+
PRIMARY KEY(person_id)
|
26
|
+
);
|
27
|
+
|
28
|
+
INSERT INTO person(nick_name) VALUES ('blossom');
|
29
|
+
INSERT INTO person(nick_name) VALUES ('buttercup');
|
30
|
+
INSERT INTO person(nick_name) VALUES ('bubbles');
|
31
|
+
INSERT INTO person(nick_name) VALUES ('mojojojo');
|
32
|
+
|
33
|
+
CREATE TABLE event (
|
34
|
+
event_id SERIAL,
|
35
|
+
title TEXT,
|
36
|
+
subtitle TEXT,
|
37
|
+
PRIMARY KEY(event_id)
|
38
|
+
);
|
39
|
+
|
40
|
+
CREATE TABLE event_person (
|
41
|
+
event_id INTEGER,
|
42
|
+
person_id INTEGER,
|
43
|
+
description TEXT,
|
44
|
+
FOREIGN KEY(event_id) REFERENCES event(event_id),
|
45
|
+
FOREIGN KEY(person_id) REFERENCES person(person_id),
|
46
|
+
PRIMARY KEY(event_id, person_id, description)
|
47
|
+
);
|
48
|
+
|
49
|
+
CREATE TABLE test_bigint( id SERIAL, data BIGINT, PRIMARY KEY(id));
|
50
|
+
CREATE TABLE test_boolean( id SERIAL, data BOOLEAN, PRIMARY KEY(id));
|
51
|
+
CREATE TABLE test_bytea( id SERIAL, data BYTEA, PRIMARY KEY(id));
|
52
|
+
CREATE TABLE test_character( id SERIAL, data CHARACTER(1000), PRIMARY KEY(id));
|
53
|
+
CREATE TABLE test_character_varying( id SERIAL, data VARCHAR(1000), PRIMARY KEY(id));
|
54
|
+
CREATE TABLE test_date( id SERIAL, data DATE, PRIMARY KEY(id));
|
55
|
+
CREATE TABLE test_inet( id SERIAL, data INET, PRIMARY KEY(id));
|
56
|
+
CREATE TABLE test_integer( id SERIAL, data INTEGER, PRIMARY KEY(id));
|
57
|
+
CREATE TABLE test_interval( id SERIAL, data INTERVAL, PRIMARY KEY(id));
|
58
|
+
CREATE TABLE test_nodefault ( id INTEGER, data TEXT, PRIMARY KEY(id));
|
59
|
+
CREATE TABLE test_numeric( id SERIAL, data NUMERIC, PRIMARY KEY(id));
|
60
|
+
CREATE TABLE test_real( id SERIAL, data REAL, PRIMARY KEY(id));
|
61
|
+
CREATE TABLE test_smallint( id SERIAL, data SMALLINT, PRIMARY KEY(id));
|
62
|
+
CREATE TABLE test_text( id SERIAL, data TEXT, PRIMARY KEY(id));
|
63
|
+
CREATE TABLE test_time_with_time_zone( id SERIAL, data TIME WITH TIME ZONE, PRIMARY KEY(id));
|
64
|
+
CREATE TABLE test_time_without_time_zone( id SERIAL, data TIME WITHOUT TIME ZONE, PRIMARY KEY(id));
|
65
|
+
CREATE TABLE test_timestamp_with_time_zone( id SERIAL, data TIMESTAMP WITH TIME ZONE, PRIMARY KEY(id));
|
66
|
+
CREATE TABLE test_timestamp_without_time_zone( id SERIAL, data TIMESTAMP WITHOUT TIME ZONE, PRIMARY KEY(id));
|
67
|
+
|
68
|
+
|
data/test/test_base.rb
CHANGED
@@ -8,9 +8,9 @@ class TestBase < Test::Unit::TestCase
|
|
8
8
|
assert_equal( " WHERE person_id = '1'" , t.compile_where( :person_id => '1' ) )
|
9
9
|
assert_equal( " WHERE person_id IN ('1')" , t.compile_where( :person_id => ['1'] ) )
|
10
10
|
assert_equal( " WHERE person_id IN ('1','2')" , t.compile_where( :person_id => ['1',2] ) )
|
11
|
-
assert_equal( " WHERE first_name = '1'" , t.compile_where( :first_name => '1' ) )
|
12
|
-
assert_equal( " WHERE first_name = 'chu''nky'" , t.compile_where( :first_name => "chu'nky" ) )
|
13
|
-
assert_equal( " WHERE first_name IN ('chu''nky','bac''n')" , t.compile_where( :first_name => ["chu'nky","bac'n"] ) )
|
11
|
+
assert_equal( " WHERE first_name = E'1'" , t.compile_where( :first_name => '1' ) )
|
12
|
+
assert_equal( " WHERE first_name = E'chu''nky'" , t.compile_where( :first_name => "chu'nky" ) )
|
13
|
+
assert_equal( " WHERE first_name IN (E'chu''nky',E'bac''n')" , t.compile_where( :first_name => ["chu'nky","bac'n"] ) )
|
14
14
|
end
|
15
15
|
|
16
16
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
CREATE OR REPLACE FUNCTION test_parameter_sql( param1 INTEGER ) RETURNS INTEGER AS $$
|
3
|
+
SELECT $1;
|
4
|
+
$$ LANGUAGE sql;
|
5
|
+
|
6
|
+
CREATE OR REPLACE FUNCTION test_parameter_plpgsql( param1 INTEGER, param2 TEXT ) RETURNS INTEGER AS $$
|
7
|
+
DECLARE
|
8
|
+
BEGIN
|
9
|
+
RETURN param1;
|
10
|
+
END;
|
11
|
+
$$ LANGUAGE plpgsql;
|
12
|
+
|
13
|
+
CREATE OR REPLACE FUNCTION test_set_returning( person_id INTEGER ) RETURNS SETOF person AS $$
|
14
|
+
DECLARE
|
15
|
+
result RECORD;
|
16
|
+
BEGIN
|
17
|
+
FOR result IN
|
18
|
+
SELECT person.* FROM person WHERE person.person_id <> person_id
|
19
|
+
LOOP
|
20
|
+
RETURN NEXT result;
|
21
|
+
END LOOP;
|
22
|
+
RETURN;
|
23
|
+
END;
|
24
|
+
$$ LANGUAGE plpgsql;
|
25
|
+
|
@@ -17,10 +17,8 @@ class TestInformationSchema < Test::Unit::TestCase
|
|
17
17
|
|
18
18
|
# test for working information_schema.table_constraints class
|
19
19
|
def test_information_schema_table_constraints
|
20
|
-
a = Momomoto::Information_schema::Table_constraints.select(:table_schema => 'pg_catalog', :table_name => 'pg_class')
|
21
|
-
assert_equal( 0, a.length )
|
22
20
|
a = Momomoto::Information_schema::Table_constraints.select(:table_schema => 'public')
|
23
|
-
|
21
|
+
assert( a.length > 0 )
|
24
22
|
end
|
25
23
|
|
26
24
|
end
|
data/test/test_table.rb
CHANGED
@@ -2,18 +2,32 @@
|
|
2
2
|
class TestTable < Test::Unit::TestCase
|
3
3
|
|
4
4
|
class Person < Momomoto::Table
|
5
|
-
|
6
|
-
newvalue
|
7
|
-
|
8
|
-
|
9
|
-
def self.nick_name=( row, newvalue )
|
10
|
-
row.first_name + newvalue
|
5
|
+
module Methods
|
6
|
+
def nick_name=( newvalue )
|
7
|
+
set_column(:nick_name, get_column(:first_name) + newvalue )
|
8
|
+
end
|
11
9
|
end
|
12
10
|
end
|
13
11
|
|
14
12
|
class Conference < Momomoto::Table
|
15
13
|
end
|
16
14
|
|
15
|
+
def test_default_order_getter
|
16
|
+
c1 = Class.new( Momomoto::Table )
|
17
|
+
c1.default_order = [:a,:b]
|
18
|
+
assert_equal( [:a,:b], c1.default_order )
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_default_order_setter
|
22
|
+
c1 = Class.new( Momomoto::Table )
|
23
|
+
c1.default_order = :a
|
24
|
+
assert_equal( :a, c1.default_order )
|
25
|
+
c1.default_order = :b
|
26
|
+
assert_equal( :b, c1.default_order )
|
27
|
+
c1.default_order( :c )
|
28
|
+
assert_equal( :c, c1.default_order )
|
29
|
+
end
|
30
|
+
|
17
31
|
def test_columns_getter
|
18
32
|
c1 = Class.new( Momomoto::Table )
|
19
33
|
c1.columns = {:a=>Momomoto::Datatype::Text}
|
@@ -109,6 +123,14 @@ class TestTable < Test::Unit::TestCase
|
|
109
123
|
assert_equal( true, sven.new_record? )
|
110
124
|
end
|
111
125
|
|
126
|
+
def test_offset
|
127
|
+
p = Person.select( {}, {:limit => 1, :order => :person_id,:offset=>2})
|
128
|
+
assert_operator( 2, :<, p[0].person_id )
|
129
|
+
assert_raise( Momomoto::Error ) do
|
130
|
+
Person.select( {}, {:limit => 1, :order => :person_id,:offset=>'bacon'})
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
112
134
|
def test_select
|
113
135
|
r = Person.select( nil, {:limit => 3})
|
114
136
|
assert_equal( 3, r.length )
|
metadata
CHANGED
@@ -3,7 +3,7 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: momomoto
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1.
|
6
|
+
version: 0.1.1
|
7
7
|
date: 2007-08-13 00:00:00 +02:00
|
8
8
|
summary: Momomoto is an object relational mapper for PostgreSQL.
|
9
9
|
require_paths:
|
@@ -90,6 +90,8 @@ files:
|
|
90
90
|
- test/test_datatype.rb
|
91
91
|
- test/test_bigint.rb
|
92
92
|
- test/test_date.rb
|
93
|
+
- test/test_functions.sql
|
94
|
+
- test/test.sql
|
93
95
|
- LICENSE
|
94
96
|
- Rakefile
|
95
97
|
test_files: []
|
@@ -103,7 +105,7 @@ executables: []
|
|
103
105
|
extensions: []
|
104
106
|
|
105
107
|
requirements:
|
106
|
-
- PostgreSQL 8.1.
|
108
|
+
- PostgreSQL 8.1.x or greater
|
107
109
|
dependencies:
|
108
110
|
- !ruby/object:Gem::Dependency
|
109
111
|
name: ruby-postgres
|