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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 43a52b61961fb85e568c481ec205a0367f13a50b
4
- data.tar.gz: 9b9064f20a24ebe7b141ea54f9e201ce447fa1d7
3
+ metadata.gz: c428125e9eb84488c728ccefe771cc2999661ad5
4
+ data.tar.gz: 73a3385af85fec918db78ac0dcf2e688b0650a09
5
5
  SHA512:
6
- metadata.gz: 389d463817cdad3695f0355216e3e6eba492ed092c63ffe18a7c391351f9a66305121b7242d4076c74fdb5cd64ff68195e980caba5298fc3149771c9a8e3a591
7
- data.tar.gz: b23b19e80b655b8020bd5f57ef71772093c5b351c7a47026dbe08490e5074223e29653ae532afb649c895a9c5efa85ae55d9f3ec3b5cd0520c7b5ffe09ba49a4
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.0
1
+ 3.2.1
@@ -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(name) if Datoki.db.tables.include?(t_name)
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, :data
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
- if unknown.keys.all? { |f| self.class.fields.has_key?(f) }
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? && respond_to?(:create)
535
+ when create?
493
536
  create
494
- when update? && respond_to?(:update)
537
+ when update?
538
+ clean primary_key[:name]
495
539
  update
496
- when delete? && respond_to?(: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["'\"#{f}_"]
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: #{final[f]}"
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
- !self.class.fields[k][:pseudo]
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
- arr = self.class.fields.detect { |k, v| v[:primary_key] }
813
- fail "Primary key not found." unless arr
814
- arr.last
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
- @data = (@data || {}).merge(TABLE().returning.insert(final).first)
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
 
@@ -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 "allows an undefined field that exists in the db schema" do
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.should == {:id=>1, :title=>'title', :body=>'hello'}
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
@@ -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.0
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-03-24 00:00:00.000000000 Z
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.5
150
+ rubygems_version: 2.4.6
148
151
  signing_key:
149
152
  specification_version: 4
150
153
  summary: A gem to manage PGsql records.