post_json 1.0.6 → 1.0.7
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 +48 -1
- data/lib/post_json.rb +1 -0
- data/lib/post_json/base.rb +1 -0
- data/lib/post_json/concerns/copyable.rb +36 -0
- data/lib/post_json/concerns/finder_methods.rb +21 -4
- data/lib/post_json/concerns/settings_methods.rb +8 -0
- data/lib/post_json/query_translator.rb +4 -0
- data/lib/post_json/version.rb +1 -1
- data/spec/models/base_spec.rb +44 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2f25ad4b6cb31d0b679bfa6c41d8b5533c3c69a8
|
|
4
|
+
data.tar.gz: 25b074ed6292d61272a2b3bb08c021d32ca881af
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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'
|
data/lib/post_json/base.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
218
|
-
"\"#{table_name}\"
|
|
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
|
data/lib/post_json/version.rb
CHANGED
data/spec/models/base_spec.rb
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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-
|
|
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
|