postgres_ext-serializers 0.0.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 +7 -0
- data/.gitignore +19 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +82 -0
- data/Rakefile +88 -0
- data/lib/postgres_ext/serializers.rb +12 -0
- data/lib/postgres_ext/serializers/active_model.rb +6 -0
- data/lib/postgres_ext/serializers/active_model/array_serializer.rb +194 -0
- data/lib/postgres_ext/serializers/version.rb +5 -0
- data/postgres_ext-serializers.gemspec +37 -0
- data/test/serializer_test.rb +24 -0
- data/test/sideloading_test.rb +52 -0
- data/test/test_helper.rb +81 -0
- metadata +214 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bc2786f412177b97b379240e2c651b3af66b4529
|
4
|
+
data.tar.gz: a593579437d26066cdc7ba5afce361447cd27bb5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dedcaefb8fa0a5228cd7221381550621eed39c63c7c031e88483e901ccf57aa587c4a79ffc4cc0f8a0420a15b7c42ebb8fe3c31cf1623a9bb2a8a94c3a81c4ac
|
7
|
+
data.tar.gz: c7ef64efe1d96a3aa2171560b6d775b7706fc736c0d1840bd5ba1d1e56330bb973b996cc2d43e17082e1d4196ab9ff4b0fbbdac99f9174394a307a684c220040
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Dan McClain
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# PostgresExt-Serializers
|
2
|
+
|
3
|
+
|
4
|
+
[](http://travis-ci.org/dockyard/postgres_ext-serializers)
|
6
|
+
[](https://codeclimate.com/github/dockyard/postgres_ext-serializers)
|
8
|
+
[](http://badge.fury.io/rb/postgres_ext-serializers)
|
10
|
+
|
11
|
+
## Looking for help? ##
|
12
|
+
|
13
|
+
If it is a bug [please open an issue on
|
14
|
+
Github](https://github.com/dockyard/postgres_ext-serializers/issues). If you need
|
15
|
+
help using the gem please ask the question on
|
16
|
+
[Stack Overflow](http://stackoverflow.com). Be sure to tag the
|
17
|
+
question with `DockYard` so we can find it.
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
gem 'postgres_ext-serializers'
|
24
|
+
|
25
|
+
And then execute:
|
26
|
+
|
27
|
+
$ bundle
|
28
|
+
|
29
|
+
Or install it yourself as:
|
30
|
+
|
31
|
+
$ gem install postgres_ext-serializers
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
Just `require 'postgres_ext/serializers'` and use
|
36
|
+
ActiveModel::Serializers as you normally would!
|
37
|
+
Postgres\_ext-serializers will take over anytime you try to serialize an
|
38
|
+
ActiveRecord::Relation.
|
39
|
+
|
40
|
+
### Methods in Serializers and Models
|
41
|
+
|
42
|
+
If you are using methods to compute properties for your JSON responses
|
43
|
+
in your models or serializers, postgres\_ext-serializers will try to
|
44
|
+
discover a SQL version of this call by looking for a class method with
|
45
|
+
the same name and the prefex `__sql`. Here's an example:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class MySerializer < ActiveModel::Serializer
|
49
|
+
def full_name
|
50
|
+
"#{object.first_name} #{object.last_name}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.full_name__sql(scope)
|
54
|
+
'first_name || ' ' || last_name'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
The scope is passed to methods in a serializer, while there are no
|
60
|
+
arguments passed to `__sql` methods in a model. You will not have access
|
61
|
+
to the `current_user` alias of `scope`, but the scope passed in will be
|
62
|
+
the same object. Right now, this string is used as a SQL literal, so be
|
63
|
+
sure to *not* use untrusted values in the return value. This feature may
|
64
|
+
change before the 1.0 release, if a cleaner implementation is found.
|
65
|
+
|
66
|
+
## Developing
|
67
|
+
|
68
|
+
To work on postgres\_ext locally, follow these steps:
|
69
|
+
|
70
|
+
1. Run `bundle install`, this will install all the development
|
71
|
+
dependencies
|
72
|
+
2. Run `rake setup`, this will set up the `.env` file necessary to run
|
73
|
+
the tests and set up the database
|
74
|
+
3. Run `rake db:create`, this will create the test database
|
75
|
+
4. Run `rake db:migrate`, this will set up the database tables required
|
76
|
+
by the test
|
77
|
+
|
78
|
+
## Authors
|
79
|
+
|
80
|
+
Dan McClain [twitter](http://twitter.com/_danmcclain)
|
81
|
+
[github](http://github.com/danmcclain)
|
82
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << 'lib'
|
6
|
+
t.libs << 'test'
|
7
|
+
t.pattern = 'test/**/*_test.rb'
|
8
|
+
t.verbose = false
|
9
|
+
end
|
10
|
+
|
11
|
+
task :default => :test
|
12
|
+
|
13
|
+
task :setup do
|
14
|
+
if File.exist?('.env')
|
15
|
+
puts 'This will overwrite your existing .env file'
|
16
|
+
end
|
17
|
+
print 'Enter your database name: [postgres_ext_serializers_test] '
|
18
|
+
db_name = STDIN.gets.chomp
|
19
|
+
print 'Enter your database user: [] '
|
20
|
+
db_user = STDIN.gets.chomp
|
21
|
+
print 'Enter your database password: [] '
|
22
|
+
db_password = STDIN.gets.chomp
|
23
|
+
print 'Enter your database server: [localhost] '
|
24
|
+
db_server = STDIN.gets.chomp
|
25
|
+
|
26
|
+
db_name = 'postgres_ext_test' if db_name.empty?
|
27
|
+
db_password = ":#{db_password}" unless db_password.empty?
|
28
|
+
db_server = 'localhost' if db_server.empty?
|
29
|
+
|
30
|
+
db_server = "@#{db_server}" unless db_user.empty?
|
31
|
+
|
32
|
+
env_path = File.expand_path('./.env')
|
33
|
+
File.open(env_path, 'w') do |file|
|
34
|
+
file.puts "DATABASE_NAME=#{db_name}"
|
35
|
+
file.puts "DATABASE_URL=\"postgres://#{db_user}#{db_password}#{db_server}/#{db_name}\""
|
36
|
+
end
|
37
|
+
|
38
|
+
puts '.env file saved'
|
39
|
+
end
|
40
|
+
|
41
|
+
namespace :db do
|
42
|
+
task :load_db_settings do
|
43
|
+
require 'active_record'
|
44
|
+
unless ENV['DATABASE_URL']
|
45
|
+
require 'dotenv'
|
46
|
+
Dotenv.load
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
task :psql => :load_db_settings do
|
51
|
+
exec "psql #{ENV['DATABASE_NAME']}"
|
52
|
+
end
|
53
|
+
|
54
|
+
task :drop => :load_db_settings do
|
55
|
+
%x{ dropdb #{ENV['DATABASE_NAME']} }
|
56
|
+
end
|
57
|
+
|
58
|
+
task :create => :load_db_settings do
|
59
|
+
%x{ createdb #{ENV['DATABASE_NAME']} }
|
60
|
+
end
|
61
|
+
|
62
|
+
task :migrate => :load_db_settings do
|
63
|
+
ActiveRecord::Base.establish_connection
|
64
|
+
|
65
|
+
ActiveRecord::Base.connection.create_table :people, force: true do |t|
|
66
|
+
t.string "first_name"
|
67
|
+
t.string "last_name"
|
68
|
+
t.datetime "created_at"
|
69
|
+
t.datetime "updated_at"
|
70
|
+
end
|
71
|
+
|
72
|
+
ActiveRecord::Base.connection.create_table :notes, force: true do |t|
|
73
|
+
t.string "name"
|
74
|
+
t.string "content"
|
75
|
+
t.datetime "created_at"
|
76
|
+
t.datetime "updated_at"
|
77
|
+
end
|
78
|
+
|
79
|
+
ActiveRecord::Base.connection.create_table :tags, force: true do |t|
|
80
|
+
t.integer "note_id"
|
81
|
+
t.string "name"
|
82
|
+
t.datetime "created_at"
|
83
|
+
t.datetime "updated_at"
|
84
|
+
end
|
85
|
+
|
86
|
+
puts 'Database migrated'
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'postgres_ext'
|
2
|
+
require 'postgres_ext/serializers/version'
|
3
|
+
|
4
|
+
module PostgresExt
|
5
|
+
module Serializers
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'postgres_ext/serializers/active_model'
|
10
|
+
require 'active_model_serializers'
|
11
|
+
|
12
|
+
ActiveModel::ArraySerializer.send :prepend, PostgresExt::Serializers::ActiveModel::ArraySerializer
|
@@ -0,0 +1,194 @@
|
|
1
|
+
module PostgresExt::Serializers::ActiveModel
|
2
|
+
module ArraySerializer
|
3
|
+
def self.prepended(base)
|
4
|
+
base.send :include, IncludeMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module IncludeMethods
|
8
|
+
def to_json(*)
|
9
|
+
if ActiveRecord::Relation === object
|
10
|
+
_postgres_serializable_array
|
11
|
+
else
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(*)
|
18
|
+
super
|
19
|
+
@_ctes = []
|
20
|
+
@_results_tables = []
|
21
|
+
@_embedded = []
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def _postgres_serializable_array
|
27
|
+
_include_relation_in_root(object)
|
28
|
+
|
29
|
+
jsons_select_manager = _results_table_arel
|
30
|
+
jsons_select_manager.with @_ctes
|
31
|
+
|
32
|
+
object.klass.connection.select_value _visitor.accept(jsons_select_manager)
|
33
|
+
end
|
34
|
+
|
35
|
+
def _include_relation_in_root(relation, foreign_key_column = nil, constraining_table = nil)
|
36
|
+
relation_query = relation.dup
|
37
|
+
relation_query_arel = relation_query.arel_table
|
38
|
+
@_embedded << relation.table_name
|
39
|
+
|
40
|
+
klass = ActiveRecord::Relation === relation ? relation.klass : relation
|
41
|
+
serializer_class = _serializer_class(klass)
|
42
|
+
_serializer = serializer_class.new klass.new, options
|
43
|
+
|
44
|
+
attributes = serializer_class._attributes
|
45
|
+
attributes.each do |name, key|
|
46
|
+
if name.to_s == key.to_s
|
47
|
+
if serializer_class.respond_to? "#{name}__sql"
|
48
|
+
relation_query = relation_query.select Arel::Nodes::As.new Arel.sql(serializer_class.send("#{name}__sql", options[:scope])), Arel.sql(name.to_s)
|
49
|
+
elsif klass.respond_to? "#{name}__sql"
|
50
|
+
relation_query = relation_query.select Arel::Nodes::As.new Arel.sql(klass.send("#{name}__sql")), Arel.sql(name.to_s)
|
51
|
+
else
|
52
|
+
relation_query = relation_query.select(relation_query_arel[name])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if foreign_key_column && constraining_table
|
58
|
+
relation_query = relation_query.where(relation_query_arel[foreign_key_column].in(constraining_table.project(constraining_table[:id])))
|
59
|
+
end
|
60
|
+
|
61
|
+
associations = serializer_class._associations
|
62
|
+
association_sql_tables = []
|
63
|
+
ids_table_name = nil
|
64
|
+
id_query = nil
|
65
|
+
unless associations.empty?
|
66
|
+
ids_table_name = "#{relation.table_name}_ids"
|
67
|
+
ids_table_arel = Arel::Table.new ids_table_name
|
68
|
+
id_query = relation.dup.select(:id)
|
69
|
+
if foreign_key_column && constraining_table
|
70
|
+
id_query.where!(relation_query_arel[foreign_key_column].in(constraining_table.project(constraining_table[:id])))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
associations.each do |key, association_class|
|
75
|
+
association = association_class.new key, _serializer, options
|
76
|
+
|
77
|
+
association_reflection = klass.reflect_on_association(key)
|
78
|
+
if association.embed_ids?
|
79
|
+
if association_reflection.macro == :has_many
|
80
|
+
unless @_ctes.find { |as| as.left == ids_table_name }
|
81
|
+
@_ctes << _postgres_cte_as(ids_table_name, "(#{id_query.to_sql})")
|
82
|
+
end
|
83
|
+
association_sql_tables << _process_has_many_relation(key, association_reflection, relation_query, ids_table_arel)
|
84
|
+
else
|
85
|
+
relation_query = relation_query.select(relation_query_arel["#{key}_id"])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if association.embed_in_root? && !@_embedded.member?(key.to_s)
|
90
|
+
_include_relation_in_root(association_reflection.klass,association_reflection.foreign_key,ids_table_arel)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
arel = relation_query.arel.dup
|
94
|
+
|
95
|
+
association_sql_tables.each do |assoc_hash|
|
96
|
+
assoc_table = Arel::Table.new assoc_hash[:table]
|
97
|
+
arel.join(assoc_table, Arel::Nodes::OuterJoin).on(relation_query_arel[:id].eq(assoc_table[assoc_hash[:foreign_key]]))
|
98
|
+
arel.project _coalesce_arrays(assoc_table[assoc_hash[:ids_column]], assoc_hash[:ids_column])
|
99
|
+
end
|
100
|
+
|
101
|
+
_arel_to_json_array_arel(arel, relation_query.table_name)
|
102
|
+
end
|
103
|
+
|
104
|
+
def _process_has_many_relation(key, association_reflection, relation_query, ids_table_arel)
|
105
|
+
association_class = association_reflection.klass
|
106
|
+
association_arel_table = association_class.arel_table
|
107
|
+
association_query = association_class.group association_arel_table[association_reflection.foreign_key]
|
108
|
+
association_query = association_query.select(association_arel_table[association_reflection.foreign_key])
|
109
|
+
id_column_name = "#{key.to_s.singularize}_ids"
|
110
|
+
cte_name = "#{id_column_name}_by_#{relation_query.table_name}"
|
111
|
+
association_query = association_query.select(_array_agg(association_arel_table[:id], id_column_name))
|
112
|
+
association_query = association_query.having(association_arel_table[association_reflection.foreign_key].in(ids_table_arel.project(ids_table_arel[:id])))
|
113
|
+
@_ctes << _postgres_cte_as(cte_name, "(#{association_query.to_sql})")
|
114
|
+
{ table: cte_name, ids_column: id_column_name, foreign_key: association_reflection.foreign_key }
|
115
|
+
end
|
116
|
+
|
117
|
+
def _visitor
|
118
|
+
@_visitior ||= object.klass.connection.visitor
|
119
|
+
end
|
120
|
+
|
121
|
+
def _serializer_class(klass)
|
122
|
+
klass.active_model_serializer
|
123
|
+
end
|
124
|
+
|
125
|
+
def _coalesce_arrays(column, aliaz = nil)
|
126
|
+
_postgres_function_node 'coalesce', [column, Arel.sql("'{}'::int[]")], aliaz
|
127
|
+
end
|
128
|
+
|
129
|
+
def _results_table_arel
|
130
|
+
first = @_results_tables.shift
|
131
|
+
first_table = Arel::Table.new first[:table]
|
132
|
+
jsons_select = first_table.project first_table[first[:column]]
|
133
|
+
|
134
|
+
@_results_tables.each do |table_info|
|
135
|
+
table = Arel::Table.new table_info[:table]
|
136
|
+
jsons_select = jsons_select.project table[table_info[:column]]
|
137
|
+
jsons_select.join(table).on(first_table[:match].eq(table[:match]))
|
138
|
+
end
|
139
|
+
|
140
|
+
@_ctes << _postgres_cte_as('jsons', _visitor.accept(jsons_select))
|
141
|
+
|
142
|
+
jsons_table = Arel::Table.new 'jsons'
|
143
|
+
jsons_row_to_json = _row_to_json jsons_table.name
|
144
|
+
jsons_table.project jsons_row_to_json
|
145
|
+
end
|
146
|
+
|
147
|
+
def _arel_to_json_array_arel(arel, name)
|
148
|
+
json_table = Arel::Table.new "#{name}_attributes_filter"
|
149
|
+
json_select_manager = json_table.project _results_as_json_array(json_table.name, name)
|
150
|
+
json_select_manager.project Arel::Nodes::As.new Arel.sql('1'), Arel.sql('match')
|
151
|
+
|
152
|
+
@_ctes << _postgres_cte_as(json_table.name, _visitor.accept(arel))
|
153
|
+
@_ctes << _postgres_cte_as("#{name}_as_json_array", _visitor.accept(json_select_manager))
|
154
|
+
@_results_tables << { table: "#{name}_as_json_array", column: name }
|
155
|
+
end
|
156
|
+
|
157
|
+
def _relation_to_json_array_arel(relation)
|
158
|
+
json_table = Arel::Table.new "#{relation.table_name}_json"
|
159
|
+
json_select_manager = json_table.project _results_as_json_array(json_table.name, relation.table_name)
|
160
|
+
|
161
|
+
@_ctes << _postgres_cte_as(json_table.name, "(#{relation.to_sql})")
|
162
|
+
|
163
|
+
json_select_manager
|
164
|
+
end
|
165
|
+
|
166
|
+
def _row_to_json(table_name, aliaz = nil)
|
167
|
+
_postgres_function_node 'row_to_json', [Arel.sql(table_name)], aliaz
|
168
|
+
end
|
169
|
+
|
170
|
+
def _postgres_cte_as(name, sql_string)
|
171
|
+
Arel::Nodes::As.new Arel.sql(name), Arel.sql(sql_string)
|
172
|
+
end
|
173
|
+
|
174
|
+
def _results_as_json_array(table_name, aliaz = nil)
|
175
|
+
row_as_json = _row_to_json table_name
|
176
|
+
array_of_json = _postgres_function_node 'array_agg', [row_as_json]
|
177
|
+
_postgres_function_node 'array_to_json', [array_of_json], aliaz
|
178
|
+
end
|
179
|
+
|
180
|
+
def _array_agg(column, aliaz = nil)
|
181
|
+
_postgres_function_node 'array_agg', [column], aliaz
|
182
|
+
end
|
183
|
+
|
184
|
+
def _array_agg_as_json(column, aliaz = nil)
|
185
|
+
array_agg = _array_agg [column]
|
186
|
+
_postgres_function_node 'array_to_json', [array_agg], aliaz
|
187
|
+
end
|
188
|
+
|
189
|
+
def _postgres_function_node(name, values, aliaz = nil)
|
190
|
+
Arel::Nodes::NamedFunction.new(name, values, aliaz)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'postgres_ext/serializers/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "postgres_ext-serializers"
|
8
|
+
spec.version = PostgresExt::Serializers::VERSION
|
9
|
+
spec.authors = ["Dan McClain"]
|
10
|
+
spec.email = ["git@danmcclain.net"]
|
11
|
+
spec.summary = %q{Harness the power of PostgreSQL when crafting JSON reponses }
|
12
|
+
spec.description = %q{}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'postgres_ext', '~> 2.1.0'
|
22
|
+
spec.add_runtime_dependency 'active_model_serializers'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
25
|
+
spec.add_development_dependency 'actionpack', '~> 4.0.0'
|
26
|
+
spec.add_development_dependency 'rake'
|
27
|
+
spec.add_development_dependency 'minitest'
|
28
|
+
spec.add_development_dependency 'm'
|
29
|
+
spec.add_development_dependency 'bourne', '~> 1.3.0'
|
30
|
+
spec.add_development_dependency 'database_cleaner'
|
31
|
+
spec.add_development_dependency 'dotenv'
|
32
|
+
if RUBY_PLATFORM =~ /java/
|
33
|
+
spec.add_development_dependency 'activerecord-jdbcpostgresql-adapter', '1.3.0.beta2'
|
34
|
+
else
|
35
|
+
spec.add_development_dependency 'pg', '~> 0.13.2'
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe 'ArraySerializer patch' do
|
5
|
+
let(:json_data) { ActiveModel::Serializer.build_json(controller, relation, {}).to_json }
|
6
|
+
|
7
|
+
context 'computed value methods' do
|
8
|
+
let(:relation) { Person.all }
|
9
|
+
let(:controller) { PeopleController.new }
|
10
|
+
let(:person) { Person.create first_name: 'Test', last_name: 'User' }
|
11
|
+
|
12
|
+
it 'generates the proper json output for the serializer' do
|
13
|
+
json_expected = %{{"people":[{"id":#{person.id},"full_name":"Test User","attendance_name":"User, Test"}]}}
|
14
|
+
json_data.must_equal json_expected
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'passes scope to the serializer method' do
|
18
|
+
controller.stubs(:current_user).returns({ admin: true })
|
19
|
+
|
20
|
+
json_expected = %{{"people":[{"id":#{person.id},"full_name":"Test User","attendance_name":"ADMIN User, Test"}]}}
|
21
|
+
json_data.must_equal json_expected
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
describe 'ArraySerializer patch' do
|
3
|
+
let(:json_data) { ActiveModel::Serializer.build_json(controller, relation, {}).to_json }
|
4
|
+
|
5
|
+
context 'no where clause on root relation' do
|
6
|
+
let(:relation) { Note.all }
|
7
|
+
let(:controller) { NotesController.new }
|
8
|
+
|
9
|
+
before do
|
10
|
+
note_1 = Note.create name: 'test', content: 'dummy content'
|
11
|
+
note_2 = Note.create name: 'test 2', content: 'dummy content'
|
12
|
+
|
13
|
+
tag = Tag.create name: 'tag 1', note_id: note_1.id
|
14
|
+
Tag.create name: 'tag 2'
|
15
|
+
@json_expected = "{\"tags\":[{\"id\":#{tag.id},\"name\":\"tag 1\",\"note_id\":#{note_1.id}}],\"notes\":[{\"id\":#{note_1.id},\"content\":\"dummy content\",\"name\":\"test\",\"tag_ids\":[#{tag.id}]},{\"id\":#{note_2.id},\"content\":\"dummy content\",\"name\":\"test 2\",\"tag_ids\":[]}]}"
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'generates the proper json output for the serializer' do
|
19
|
+
json_data.must_equal @json_expected
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'does not instantiate ruby objects for relations' do
|
23
|
+
relation.stubs(:to_a).returns([])
|
24
|
+
json_data
|
25
|
+
assert_received(relation, :to_a) { |expect| expect.never}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'where clause on root relation' do
|
30
|
+
let(:relation) { Note.where(name: 'test') }
|
31
|
+
let(:controller) { NotesController.new }
|
32
|
+
|
33
|
+
before do
|
34
|
+
note_1 = Note.create name: 'test', content: 'dummy content'
|
35
|
+
note_2 = Note.create name: 'test 2', content: 'dummy content'
|
36
|
+
|
37
|
+
tag = Tag.create name: 'tag 1', note_id: note_1.id
|
38
|
+
Tag.create name: 'tag 2', note_id: note_2.id
|
39
|
+
@json_expected = "{\"tags\":[{\"id\":#{tag.id},\"name\":\"tag 1\",\"note_id\":#{note_1.id}}],\"notes\":[{\"id\":#{note_1.id},\"content\":\"dummy content\",\"name\":\"test\",\"tag_ids\":[#{tag.id}]}]}"
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'generates the proper json output for the serializer' do
|
43
|
+
json_data.must_equal @json_expected
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'does not instantiate ruby objects for relations' do
|
47
|
+
relation.stubs(:to_a).returns([])
|
48
|
+
json_data
|
49
|
+
assert_received(relation, :to_a) { |expect| expect.never}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'mocha/setup'
|
5
|
+
require 'bourne'
|
6
|
+
require 'database_cleaner'
|
7
|
+
unless ENV['CI'] || RUBY_PLATFORM =~ /java/
|
8
|
+
require 'byebug'
|
9
|
+
end
|
10
|
+
require 'postgres_ext/serializers'
|
11
|
+
|
12
|
+
require 'dotenv'
|
13
|
+
Dotenv.load
|
14
|
+
|
15
|
+
ActiveRecord::Base.establish_connection
|
16
|
+
|
17
|
+
class TestController < ActionController::Base
|
18
|
+
def url_options
|
19
|
+
{}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Person < ActiveRecord::Base
|
24
|
+
def self.full_name__sql
|
25
|
+
"first_name || ' ' || last_name"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class PeopleController < TestController; end
|
30
|
+
|
31
|
+
class PersonSerializer < ActiveModel::Serializer
|
32
|
+
attributes :id, :full_name, :attendance_name
|
33
|
+
|
34
|
+
def self.attendance_name__sql(scope)
|
35
|
+
if scope && scope[:admin]
|
36
|
+
"'ADMIN ' || last_name || ', ' || first_name"
|
37
|
+
else
|
38
|
+
"last_name || ', ' || first_name"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Note < ActiveRecord::Base
|
44
|
+
has_many :tags
|
45
|
+
end
|
46
|
+
|
47
|
+
class NotesController < TestController; end
|
48
|
+
|
49
|
+
class NoteSerializer < ActiveModel::Serializer
|
50
|
+
attributes :id, :content, :name
|
51
|
+
has_many :tags
|
52
|
+
embed :ids, include: true
|
53
|
+
end
|
54
|
+
|
55
|
+
class Tag < ActiveRecord::Base
|
56
|
+
belongs_to :note
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
class TagSerializer < ActiveModel::Serializer
|
62
|
+
attributes :id, :name
|
63
|
+
embed :ids
|
64
|
+
has_one :note
|
65
|
+
end
|
66
|
+
|
67
|
+
DatabaseCleaner.strategy = :deletion
|
68
|
+
|
69
|
+
class MiniTest::Spec
|
70
|
+
class << self
|
71
|
+
alias :context :describe
|
72
|
+
end
|
73
|
+
|
74
|
+
before do
|
75
|
+
DatabaseCleaner.start
|
76
|
+
end
|
77
|
+
|
78
|
+
after do
|
79
|
+
DatabaseCleaner.clean
|
80
|
+
end
|
81
|
+
end
|
metadata
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: postgres_ext-serializers
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dan McClain
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: postgres_ext
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: active_model_serializers
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: actionpack
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 4.0.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 4.0.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: m
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: bourne
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.3.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.3.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: database_cleaner
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: dotenv
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: pg
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 0.13.2
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 0.13.2
|
167
|
+
description: ''
|
168
|
+
email:
|
169
|
+
- git@danmcclain.net
|
170
|
+
executables: []
|
171
|
+
extensions: []
|
172
|
+
extra_rdoc_files: []
|
173
|
+
files:
|
174
|
+
- ".gitignore"
|
175
|
+
- Gemfile
|
176
|
+
- LICENSE.txt
|
177
|
+
- README.md
|
178
|
+
- Rakefile
|
179
|
+
- lib/postgres_ext/serializers.rb
|
180
|
+
- lib/postgres_ext/serializers/active_model.rb
|
181
|
+
- lib/postgres_ext/serializers/active_model/array_serializer.rb
|
182
|
+
- lib/postgres_ext/serializers/version.rb
|
183
|
+
- postgres_ext-serializers.gemspec
|
184
|
+
- test/serializer_test.rb
|
185
|
+
- test/sideloading_test.rb
|
186
|
+
- test/test_helper.rb
|
187
|
+
homepage: ''
|
188
|
+
licenses:
|
189
|
+
- MIT
|
190
|
+
metadata: {}
|
191
|
+
post_install_message:
|
192
|
+
rdoc_options: []
|
193
|
+
require_paths:
|
194
|
+
- lib
|
195
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - ">="
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '0'
|
200
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
201
|
+
requirements:
|
202
|
+
- - ">="
|
203
|
+
- !ruby/object:Gem::Version
|
204
|
+
version: '0'
|
205
|
+
requirements: []
|
206
|
+
rubyforge_project:
|
207
|
+
rubygems_version: 2.2.0
|
208
|
+
signing_key:
|
209
|
+
specification_version: 4
|
210
|
+
summary: Harness the power of PostgreSQL when crafting JSON reponses
|
211
|
+
test_files:
|
212
|
+
- test/serializer_test.rb
|
213
|
+
- test/sideloading_test.rb
|
214
|
+
- test/test_helper.rb
|