datoki 3.1.0 → 3.2.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.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/VERSION +1 -1
- data/lib/datoki.rb +100 -26
- data/specs/0010-Datoki.db.rb +43 -4
- data/specs/0010-create.rb +45 -0
- data/specs/0010-update.rb +39 -0
- data/specs/0011-new.rb +37 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c428125e9eb84488c728ccefe771cc2999661ad5
|
4
|
+
data.tar.gz: 73a3385af85fec918db78ac0dcf2e688b0650a09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33c0f0d96d1c411211f50f36bf103d25d441ac1456ae19b765ba191df6379913bcb6d403b6b1a3470d0c5d8a97279022f60b13836b5539217303d48c05348d93
|
7
|
+
data.tar.gz: 59b1622720b9c1b909395fbaa1dbd1bd837384c9c7b6c4a0448c515c9baf76cd3e2410d09c720df1a940b10331cfc4b6d9fb1d8328ec8bb40ccd2072ed9e9662
|
data/README.md
CHANGED
@@ -11,6 +11,14 @@ for managing data in PostgreSQL.
|
|
11
11
|
## Usage
|
12
12
|
|
13
13
|
```ruby
|
14
|
+
# === Set it up: =======================
|
15
|
+
require 'datoki'
|
16
|
+
require 'sequel'
|
17
|
+
DB = Sequel.connect ENV['DATABASE_URL']
|
18
|
+
DB.cache_schema = false
|
19
|
+
Datoki.db DB
|
20
|
+
# ======================================
|
21
|
+
|
14
22
|
class Computer
|
15
23
|
include Datoki
|
16
24
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1
|
1
|
+
3.2.1
|
data/lib/datoki.rb
CHANGED
@@ -48,7 +48,7 @@ module Datoki
|
|
48
48
|
|
49
49
|
module Def_Field
|
50
50
|
|
51
|
-
attr_reader :ons, :fields, :fields_as_required
|
51
|
+
attr_reader :ons, :fields, :table_name, :fields_as_required
|
52
52
|
|
53
53
|
def initialize_def_field
|
54
54
|
@ons = {}
|
@@ -137,15 +137,35 @@ module Datoki
|
|
137
137
|
fields[@current_field][:allow][sym] = true;
|
138
138
|
end
|
139
139
|
|
140
|
+
#
|
141
|
+
# This method removes keys that
|
142
|
+
# are meant to be secret: e.g. encrypted passwords.
|
143
|
+
# This decreases the chance they end up in logs.
|
144
|
+
#
|
145
|
+
def returning_fields
|
146
|
+
return [] unless table_name
|
147
|
+
s = Datoki.db.schema(table_name)
|
148
|
+
return [] unless s
|
149
|
+
s.map { |pair|
|
150
|
+
name, meta = pair
|
151
|
+
field = fields[name]
|
152
|
+
if !field || !field[:secret]
|
153
|
+
name
|
154
|
+
else
|
155
|
+
nil
|
156
|
+
end
|
157
|
+
}.compact
|
158
|
+
end
|
159
|
+
|
140
160
|
def field? *args
|
141
161
|
inspect_field?(:type, field[:name], *args)
|
142
162
|
end
|
143
163
|
|
144
164
|
def field *args
|
145
165
|
# === Setup a default table if none specified:
|
146
|
-
if !@table_name
|
166
|
+
if !@table_name && Datoki.db
|
147
167
|
t_name = self.to_s.downcase.to_sym
|
148
|
-
table(
|
168
|
+
table(t_name) if Datoki.db.tables.include?(t_name)
|
149
169
|
end
|
150
170
|
|
151
171
|
return fields[@current_field] if args.empty?
|
@@ -294,6 +314,19 @@ module Datoki
|
|
294
314
|
self
|
295
315
|
end
|
296
316
|
|
317
|
+
def unique_index name, msg = nil
|
318
|
+
field[:unique_index] = name
|
319
|
+
if msg
|
320
|
+
field[:error_msgs] ||= {}
|
321
|
+
field[:error_msgs][:unique] = msg
|
322
|
+
end
|
323
|
+
self
|
324
|
+
end
|
325
|
+
|
326
|
+
def secret
|
327
|
+
field[:secret] = true
|
328
|
+
end
|
329
|
+
|
297
330
|
def primary_key
|
298
331
|
field[:primary_key] = true
|
299
332
|
if field?(:unknown)
|
@@ -452,13 +485,17 @@ module Datoki
|
|
452
485
|
}
|
453
486
|
|
454
487
|
def matches v = :blok
|
455
|
-
fail "Not allowed for #{field[:type].inspect}" unless field?(:chars)
|
456
488
|
field[:cleaners][:match] ||= []
|
457
489
|
field[:cleaners][:match] << (v == :blok ? Proc.new : v)
|
458
490
|
end
|
459
491
|
|
460
492
|
def create raw
|
461
|
-
raw[:create] = self
|
493
|
+
raw[:create] = self.to_s
|
494
|
+
new raw
|
495
|
+
end
|
496
|
+
|
497
|
+
def update raw
|
498
|
+
raw[:update] = self.to_s
|
462
499
|
new raw
|
463
500
|
end
|
464
501
|
|
@@ -466,7 +503,7 @@ module Datoki
|
|
466
503
|
|
467
504
|
# ================= Instance Methods ===============
|
468
505
|
|
469
|
-
attr_reader :error, :
|
506
|
+
attr_reader :error, :raw
|
470
507
|
def initialize unknown = nil
|
471
508
|
@data = nil
|
472
509
|
@field_name = nil
|
@@ -476,12 +513,18 @@ module Datoki
|
|
476
513
|
@db_ops = {} # Ex: :db_insert=>true, :db_update=>true
|
477
514
|
|
478
515
|
if unknown
|
479
|
-
|
516
|
+
is_record = unknown.keys.all? { |f|
|
517
|
+
self.class.fields.has_key?(f) ||
|
518
|
+
(self.class.schema && self.class.schema.has_key?(f))
|
519
|
+
}
|
520
|
+
|
521
|
+
if is_record
|
480
522
|
@data = unknown
|
481
523
|
@data.default_proc = Key_Not_Found
|
482
524
|
else
|
483
525
|
@raw = unknown
|
484
526
|
end
|
527
|
+
|
485
528
|
end
|
486
529
|
|
487
530
|
if @raw
|
@@ -489,11 +532,12 @@ module Datoki
|
|
489
532
|
schema = self.class.schema
|
490
533
|
|
491
534
|
case
|
492
|
-
when create?
|
535
|
+
when create?
|
493
536
|
create
|
494
|
-
when update?
|
537
|
+
when update?
|
538
|
+
clean primary_key[:name]
|
495
539
|
update
|
496
|
-
when delete?
|
540
|
+
when delete?
|
497
541
|
delete
|
498
542
|
end
|
499
543
|
|
@@ -508,7 +552,6 @@ module Datoki
|
|
508
552
|
|
509
553
|
if !@skips[:db] && !self.class.schema.empty?
|
510
554
|
|
511
|
-
final = db_clean
|
512
555
|
begin
|
513
556
|
case
|
514
557
|
|
@@ -516,12 +559,10 @@ module Datoki
|
|
516
559
|
db_insert
|
517
560
|
|
518
561
|
when update?
|
519
|
-
|
520
|
-
DB[self.class.table].
|
521
|
-
where(primary_key[:name] => final.delete(primary_key[:name])).
|
522
|
-
update(final)
|
562
|
+
db_update
|
523
563
|
|
524
564
|
when delete?
|
565
|
+
final = db_clean
|
525
566
|
DB[self.class.table].
|
526
567
|
where(primary_key[:name] => final.delete(primary_key[:name])).
|
527
568
|
delete
|
@@ -530,10 +571,10 @@ module Datoki
|
|
530
571
|
|
531
572
|
rescue Sequel::UniqueConstraintViolation => e
|
532
573
|
|
533
|
-
self.class.fields.each { |f|
|
534
|
-
if e.message["
|
574
|
+
self.class.fields.each { |f, meta|
|
575
|
+
if meta[:unique_index] && e.message[%^unique constraint "#{meta[:unique_index]}"^]
|
535
576
|
field_name f
|
536
|
-
fail! :unique, "{{English name}} already taken: #{
|
577
|
+
fail! :unique, "{{English name}} already taken: #{meta[:name]}"
|
537
578
|
end
|
538
579
|
}
|
539
580
|
raise e
|
@@ -543,6 +584,11 @@ module Datoki
|
|
543
584
|
end # === if @raw
|
544
585
|
end
|
545
586
|
|
587
|
+
def data
|
588
|
+
fail "Data not set." unless @data
|
589
|
+
@data
|
590
|
+
end
|
591
|
+
|
546
592
|
def skip name
|
547
593
|
@skips[name] = true
|
548
594
|
end
|
@@ -553,7 +599,8 @@ module Datoki
|
|
553
599
|
|
554
600
|
def db_clean
|
555
601
|
@clean.select { |k, v|
|
556
|
-
|
602
|
+
meta = self.class.fields[k]
|
603
|
+
!meta || !meta[:pseudo]
|
557
604
|
}
|
558
605
|
end
|
559
606
|
|
@@ -808,10 +855,17 @@ module Datoki
|
|
808
855
|
self.class.inspect_field? :type, field_name, *args
|
809
856
|
end
|
810
857
|
|
858
|
+
def id
|
859
|
+
d = data
|
860
|
+
pk = primary_key[:name]
|
861
|
+
fail "No primary key set yet." unless d.has_key?(pk)
|
862
|
+
d[pk]
|
863
|
+
end
|
864
|
+
|
811
865
|
def primary_key
|
812
|
-
|
813
|
-
fail "Primary key not found." unless
|
814
|
-
|
866
|
+
name, meta = self.class.fields.detect { |k, v| v[:primary_key] }
|
867
|
+
fail "Primary key not found." unless meta
|
868
|
+
meta
|
815
869
|
end
|
816
870
|
|
817
871
|
def new?
|
@@ -819,8 +873,7 @@ module Datoki
|
|
819
873
|
end
|
820
874
|
|
821
875
|
def create?
|
822
|
-
(@raw.has_key?(:create) && @raw[:create])
|
823
|
-
@raw.has_key?(primary_key[:name]) && !@raw[primary_key[:name]]
|
876
|
+
!!(@raw.has_key?(:create) && @raw[:create])
|
824
877
|
end
|
825
878
|
|
826
879
|
def read?
|
@@ -839,14 +892,35 @@ module Datoki
|
|
839
892
|
self.class::TABLE
|
840
893
|
end
|
841
894
|
|
895
|
+
def returning_fields
|
896
|
+
self.class.returning_fields
|
897
|
+
end
|
898
|
+
|
842
899
|
def db_insert
|
843
900
|
k = :db_insert
|
844
|
-
final = db_clean
|
845
901
|
fail "Already inserted." if @db_ops[k]
|
846
|
-
|
902
|
+
|
903
|
+
final = db_clean
|
904
|
+
new_data = TABLE().returning(*returning_fields).insert(final).first
|
905
|
+
@data = (@data || {}).merge(new_data)
|
847
906
|
@db_ops[k] = true
|
848
907
|
end
|
849
908
|
|
909
|
+
def db_update
|
910
|
+
k = :db_update
|
911
|
+
fail "Already updated" if @db_ops[k]
|
912
|
+
|
913
|
+
final = db_clean
|
914
|
+
new_data = TABLE().
|
915
|
+
returning(*returning_fields).
|
916
|
+
where(primary_key[:name] => final.delete(primary_key[:name])).
|
917
|
+
update(final).
|
918
|
+
first
|
919
|
+
|
920
|
+
@data = (@data || {}).merge(new_data)
|
921
|
+
@db_ops[:db_update] = true
|
922
|
+
end
|
923
|
+
|
850
924
|
end # === module Datoki ===
|
851
925
|
|
852
926
|
|
data/specs/0010-Datoki.db.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
|
2
|
+
class Datoki_Test
|
3
|
+
end
|
2
4
|
|
3
5
|
describe "Datoki.db" do
|
4
6
|
|
5
7
|
before {
|
6
|
-
|
7
8
|
CACHE[:datoki_db_test] ||= reset_db <<-EOF
|
8
9
|
CREATE TABLE "datoki_test" (
|
9
10
|
id serial NOT NULL PRIMARY KEY,
|
@@ -23,18 +24,56 @@ describe "Datoki.db" do
|
|
23
24
|
clean :title, :body
|
24
25
|
end
|
25
26
|
}
|
26
|
-
}
|
27
|
+
} # === before
|
27
28
|
|
28
|
-
it "
|
29
|
+
it "sets :table_name to name of class" do
|
30
|
+
class Datoki_Test
|
31
|
+
include Datoki
|
32
|
+
field(:title) { varchar 1,123 }
|
33
|
+
end
|
34
|
+
|
35
|
+
Datoki_Test.table_name.should == :datoki_test
|
36
|
+
end # === it sets :table_name to name of class
|
37
|
+
|
38
|
+
it "does not return fields marked as :secret" do
|
39
|
+
c = Class.new {
|
40
|
+
include Datoki
|
41
|
+
table :datoki_test
|
42
|
+
field(:title) { varchar 1, 123 }
|
43
|
+
field(:body) { text nil, 1, 123; secret }
|
44
|
+
|
45
|
+
def create
|
46
|
+
clean :id, :title, :body
|
47
|
+
end
|
48
|
+
}
|
49
|
+
r = c.create(:title=>'test', :body=>'my body')
|
50
|
+
r.data.keys.should == [:id, :title]
|
51
|
+
end # === it does not return fields marked as :secret
|
52
|
+
|
53
|
+
it "allows to save undefined field to the db" do
|
29
54
|
Class.new {
|
30
55
|
include Datoki
|
31
56
|
table :datoki_test
|
57
|
+
|
58
|
+
def create
|
59
|
+
clean[:title] = 'title 123'
|
60
|
+
end
|
61
|
+
}.create({})
|
62
|
+
DB[:datoki_test].all.last[:title].should == 'title 123'
|
63
|
+
end # === it allows to save undefined field to the db
|
64
|
+
|
65
|
+
it "allows an undefined field that exists in the db schema" do
|
66
|
+
r = Class.new {
|
67
|
+
include Datoki
|
68
|
+
table :datoki_test
|
32
69
|
field(:id) { primary_key }
|
33
70
|
field(:title) { varchar 1, 123 }
|
34
71
|
def create
|
35
72
|
clean :title
|
36
73
|
end
|
37
|
-
}.create(:title=>'title').data
|
74
|
+
}.create(:title=>'title').data
|
75
|
+
r[:title].should == 'title'
|
76
|
+
r[:body].should == 'hello'
|
38
77
|
end
|
39
78
|
|
40
79
|
it 'raises Schema_Conflict if a field is found that allows null, but not specifed to do so' do
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
describe :create do
|
3
|
+
|
4
|
+
before {
|
5
|
+
CACHE[:datoki_db_test] ||= reset_db <<-EOF
|
6
|
+
CREATE TABLE "datoki_test" (
|
7
|
+
id serial NOT NULL PRIMARY KEY,
|
8
|
+
title varchar(123) NOT NULL,
|
9
|
+
body text DEFAULT 'hello'
|
10
|
+
);
|
11
|
+
EOF
|
12
|
+
|
13
|
+
@klass = Class.new {
|
14
|
+
include Datoki
|
15
|
+
table :datoki_test
|
16
|
+
field(:id) { integer; primary_key }
|
17
|
+
field(:title) { varchar 1, 123 }
|
18
|
+
field(:body) { text nil, 1, 123 }
|
19
|
+
|
20
|
+
def create
|
21
|
+
clean :title, :body
|
22
|
+
end
|
23
|
+
}
|
24
|
+
} # === before
|
25
|
+
|
26
|
+
it "throws :invalid for a violation of a unique key constraint of a defined field" do
|
27
|
+
c = Class.new {
|
28
|
+
include Datoki
|
29
|
+
table :datoki_test
|
30
|
+
field(:id) { integer; primary_key; unique_index 'datoki_test_pkey' }
|
31
|
+
field(:title) { varchar 1, 123 }
|
32
|
+
field(:body) { text nil, 1, 123 }
|
33
|
+
|
34
|
+
def create
|
35
|
+
clean :id, :title, :body
|
36
|
+
end
|
37
|
+
}
|
38
|
+
r = @klass.create :title=>'the title', :body=>'yes yes yes'
|
39
|
+
catch(:invalid) {
|
40
|
+
c.create :id=>r.data[:id], :title=>r.data[:title], :body=>r.data[:body]
|
41
|
+
}.error[:msg].should.match /Id already taken/
|
42
|
+
end # === it
|
43
|
+
|
44
|
+
|
45
|
+
end # === describe :create
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
describe :update do
|
3
|
+
|
4
|
+
before {
|
5
|
+
CACHE[:update] ||= reset_db <<-EOF
|
6
|
+
CREATE TABLE "datoki_test" (
|
7
|
+
id serial NOT NULL PRIMARY KEY,
|
8
|
+
title varchar(123) NOT NULL,
|
9
|
+
body text DEFAULT 'hello'
|
10
|
+
);
|
11
|
+
EOF
|
12
|
+
} # === before
|
13
|
+
|
14
|
+
it "updates the record" do
|
15
|
+
c = Class.new {
|
16
|
+
include Datoki
|
17
|
+
table :datoki_test
|
18
|
+
field(:id) { integer; primary_key }
|
19
|
+
field(:title) { varchar 1, 123 }
|
20
|
+
field(:body) { text nil, 1, 123 }
|
21
|
+
|
22
|
+
def create
|
23
|
+
clean :title, :body
|
24
|
+
end
|
25
|
+
|
26
|
+
def update
|
27
|
+
clean :title, :body
|
28
|
+
end
|
29
|
+
}
|
30
|
+
|
31
|
+
r = c.create :title=>'My Old', :body=>'My Old'
|
32
|
+
c.update :id=>r.id, :title=>'My New Title', :body=>'My New Body'
|
33
|
+
|
34
|
+
record = DB[:datoki_test].where(:id=>r.id).first
|
35
|
+
record[:title].should == 'My New Title'
|
36
|
+
record[:body].should == 'My New Body'
|
37
|
+
end # === it updates the record
|
38
|
+
|
39
|
+
end # === describe :update
|
data/specs/0011-new.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
describe :new do
|
3
|
+
|
4
|
+
before {
|
5
|
+
CACHE[:datoki_db_test] ||= reset_db <<-EOF
|
6
|
+
CREATE TABLE "datoki_test" (
|
7
|
+
id serial NOT NULL PRIMARY KEY,
|
8
|
+
title varchar(123) NOT NULL,
|
9
|
+
body text DEFAULT 'hello'
|
10
|
+
);
|
11
|
+
EOF
|
12
|
+
|
13
|
+
} # === before
|
14
|
+
|
15
|
+
it "saves hash as data" do
|
16
|
+
klass = Class.new {
|
17
|
+
include Datoki
|
18
|
+
field(:title) { varchar 1, 123 }
|
19
|
+
field(:body) { text nil, 1, 123 }
|
20
|
+
}
|
21
|
+
r = klass.new(title: 'title1', body: 'body1')
|
22
|
+
r.data[:title].should == 'title1'
|
23
|
+
end # === it saves hash as data
|
24
|
+
|
25
|
+
it "saves hash even for undefined, yet schema, fields" do
|
26
|
+
klass = Class.new {
|
27
|
+
include Datoki
|
28
|
+
table :datoki_test
|
29
|
+
field(:title) { varchar 1, 123 }
|
30
|
+
}
|
31
|
+
r = klass.new(id: 1, title: 'title1', body: 'body1')
|
32
|
+
r.data[:title].should == 'title1'
|
33
|
+
end # === it saves hash even for undefined, yet schema, fields
|
34
|
+
|
35
|
+
end # === describe :new
|
36
|
+
|
37
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: datoki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1
|
4
|
+
version: 3.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- da99
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -111,12 +111,15 @@ files:
|
|
111
111
|
- specs/0010-Datoki.db.rb
|
112
112
|
- specs/0010-Numeric.rb
|
113
113
|
- specs/0010-Numeric_db.rb
|
114
|
+
- specs/0010-create.rb
|
114
115
|
- specs/0010-href.rb
|
115
116
|
- specs/0010-html_escape.rb
|
116
117
|
- specs/0010-no_type.rb
|
117
118
|
- specs/0010-schema_conflict.rb
|
119
|
+
- specs/0010-update.rb
|
118
120
|
- specs/0010-varchar.rb
|
119
121
|
- specs/0010-varchar_db.rb
|
122
|
+
- specs/0011-new.rb
|
120
123
|
- specs/0011-string_ish.rb
|
121
124
|
- specs/0012-pseudo.rb
|
122
125
|
- specs/0020-clean!.rb
|
@@ -144,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
147
|
version: '0'
|
145
148
|
requirements: []
|
146
149
|
rubyforge_project:
|
147
|
-
rubygems_version: 2.4.
|
150
|
+
rubygems_version: 2.4.6
|
148
151
|
signing_key:
|
149
152
|
specification_version: 4
|
150
153
|
summary: A gem to manage PGsql records.
|