fast_jsonapi 1.0.17 → 1.1.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.
Files changed (38) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +106 -38
  3. data/lib/extensions/has_one.rb +19 -13
  4. data/lib/fast_jsonapi.rb +2 -0
  5. data/lib/fast_jsonapi/instrumentation.rb +2 -0
  6. data/lib/fast_jsonapi/instrumentation/serializable_hash.rb +15 -0
  7. data/lib/fast_jsonapi/instrumentation/serialized_json.rb +15 -0
  8. data/lib/fast_jsonapi/instrumentation/skylight.rb +2 -0
  9. data/lib/fast_jsonapi/instrumentation/skylight/normalizers/serializable_hash.rb +22 -0
  10. data/lib/fast_jsonapi/instrumentation/skylight/normalizers/serialized_json.rb +22 -0
  11. data/lib/fast_jsonapi/multi_to_json.rb +92 -0
  12. data/lib/fast_jsonapi/object_serializer.rb +120 -91
  13. data/lib/fast_jsonapi/serialization_core.rb +44 -32
  14. data/lib/generators/serializer/USAGE +8 -0
  15. data/lib/generators/serializer/serializer_generator.rb +19 -0
  16. data/lib/generators/serializer/templates/serializer.rb.tt +6 -0
  17. metadata +48 -88
  18. data/.document +0 -5
  19. data/.rspec +0 -1
  20. data/Gemfile +0 -4
  21. data/Gemfile.lock +0 -158
  22. data/README.rdoc +0 -231
  23. data/Rakefile +0 -55
  24. data/VERSION +0 -1
  25. data/docs/collection_serializer_output.json +0 -35
  26. data/docs/object_serializer.json +0 -30
  27. data/fast_jsonapi.gemspec +0 -108
  28. data/spec/lib/extensions/active_record_spec.rb +0 -67
  29. data/spec/lib/object_serializer_caching_spec.rb +0 -68
  30. data/spec/lib/object_serializer_class_methods_spec.rb +0 -69
  31. data/spec/lib/object_serializer_hyphen_spec.rb +0 -40
  32. data/spec/lib/object_serializer_performance_spec.rb +0 -87
  33. data/spec/lib/object_serializer_spec.rb +0 -126
  34. data/spec/lib/object_serializer_struct_spec.rb +0 -31
  35. data/spec/lib/serialization_core_spec.rb +0 -84
  36. data/spec/shared/contexts/ams_context.rb +0 -83
  37. data/spec/shared/contexts/movie_context.rb +0 -192
  38. data/spec/spec_helper.rb +0 -15
@@ -1,67 +0,0 @@
1
- require 'spec_helper'
2
- require 'active_record'
3
- require 'sqlite3'
4
-
5
- describe 'active record' do
6
-
7
- # Setup DB
8
- before(:all) do
9
- @db_file = "test.db"
10
-
11
- # Open a database
12
- db = SQLite3::Database.new @db_file
13
-
14
- # Create tables
15
- db.execute_batch <<-SQL
16
- create table suppliers (
17
- name varchar(30),
18
- id int primary key
19
- );
20
-
21
- create table accounts (
22
- name varchar(30),
23
- id int primary key,
24
- supplier_id int,
25
- FOREIGN KEY (supplier_id) REFERENCES suppliers(id)
26
- );
27
- SQL
28
-
29
- # Insert records
30
- @account_id = 2
31
- @supplier_id = 1
32
- db.execute_batch <<-SQL
33
- insert into suppliers values ('Supplier1', #{@supplier_id});
34
- insert into accounts values ('Dollar Account', #{@account_id}, #{@supplier_id});
35
- SQL
36
- end
37
-
38
- # Setup Active Record
39
- before(:all) do
40
- class Supplier < ActiveRecord::Base
41
- has_one :account
42
- end
43
-
44
- class Account < ActiveRecord::Base
45
- belongs_to :supplier
46
- end
47
-
48
- ActiveRecord::Base.establish_connection(
49
- :adapter => 'sqlite3',
50
- :database => @db_file
51
- )
52
- end
53
-
54
- context 'has one patch' do
55
-
56
- it 'has account_id method for a supplier' do
57
- expect(Supplier.first.respond_to?(:account_id)).to be true
58
- expect(Supplier.first.account_id).to eq @account_id
59
- end
60
-
61
- end
62
-
63
- # Clean up DB
64
- after(:all) do
65
- File.delete(@db_file) if File.exist?(@db_file)
66
- end
67
- end
@@ -1,68 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FastJsonapi::ObjectSerializer do
4
- include_context 'movie class'
5
-
6
- context 'when caching has_many' do
7
- before(:each) do
8
- rails = OpenStruct.new
9
- rails.cache = ActiveSupport::Cache::MemoryStore.new
10
- stub_const('Rails', rails)
11
- end
12
-
13
- it 'returns correct hash when serializable_hash is called' do
14
- options = {}
15
- options[:meta] = { total: 2 }
16
- options[:include] = [:actors]
17
- serializable_hash = CachingMovieSerializer.new([movie, movie], options).serializable_hash
18
-
19
- expect(serializable_hash[:data].length).to eq 2
20
- expect(serializable_hash[:data][0][:relationships].length).to eq 3
21
- expect(serializable_hash[:data][0][:attributes].length).to eq 2
22
-
23
- expect(serializable_hash[:meta]).to be_instance_of(Hash)
24
-
25
- expect(serializable_hash[:included]).to be_instance_of(Array)
26
- expect(serializable_hash[:included][0]).to be_instance_of(Hash)
27
- expect(serializable_hash[:included].length).to eq 3
28
-
29
- serializable_hash = CachingMovieSerializer.new(movie).serializable_hash
30
-
31
- expect(serializable_hash[:data]).to be_instance_of(Hash)
32
- expect(serializable_hash[:meta]).to be nil
33
- expect(serializable_hash[:included]).to be nil
34
- end
35
-
36
- it 'uses cached values for the record' do
37
- previous_name = movie.name
38
- previous_actors = movie.actors
39
- CachingMovieSerializer.new(movie).serializable_hash
40
-
41
- movie.name = 'should not match'
42
- allow(movie).to receive(:actor_ids).and_return([99])
43
-
44
- expect(previous_name).not_to eq(movie.name)
45
- expect(previous_actors).not_to eq(movie.actors)
46
- serializable_hash = CachingMovieSerializer.new(movie).serializable_hash
47
-
48
- expect(serializable_hash[:data][:attributes][:name]).to eq(previous_name)
49
- expect(serializable_hash[:data][:relationships][:actors][:data].length).to eq movie.actors.length
50
- end
51
-
52
- it 'uses cached values for has many as specified' do
53
- previous_name = movie.name
54
- previous_actors = movie.actors
55
- CachingMovieWithHasManySerializer.new(movie).serializable_hash
56
-
57
- movie.name = 'should not match'
58
- allow(movie).to receive(:actor_ids).and_return([99])
59
-
60
- expect(previous_name).not_to eq(movie.name)
61
- expect(previous_actors).not_to eq(movie.actors)
62
- serializable_hash = CachingMovieWithHasManySerializer.new(movie).serializable_hash
63
-
64
- expect(serializable_hash[:data][:attributes][:name]).to eq(previous_name)
65
- expect(serializable_hash[:data][:relationships][:actors][:data].length).to eq previous_actors.length
66
- end
67
- end
68
- end
@@ -1,69 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FastJsonapi::ObjectSerializer do
4
-
5
- include_context 'movie class'
6
-
7
- context 'when testing class methods of object serializer' do
8
-
9
- before(:example) do
10
- MovieSerializer.relationships_to_serialize = {}
11
- end
12
-
13
- it 'returns correct relationship hash for a has_many relationship' do
14
- MovieSerializer.has_many :roles
15
- relationship = MovieSerializer.relationships_to_serialize[:roles]
16
- expect(relationship).to be_instance_of(Hash)
17
- expect(relationship.keys).to all(be_instance_of(Symbol))
18
- expect(relationship[:id_method_name]).to end_with '_ids'
19
- expect(relationship[:record_type]).to eq 'roles'.singularize.to_sym
20
- end
21
-
22
- it 'returns correct relationship hash for a has_many relationship with overrides' do
23
- MovieSerializer.has_many :roles, id_method_name: :roles_only_ids, record_type: :super_role
24
- relationship = MovieSerializer.relationships_to_serialize[:roles]
25
- expect(relationship[:id_method_name]).to be :roles_only_ids
26
- expect(relationship[:record_type]).to be :super_role
27
- end
28
-
29
- it 'returns correct relationship hash for a belongs_to relationship' do
30
- MovieSerializer.belongs_to :area
31
- relationship = MovieSerializer.relationships_to_serialize[:area]
32
- expect(relationship).to be_instance_of(Hash)
33
- expect(relationship.keys).to all(be_instance_of(Symbol))
34
- expect(relationship[:id_method_name]).to end_with '_id'
35
- expect(relationship[:record_type]).to eq 'area'.singularize.to_sym
36
- end
37
-
38
- it 'returns correct relationship hash for a belongs_to relationship with overrides' do
39
- MovieSerializer.has_many :area, id_method_name: :blah_id, record_type: :awesome_area, serializer: :my_area
40
- relationship = MovieSerializer.relationships_to_serialize[:area]
41
- expect(relationship[:id_method_name]).to be :blah_id
42
- expect(relationship[:record_type]).to be :awesome_area
43
- expect(relationship[:serializer]).to be :MyAreaSerializer
44
- end
45
-
46
- it 'returns correct relationship hash for a has_one relationship' do
47
- MovieSerializer.has_one :area
48
- relationship = MovieSerializer.relationships_to_serialize[:area]
49
- expect(relationship).to be_instance_of(Hash)
50
- expect(relationship.keys).to all(be_instance_of(Symbol))
51
- expect(relationship[:id_method_name]).to end_with '_id'
52
- expect(relationship[:record_type]).to eq 'area'.singularize.to_sym
53
- end
54
-
55
- it 'returns correct relationship hash for a has_one relationship with overrides' do
56
- MovieSerializer.has_one :area, id_method_name: :blah_id, record_type: :awesome_area
57
- relationship = MovieSerializer.relationships_to_serialize[:area]
58
- expect(relationship[:id_method_name]).to be :blah_id
59
- expect(relationship[:record_type]).to be :awesome_area
60
- end
61
-
62
- it 'returns serializer name correctly with namespaces' do
63
- AppName::V1::MovieSerializer.has_many :area, id_method_name: :blah_id
64
- relationship = AppName::V1::MovieSerializer.relationships_to_serialize[:area]
65
- expect(relationship[:serializer]).to be :'AppName::V1::AreaSerializer'
66
- end
67
- end
68
-
69
- end
@@ -1,40 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FastJsonapi::ObjectSerializer do
4
- include_context 'movie class'
5
- include_context 'ams movie class'
6
-
7
- context 'when using hyphens for word separation in the JSON API members' do
8
- it 'returns correct hash when serializable_hash is called' do
9
- serializable_hash = HyphenMovieSerializer.new([movie, movie]).serializable_hash
10
- expect(serializable_hash[:data].length).to eq 2
11
- expect(serializable_hash[:data][0][:relationships].length).to eq 3
12
- expect(serializable_hash[:data][0][:relationships]).to have_key('movie-type'.to_sym)
13
- expect(serializable_hash[:data][0][:attributes].length).to eq 2
14
- expect(serializable_hash[:data][0][:attributes]).to have_key("release-year".to_sym)
15
-
16
- serializable_hash = HyphenMovieSerializer.new(movie_struct).serializable_hash
17
- expect(serializable_hash[:data][:relationships].length).to eq 3
18
- expect(serializable_hash[:data][:relationships]).to have_key('movie-type'.to_sym)
19
- expect(serializable_hash[:data][:attributes].length).to eq 2
20
- expect(serializable_hash[:data][:attributes]).to have_key('release-year'.to_sym)
21
- expect(serializable_hash[:data][:id]).to eq movie_struct.id.to_s
22
- end
23
-
24
- it 'returns same thing as ams' do
25
- ams_movie = build_ams_movies(1).first
26
- movie = build_movies(1).first
27
- our_json = HyphenMovieSerializer.new([movie]).serialized_json
28
- ams_json = ActiveModelSerializers::SerializableResource.new([ams_movie], key_transform: :dash).to_json
29
- expect(our_json.length).to eq (ams_json.length)
30
- end
31
-
32
- it 'returns type hypenated when trying to serializing a class with multiple words' do
33
- movie_type = MovieType.new
34
- movie_type.id = 3
35
- movie_type.name = "x"
36
- serializable_hash = HyphenMovieTypeSerializer.new(movie_type).serializable_hash
37
- expect(serializable_hash[:data][:type].to_sym).to eq 'movie-type'.to_sym
38
- end
39
- end
40
- end
@@ -1,87 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FastJsonapi::ObjectSerializer do
4
- include_context 'movie class'
5
- include_context 'ams movie class'
6
-
7
- context 'when testing performance of serialization' do
8
- it 'should create a hash of 1000 records in less than 25 ms' do
9
- movies = 1000.times.map { |_i| movie }
10
- expect { MovieSerializer.new(movies).serializable_hash }.to perform_under(25).ms
11
- end
12
-
13
- it 'should serialize 1000 records to jsonapi in less than 30 ms' do
14
- movies = 1000.times.map { |_i| movie }
15
- expect { MovieSerializer.new(movies).serialized_json }.to perform_under(30).ms
16
- end
17
-
18
- it 'should create a hash of 1000 records with includes and meta in less than 75 ms' do
19
- count = 1000
20
- movies = count.times.map { |_i| movie }
21
- options = {}
22
- options[:meta] = { total: count }
23
- options[:include] = [:actors]
24
- expect { MovieSerializer.new(movies, options).serializable_hash }.to perform_under(75).ms
25
- end
26
-
27
- it 'should serialize 1000 records to jsonapi with includes and meta in less than 75 ms' do
28
- count = 1000
29
- movies = count.times.map { |_i| movie }
30
- options = {}
31
- options[:meta] = { total: count }
32
- options[:include] = [:actors]
33
- expect { MovieSerializer.new(movies, options).serialized_json }.to perform_under(75).ms
34
- end
35
- end
36
-
37
- def print_stats(count, ams_time, our_time)
38
- format = '%-15s %-10s %s'
39
- puts ''
40
- puts format(format, 'Serializer', 'Records', 'Time')
41
- puts format(format, 'AMS serializer', count, ams_time.round(2).to_s + ' ms')
42
- puts format(format, 'Fast serializer', count, our_time.round(2).to_s + ' ms')
43
- end
44
-
45
- context 'when comparing with AMS 0.10.x' do
46
- [1, 25, 250, 1000].each do |movie_count|
47
- speed_factor = 25
48
- it "should serialize #{movie_count} records atleast #{speed_factor} times faster than AMS" do
49
- ams_movies = build_ams_movies(movie_count)
50
- movies = build_movies(movie_count)
51
- our_json = nil
52
- ams_json = nil
53
- our_serializer = MovieSerializer.new(movies)
54
- ams_serializer = ActiveModelSerializers::SerializableResource.new(ams_movies)
55
- our_time = Benchmark.measure { our_json = our_serializer.serialized_json }.real * 1000
56
- ams_time = Benchmark.measure { ams_json = ams_serializer.to_json }.real * 1000
57
- print_stats(movie_count, ams_time, our_time)
58
- expect(our_json.length).to eq ams_json.length
59
- expect { our_serializer.serialized_json }.to perform_faster_than { ams_serializer.to_json }.at_least(speed_factor).times
60
- end
61
- end
62
- end
63
-
64
- context 'when comparing with AMS 0.10.x and with includes and meta' do
65
- [1, 25, 250, 1000].each do |movie_count|
66
- speed_factor = 25
67
- it "should serialize #{movie_count} records atleast #{speed_factor} times faster than AMS" do
68
- ams_movies = build_ams_movies(movie_count)
69
- movies = build_movies(movie_count)
70
- our_json = nil
71
- ams_json = nil
72
-
73
- options = {}
74
- options[:meta] = { total: movie_count }
75
- options[:include] = [:actors, :movie_type]
76
-
77
- our_serializer = MovieSerializer.new(movies, options)
78
- ams_serializer = ActiveModelSerializers::SerializableResource.new(ams_movies, include: options[:include], meta: options[:meta])
79
- our_time = Benchmark.measure { our_json = our_serializer.serialized_json }.real * 1000
80
- ams_time = Benchmark.measure { ams_json = ams_serializer.to_json }.real * 1000
81
- print_stats(movie_count, ams_time, our_time)
82
- expect(our_json.length).to eq ams_json.length
83
- expect { our_serializer.serialized_json }.to perform_faster_than { ams_serializer.to_json }.at_least(speed_factor).times
84
- end
85
- end
86
- end
87
- end
@@ -1,126 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FastJsonapi::ObjectSerializer do
4
- include_context 'movie class'
5
-
6
- context 'when testing instance methods of object serializer' do
7
- it 'returns correct hash when serializable_hash is called' do
8
- options = {}
9
- options[:meta] = { total: 2 }
10
- options[:include] = [:actors]
11
- serializable_hash = MovieSerializer.new([movie, movie], options).serializable_hash
12
-
13
- expect(serializable_hash[:data].length).to eq 2
14
- expect(serializable_hash[:data][0][:relationships].length).to eq 3
15
- expect(serializable_hash[:data][0][:attributes].length).to eq 2
16
-
17
- expect(serializable_hash[:meta]).to be_instance_of(Hash)
18
-
19
- expect(serializable_hash[:included]).to be_instance_of(Array)
20
- expect(serializable_hash[:included][0]).to be_instance_of(Hash)
21
- expect(serializable_hash[:included].length).to eq 3
22
-
23
- serializable_hash = MovieSerializer.new(movie).serializable_hash
24
-
25
- expect(serializable_hash[:data]).to be_instance_of(Hash)
26
- expect(serializable_hash[:meta]).to be nil
27
- expect(serializable_hash[:included]).to be nil
28
- end
29
-
30
- it 'returns correct number of records when serialized_json is called for an array' do
31
- options = {}
32
- options[:meta] = { total: 2 }
33
- json = MovieSerializer.new([movie, movie], options).serialized_json
34
- serializable_hash = JSON.parse(json)
35
- expect(serializable_hash['data'].length).to eq 2
36
- expect(serializable_hash['meta']).to be_instance_of(Hash)
37
- end
38
-
39
- it 'returns correct id when serialized_json is called for a single object' do
40
- json = MovieSerializer.new(movie).serialized_json
41
- serializable_hash = JSON.parse(json)
42
- expect(serializable_hash['data']['id']).to eq movie.id.to_s
43
- end
44
-
45
- it 'returns correct json when serializing nil' do
46
- json = MovieSerializer.new(nil).serialized_json
47
- serializable_hash = JSON.parse(json)
48
- expect(serializable_hash['data']).to eq nil
49
- end
50
-
51
- it 'returns correct json when record id is nil' do
52
- movie.id = nil
53
- json = MovieSerializer.new(movie).serialized_json
54
- serializable_hash = JSON.parse(json)
55
- expect(serializable_hash['data']['id']).to be nil
56
- end
57
-
58
- it 'returns correct json when has_many returns []' do
59
- movie.actor_ids = []
60
- json = MovieSerializer.new(movie).serialized_json
61
- serializable_hash = JSON.parse(json)
62
- expect(serializable_hash['data']['relationships']['actors']['data'].length).to eq 0
63
- end
64
-
65
- it 'returns correct json when belongs_to returns nil' do
66
- movie.owner_id = nil
67
- json = MovieSerializer.new(movie).serialized_json
68
- serializable_hash = JSON.parse(json)
69
- expect(serializable_hash['data']['relationships']['owner']['data']).to be nil
70
- end
71
-
72
- it 'returns correct json when serializing []' do
73
- json = MovieSerializer.new([]).serialized_json
74
- serializable_hash = JSON.parse(json)
75
- expect(serializable_hash['data']).to eq []
76
- end
77
-
78
- it 'returns errors when serializing with non-existent includes key' do
79
- options = {}
80
- options[:meta] = { total: 2 }
81
- options[:include] = [:blah_blah]
82
- expect { MovieSerializer.new([movie, movie], options).serializable_hash }.to raise_error(ArgumentError)
83
- end
84
-
85
- it 'returns keys when serializing with empty string/nil array includes key' do
86
- options = {}
87
- options[:meta] = { total: 2 }
88
- options[:include] = ['']
89
- expect(MovieSerializer.new([movie, movie], options).serializable_hash.keys).to eq [:data, :meta]
90
- options[:include] = [nil]
91
- expect(MovieSerializer.new([movie, movie], options).serializable_hash.keys).to eq [:data, :meta]
92
- end
93
- end
94
-
95
- context 'when testing included do block of object serializer' do
96
- it 'should set default_type based on serializer class name' do
97
- class BlahSerializer
98
- include FastJsonapi::ObjectSerializer
99
- end
100
- expect(BlahSerializer.record_type).to be :blah
101
- end
102
-
103
- it 'should set default_type for a multi word class name' do
104
- class BlahBlahSerializer
105
- include FastJsonapi::ObjectSerializer
106
- end
107
- expect(BlahBlahSerializer.record_type).to be :blah_blah
108
- end
109
-
110
- it 'shouldnt set default_type for a serializer that doesnt follow convention' do
111
- class BlahBlahSerializerBuilder
112
- include FastJsonapi::ObjectSerializer
113
- end
114
- expect(BlahBlahSerializerBuilder.record_type).to be_nil
115
- end
116
-
117
- it 'shouldnt set default_type for a serializer that doesnt follow convention' do
118
- module V1
119
- class BlahSerializer
120
- include FastJsonapi::ObjectSerializer
121
- end
122
- end
123
- expect(V1::BlahSerializer.record_type).to be :blah
124
- end
125
- end
126
- end