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 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.