datoki 3.1.0 → 3.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|