surus 0.5.1 → 0.6.0
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/.travis.yml +17 -0
- data/CHANGELOG.md +5 -0
- data/README.md +37 -19
- data/Rakefile +10 -0
- data/gemfiles/4.0.gemfile +5 -0
- data/gemfiles/4.1.gemfile +5 -0
- data/gemfiles/4.2.gemfile +5 -0
- data/lib/surus/json/query.rb +28 -2
- data/lib/surus/version.rb +1 -1
- data/spec/database.yml +1 -0
- data/spec/database.yml.travis +5 -0
- data/spec/database_structure.sql +22 -1
- data/spec/factories.rb +15 -0
- data/spec/json/json_spec.rb +45 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/synchronous_commit/model_spec.rb +5 -5
- data/surus.gemspec +2 -1
- metadata +25 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd4bbbf8c57e01cfb2627d2b0a3913006f1432c7
|
4
|
+
data.tar.gz: 73504b7836c48ee52f43d62f91d93eeb0f52e733
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce79c2dabce1600a7a3503f992cd735e7eac90fd59c65ad557ee5a55e58cde0eb0eebfb91a8be97456479ca31c0efe88375b3cc0e8ae8f9ac7e699faf7b8cef0
|
7
|
+
data.tar.gz: 498d6d89a59f5c2d49d0119a94ec76429a7a589f398050ab3a22824264ada83c886017f7e7e9632188fd8f37eccda0f585eeca579610cea9f7a8ab87a00966fa
|
data/.travis.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.2.0
|
4
|
+
- 2.1.5
|
5
|
+
- 2.0.0
|
6
|
+
gemfile:
|
7
|
+
- gemfiles/4.0.gemfile
|
8
|
+
- gemfiles/4.1.gemfile
|
9
|
+
- gemfiles/4.2.gemfile
|
10
|
+
|
11
|
+
addons:
|
12
|
+
postgresql: "9.2"
|
13
|
+
|
14
|
+
before_script:
|
15
|
+
- cp spec/database.yml.travis spec/database.yml
|
16
|
+
- psql -U postgres -c 'create database surus_test;'
|
17
|
+
- psql -U postgres -f spec/database_structure.sql surus_test
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
Surus
|
2
2
|
=====
|
3
3
|
|
4
|
+
[](https://travis-ci.org/jackc/surus)
|
5
|
+
|
4
6
|
# Description
|
5
7
|
|
6
8
|
Surus adds PostgreSQL specific functionality to ActiveRecord. It adds
|
@@ -14,16 +16,33 @@ substantially faster than converting ActiveRecord objects to JSON.
|
|
14
16
|
|
15
17
|
gem install surus
|
16
18
|
|
17
|
-
Or add to your Gemfile.
|
19
|
+
Or add to your Gemfile. This version of Surus only works on Rails 4.
|
18
20
|
|
19
21
|
gem 'surus'
|
20
22
|
|
21
23
|
## Rails 3
|
22
24
|
|
23
|
-
|
25
|
+
Use the 0.4 line for Rails 3
|
24
26
|
|
25
27
|
gem 'surus', '~> 0.4.2'
|
26
28
|
|
29
|
+
# JSON
|
30
|
+
|
31
|
+
PostgreSQL 9.2 added `row_to_json` and `array_to_json` functions. These
|
32
|
+
functions can be used to build JSON very quickly. Unfortunately, they are
|
33
|
+
somewhat cumbersome to use. The `find_json` and `all_json` methods are easy to
|
34
|
+
use wrappers around the lower level PostgreSQL functions that closely mimic
|
35
|
+
the Rails `to_json` interface.
|
36
|
+
|
37
|
+
User.find_json 1
|
38
|
+
User.find_json 1, columns: [:id, :name, :email]
|
39
|
+
Post.find_json 1, include: :author
|
40
|
+
User.find_json(user.id, include: {posts: {columns: [:id, :subject]}})
|
41
|
+
User.all_json
|
42
|
+
User.where(admin: true).all_json
|
43
|
+
User.all_json(columns: [:id, :name, :email], include: {posts: {columns: [:id, :subject]}})
|
44
|
+
Post.all_json(include: [:forum, :post])
|
45
|
+
|
27
46
|
# Hstore
|
28
47
|
|
29
48
|
Hstores can be searched with helper scopes.
|
@@ -48,6 +67,22 @@ nested data structures can be serialized to an hstore. In other words, any
|
|
48
67
|
hash that can be serialized with the normal Rails YAML serialization can be
|
49
68
|
serialized with Surus.
|
50
69
|
|
70
|
+
**Serialize example (Rails 3+)**:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class User < ActiveRecord::Base
|
74
|
+
serialize :settings, Surus::Hstore::Serializer.new
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
**Store example (Rails 4+)**:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
class User < ActiveRecord::Base
|
82
|
+
store :settings, accessors: [:session_timeout], coder: Surus::Hstore::Serializer.new
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
51
86
|
# Array
|
52
87
|
|
53
88
|
Arrays can be searched with helper scopes.
|
@@ -79,23 +114,6 @@ entire session or per transaction.
|
|
79
114
|
|
80
115
|
Read more in the [PostgreSQL asynchronous commit documentation](http://www.postgresql.org/docs/9.1/interactive/wal-async-commit.html).
|
81
116
|
|
82
|
-
# JSON
|
83
|
-
|
84
|
-
PostgreSQL 9.2 added `row_to_json` and `array_to_json` functions. These
|
85
|
-
functions can be used to build JSON very quickly. Unfortunately, they are
|
86
|
-
somewhat cumbersome to use. The `find_json` and `all_json` methods are easy to
|
87
|
-
use wrappers around the lower level PostgreSQL functions that closely mimic
|
88
|
-
the Rails `to_json` interface.
|
89
|
-
|
90
|
-
User.find_json 1
|
91
|
-
User.find_json 1, columns: [:id, :name, :email]
|
92
|
-
Post.find_json 1, include: :author
|
93
|
-
User.find_json(user.id, include: {posts: {columns: [:id, :subject]}})
|
94
|
-
User.all_json
|
95
|
-
User.where(admin: true).all_json
|
96
|
-
User.all_json(columns: [:id, :name, :email], include: {posts: {columns: [:id, :subject]}})
|
97
|
-
Post.all_json(include: [:forum, :post])
|
98
|
-
|
99
117
|
# Benchmarks
|
100
118
|
|
101
119
|
JSON generation is with all_json and find_json is substantially faster than to_json.
|
data/Rakefile
CHANGED
data/lib/surus/json/query.rb
CHANGED
@@ -15,7 +15,11 @@ module Surus
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def subquery_sql
|
18
|
-
|
18
|
+
if options.key?(:columns) || options.key?(:include)
|
19
|
+
select(columns.map(&:to_s).join(', ')).to_sql
|
20
|
+
else
|
21
|
+
original_scope.to_sql
|
22
|
+
end
|
19
23
|
end
|
20
24
|
|
21
25
|
def columns
|
@@ -39,10 +43,32 @@ module Surus
|
|
39
43
|
def association_columns
|
40
44
|
included_associations_name_and_options.map do |association_name, association_options|
|
41
45
|
association = klass.reflect_on_association association_name
|
42
|
-
|
46
|
+
|
47
|
+
# The way to get the association type is different in Rails 4.2 vs 4.0-4.1
|
48
|
+
association_type = if defined? ActiveRecord::Reflection::BelongsToReflection
|
49
|
+
# Rails 4.2+
|
50
|
+
case association
|
51
|
+
when ActiveRecord::Reflection::HasOneReflection
|
52
|
+
:has_one
|
53
|
+
when ActiveRecord::Reflection::BelongsToReflection
|
54
|
+
:belongs_to
|
55
|
+
when ActiveRecord::Reflection::HasManyReflection
|
56
|
+
:has_many
|
57
|
+
when ActiveRecord::Reflection::HasAndBelongsToManyReflection
|
58
|
+
:has_and_belongs_to_many
|
59
|
+
end
|
60
|
+
else
|
61
|
+
# Rails 4.0-4.1
|
62
|
+
association.source_macro
|
63
|
+
end
|
64
|
+
|
65
|
+
subquery = case association_type
|
43
66
|
when :belongs_to
|
44
67
|
association_scope = BelongsToScopeBuilder.new(original_scope, association).scope
|
45
68
|
RowQuery.new(association_scope, association_options).to_sql
|
69
|
+
when :has_one
|
70
|
+
association_scope = HasManyScopeBuilder.new(original_scope, association).scope
|
71
|
+
RowQuery.new(association_scope, association_options).to_sql
|
46
72
|
when :has_many
|
47
73
|
association_scope = HasManyScopeBuilder.new(original_scope, association).scope
|
48
74
|
ArrayAggQuery.new(association_scope, association_options).to_sql
|
data/lib/surus/version.rb
CHANGED
data/spec/database.yml
CHANGED
data/spec/database_structure.sql
CHANGED
@@ -62,6 +62,27 @@ CREATE TABLE users(
|
|
62
62
|
|
63
63
|
|
64
64
|
|
65
|
+
DROP TABLE IF EXISTS bios CASCADE;
|
66
|
+
|
67
|
+
CREATE TABLE bios(
|
68
|
+
id serial PRIMARY KEY,
|
69
|
+
body text NOT NULL,
|
70
|
+
website_url varchar NOT NULL,
|
71
|
+
author_id integer NOT NULL REFERENCES users
|
72
|
+
);
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
DROP TABLE IF EXISTS avatars CASCADE;
|
77
|
+
|
78
|
+
CREATE TABLE avatars(
|
79
|
+
id serial PRIMARY KEY,
|
80
|
+
url varchar NOT NULL,
|
81
|
+
author_id integer NOT NULL REFERENCES users
|
82
|
+
);
|
83
|
+
|
84
|
+
|
85
|
+
|
65
86
|
DROP TABLE IF EXISTS forums CASCADE;
|
66
87
|
|
67
88
|
CREATE TABLE forums(
|
@@ -98,4 +119,4 @@ CREATE TABLE posts_tags(
|
|
98
119
|
post_id integer NOT NULL REFERENCES posts,
|
99
120
|
tag_id integer NOT NULL REFERENCES tags,
|
100
121
|
PRIMARY KEY (post_id, tag_id)
|
101
|
-
);
|
122
|
+
);
|
data/spec/factories.rb
CHANGED
@@ -17,5 +17,20 @@ FactoryGirl.define do
|
|
17
17
|
factory :user, aliases: [:author] do
|
18
18
|
name { Faker::Internet.user_name }
|
19
19
|
email { Faker::Internet.email }
|
20
|
+
after(:build) do |user|
|
21
|
+
user.bio ||= FactoryGirl.build(:bio, author: user)
|
22
|
+
user.avatar ||= FactoryGirl.build(:avatar, author: user)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
factory :bio do
|
27
|
+
author
|
28
|
+
body { Faker::Lorem.paragraph }
|
29
|
+
website_url { Faker::Internet.url }
|
30
|
+
end
|
31
|
+
|
32
|
+
factory :avatar do
|
33
|
+
author
|
34
|
+
url { Faker::Avatar.image }
|
20
35
|
end
|
21
36
|
end
|
data/spec/json/json_spec.rb
CHANGED
@@ -22,6 +22,15 @@ describe 'json' do
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
context 'when scope chain has select' do
|
26
|
+
it 'uses the select for json' do
|
27
|
+
user = FactoryGirl.create :user
|
28
|
+
to_json = Oj.load user.to_json only: [:id, :name]
|
29
|
+
find_json = Oj.load User.select("id, name").find_json(user.id)
|
30
|
+
expect(find_json).to eq(to_json)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
25
34
|
context 'when scope chain has a joins with ambiguous column names' do
|
26
35
|
it 'works' do
|
27
36
|
user = FactoryGirl.create :user
|
@@ -60,6 +69,33 @@ describe 'json' do
|
|
60
69
|
expect(find_json).to eq(to_json)
|
61
70
|
end
|
62
71
|
|
72
|
+
it 'includes entire has_one object' do
|
73
|
+
user = FactoryGirl.create :user
|
74
|
+
to_json = Oj.load user.to_json(include: :bio)
|
75
|
+
find_json = Oj.load User.find_json(user.id, include: :bio)
|
76
|
+
expect(find_json).to eq(to_json)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'filters by has_one conditions' do
|
80
|
+
user = FactoryGirl.create :user
|
81
|
+
find_json = Oj.load User.find_json(user.id, include: :bio_with_impossible_conditions)
|
82
|
+
expect(find_json.fetch('bio_with_impossible_conditions')).to be_nil
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'includes multiple entire has_one objects' do
|
86
|
+
user = FactoryGirl.create :user
|
87
|
+
to_json = Oj.load user.to_json(include: [:bio, :avatar])
|
88
|
+
find_json = Oj.load User.find_json(user.id, include: [:bio, :avatar])
|
89
|
+
expect(find_json).to eq(to_json)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'includes only selected columns of has_one object' do
|
93
|
+
user = FactoryGirl.create :user
|
94
|
+
to_json = Oj.load user.to_json(include: {bio: {only: [:id, :body]}})
|
95
|
+
find_json = Oj.load User.find_json(user.id, include: {bio: {columns: [:id, :body]}})
|
96
|
+
expect(find_json).to eq(to_json)
|
97
|
+
end
|
98
|
+
|
63
99
|
it 'includes entire has_many association' do
|
64
100
|
user = FactoryGirl.create :user
|
65
101
|
posts = FactoryGirl.create_list :post, 2, author: user
|
@@ -168,5 +204,14 @@ describe 'json' do
|
|
168
204
|
all_json = Oj.load User.all_json
|
169
205
|
expect(all_json).to eq(to_json)
|
170
206
|
end
|
207
|
+
|
208
|
+
context 'when scope chain has select' do
|
209
|
+
it 'uses the select for json' do
|
210
|
+
users = FactoryGirl.create_list :user, 3
|
211
|
+
to_json = Oj.load users.to_json only: [:id, :name]
|
212
|
+
all_json = Oj.load User.select("id, name").all_json
|
213
|
+
expect(all_json).to eq(to_json)
|
214
|
+
end
|
215
|
+
end
|
171
216
|
end
|
172
217
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -30,6 +30,21 @@ class User < ActiveRecord::Base
|
|
30
30
|
|
31
31
|
# association name is reserved word in PostgreSQL
|
32
32
|
has_many :rows, foreign_key: :author_id, class_name: 'Post', table_name: 'posts'
|
33
|
+
|
34
|
+
has_one :bio, foreign_key: :author_id
|
35
|
+
has_one :avatar, foreign_key: :author_id
|
36
|
+
has_one :bio_with_impossible_conditions,
|
37
|
+
-> { where '1=2' },
|
38
|
+
foreign_key: :author_id,
|
39
|
+
class_name: 'Bio'
|
40
|
+
end
|
41
|
+
|
42
|
+
class Bio < ActiveRecord::Base
|
43
|
+
belongs_to :author, class_name: 'User'
|
44
|
+
end
|
45
|
+
|
46
|
+
class Avatar < ActiveRecord::Base
|
47
|
+
belongs_to :author, class_name: 'User'
|
33
48
|
end
|
34
49
|
|
35
50
|
class Forum < ActiveRecord::Base
|
@@ -2,18 +2,18 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Surus::SynchronousCommit::Model do
|
4
4
|
let(:conn) { ActiveRecord::Base.connection }
|
5
|
-
|
5
|
+
|
6
6
|
describe "synchronous_commit" do
|
7
7
|
it "is delegated to connection" do
|
8
|
-
conn.
|
8
|
+
expect(conn).to receive(:synchronous_commit)
|
9
9
|
ActiveRecord::Base.synchronous_commit
|
10
10
|
end
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
describe "synchronous_commit=" do
|
14
14
|
it "is delegated to connection" do
|
15
|
-
conn.
|
15
|
+
expect(conn).to receive(:synchronous_commit=)
|
16
16
|
ActiveRecord::Base.synchronous_commit = true
|
17
17
|
end
|
18
|
-
end
|
18
|
+
end
|
19
19
|
end
|
data/surus.gemspec
CHANGED
@@ -34,5 +34,6 @@ Gem::Specification.new do |s|
|
|
34
34
|
s.add_development_dependency 'pg'
|
35
35
|
s.add_development_dependency 'pry', '~> 0.9.11'
|
36
36
|
s.add_development_dependency 'factory_girl', '~> 4.2.0'
|
37
|
-
s.add_development_dependency 'faker', '~> 1.
|
37
|
+
s.add_development_dependency 'faker', '~> 1.4.3'
|
38
|
+
s.add_development_dependency 'rake'
|
38
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: surus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jack Christensen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -142,14 +142,28 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 1.
|
145
|
+
version: 1.4.3
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 1.
|
152
|
+
version: 1.4.3
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rake
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
153
167
|
description: "Surus accelerates ActiveRecord with PostgreSQL specific types and\n
|
154
168
|
\ functionality. It enables indexed searching of serialized arrays
|
155
169
|
and hashes.\n It also can control PostgreSQL synchronous commit
|
@@ -163,6 +177,7 @@ extra_rdoc_files: []
|
|
163
177
|
files:
|
164
178
|
- ".gitignore"
|
165
179
|
- ".rspec"
|
180
|
+
- ".travis.yml"
|
166
181
|
- CHANGELOG.md
|
167
182
|
- Gemfile
|
168
183
|
- Guardfile
|
@@ -175,6 +190,9 @@ files:
|
|
175
190
|
- bench/hstore_find.rb
|
176
191
|
- bench/json_generation.rb
|
177
192
|
- bench/synchronous_commit.rb
|
193
|
+
- gemfiles/4.0.gemfile
|
194
|
+
- gemfiles/4.1.gemfile
|
195
|
+
- gemfiles/4.2.gemfile
|
178
196
|
- lib/generators/surus/hstore/install_generator.rb
|
179
197
|
- lib/generators/surus/hstore/templates/install_hstore.rb
|
180
198
|
- lib/surus.rb
|
@@ -194,6 +212,7 @@ files:
|
|
194
212
|
- lib/surus/version.rb
|
195
213
|
- spec/array/scope_spec.rb
|
196
214
|
- spec/database.yml
|
215
|
+
- spec/database.yml.travis
|
197
216
|
- spec/database_structure.sql
|
198
217
|
- spec/factories.rb
|
199
218
|
- spec/hstore/scope_spec.rb
|
@@ -224,13 +243,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
224
243
|
version: '0'
|
225
244
|
requirements: []
|
226
245
|
rubyforge_project: ''
|
227
|
-
rubygems_version: 2.
|
246
|
+
rubygems_version: 2.4.5
|
228
247
|
signing_key:
|
229
248
|
specification_version: 4
|
230
249
|
summary: PostgreSQL Acceleration for ActiveRecord
|
231
250
|
test_files:
|
232
251
|
- spec/array/scope_spec.rb
|
233
252
|
- spec/database.yml
|
253
|
+
- spec/database.yml.travis
|
234
254
|
- spec/database_structure.sql
|
235
255
|
- spec/factories.rb
|
236
256
|
- spec/hstore/scope_spec.rb
|