pod4 0.10.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1e0f3ba3e1a6e876874296334e8df4a789c6757403a6f72697e7f2a5506ac05f
|
4
|
+
data.tar.gz: db35eb4f442ebe83b30de9ce394354143586142144af531171f35afffa8e504c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d033f6947e0e2fcf421f764746f647c68e1158b65568a215c57db2508773aecc700815bc4ad318bb844f5252e89c64fe16eca6a1b20c60fb15730835d411b90
|
7
|
+
data.tar.gz: 68908e5107c5f1160b42b4948514554c57e53dcc337e413fd5b6282e6edc22ecf4dd51680a4a11f59103c6fb2ee1f8cb1d138f01b0f9007c5be41f4e2b984b1f
|
data/.bugs/bugs
CHANGED
@@ -1,2 +1,3 @@
|
|
1
1
|
Fixnum is Deprecated | owner:Andy Jones <andy.jones@jameshall.co.uk>, open:True, id:274eb8828bd4e7d879e4f7a99317c75eb2a2e2b0, time:1533817328.12
|
2
|
-
BigDecimal.new is deprecated | owner:Andy Jones <andy.jones@jameshall.co.uk>, open:
|
2
|
+
BigDecimal.new is deprecated | owner:Andy Jones <andy.jones@jameshall.co.uk>, open:False, id:3979ce1679bc4f8c4aef8436e344e10e3773480d, time:1533817342.0
|
3
|
+
Connection Pool Parallelism tests crash rspec when run as part of the suite | owner:Andy Jones <andy.jones@jameshall.co.uk>, open:False, id:b5368c7ef19065fc597b5692314da71772660963, time:1554280671.5
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Lines starting with '#' and sections without content
|
2
|
+
# are not displayed by a call to 'details'
|
3
|
+
#
|
4
|
+
[paths]
|
5
|
+
# Paths related to this bug.
|
6
|
+
# suggested format: REPO_PATH:LINENUMBERS
|
7
|
+
|
8
|
+
|
9
|
+
[details]
|
10
|
+
# Additional details
|
11
|
+
You can duplicate this by running the following tests in this order, in Jruby:
|
12
|
+
|
13
|
+
* common/connection_pool_parallelism_spec
|
14
|
+
* common/nebulous_interface_spec
|
15
|
+
* common/sequel_pg_interface_spec
|
16
|
+
|
17
|
+
Here's the error:
|
18
|
+
|
19
|
+
```
|
20
|
+
Stomp::Error::ReceiveTimeout: Stomp::Error::ReceiveTimeout
|
21
|
+
block in _receive at /home/jonea/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/stomp-1.4.4/lib/connec
|
22
|
+
tion/netio.rb:66
|
23
|
+
synchronize at org/jruby/ext/thread/Mutex.java:158
|
24
|
+
_receive at /home/jonea/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/stomp-1.4.4/lib/connec
|
25
|
+
tion/netio.rb:31
|
26
|
+
__old_receive at /home/jonea/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/stomp-1.4.4/lib/connec
|
27
|
+
tion/utils.rb:250
|
28
|
+
receive at /home/jonea/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/stomp-1.4.4/lib/stomp/
|
29
|
+
connection.rb:481
|
30
|
+
block in start_listeners at /home/jonea/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/stomp-1.4.4/lib/client
|
31
|
+
/utils.rb:194
|
32
|
+
loop at org/jruby/RubyKernel.java:1316
|
33
|
+
block in start_listeners at /home/jonea/.rbenv/versions/jruby-9.1.17.0/lib/ruby/gems/shared/gems/stomp-1.4.4/lib/client
|
34
|
+
/utils.rb:193
|
35
|
+
r
|
36
|
+
```
|
37
|
+
|
38
|
+
This might be related to this jRuby bug: https://github.com/jruby/jruby/issues/5476.
|
39
|
+
|
40
|
+
[expected]
|
41
|
+
# The expected result
|
42
|
+
|
43
|
+
|
44
|
+
[actual]
|
45
|
+
# What happened instead
|
46
|
+
|
47
|
+
|
48
|
+
[reproduce]
|
49
|
+
# Reproduction steps
|
50
|
+
|
51
|
+
|
52
|
+
[comments]
|
53
|
+
# Comments and updates - leave your name
|
data/.hgtags
CHANGED
data/Gemfile
CHANGED
@@ -6,19 +6,19 @@ gemspec
|
|
6
6
|
group :development, :test do
|
7
7
|
|
8
8
|
# for bundler, management, etc etc
|
9
|
-
gem "bundler", "~>
|
9
|
+
gem "bundler", "~> 2"
|
10
10
|
gem "rake", "~> 12"
|
11
|
-
gem "rspec", "~> 3.
|
11
|
+
gem "rspec", "~> 3.8"
|
12
12
|
gem 'pry'
|
13
13
|
gem "pry-doc"
|
14
14
|
|
15
15
|
# For testing
|
16
|
-
gem "sequel", "~> 5.
|
16
|
+
gem "sequel", "~> 5.20"
|
17
17
|
gem "nebulous_stomp", "~> 3"
|
18
18
|
|
19
19
|
platforms :ruby do
|
20
|
-
gem "sqlite3", "~> 1.
|
21
|
-
gem "tiny_tds", "~> 1
|
20
|
+
gem "sqlite3", "~> 1.4"
|
21
|
+
gem "tiny_tds", "~> 2.1"
|
22
22
|
gem "pg"
|
23
23
|
end
|
24
24
|
|
data/README.md
CHANGED
@@ -49,7 +49,8 @@ I don't want the people who maintain my code to have to know the differences bet
|
|
49
49
|
or so methods you need to worry about, and six of those are pretty much self-explanatory. Or, you
|
50
50
|
can inherit from Pod4::BasicModel instead, and do without even that.
|
51
51
|
|
52
|
-
I honestly don't think of it as an Object Relational Manager. I think of it as a Way To Have Nice
|
52
|
+
I honestly don't think of it as an Object Relational Manager. I think of it as a Way To Have Nice
|
53
|
+
Models.
|
53
54
|
|
54
55
|
If you are looking for something with all the features of, say, ActiveRecord, then this isn't for
|
55
56
|
you. I provide basic access to and maintenance of records, with validation. For anything more, you
|
@@ -168,7 +169,7 @@ Here is the model and interface definition that goes with the above example:
|
|
168
169
|
|
169
170
|
class ExampleInterface < Pod4::PgInterface
|
170
171
|
set_table :example
|
171
|
-
set_id_fld :id
|
172
|
+
set_id_fld :id, autoincrement: true
|
172
173
|
end
|
173
174
|
|
174
175
|
set_interface ExampleInterface.new($pg_conn)
|
@@ -199,11 +200,12 @@ the data. What they are depends on the interface, but the ones for PgInterface a
|
|
199
200
|
|
200
201
|
Actually, _every_ interface defines `set_id_fld`. Instances of a model _must_ be represented by a
|
201
202
|
single ID field that provides a unique identifier. Pod4 does not care what it's called or what data
|
202
|
-
type it is -- if you say that's what makes it unique, that's good enough.
|
203
|
+
type it is -- if you say that's what makes it unique, that's good enough. Additionally you can
|
204
|
+
specify whether your key autoincrements or not. If you don't say, we assume that it does.
|
203
205
|
|
204
206
|
Internally, Interfaces talk the same basic language of list / create / read / update / delete that
|
205
|
-
models do.
|
206
|
-
for your Interface definition.
|
207
|
+
models do. Sometimes you might want to add a special interface method for a specific database
|
208
|
+
operation, but otherwise that's probably going to be it for your Interface definition.
|
207
209
|
|
208
210
|
### Model ###
|
209
211
|
|
@@ -214,14 +216,16 @@ Models have two of their own DSLish methods:
|
|
214
216
|
|
215
217
|
You can see that interfaces are instantiated when the model is required. Exactly what you need to
|
216
218
|
pass to the interface to instantiate it depends on the interface. SequelInterface wants the Sequel
|
217
|
-
DB object
|
218
|
-
|
219
|
+
DB object; the other interfaces only want connection hashes.
|
220
|
+
|
221
|
+
(If you are finding it annoying to have to, for example, figure out your database connection hash
|
222
|
+
or get a Sequel DB object _before_ requiring your models, then see "Connections", below.)
|
219
223
|
|
220
224
|
Any attributes you define using `attr_columns` are treated specially by Pod4::Model. You get all
|
221
225
|
the effect of the standard Ruby `attr_accessor` call, but in addition, the attribute will be passed
|
222
226
|
to and from the interface, and to and from your external code, by the standard model methods.
|
223
227
|
|
224
|
-
In addition to the
|
228
|
+
In addition to the methods above, we have:
|
225
229
|
|
226
230
|
* `validate` -- override this to provide validation
|
227
231
|
* `map_to_model` -- controls how the interface sets attributes on the model
|
@@ -231,7 +235,7 @@ In addition to the ones above, we have:
|
|
231
235
|
A model also has some built-in attributes of its own:
|
232
236
|
|
233
237
|
* `model_id` -- this is the value of the ID column you set in the interface.
|
234
|
-
* `model_status` -- one of :error :warning :okay :deleted :
|
238
|
+
* `model_status` -- one of :error :warning :okay :deleted :unknown
|
235
239
|
|
236
240
|
We'll deal with all these below.
|
237
241
|
|
@@ -240,11 +244,12 @@ Adding Validation
|
|
240
244
|
-----------------
|
241
245
|
|
242
246
|
Built into the model is an array of alerts (Pod4::Alert) which are messages that have been raised
|
243
|
-
against the instance of the model class. Each alert can have a
|
244
|
-
:success. If any alert has a
|
245
|
-
|
247
|
+
against the instance of the model class. Each alert can have a type of :error, :warning, :info or
|
248
|
+
:success. If any alert has a type of :error or :warning, then that is reflected in the model's
|
249
|
+
`model_status` attribute. A model that has passed validation with no :error or :warning alerts is
|
250
|
+
status :okay.
|
246
251
|
|
247
|
-
(
|
252
|
+
(There are two other possible statuses -- models are :unknown when validation has yet to be run,
|
248
253
|
and :deleted after a call to delete.)
|
249
254
|
|
250
255
|
You can raise alerts yourself, and you normally do so by overriding `validate`. This method is
|
@@ -259,7 +264,7 @@ Here's a model with some validation:
|
|
259
264
|
class CustomerInterface < Pod4::PgInterface
|
260
265
|
set_schema :pod4example
|
261
266
|
set_table :customer
|
262
|
-
set_id_fld :id
|
267
|
+
set_id_fld :id, autoincrement: true
|
263
268
|
end
|
264
269
|
|
265
270
|
set_interface CustomerInterface.new($pg_conn)
|
@@ -287,7 +292,7 @@ the validation will fail. (Probably you do not want this on delete; test the pa
|
|
287
292
|
to validate as in the example above).
|
288
293
|
|
289
294
|
In passing I should note that validation is _not_ run on list: every record that list returns
|
290
|
-
should be complete, but the `model_status` will be :
|
295
|
+
should be complete, but the `model_status` will be :unknown because validation has not been run.
|
291
296
|
(This is partly for the sake of speed.)
|
292
297
|
|
293
298
|
You should be aware that validation is not called on `set`, either. Because of that, it's entirely
|
@@ -304,16 +309,16 @@ datatimes should all end up as the right type in the model. (It depends on the
|
|
304
309
|
going to get tired of me saying that, aren't you?) But maybe you want more than that.
|
305
310
|
|
306
311
|
Let's imagine you have a database table in PostreSQL with a column called cost that uses the money
|
307
|
-
type. And you want it to be a `BigDecimal` in the model.
|
308
|
-
all I know someone might have a problem with my requiring
|
309
|
-
yourself.
|
312
|
+
type. (This is a terrible idea, by the way.) And you want it to be a `BigDecimal` in the model.
|
313
|
+
Well, Pod4 won't do that for you -- for all I know someone might have a problem with my requiring
|
314
|
+
BigDecimal -- but it's not hard to do yourself.
|
310
315
|
|
311
316
|
class Product < Pod4::Model
|
312
317
|
|
313
318
|
class ProductInterface < Pod4::PgInterface
|
314
319
|
set_schema :pod4example
|
315
320
|
set_table :product
|
316
|
-
set_id_fld :product_id
|
321
|
+
set_id_fld :product_id, autoincrement: true
|
317
322
|
end
|
318
323
|
|
319
324
|
set_interface ProductInterface.new($pg_conn)
|
@@ -340,7 +345,8 @@ interface from the model. It _returns_ an Octothorpe to the interface. By defaul
|
|
340
345
|
You might also want to ensure that your data types are honoured when your application updates a
|
341
346
|
model object; in which case you will need to override `set` as well.
|
342
347
|
|
343
|
-
|
348
|
+
If this seems like a lot of work, take a look at the Pod4::TypeCasting mixin. it will handle it for
|
349
|
+
you.
|
344
350
|
|
345
351
|
|
346
352
|
Relations
|
@@ -352,7 +358,7 @@ Pod4 does not provide relations. But, I'm not sure that it needs to. Look:
|
|
352
358
|
|
353
359
|
class BlogPostInterface < Pod4::PgInterface
|
354
360
|
set_table :blogpost
|
355
|
-
set_id_fld :id
|
361
|
+
set_id_fld :id, autoincrement: true
|
356
362
|
end
|
357
363
|
|
358
364
|
set_interface BlogPostInterface.new($conn)
|
@@ -396,7 +402,7 @@ If your interface is connected to a SQL database, it should provide two more met
|
|
396
402
|
|
397
403
|
class BlogPostInterface < Pod4::PgInterface
|
398
404
|
set_table :blogpost
|
399
|
-
set_id_fld :id
|
405
|
+
set_id_fld :id, autoincrement: true
|
400
406
|
end
|
401
407
|
|
402
408
|
set_interface BlogPostInterface.new($conn)
|
@@ -434,12 +440,110 @@ certainly need revisiting if you change database. But how often does that happen
|
|
434
440
|
it ever does, you are likely to need to revisit the effected models anyway...
|
435
441
|
|
436
442
|
|
443
|
+
Connections
|
444
|
+
-----------
|
445
|
+
|
446
|
+
### A Couple Of Wrinkles ###
|
447
|
+
|
448
|
+
There are a couple of weird wrinkles in all this which you may or may not have missed. Wrinkle
|
449
|
+
one:
|
450
|
+
|
451
|
+
class MyModel < Pod4::Model
|
452
|
+
|
453
|
+
class Interface < Pod4::PgInterface
|
454
|
+
set_id_fld :id, autoincrement: true
|
455
|
+
set_table :my_table
|
456
|
+
end
|
457
|
+
|
458
|
+
set_interface Interface.new($pgconn) # <- wrinkle
|
459
|
+
attr_columns :one, two, three
|
460
|
+
end
|
461
|
+
|
462
|
+
You _instantiate_ the interface at the point where you _define_ the model. I admit this is a
|
463
|
+
little odd. It wasn't a specific design decision on my part; rather it was the cleanest way to get
|
464
|
+
where I was going.
|
465
|
+
|
466
|
+
In practice this means you need to get your DB connection details from somewhere, maybe create your
|
467
|
+
Sequel DB object; and only then can you require your models.
|
468
|
+
|
469
|
+
Leading on from this, wrinkle two: except when using Sequel (which behaves differently) each
|
470
|
+
interface has its own connection to the database. This means that your application has (simplifying
|
471
|
+
a bit here) one database connection for each model class. So if you have a Customer model and a
|
472
|
+
Orders model, your application will hold two connections to the database. All customer enquiries
|
473
|
+
share a single connection, and all order enquiries share a single connection.
|
474
|
+
|
475
|
+
I'm finding that, generally, this scales about right. But if you have a lot of different models and a
|
476
|
+
database that runs out of connections easily, it might be problematic.
|
477
|
+
|
478
|
+
### The Connection Object ###
|
479
|
+
|
480
|
+
The solution to both of these wrinkles, if you need one, is to use a Pod4::Connection object:
|
481
|
+
|
482
|
+
#
|
483
|
+
# init.rb -- bootup for my project
|
484
|
+
#
|
485
|
+
|
486
|
+
# Require libraries
|
487
|
+
require "sequel"
|
488
|
+
require "pod4"
|
489
|
+
require "pod4/sequel_interface"
|
490
|
+
require "pod4/connection"
|
491
|
+
|
492
|
+
# require models
|
493
|
+
$conn = Pod4::Connection.new(interface: Pod4::SequelInterface)
|
494
|
+
require_relative "models/customer"
|
495
|
+
|
496
|
+
# set up database connection
|
497
|
+
hash = get_sequel_params
|
498
|
+
$conn.data_layer_options = Sequel.connect(hash)
|
499
|
+
|
500
|
+
#############
|
501
|
+
|
502
|
+
#
|
503
|
+
# models/customer.rb ( only a part shown)
|
504
|
+
#
|
505
|
+
|
506
|
+
class Foo < Pod4::Model
|
507
|
+
class Interface < Pod4::SequelInterface
|
508
|
+
set_table :foo
|
509
|
+
set_id_field :id, autoincrement: true
|
510
|
+
end
|
511
|
+
|
512
|
+
set_interface Interface.new($conn)
|
513
|
+
|
514
|
+
TL;DR: the only code that needs to go in the middle of your requires is the line defining a
|
515
|
+
Connection object; you pass that to the interface instead. You can set up the parameters
|
516
|
+
the interface needs and pass them to the connection object afterwards.
|
517
|
+
|
518
|
+
With TdsInterface and PgInterface you can pass the same connection to multiple models and they will
|
519
|
+
share it. These interfaces take a Pod4::ConnectionPool instead, but otherwise the code looks
|
520
|
+
exactly the same as the above example.
|
521
|
+
|
522
|
+
(Technical note: the ConnectionPool object will actually provide multiple connections, one per
|
523
|
+
thread that uses it. This satisfies the requirement of the underlying libraries that connections
|
524
|
+
are not shared between threads, and therefore ensures that Pod4 is more or less thread safe. You
|
525
|
+
get this functionality automatically -- if you don't define a ConnectionPool, then the interface
|
526
|
+
will create one internally. Sequel uses its own thread pool, of course, and we only use the one
|
527
|
+
Sequel DB object for the whole of Pod4, so it doesn't need any of that. That's why it uses
|
528
|
+
Pod4::Connection, instead.)
|
529
|
+
|
530
|
+
|
437
531
|
BasicModel
|
438
532
|
----------
|
439
533
|
|
440
534
|
Sometimes your model needs to represent data in a way which is so radically different from the data
|
441
535
|
source that the whole list, create, read, update, delete thing that Pod4::Model gives you is no
|
442
|
-
use.
|
536
|
+
use.
|
537
|
+
|
538
|
+
Pod4::BasicModel gives you:
|
539
|
+
|
540
|
+
* `set_interface`
|
541
|
+
* the `model_id`, `model_status` and `alerts` attributes
|
542
|
+
* `add_alert`
|
543
|
+
|
544
|
+
...and nothing else. But that's enough to make a model, your way, using the methods on the
|
545
|
+
interface. These are the same CRUDL methods that Pod4::Model provides -- except that on the
|
546
|
+
interface, the CRUD methods take a record id as a key.
|
443
547
|
|
444
548
|
A real world example: at James Hall my intranet system has a User model, where each attribute is a
|
445
549
|
parameter that controls how the system behaves for that user -- email address, security settings,
|
@@ -450,16 +554,6 @@ add a user parameter. The logical place to change the parameter is in the User m
|
|
450
554
|
database, and certainly not both. So on the database, I have a settings table where the key runs:
|
451
555
|
userid, setting name.
|
452
556
|
|
453
|
-
Pod4::BasicModel gives you:
|
454
|
-
|
455
|
-
* `set_interface`
|
456
|
-
* the `model_id`, `model_status` and `alerts` attributes
|
457
|
-
* `add_alert`
|
458
|
-
|
459
|
-
...and nothing else. But that's enough to make a model, your way, using the methods on the
|
460
|
-
interface. These are the same CRUDL methods that Pod4::Model provides -- except that the CRUD
|
461
|
-
methods take a record id as a key.
|
462
|
-
|
463
557
|
Here's a simplified version of my User model. This one is read only, but it's hopefully enough to
|
464
558
|
get the idea:
|
465
559
|
|
@@ -467,10 +561,9 @@ get the idea:
|
|
467
561
|
|
468
562
|
class UserInterface < ::Pod4::SequelInterface
|
469
563
|
set_table :settings
|
470
|
-
set_id_fld :id
|
564
|
+
set_id_fld :id, autoincrement: false
|
471
565
|
end
|
472
566
|
|
473
|
-
|
474
567
|
# Here we set what settings always exist for a user
|
475
568
|
Setting = Struct.new(:setName, :default)
|
476
569
|
|
@@ -485,19 +578,14 @@ get the idea:
|
|
485
578
|
set_interface UserInterface.new($db)
|
486
579
|
attr_reader :userid, :depot, :store, :menu, :roles, :name, :nick, :mail
|
487
580
|
|
488
|
-
|
489
581
|
class << self
|
490
|
-
|
491
582
|
def keys; DefaultSettings.map{|x| x.setName }; end
|
492
583
|
|
493
584
|
def list
|
494
585
|
array = interface.select(%Q|select distinct userid from settings;|)
|
495
586
|
array.map {|r| self.new( r[:userid] ).read }
|
496
587
|
end
|
497
|
-
|
498
|
-
end
|
499
|
-
##
|
500
|
-
|
588
|
+
end # of class << self
|
501
589
|
|
502
590
|
def initialize(userid=nil)
|
503
591
|
super(userid)
|
@@ -507,7 +595,6 @@ get the idea:
|
|
507
595
|
end
|
508
596
|
end
|
509
597
|
|
510
|
-
|
511
598
|
def read
|
512
599
|
lst = interface.list(userid: @model_id)
|
513
600
|
|
@@ -517,12 +604,11 @@ get the idea:
|
|
517
604
|
|
518
605
|
@userid = @model_id
|
519
606
|
set_merge( Octothorpe.new(data) )
|
520
|
-
validate; @model_status = :okay unless @model_status != :
|
607
|
+
validate; @model_status = :okay unless @model_status != :unknown
|
521
608
|
|
522
609
|
self
|
523
610
|
end
|
524
611
|
|
525
|
-
|
526
612
|
def to_ot
|
527
613
|
hash = self.class.keys.each_with_object({}) do |k,m|
|
528
614
|
m[k] = instance_variable_get("@#{k}".to_sym)
|
@@ -531,7 +617,6 @@ get the idea:
|
|
531
617
|
Octothorpe.new(hash)
|
532
618
|
end
|
533
619
|
|
534
|
-
|
535
620
|
def set_merge(hash)
|
536
621
|
self.class.keys.each do |key|
|
537
622
|
value = hash[key]
|
@@ -541,11 +626,37 @@ get the idea:
|
|
541
626
|
|
542
627
|
end
|
543
628
|
|
629
|
+
|
544
630
|
Extensions
|
545
631
|
----------
|
546
632
|
|
547
|
-
There are
|
633
|
+
There are some mixins that you can use to extend the functionality of Pod4 models. Have a look
|
548
634
|
at the comments at the top of the mixin in question if you want details.
|
549
635
|
|
550
636
|
* typecasting -- force columns to be a specific ruby type, validation helpers, some encoding stuff
|
551
637
|
* encrypting -- encrypt text columns
|
638
|
+
* tweaking -- adds DSL commands to support custom methods on the interface.
|
639
|
+
|
640
|
+
|
641
|
+
Gotchas
|
642
|
+
-------
|
643
|
+
|
644
|
+
Some hopefully-not-too-unexpected behaviour:
|
645
|
+
|
646
|
+
* If you change attributes on a record, then call #delete or #read on it, we don't warn you that
|
647
|
+
your changes are lost.
|
648
|
+
|
649
|
+
* If you attempt to update an autoincrement ID field, we don't write that change to the database
|
650
|
+
and we don't warn you about that.
|
651
|
+
|
652
|
+
* As mentioned above, we only run validate on #create, #read, #update and #delete. So you can
|
653
|
+
change the attributes of a record to something invalid without it immediately warning you. (You
|
654
|
+
can always run #validate yourself, though.)
|
655
|
+
|
656
|
+
* Again, as mentioned above, the array of model instances returned by #list will all be status
|
657
|
+
:unknown. This is because we have run neither #read nor #validate against them.
|
658
|
+
|
659
|
+
* I can't stop you writing to `@model_id` or `@model_status` in your model. I have no idea what
|
660
|
+
might happen if you do, but I doubt that it would ever be a good idea. (In a non-autoincrement
|
661
|
+
model, write to your ID field directly instead; `@model_id` will be updated when you call
|
662
|
+
#create, #update or of course #read.)
|