post_json 1.0.6 → 1.0.7

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: 96d7ef19a5b074957629924c45a9a71894cc5f97
4
- data.tar.gz: ca189492fea7bf032db65d2762c852b66c39532b
3
+ metadata.gz: 2f25ad4b6cb31d0b679bfa6c41d8b5533c3c69a8
4
+ data.tar.gz: 25b074ed6292d61272a2b3bb08c021d32ca881af
5
5
  SHA512:
6
- metadata.gz: 263da488e04ee6c7dc08aaaed72d21c0802bc3d6ec96aa5575e0519c8945c72c31f20c346e432eaa182cfe8b1b964f5bcd0eeacdca7f02b3d693606ae73cc8d1
7
- data.tar.gz: b3a221adbf2b1b67c810a0c0b7c76c942ff4f68dc3a3234e75557a7006c07ce49be538560218884085f94ff08e8108a8050464cee7e6b1b35cee78c7edf6d389
6
+ metadata.gz: 9783c9e9b72e4d5f6fadd58718a25c3a13c29a1b6168997f1abbbb7511c21d5891badde842b51b70885b19a077d63d5595acc891a7e486f464eb9bf574d9667f
7
+ data.tar.gz: 71267eaa0731c1a4340ec28808fcbcd3961ccddb36b5525170bc3b85727fac0d9d78d22f96ae2133c82758462c6d1ec6af385472b8de03c3c7f53e4eacd3d327
data/README.md CHANGED
@@ -135,7 +135,32 @@ find_by!, find_each, find_in_batches, first, first!, first_or_create, first_or_i
135
135
  many?, offset, only, order, pluck, reorder, reverse_order, select, size, take, take!, to_a, to_sql, and where.
136
136
 
137
137
  We also added `page(page, per_page)`, which translate into `offset((page-1)*per_page).limit(per_page)`.
138
+
139
+
140
+ ## Performance
141
+
142
+ On a virtual machine running on a 3 year old laptop we created 100.000 documents:
143
+
144
+ test_model = PostJson::Collection["test"]
145
+ 100000.times { test_model.create(content: SecureRandom.uuid) }
146
+ content = test_model.last.content
138
147
 
148
+ result = test_model.where(content: content).count
149
+ # Rails debug tells me the duration was 975.5ms
150
+
151
+ The duration was above 50ms as you can see.
152
+
153
+ PostJson has a feature called "Dynamic Index". It is enabled by default and works automatic behind the scene. It has now created an index on 'content'.
154
+
155
+ Now lets see how the performance will be on the second and future queries using 'content':
156
+
157
+ result = test_model.where(content: content).count
158
+ # Rails debug tells me the duration was 1.5ms
159
+
160
+ It shows PostgreSQL as a document database combined with indexing has great performance out of the box.
161
+
162
+ See the next section about "Dynamic Indexes" for details.
163
+
139
164
  ## Dynamic Indexes
140
165
 
141
166
  Most applications do the same queries over and over again. This is why we think it is useful, if PostJson create indexes on slow queries.
@@ -171,7 +196,29 @@ You can adjust the settings:
171
196
 
172
197
  You might already know this about User Interfaces, but it is usual considered good practice if auto-complete responses are served to the user within 100 milliseconds. Other results are usual okay within 500 milliseconds. So leave room for application processing and network delay.
173
198
 
174
- Do not set create_dynamic_index_milliseconds_threshold too low as PostJson will try to create an index for every query performance. Like a threshold of 1 millisecond will be less than almost all query durations.
199
+ Do not set create_dynamic_index_milliseconds_threshold too low as PostJson will try to create an index for every query performance. Like a threshold of 1 millisecond will be less than the duration of almost all queries.
200
+
201
+ ## Primary Keys
202
+
203
+ PostJson assign UUID as primary key (id):
204
+
205
+ me = Person.create(name: "Jacob")
206
+ puts me.id
207
+ # "297a2500-a456-459b-b3e9-e876f59602c2"
208
+
209
+ But you also set the primary key yourself:
210
+
211
+ john_doe = Person.create(id: "John Doe")
212
+
213
+ Notice the primary key is downcased when doing a query or finding records:
214
+
215
+ found = Person.where(id: "JOhN DoE").first
216
+ puts found
217
+ # {"id"=>"John Doe", "version"=>1, "created_at"=>"2013-10-22T10:42:26.190Z", "updated_at"=>"2013-10-22T10:42:26.190Z"}
218
+
219
+ found_again = Person.find("JOhN DoE")
220
+ puts found_again.attributes
221
+ # {"id"=>"John Doe", "version"=>1, "created_at"=>"2013-10-22T10:42:26.190Z", "updated_at"=>"2013-10-22T10:42:26.190Z"}
175
222
 
176
223
  ## The future
177
224
 
data/lib/post_json.rb CHANGED
@@ -6,6 +6,7 @@ require 'post_json/concerns/query_methods'
6
6
  require 'post_json/concerns/finder_methods'
7
7
  require 'post_json/concerns/settings_methods'
8
8
  require 'post_json/concerns/dynamic_index_methods'
9
+ require 'post_json/concerns/copyable'
9
10
  require 'post_json/query_translator'
10
11
  require 'post_json/base'
11
12
  require 'post_json/model_settings'
@@ -9,6 +9,7 @@ module PostJson
9
9
 
10
10
  include SettingsMethods
11
11
  include DynamicIndexMethods
12
+ include Copyable
12
13
 
13
14
  def initialize(*args)
14
15
  __local__primary_key = self.class.primary_key
@@ -0,0 +1,36 @@
1
+ module PostJson
2
+ module Copyable
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def copy(destination_collection_name)
7
+ destination = Collection[destination_collection_name]
8
+ if exists?
9
+ src_id = persisted_settings.id
10
+
11
+ if destination.persisted?
12
+ dest_id = destination.persisted_settings.id
13
+ query = original_all
14
+ query = query.joins("INNER JOIN #{table_name} as dest ON dest.id = #{table_name}.id")
15
+ query = query.where("dest.__doc__model_settings_id = '#{dest_id}'")
16
+ query = query.where("\"#{table_name}\".__doc__model_settings_id = '#{src_id}'")
17
+ query = query.where("dest.id = \"#{table_name}\".id")
18
+ conflicting_ids = query.pluck("dest.id").join(", ")
19
+ if conflicting_ids.present?
20
+ error_message = "Following primary keys (#{primary_key}) already exists in collection \"#{destination.collection_name}\": #{conflicting_ids}."
21
+ raise ActiveRecord::RecordNotUnique, error_message
22
+ end
23
+ end
24
+
25
+ dest_id = destination.persisted_settings.id
26
+ selectors = PostJson::Base.column_names.map { |s| s == "__doc__model_settings_id" ? "'#{dest_id}' as #{s}" : s }.join(", ")
27
+ condition = "__doc__model_settings_id = '#{src_id}'"
28
+ destination.transaction do
29
+ destination.connection.execute("INSERT INTO #{table_name} (SELECT #{selectors} FROM #{table_name} WHERE #{condition})")
30
+ end
31
+ end
32
+ destination
33
+ end
34
+ end
35
+ end
36
+ end
@@ -37,7 +37,8 @@ module PostJson
37
37
  end
38
38
 
39
39
  def destroy(id)
40
- execute { |documents| documents.destroy(id) }
40
+ value = id ? id.to_s.downcase : nil
41
+ execute { |documents| documents.destroy(value) }
41
42
  end
42
43
 
43
44
  def destroy_all(conditions = nil)
@@ -62,7 +63,18 @@ module PostJson
62
63
  end
63
64
 
64
65
  def find(*args)
65
- execute { |documents| documents.find(*args) }
66
+ if args.length == 0
67
+ execute { |documents| documents.find }
68
+ elsif args.length == 1 && args[0].is_a?(Array)
69
+ ids = args[0].map{|id| id ? id.to_s.downcase : nil}
70
+ execute { |documents| documents.find(ids) }
71
+ elsif args.length == 1 && args[0].is_a?(Array) == false
72
+ id = args[0] ? args[0].to_s.downcase : nil
73
+ execute { |documents| documents.find(id) }
74
+ else
75
+ ids = args.map{|id| id ? id.to_s.downcase : nil}
76
+ execute { |documents| documents.find(ids) }
77
+ end
66
78
  end
67
79
 
68
80
  def find_by(*args)
@@ -214,8 +226,8 @@ module PostJson
214
226
 
215
227
  def define_selector(attribute_name)
216
228
  case attribute_name.to_s
217
- when "id"
218
- "\"#{table_name}\".id"
229
+ when primary_key
230
+ "\"#{table_name}\".#{primary_key}"
219
231
  else
220
232
  "json_selector('#{attribute_name}', \"#{table_name}\".__doc__body)"
221
233
  end
@@ -248,17 +260,22 @@ module PostJson
248
260
  [:where, arguments]
249
261
  when :where_equal
250
262
  selector = define_selector(arguments[:attribute])
263
+ selector_is_primary_key = arguments[:attribute].to_s == primary_key
251
264
  argument = arguments[:argument]
252
265
  case argument
253
266
  when Array
254
267
  values = argument.map{|v| v ? v.to_s : nil}
268
+ values = values.map{|v| v.try(:downcase)} if selector_is_primary_key
255
269
  [:where, "(#{selector} IN (?))", values]
256
270
  when Range
257
271
  first_value = argument.first ? argument.first.to_s : nil
272
+ first_value = first_value.try(:downcase) if selector_is_primary_key
258
273
  last_value = argument.last ? argument.last.to_s : nil
274
+ last_value = last_value.try(:downcase) if selector_is_primary_key
259
275
  [:where, "(#{selector} BETWEEN ? AND ?)", first_value, last_value]
260
276
  else
261
277
  value = argument ? argument.to_s : nil
278
+ value = value.try(:downcase) if selector_is_primary_key
262
279
  [:where, "#{selector} = ?", value]
263
280
  end
264
281
  else
@@ -21,6 +21,14 @@ module PostJson
21
21
  settings
22
22
  end
23
23
 
24
+ def new?
25
+ settings.new_record?
26
+ end
27
+
28
+ def persisted?
29
+ settings.persisted?
30
+ end
31
+
24
32
  def reload_settings!
25
33
  @settings = nil
26
34
  settings
@@ -11,6 +11,10 @@ module PostJson
11
11
  @relation.klass
12
12
  end
13
13
 
14
+ def primary_key
15
+ model_class.primary_key
16
+ end
17
+
14
18
  def table_name
15
19
  model_class.table_name
16
20
  end
@@ -1,3 +1,3 @@
1
1
  module PostJson
2
- VERSION = "1.0.6"
2
+ VERSION = "1.0.7"
3
3
  end
@@ -48,8 +48,13 @@ describe "Base model" do
48
48
 
49
49
  context "should downcase primary key" do
50
50
  let(:new_id) { "abc" }
51
- subject { PostJson::Collection['Customer'].create id: "#{new_id.upcase}" }
51
+ let(:model) { PostJson::Collection['Customer'] }
52
+ let!(:record) { model.create id: "#{new_id.upcase}" }
53
+ subject { record }
52
54
  its(:id) { should == new_id }
55
+ it { model.exists?(id: "#{new_id.upcase}").should be_true }
56
+ it { model.where(id: "#{new_id.upcase}").count.should == 1 }
57
+ it { model.find("#{new_id.upcase}").id.should == new_id }
53
58
  end
54
59
 
55
60
  context "should now allow change of primary key" do
@@ -390,4 +395,42 @@ describe "Base model" do
390
395
  it { subject["updated_at"].should == document.updated_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
391
396
  it { subject["version"].should == document.version }
392
397
  end
398
+
399
+ context "copy" do
400
+ let(:orig_model) { PostJson::Collection["Originals"] }
401
+ let(:copy_model) { orig_model.copy("Copies") }
402
+ before do
403
+ orig_model.create(id: "Jacob", age: 33)
404
+ orig_model.create(id: "Martin", age: 29)
405
+ end
406
+
407
+ subject { copy_model }
408
+
409
+ its(:count) { should == 2 }
410
+ it { subject.find("Jacob").age.should == 33 }
411
+ it { subject.find("Martin").age.should == 29 }
412
+
413
+ context "conflict" do
414
+ before do
415
+ copy_model
416
+ orig_model.create(id: "Jonathan", age: 33)
417
+ end
418
+ it { expect { orig_model.copy(copy_model.collection_name) }.to raise_error(ActiveRecord::RecordNotUnique) }
419
+ end
420
+
421
+ context "to existing collection" do
422
+ let(:other_model) { PostJson::Collection["Others"] }
423
+ before do
424
+ other_model.create(id: "John", age: 25)
425
+ other_model.copy(copy_model.collection_name)
426
+ orig_model.create(id: "Jonathan", age: 33)
427
+ end
428
+ subject { copy_model }
429
+
430
+ its(:count) { should == 3 }
431
+ it { subject.find("Jacob").age.should == 33 }
432
+ it { subject.find("Martin").age.should == 29 }
433
+ it { subject.find("John").age.should == 25 }
434
+ end
435
+ end
393
436
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: post_json
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacob Madsen and Martin Thoegersen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-20 00:00:00.000000000 Z
11
+ date: 2013-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -103,6 +103,7 @@ files:
103
103
  - lib/post_json/concerns/settings_methods.rb
104
104
  - lib/post_json/concerns/query_methods.rb
105
105
  - lib/post_json/concerns/argument_methods.rb
106
+ - lib/post_json/concerns/copyable.rb
106
107
  - lib/post_json/concerns/finder_methods.rb
107
108
  - lib/post_json/concerns/dynamic_index_methods.rb
108
109
  - lib/post_json/version.rb