m4dbi 0.8.1 → 0.8.2
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/m4dbi/model.rb +19 -6
- data/lib/m4dbi/version.rb +1 -1
- data/spec/collection.rb +84 -0
- data/spec/model.rb +22 -90
- metadata +63 -50
data/lib/m4dbi/model.rb
CHANGED
@@ -2,7 +2,7 @@ module M4DBI
|
|
2
2
|
class Model
|
3
3
|
#attr_reader :row
|
4
4
|
ancestral_trait_reader :dbh, :table
|
5
|
-
ancestral_trait_class_reader :dbh, :table, :pk, :columns, :st
|
5
|
+
ancestral_trait_class_reader :dbh, :table, :pk, :columns, :st, :callbacks
|
6
6
|
|
7
7
|
M4DBI_UNASSIGNED = '__m4dbi_unassigned__'
|
8
8
|
|
@@ -142,9 +142,15 @@ module M4DBI
|
|
142
142
|
end
|
143
143
|
if ! pk_hash.empty?
|
144
144
|
rec = self.one_where( pk_hash )
|
145
|
+
callbacks[:after_create].each do |block|
|
146
|
+
block.yield rec
|
147
|
+
end
|
145
148
|
else
|
146
149
|
begin
|
147
150
|
rec = last_record( dbh_ )
|
151
|
+
callbacks[:after_create].each do |block|
|
152
|
+
block.yield rec
|
153
|
+
end
|
148
154
|
rescue NoMethodError => e
|
149
155
|
# ignore
|
150
156
|
#puts "not implemented: #{e.message}"
|
@@ -221,6 +227,10 @@ module M4DBI
|
|
221
227
|
stm.execute( *params )
|
222
228
|
end
|
223
229
|
|
230
|
+
def self.after_create(&block)
|
231
|
+
callbacks[:after_create] << block
|
232
|
+
end
|
233
|
+
|
224
234
|
# Example:
|
225
235
|
# M4DBI::Model.one_to_many( Author, Post, :posts, :author, :author_id )
|
226
236
|
# her_posts = some_author.posts
|
@@ -413,11 +423,14 @@ module M4DBI
|
|
413
423
|
@models ||= Hash.new
|
414
424
|
@models[ model_key ] ||= Class.new( M4DBI::Model ) do |klass|
|
415
425
|
klass.trait( {
|
416
|
-
:dbh
|
417
|
-
:table
|
418
|
-
:pk
|
419
|
-
:columns
|
420
|
-
:st
|
426
|
+
:dbh => h,
|
427
|
+
:table => table,
|
428
|
+
:pk => pk_,
|
429
|
+
:columns => h.table_schema( table.to_sym ).columns,
|
430
|
+
:st => Hash.new, # prepared statements for all queries
|
431
|
+
:callbacks => {
|
432
|
+
after_create: []
|
433
|
+
}
|
421
434
|
} )
|
422
435
|
|
423
436
|
meta_def( 'pk_str'.to_sym ) do
|
data/lib/m4dbi/version.rb
CHANGED
data/spec/collection.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
$dbh = connect_to_spec_database
|
4
|
+
reset_data
|
5
|
+
|
6
|
+
describe 'M4DBI::Collection' do
|
7
|
+
before do
|
8
|
+
@m_author = Class.new( M4DBI::Model( :authors ) )
|
9
|
+
@m_post = Class.new( M4DBI::Model( :posts ) )
|
10
|
+
|
11
|
+
M4DBI::Model.one_to_many(
|
12
|
+
@m_author, @m_post, :posts, :author, :author_id
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'accepts additions' do
|
17
|
+
num_posts = @m_post.count
|
18
|
+
|
19
|
+
a = @m_author[ 1 ]
|
20
|
+
the_text = 'A new post.'
|
21
|
+
|
22
|
+
num_posts_of_author = a.posts.count
|
23
|
+
|
24
|
+
# Insert without auto-incrementing primary key specified
|
25
|
+
# Try at least as many times as there were records in the DB,
|
26
|
+
# because the sequence used for the IDs is independent of
|
27
|
+
# the actual ID values in the DB for some RDBMSes.
|
28
|
+
num_posts.times do
|
29
|
+
begin
|
30
|
+
a.posts << { :text => the_text }
|
31
|
+
break # Stop on success
|
32
|
+
rescue Exception => e
|
33
|
+
if e.message !~ /duplicate/
|
34
|
+
raise e
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
a.posts.count.should.equal num_posts_of_author + 1
|
40
|
+
|
41
|
+
p = a.posts.find { |p| p.text == the_text }
|
42
|
+
p.should.not.be.nil
|
43
|
+
p.author.should.equal a
|
44
|
+
|
45
|
+
a_ = @m_author[ 1 ]
|
46
|
+
a_.posts.find { |p| p.text == the_text }.should.not.be.nil
|
47
|
+
|
48
|
+
reset_data
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'facilitates single record deletions' do
|
52
|
+
a = @m_author[ 1 ]
|
53
|
+
posts = a.posts
|
54
|
+
n = posts.size
|
55
|
+
p = posts[ 0 ]
|
56
|
+
|
57
|
+
posts.delete( p ).should.be.true
|
58
|
+
a.posts.size.should.equal( n - 1 )
|
59
|
+
posts.find { |p_| p_ == p }.should.be.nil
|
60
|
+
|
61
|
+
reset_data
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'facilitates multi-record deletions' do
|
65
|
+
a = @m_author[ 1 ]
|
66
|
+
posts = a.posts
|
67
|
+
n = posts.size
|
68
|
+
posts.delete( :text => 'Third post.' ).should.equal 1
|
69
|
+
a.posts.size.should.equal( n - 1 )
|
70
|
+
posts.find { |p| p.text == 'Third post.' }.should.be.nil
|
71
|
+
posts.find { |p| p.text == 'First post.' }.should.not.be.nil
|
72
|
+
|
73
|
+
reset_data
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'facilitates table-wide deletion' do
|
77
|
+
a = @m_author[ 1 ]
|
78
|
+
a.posts.should.not.be.empty
|
79
|
+
a.posts.clear.should.be > 0
|
80
|
+
a.posts.should.be.empty
|
81
|
+
|
82
|
+
reset_data
|
83
|
+
end
|
84
|
+
end
|
data/spec/model.rb
CHANGED
@@ -86,16 +86,16 @@ describe 'A M4DBI::Model subclass' do
|
|
86
86
|
end
|
87
87
|
|
88
88
|
it 'provides the database handle it is using' do
|
89
|
-
begin
|
90
|
-
@m_author.dbh.should.equal $dbh
|
89
|
+
# begin
|
90
|
+
# @m_author.dbh.should.equal $dbh
|
91
91
|
|
92
|
-
dbh = connect_to_spec_database( ENV[ 'M4DBI_DATABASE2' ] || 'm4dbi2' )
|
93
|
-
@m_author2 = Class.new( M4DBI::Model( :authors ) )
|
94
|
-
@m_author2.dbh.should.equal dbh
|
95
|
-
ensure
|
96
|
-
# Clean up handles for later specs
|
97
|
-
connect_to_spec_database
|
98
|
-
end
|
92
|
+
# dbh = connect_to_spec_database( ENV[ 'M4DBI_DATABASE2' ] || 'm4dbi2' )
|
93
|
+
# @m_author2 = Class.new( M4DBI::Model( :authors ) )
|
94
|
+
# @m_author2.dbh.should.equal dbh
|
95
|
+
# ensure
|
96
|
+
# # Clean up handles for later specs
|
97
|
+
# connect_to_spec_database
|
98
|
+
# end
|
99
99
|
end
|
100
100
|
|
101
101
|
it 'maintains distinction from models of the same name in different databases' do
|
@@ -670,6 +670,19 @@ describe 'A M4DBI::Model subclass' do
|
|
670
670
|
|
671
671
|
reset_data
|
672
672
|
end
|
673
|
+
|
674
|
+
it 'after creation, executes code provided in an after_create hook' do
|
675
|
+
class Author < M4DBI::Model( :authors )
|
676
|
+
after_create do |author|
|
677
|
+
$test = 2
|
678
|
+
author.name = 'different name'
|
679
|
+
end
|
680
|
+
end
|
681
|
+
$test.should.not.equal 2
|
682
|
+
a = Author.create(name: 'theauthor')
|
683
|
+
$test.should.equal 2
|
684
|
+
a.name.should.equal 'different name'
|
685
|
+
end
|
673
686
|
end
|
674
687
|
|
675
688
|
describe 'A created M4DBI::Model subclass instance' do
|
@@ -950,7 +963,6 @@ describe 'A found M4DBI::Model subclass instance' do
|
|
950
963
|
p.save!
|
951
964
|
end
|
952
965
|
end
|
953
|
-
|
954
966
|
end
|
955
967
|
|
956
968
|
describe 'M4DBI::Model (relationships)' do
|
@@ -1029,83 +1041,3 @@ describe 'M4DBI::Model (relationships)' do
|
|
1029
1041
|
@m_fan[ 5 ].authors_liked.should.be.empty
|
1030
1042
|
end
|
1031
1043
|
end
|
1032
|
-
|
1033
|
-
describe 'M4DBI::Collection' do
|
1034
|
-
before do
|
1035
|
-
@m_author = Class.new( M4DBI::Model( :authors ) )
|
1036
|
-
@m_post = Class.new( M4DBI::Model( :posts ) )
|
1037
|
-
|
1038
|
-
M4DBI::Model.one_to_many(
|
1039
|
-
@m_author, @m_post, :posts, :author, :author_id
|
1040
|
-
)
|
1041
|
-
end
|
1042
|
-
|
1043
|
-
it 'accepts additions' do
|
1044
|
-
num_posts = @m_post.count
|
1045
|
-
|
1046
|
-
a = @m_author[ 1 ]
|
1047
|
-
the_text = 'A new post.'
|
1048
|
-
|
1049
|
-
num_posts_of_author = a.posts.count
|
1050
|
-
|
1051
|
-
# Insert without auto-incrementing primary key specified
|
1052
|
-
# Try at least as many times as there were records in the DB,
|
1053
|
-
# because the sequence used for the IDs is independent of
|
1054
|
-
# the actual ID values in the DB for some RDBMSes.
|
1055
|
-
num_posts.times do
|
1056
|
-
begin
|
1057
|
-
a.posts << { :text => the_text }
|
1058
|
-
break # Stop on success
|
1059
|
-
rescue Exception => e
|
1060
|
-
if e.message !~ /duplicate/
|
1061
|
-
raise e
|
1062
|
-
end
|
1063
|
-
end
|
1064
|
-
end
|
1065
|
-
|
1066
|
-
a.posts.count.should.equal num_posts_of_author + 1
|
1067
|
-
|
1068
|
-
p = a.posts.find { |p| p.text == the_text }
|
1069
|
-
p.should.not.be.nil
|
1070
|
-
p.author.should.equal a
|
1071
|
-
|
1072
|
-
a_ = @m_author[ 1 ]
|
1073
|
-
a_.posts.find { |p| p.text == the_text }.should.not.be.nil
|
1074
|
-
|
1075
|
-
reset_data
|
1076
|
-
end
|
1077
|
-
|
1078
|
-
it 'facilitates single record deletions' do
|
1079
|
-
a = @m_author[ 1 ]
|
1080
|
-
posts = a.posts
|
1081
|
-
n = posts.size
|
1082
|
-
p = posts[ 0 ]
|
1083
|
-
|
1084
|
-
posts.delete( p ).should.be.true
|
1085
|
-
a.posts.size.should.equal( n - 1 )
|
1086
|
-
posts.find { |p_| p_ == p }.should.be.nil
|
1087
|
-
|
1088
|
-
reset_data
|
1089
|
-
end
|
1090
|
-
|
1091
|
-
it 'facilitates multi-record deletions' do
|
1092
|
-
a = @m_author[ 1 ]
|
1093
|
-
posts = a.posts
|
1094
|
-
n = posts.size
|
1095
|
-
posts.delete( :text => 'Third post.' ).should.equal 1
|
1096
|
-
a.posts.size.should.equal( n - 1 )
|
1097
|
-
posts.find { |p| p.text == 'Third post.' }.should.be.nil
|
1098
|
-
posts.find { |p| p.text == 'First post.' }.should.not.be.nil
|
1099
|
-
|
1100
|
-
reset_data
|
1101
|
-
end
|
1102
|
-
|
1103
|
-
it 'facilitates table-wide deletion' do
|
1104
|
-
a = @m_author[ 1 ]
|
1105
|
-
a.posts.should.not.be.empty
|
1106
|
-
a.posts.clear.should.be > 0
|
1107
|
-
a.posts.should.be.empty
|
1108
|
-
|
1109
|
-
reset_data
|
1110
|
-
end
|
1111
|
-
end
|
metadata
CHANGED
@@ -1,58 +1,61 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: m4dbi
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 59
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 8
|
9
|
+
- 2
|
10
|
+
version: 0.8.2
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Pistos
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
|
18
|
+
date: 2012-06-25 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
15
21
|
name: metaid
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
22
|
-
type: :runtime
|
23
22
|
prerelease: false
|
24
|
-
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: rdbi
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
33
24
|
none: false
|
34
|
-
requirements:
|
35
|
-
- -
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
38
32
|
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rdbi
|
39
36
|
prerelease: false
|
40
|
-
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
38
|
none: false
|
42
|
-
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
|
46
|
-
|
47
|
-
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
description: M4DBI provides models, associations and some convenient extensions to RDBI.
|
48
49
|
email: m4dbi dot pistos at purepistos dot net
|
49
50
|
executables: []
|
51
|
+
|
50
52
|
extensions: []
|
51
|
-
|
53
|
+
|
54
|
+
extra_rdoc_files:
|
52
55
|
- README.rdoc
|
53
56
|
- CHANGELOG
|
54
57
|
- LICENCE
|
55
|
-
files:
|
58
|
+
files:
|
56
59
|
- README.rdoc
|
57
60
|
- CHANGELOG
|
58
61
|
- LICENCE
|
@@ -69,34 +72,44 @@ files:
|
|
69
72
|
- spec/database.rb
|
70
73
|
- spec/model.rb
|
71
74
|
- spec/helper.rb
|
75
|
+
- spec/collection.rb
|
72
76
|
- spec/hash.rb
|
73
77
|
homepage: https://github.com/Pistos/m4dbi
|
74
78
|
licenses: []
|
79
|
+
|
75
80
|
post_install_message:
|
76
81
|
rdoc_options: []
|
77
|
-
|
82
|
+
|
83
|
+
require_paths:
|
78
84
|
- lib
|
79
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
86
|
none: false
|
81
|
-
requirements:
|
82
|
-
- -
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
|
85
|
-
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
95
|
none: false
|
87
|
-
requirements:
|
88
|
-
- -
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
|
91
|
-
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
hash: 3
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
requirements:
|
92
104
|
- bacon (optional)
|
93
105
|
rubyforge_project:
|
94
|
-
rubygems_version: 1.8.
|
106
|
+
rubygems_version: 1.8.24
|
95
107
|
signing_key:
|
96
108
|
specification_version: 3
|
97
109
|
summary: Models (and More) for RDBI
|
98
|
-
test_files:
|
110
|
+
test_files:
|
99
111
|
- spec/database.rb
|
100
112
|
- spec/model.rb
|
101
113
|
- spec/helper.rb
|
114
|
+
- spec/collection.rb
|
102
115
|
- spec/hash.rb
|