pod4 0.10.6 → 1.0.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.
- checksums.yaml +5 -5
- data/.bugs/bugs +2 -1
- data/.bugs/details/b5368c7ef19065fc597b5692314da71772660963.txt +53 -0
- data/.hgtags +1 -0
- data/Gemfile +5 -5
- data/README.md +157 -46
- data/lib/pod4/basic_model.rb +9 -22
- data/lib/pod4/connection.rb +67 -0
- data/lib/pod4/connection_pool.rb +154 -0
- data/lib/pod4/errors.rb +20 -0
- data/lib/pod4/interface.rb +34 -12
- data/lib/pod4/model.rb +32 -27
- data/lib/pod4/nebulous_interface.rb +25 -30
- data/lib/pod4/null_interface.rb +22 -16
- data/lib/pod4/pg_interface.rb +84 -104
- data/lib/pod4/sequel_interface.rb +138 -82
- data/lib/pod4/tds_interface.rb +83 -70
- data/lib/pod4/tweaking.rb +105 -0
- data/lib/pod4/version.rb +1 -1
- data/md/breaking_changes.md +80 -0
- data/spec/common/basic_model_spec.rb +67 -70
- data/spec/common/connection_pool_parallelism_spec.rb +154 -0
- data/spec/common/connection_pool_spec.rb +246 -0
- data/spec/common/connection_spec.rb +129 -0
- data/spec/common/model_ai_missing_id_spec.rb +256 -0
- data/spec/common/model_plus_encrypting_spec.rb +16 -4
- data/spec/common/model_plus_tweaking_spec.rb +128 -0
- data/spec/common/model_plus_typecasting_spec.rb +10 -4
- data/spec/common/model_spec.rb +283 -363
- data/spec/common/nebulous_interface_spec.rb +159 -108
- data/spec/common/null_interface_spec.rb +88 -65
- data/spec/common/sequel_interface_pg_spec.rb +217 -161
- data/spec/common/shared_examples_for_interface.rb +50 -50
- data/spec/jruby/sequel_encrypting_jdbc_pg_spec.rb +1 -1
- data/spec/jruby/sequel_interface_jdbc_ms_spec.rb +3 -3
- data/spec/jruby/sequel_interface_jdbc_pg_spec.rb +3 -23
- data/spec/mri/pg_encrypting_spec.rb +1 -1
- data/spec/mri/pg_interface_spec.rb +311 -223
- data/spec/mri/sequel_encrypting_spec.rb +1 -1
- data/spec/mri/sequel_interface_spec.rb +177 -180
- data/spec/mri/tds_encrypting_spec.rb +1 -1
- data/spec/mri/tds_interface_spec.rb +296 -212
- data/tags +340 -174
- metadata +19 -11
- data/md/fixme.md +0 -3
- data/md/roadmap.md +0 -125
- data/md/typecasting.md +0 -80
- data/spec/common/model_new_validate_spec.rb +0 -204
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pod4
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Jones
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: devnull
|
@@ -47,12 +47,11 @@ email:
|
|
47
47
|
executables: []
|
48
48
|
extensions: []
|
49
49
|
extra_rdoc_files:
|
50
|
-
- md/
|
51
|
-
- md/roadmap.md
|
52
|
-
- md/typecasting.md
|
50
|
+
- md/breaking_changes.md
|
53
51
|
files:
|
54
52
|
- ".bugs/bugs"
|
55
53
|
- ".bugs/details/3979ce1679bc4f8c4aef8436e344e10e3773480d.txt"
|
54
|
+
- ".bugs/details/b5368c7ef19065fc597b5692314da71772660963.txt"
|
56
55
|
- ".hgignore"
|
57
56
|
- ".hgtags"
|
58
57
|
- ".rspec"
|
@@ -63,6 +62,8 @@ files:
|
|
63
62
|
- lib/pod4.rb
|
64
63
|
- lib/pod4/alert.rb
|
65
64
|
- lib/pod4/basic_model.rb
|
65
|
+
- lib/pod4/connection.rb
|
66
|
+
- lib/pod4/connection_pool.rb
|
66
67
|
- lib/pod4/encrypting.rb
|
67
68
|
- lib/pod4/errors.rb
|
68
69
|
- lib/pod4/interface.rb
|
@@ -75,17 +76,20 @@ files:
|
|
75
76
|
- lib/pod4/sequel_interface.rb
|
76
77
|
- lib/pod4/sql_helper.rb
|
77
78
|
- lib/pod4/tds_interface.rb
|
79
|
+
- lib/pod4/tweaking.rb
|
78
80
|
- lib/pod4/typecasting.rb
|
79
81
|
- lib/pod4/version.rb
|
80
|
-
- md/
|
81
|
-
- md/roadmap.md
|
82
|
-
- md/typecasting.md
|
82
|
+
- md/breaking_changes.md
|
83
83
|
- pod4.gemspec
|
84
84
|
- spec/README.md
|
85
85
|
- spec/common/alert_spec.rb
|
86
86
|
- spec/common/basic_model_spec.rb
|
87
|
-
- spec/common/
|
87
|
+
- spec/common/connection_pool_parallelism_spec.rb
|
88
|
+
- spec/common/connection_pool_spec.rb
|
89
|
+
- spec/common/connection_spec.rb
|
90
|
+
- spec/common/model_ai_missing_id_spec.rb
|
88
91
|
- spec/common/model_plus_encrypting_spec.rb
|
92
|
+
- spec/common/model_plus_tweaking_spec.rb
|
89
93
|
- spec/common/model_plus_typecasting_spec.rb
|
90
94
|
- spec/common/model_spec.rb
|
91
95
|
- spec/common/nebulous_interface_spec.rb
|
@@ -129,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
133
|
version: '0'
|
130
134
|
requirements: []
|
131
135
|
rubyforge_project:
|
132
|
-
rubygems_version: 2.
|
136
|
+
rubygems_version: 2.7.6
|
133
137
|
signing_key:
|
134
138
|
specification_version: 4
|
135
139
|
summary: Totally not an ORM
|
@@ -137,8 +141,12 @@ test_files:
|
|
137
141
|
- spec/README.md
|
138
142
|
- spec/common/alert_spec.rb
|
139
143
|
- spec/common/basic_model_spec.rb
|
140
|
-
- spec/common/
|
144
|
+
- spec/common/connection_pool_parallelism_spec.rb
|
145
|
+
- spec/common/connection_pool_spec.rb
|
146
|
+
- spec/common/connection_spec.rb
|
147
|
+
- spec/common/model_ai_missing_id_spec.rb
|
141
148
|
- spec/common/model_plus_encrypting_spec.rb
|
149
|
+
- spec/common/model_plus_tweaking_spec.rb
|
142
150
|
- spec/common/model_plus_typecasting_spec.rb
|
143
151
|
- spec/common/model_spec.rb
|
144
152
|
- spec/common/nebulous_interface_spec.rb
|
data/md/fixme.md
DELETED
data/md/roadmap.md
DELETED
@@ -1,125 +0,0 @@
|
|
1
|
-
Transactions
|
2
|
-
============
|
3
|
-
|
4
|
-
I'd like to support basic transactions because without it we can't really claim to do optimistic
|
5
|
-
locking properly. And it would be nice to claim that.
|
6
|
-
|
7
|
-
Thought I had a solid idea of how to do it without any faffing around, but, it had some holes. Will
|
8
|
-
have to think again.
|
9
|
-
|
10
|
-
But, this is top of my wish list.
|
11
|
-
|
12
|
-
For the record, my current thinking:
|
13
|
-
|
14
|
-
customer.new(4).read.or_die
|
15
|
-
customer.transaction do |c|
|
16
|
-
c.update(foo: 'bar')
|
17
|
-
c.orders.update(foo: 'bar')
|
18
|
-
end.or_die
|
19
|
-
|
20
|
-
* a method supports_transactions() will control whether the interface does that. sql_helper will
|
21
|
-
define it to return true.
|
22
|
-
|
23
|
-
* sql_helper will define a sql_transaction method which wraps SQL as a transaction.
|
24
|
-
|
25
|
-
* interface methods create() delete() and update now accept an extra parameter, a boolean; if true,
|
26
|
-
they will return sql (and values), rather than doing anything. This is defined in Pod4::Interface.
|
27
|
-
|
28
|
-
* BasicModel defines @in_transaction = false; @tx_sql = ""; @tx_vals = [].
|
29
|
-
|
30
|
-
* When a Model is @in_transaction, the create, delete and update methods pass the extra parameter
|
31
|
-
to the corresponding interface methods. The results are accumulated in @tx_sql and @tx_vals.
|
32
|
-
|
33
|
-
* the method BasicModel.transaction will:
|
34
|
-
|
35
|
-
* set interface.in_transaction = true, or raise an error if the interface doesn't support them
|
36
|
-
* yield a block passing the model instance so that the caller can run methods inside it
|
37
|
-
* set in_transaction back to false.
|
38
|
-
* call interface.executep( interface._sql_transaction( @tx_sql ), @tx_vals )
|
39
|
-
|
40
|
-
Notes:
|
41
|
-
|
42
|
-
* We will either have to standardize the execute method or check for it each time?
|
43
|
-
* Ditto with executep. Ditto with whether an interface supports parameterisation.
|
44
|
-
* trying to do a transaction across databases will fall over, but, really, no expectation there.
|
45
|
-
* You can't have a transaction that uses the result of the first half to do the last half.
|
46
|
-
* You can no longer call select() in a create, as we currently do for some interfaces? This is the
|
47
|
-
real problem I am wrestling with -- how to allow a transaction that returns a value from create().
|
48
|
-
|
49
|
-
|
50
|
-
Migrations
|
51
|
-
==========
|
52
|
-
|
53
|
-
This will almost certainly be something crude -- since we don't really control the database
|
54
|
-
connection in the same way as, say, ActiveRecord -- but I honestly think it's a worthwhile feature.
|
55
|
-
Just having something that you can version control and run to update a data model is enough,
|
56
|
-
really.
|
57
|
-
|
58
|
-
I'm not yet sure of the least useless way to implement it. Again, I favour SQL as the DSL.
|
59
|
-
|
60
|
-
We will clearly need transactions first, though.
|
61
|
-
|
62
|
-
My Current thoughts:
|
63
|
-
|
64
|
-
* a migration against a database is on a par with a model but very different. You subclass
|
65
|
-
migration and give it an interface, pointing to the table that stores the current migration
|
66
|
-
state.
|
67
|
-
|
68
|
-
* The methods in a module are exectute() up() and down() -- the last two call the first one.
|
69
|
-
|
70
|
-
* Each instance of a model is stored in a file and contains up and down SQL somehow. Each instance
|
71
|
-
has a version number.
|
72
|
-
|
73
|
-
* You run a migration by running up or down on your migration class, passing a version?
|
74
|
-
|
75
|
-
|
76
|
-
Connection Object
|
77
|
-
=================
|
78
|
-
|
79
|
-
PgInterface and TdsInterface both take a connection Hash, which is all very well, but it means that
|
80
|
-
we are running one database connection per model. Presumably this is a bad idea. :-)
|
81
|
-
|
82
|
-
This actually hasn't come up in my own use of Pod4 -- for complex reasons I'm either using
|
83
|
-
SequelInterface or running transient jobs which start up a couple of models, do some work, and then
|
84
|
-
stop entirely.
|
85
|
-
|
86
|
-
Connection is baked into those interfaces, and interface dependant. So I'm thinking in terms of a
|
87
|
-
memoising object that stores the connection hash and then gets passed to the interface. When the
|
88
|
-
interface wants a connection, then it asks the connection object. If the connection object doesn't
|
89
|
-
have one, then the interface connects, and gives the connection to the connection object.
|
90
|
-
|
91
|
-
It's looking as if we don't need this right now. One connection per model might not be as daft as
|
92
|
-
it seems.
|
93
|
-
|
94
|
-
|
95
|
-
JDBC-SQL interface
|
96
|
-
==================
|
97
|
-
|
98
|
-
For the jdbc-msssqlserver gem. Doable ... I *think*.
|
99
|
-
|
100
|
-
driver = Java::com.microsoft.sqlserver.jdbc.SQLServerDriver.new
|
101
|
-
props = java.util.Properties.new
|
102
|
-
props.setProperty("user", "username")
|
103
|
-
props.setProperty("password", "password")
|
104
|
-
url = 'jdbc:sqlserver://servername;instanceName=instance;databaseName=DbName;'
|
105
|
-
|
106
|
-
conn = driver.connect(url, props)
|
107
|
-
#or maybe conn = driver.get_connection(url, "username", "password")
|
108
|
-
|
109
|
-
stmt = conn.create_statement
|
110
|
-
sql = %Q|blah;|
|
111
|
-
|
112
|
-
rsS = stmt.execute_query(sql)
|
113
|
-
|
114
|
-
while (rsS.next) do
|
115
|
-
veg = Hash.new
|
116
|
-
veg["vegName"] = rsS.getObject("name")
|
117
|
-
# etc
|
118
|
-
end
|
119
|
-
|
120
|
-
stmt.close
|
121
|
-
conn.close
|
122
|
-
|
123
|
-
see https://github.com/jruby/jruby/wiki/JDBC
|
124
|
-
|
125
|
-
|
data/md/typecasting.md
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
TypeCasting
|
2
|
-
===========
|
3
|
-
|
4
|
-
Example
|
5
|
-
-------
|
6
|
-
|
7
|
-
```
|
8
|
-
require 'pod4'
|
9
|
-
require 'pod4/someinterface'
|
10
|
-
require 'pod4/typecasting'
|
11
|
-
|
12
|
-
class Foo < Pod4::Model
|
13
|
-
include Pod4::TypeCasting
|
14
|
-
|
15
|
-
class Interface < Pod4::SomeInterface
|
16
|
-
# blah blah blah
|
17
|
-
end
|
18
|
-
|
19
|
-
set_interface Interface.new($stuff)
|
20
|
-
|
21
|
-
attr_columns :name, :issue, :created, :due, :last_update, :completed, :thing
|
22
|
-
|
23
|
-
# Now the meat
|
24
|
-
typecast :issue, as: Integer
|
25
|
-
typecast :created, :due, as: Date
|
26
|
-
typecast :last_update, as: Time
|
27
|
-
typecast :completed, as: BigDecimal, ot_as: Float
|
28
|
-
typecast :thing, use: mymethod
|
29
|
-
end
|
30
|
-
```
|
31
|
-
|
32
|
-
What You Get
|
33
|
-
------------
|
34
|
-
|
35
|
-
### Every attribute named in a typecast gets:
|
36
|
-
|
37
|
-
* An accessor. (Probably it already has one, if it is named in attr_columns, but it doesn't have to
|
38
|
-
be. Note, though, that we don't add the attribute to the column list and it does not get output
|
39
|
-
in to_ot by default.)
|
40
|
-
|
41
|
-
* An attempt to force the value to that data type on set(). If the value cannot be coerced, it is
|
42
|
-
*untouched*.
|
43
|
-
|
44
|
-
* A second attempt to cast on to_interface(). This time, if the value cannot be coerced, it is set
|
45
|
-
to nil.
|
46
|
-
|
47
|
-
* if the optional `ot_as` type is set, then we cast a third time in the `to_ot()` method;
|
48
|
-
additionally we guard the OT with the base type using Octothorpe.guard. Note that this only
|
49
|
-
effects to_ot().
|
50
|
-
|
51
|
-
### Additionally the user can call these methods:
|
52
|
-
|
53
|
-
* `typecast?(:columnname, value)` returns true if the value can be cast; value defaults to the
|
54
|
-
column value if not given.
|
55
|
-
|
56
|
-
* `typecast(type, value, strict)` returns a typecast value, or either the original value, or nil if
|
57
|
-
strict is `:strict'.
|
58
|
-
|
59
|
-
* `guard(octothorpe)` will set guard conditions for nil values on the given octothorpe, based on
|
60
|
-
the attributes typecast knows about.
|
61
|
-
|
62
|
-
### The following types will be supported:
|
63
|
-
|
64
|
-
* Integer
|
65
|
-
* BigDecimal
|
66
|
-
* Float
|
67
|
-
* Date
|
68
|
-
* Time
|
69
|
-
* :boolean
|
70
|
-
|
71
|
-
Also: custom typecasting (`use: mymethod`, above). This must accept two parameters: the value, and
|
72
|
-
an option hash.
|
73
|
-
|
74
|
-
|
75
|
-
What You Don't Get
|
76
|
-
------------------
|
77
|
-
|
78
|
-
Validation. It's entirely up to you to decide how to validate and we won't second guess that. But
|
79
|
-
we do provide the `typecast?` method to help.
|
80
|
-
|
@@ -1,204 +0,0 @@
|
|
1
|
-
require 'octothorpe'
|
2
|
-
|
3
|
-
require 'pod4/model'
|
4
|
-
require 'pod4/null_interface'
|
5
|
-
|
6
|
-
|
7
|
-
##
|
8
|
-
# This is purely here to test that model works when you have a validate that accepts the new
|
9
|
-
# vmode parameter
|
10
|
-
#
|
11
|
-
describe 'Customer Model with new validate' do
|
12
|
-
|
13
|
-
let(:customer_model_class) do
|
14
|
-
Class.new Pod4::Model do
|
15
|
-
attr_columns :id, :name, :groups
|
16
|
-
attr_columns :price # specifically testing multiple calls to attr_columns
|
17
|
-
set_interface NullInterface.new(:id, :name, :price, :groups, [])
|
18
|
-
|
19
|
-
def map_to_model(ot)
|
20
|
-
super
|
21
|
-
@groups = @groups ? @groups.split(',') : []
|
22
|
-
self
|
23
|
-
end
|
24
|
-
|
25
|
-
def map_to_interface
|
26
|
-
x = super
|
27
|
-
g = (x.>>.groups || []).join(',')
|
28
|
-
x.merge(groups: g)
|
29
|
-
end
|
30
|
-
|
31
|
-
def fake_an_alert(*args)
|
32
|
-
add_alert(*args) #private method
|
33
|
-
end
|
34
|
-
|
35
|
-
def validate(vmode)
|
36
|
-
add_alert(:error, "falling over for mode #{vmode}") if name == "fall over"
|
37
|
-
end
|
38
|
-
|
39
|
-
def reset_alerts; @alerts = []; end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
let(:records) do
|
44
|
-
[ {id: 10, name: 'Gomez', price: 1.23, groups: 'trains' },
|
45
|
-
{id: 20, name: 'Morticia', price: 2.34, groups: 'spanish' },
|
46
|
-
{id: 30, name: 'Wednesday', price: 3.45, groups: 'school' },
|
47
|
-
{id: 40, name: 'Pugsley', price: 4.56, groups: 'trains,school'} ]
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
let(:records_as_ot) { records.map{|r| Octothorpe.new(r) } }
|
52
|
-
|
53
|
-
# model is just a plain newly created object that you can call read on.
|
54
|
-
# model2 and model3 are in an identical state - they have been filled with a
|
55
|
-
# read(). We have two so that we can RSpec 'allow' on one and not the other.
|
56
|
-
|
57
|
-
let(:model) { customer_model_class.new(20) }
|
58
|
-
|
59
|
-
let(:model2) do
|
60
|
-
m = customer_model_class.new(30)
|
61
|
-
|
62
|
-
allow( m.interface ).to receive(:read).and_return( Octothorpe.new(records[2]) )
|
63
|
-
m.read.or_die
|
64
|
-
end
|
65
|
-
|
66
|
-
let(:model3) do
|
67
|
-
m = customer_model_class.new(40)
|
68
|
-
|
69
|
-
allow( m.interface ).to receive(:read).and_return( Octothorpe.new(records[3]) )
|
70
|
-
m.read.or_die
|
71
|
-
end
|
72
|
-
|
73
|
-
##
|
74
|
-
|
75
|
-
|
76
|
-
describe '#create' do
|
77
|
-
|
78
|
-
let (:new_model) { customer_model_class.new }
|
79
|
-
|
80
|
-
it 'calls validate and passes the parameter' do
|
81
|
-
# validation tests arity of the validate method; rspec freaks out. So we can't
|
82
|
-
# `expect( new_model ).to receive(:validate)`
|
83
|
-
|
84
|
-
m = customer_model_class.new
|
85
|
-
m.name = "fall over"
|
86
|
-
m.create
|
87
|
-
expect( m.model_status ).to eq :error
|
88
|
-
expect( m.alerts.map(&:message) ).to include( include "create" )
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'calls create on the interface if the record is good' do
|
92
|
-
expect( customer_model_class.interface ).to receive(:create)
|
93
|
-
customer_model_class.new.create
|
94
|
-
|
95
|
-
new_model.fake_an_alert(:warning, :name, 'foo')
|
96
|
-
expect( new_model.interface ).to receive(:create)
|
97
|
-
new_model.create
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'doesnt call create on the interface if the record is bad' do
|
101
|
-
new_model.fake_an_alert(:error, :name, 'foo')
|
102
|
-
expect( new_model.interface ).not_to receive(:create)
|
103
|
-
new_model.create
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
##
|
108
|
-
|
109
|
-
|
110
|
-
describe '#read' do
|
111
|
-
|
112
|
-
it 'calls validate and passes the parameter' do
|
113
|
-
# again, because rspec is a bit stupid, we can't just `expect(model).to receive(:validate)`
|
114
|
-
|
115
|
-
allow( model.interface ).
|
116
|
-
to receive(:read).
|
117
|
-
and_return( records_as_ot.first.merge(name: "fall over") )
|
118
|
-
|
119
|
-
model.read
|
120
|
-
expect( model.model_status ).to eq :error
|
121
|
-
expect( model.alerts.map(&:message) ).to include( include "mode read" )
|
122
|
-
end
|
123
|
-
|
124
|
-
end
|
125
|
-
##
|
126
|
-
|
127
|
-
|
128
|
-
describe '#update' do
|
129
|
-
|
130
|
-
before do
|
131
|
-
allow( model2.interface ).
|
132
|
-
to receive(:update).
|
133
|
-
and_return( model2.interface )
|
134
|
-
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'calls validate and passes the parameter' do
|
138
|
-
# again, we can't `expect(model2).to receive(:validate)` because we're testing arity there
|
139
|
-
model2.name = "fall over"
|
140
|
-
model2.update
|
141
|
-
expect( model2.model_status ).to eq :error
|
142
|
-
expect( model2.alerts.map(&:message) ).to include( include "mode update" )
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'calls update on the interface if the validation passes' do
|
146
|
-
expect( model3.interface ).
|
147
|
-
to receive(:update).
|
148
|
-
and_return( model3.interface )
|
149
|
-
|
150
|
-
model3.update
|
151
|
-
end
|
152
|
-
|
153
|
-
it 'doesn\'t call update on the interface if the validation fails' do
|
154
|
-
expect( model3.interface ).not_to receive(:update)
|
155
|
-
|
156
|
-
model3.name = "fall over" # triggers validation
|
157
|
-
model3.update
|
158
|
-
end
|
159
|
-
|
160
|
-
end
|
161
|
-
##
|
162
|
-
|
163
|
-
|
164
|
-
describe '#delete' do
|
165
|
-
|
166
|
-
before do
|
167
|
-
allow( model2.interface ).
|
168
|
-
to receive(:delete).
|
169
|
-
and_return( model2.interface )
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
it 'calls validate and passes the parameter' do
|
174
|
-
# again, because rspec can't cope with us testing arity in Pod4::Model, we can't say
|
175
|
-
# `expect(model2).to receive(:validate)`. But for delete we are only running validation as a
|
176
|
-
# courtesy -- a validation fail does not stop the delete, it just sets alerts. So the model
|
177
|
-
# status should be :deleted and not :error
|
178
|
-
model2.name = "fall over"
|
179
|
-
model2.delete
|
180
|
-
expect( model2.alerts.map(&:message) ).to include(include "mode delete")
|
181
|
-
end
|
182
|
-
|
183
|
-
it 'calls delete on the interface if the model status is good' do
|
184
|
-
expect( model3.interface ).
|
185
|
-
to receive(:delete).
|
186
|
-
and_return( model3.interface )
|
187
|
-
|
188
|
-
model3.delete
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'calls delete on the interface if the model status is bad' do
|
192
|
-
expect( model3.interface ).
|
193
|
-
to receive(:delete).
|
194
|
-
and_return( model3.interface )
|
195
|
-
|
196
|
-
model3.fake_an_alert(:error, :price, 'qar')
|
197
|
-
model3.delete
|
198
|
-
end
|
199
|
-
|
200
|
-
end
|
201
|
-
##
|
202
|
-
|
203
|
-
end
|
204
|
-
|