quiver 0.21.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 +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +6 -0
- data/README.md +22 -0
- data/Rakefile +17 -0
- data/bin/quiver +9 -0
- data/lib/quiver.rb +46 -0
- data/lib/quiver/abstract_action.rb +31 -0
- data/lib/quiver/action.rb +208 -0
- data/lib/quiver/action/filter_error.rb +33 -0
- data/lib/quiver/action/filter_value.rb +152 -0
- data/lib/quiver/action/invalid_request_body_error.rb +30 -0
- data/lib/quiver/action/pagination_link_builder.rb +67 -0
- data/lib/quiver/adapter.rb +51 -0
- data/lib/quiver/adapter/active_record_adapter_filter.rb +102 -0
- data/lib/quiver/adapter/active_record_helpers.rb +258 -0
- data/lib/quiver/adapter/arec_low_level_creator.rb +82 -0
- data/lib/quiver/adapter/arec_low_level_deleter.rb +74 -0
- data/lib/quiver/adapter/arec_low_level_updater.rb +105 -0
- data/lib/quiver/adapter/filter_helpers.rb +58 -0
- data/lib/quiver/adapter/helpers_helpers.rb +53 -0
- data/lib/quiver/adapter/memory_adapter_filter.rb +71 -0
- data/lib/quiver/adapter/memory_adapter_store.rb +34 -0
- data/lib/quiver/adapter/memory_helpers.rb +182 -0
- data/lib/quiver/adapter/memory_uuid_primary_key.rb +25 -0
- data/lib/quiver/application.rb +128 -0
- data/lib/quiver/cli/app.rb +25 -0
- data/lib/quiver/cli/generators/endpoint.rb +17 -0
- data/lib/quiver/cli/generators/new_application.rb +166 -0
- data/lib/quiver/cli/generators/new_application_cli.rb +25 -0
- data/lib/quiver/cli/server.rb +37 -0
- data/lib/quiver/cli/templates/Gemfile.tt +8 -0
- data/lib/quiver/cli/templates/Rakefile.tt +12 -0
- data/lib/quiver/cli/templates/config.tt +3 -0
- data/lib/quiver/cli/templates/config/database.tt +21 -0
- data/lib/quiver/cli/templates/gemspec.tt +33 -0
- data/lib/quiver/cli/templates/gitignore.tt +10 -0
- data/lib/quiver/cli/templates/lib/application.tt +14 -0
- data/lib/quiver/cli/templates/lib/application/config/router.tt +11 -0
- data/lib/quiver/cli/templates/lib/application/version.tt +3 -0
- data/lib/quiver/cli/templates/spec/spec_helper.tt +19 -0
- data/lib/quiver/duty.rb +34 -0
- data/lib/quiver/duty_master.rb +23 -0
- data/lib/quiver/duty_master/delayed_job_adapter.rb +15 -0
- data/lib/quiver/duty_master/memory_adapter.rb +18 -0
- data/lib/quiver/duty_test_helper.rb +23 -0
- data/lib/quiver/duty_test_helper/delayed_job_helper.rb +9 -0
- data/lib/quiver/duty_test_helper/memory_helper.rb +15 -0
- data/lib/quiver/error.rb +24 -0
- data/lib/quiver/error_collection.rb +60 -0
- data/lib/quiver/json_parser.rb +17 -0
- data/lib/quiver/logger.rb +26 -0
- data/lib/quiver/mapper.rb +311 -0
- data/lib/quiver/mapper/hook.rb +21 -0
- data/lib/quiver/mapper/mapper_result.rb +7 -0
- data/lib/quiver/mapper/not_found_error.rb +27 -0
- data/lib/quiver/mapper/simple_query_builder.rb +70 -0
- data/lib/quiver/mapper/soft_delete.rb +15 -0
- data/lib/quiver/mappers.rb +75 -0
- data/lib/quiver/middleware_stack.rb +35 -0
- data/lib/quiver/model.rb +63 -0
- data/lib/quiver/model/soft_delete.rb +14 -0
- data/lib/quiver/model/validation_error.rb +27 -0
- data/lib/quiver/model/validations.rb +45 -0
- data/lib/quiver/patcher.rb +94 -0
- data/lib/quiver/result.rb +44 -0
- data/lib/quiver/route_helper.rb +16 -0
- data/lib/quiver/router.rb +37 -0
- data/lib/quiver/serialization.rb +6 -0
- data/lib/quiver/serialization/json_api.rb +7 -0
- data/lib/quiver/serialization/json_api/item_type_handler.rb +96 -0
- data/lib/quiver/serialization/json_api/serializer.rb +77 -0
- data/lib/quiver/tasks.rb +31 -0
- data/lib/quiver/validator.rb +83 -0
- data/lib/quiver/validators/base.rb +21 -0
- data/lib/quiver/validators/presence.rb +34 -0
- data/lib/quiver/validators/unique.rb +33 -0
- data/lib/quiver/version.rb +3 -0
- data/quiver.gemspec +42 -0
- metadata +393 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
module Quiver
|
2
|
+
module Adapter
|
3
|
+
module ActiveRecord
|
4
|
+
class ARecLowLevelCreator
|
5
|
+
attr_reader :primary_key
|
6
|
+
|
7
|
+
def initialize(adapter_klass, original_attributes)
|
8
|
+
self.adapter_klass = adapter_klass
|
9
|
+
self.failed = false
|
10
|
+
self.original_attributes = original_attributes
|
11
|
+
self.attrs = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def map(attributes, opts)
|
15
|
+
if opts[:foreign_key]
|
16
|
+
attributes.merge!(opts[:foreign_key])
|
17
|
+
end
|
18
|
+
|
19
|
+
if opts[:primary] && original_attributes[:__type__]
|
20
|
+
attributes.merge!(
|
21
|
+
original_attributes[:__type__][:name] => original_attributes[:__type__][:value]
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
record = record_class(opts[:to]).create(attributes)
|
26
|
+
|
27
|
+
if record.persisted?
|
28
|
+
attrs.merge!(record.attributes)
|
29
|
+
|
30
|
+
if opts[:primary]
|
31
|
+
self.primary_key = record.send(adapter_klass.primary_key_name)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
self.failed = true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def map_array(h, opts)
|
39
|
+
h.each do |key, items|
|
40
|
+
attrs[key] = items.map do |attributes|
|
41
|
+
if opts[:foreign_key]
|
42
|
+
attributes.merge!(opts[:foreign_key])
|
43
|
+
end
|
44
|
+
|
45
|
+
record = record_class(opts[:to]).create(attributes)
|
46
|
+
|
47
|
+
if record.persisted?
|
48
|
+
attributes.merge(id: record.id)
|
49
|
+
else
|
50
|
+
self.failed = true
|
51
|
+
{}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def success?
|
58
|
+
!failed
|
59
|
+
end
|
60
|
+
|
61
|
+
def failed!
|
62
|
+
self.failed = true
|
63
|
+
end
|
64
|
+
|
65
|
+
def result
|
66
|
+
original_attributes.symbolize_keys.merge(attrs.merge(
|
67
|
+
adapter_klass.primary_key_name => primary_key
|
68
|
+
).symbolize_keys)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
attr_accessor :adapter_klass, :failed, :original_attributes, :attrs, :mapper_klass
|
74
|
+
attr_writer :primary_key
|
75
|
+
|
76
|
+
def record_class(name)
|
77
|
+
adapter_klass.record_classes[name]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Quiver
|
2
|
+
module Adapter
|
3
|
+
module ActiveRecord
|
4
|
+
class ARecLowLevelDeleter
|
5
|
+
def initialize(adapter_klass, original_attributes)
|
6
|
+
self.adapter_klass = adapter_klass
|
7
|
+
self.failed = false
|
8
|
+
self.original_attributes = original_attributes
|
9
|
+
self.attrs = {}
|
10
|
+
self.calls = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def map(attributes, opts)
|
14
|
+
record = record_class(opts[:to])
|
15
|
+
|
16
|
+
if opts[:foreign_key]
|
17
|
+
record = record.where(opts[:foreign_key])
|
18
|
+
end
|
19
|
+
|
20
|
+
if opts[:primary]
|
21
|
+
record = record.where(
|
22
|
+
adapter_klass.primary_key_name => primary_key
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
calls.unshift -> {
|
27
|
+
record.delete_all == 1
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def map_array(h, opts)
|
32
|
+
raise ArgumentError, 'map_array requires opts[foreign_key] to be set' unless opts[:foreign_key]
|
33
|
+
|
34
|
+
h.each do |key, items|
|
35
|
+
record = record_class(opts[:to])
|
36
|
+
query = record.where(opts[:foreign_key])
|
37
|
+
|
38
|
+
remove_ids = record.pluck(:id)
|
39
|
+
|
40
|
+
calls.unshift -> {
|
41
|
+
query.where(id: remove_ids).delete_all == remove_ids.count
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def success?
|
47
|
+
calls.all? do |call|
|
48
|
+
call.call
|
49
|
+
end && !failed
|
50
|
+
end
|
51
|
+
|
52
|
+
def failed!
|
53
|
+
self.failed = true
|
54
|
+
end
|
55
|
+
|
56
|
+
def result
|
57
|
+
{}
|
58
|
+
end
|
59
|
+
|
60
|
+
def primary_key
|
61
|
+
original_attributes[adapter_klass.primary_key_name]
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
attr_accessor :adapter_klass, :failed, :mapper_klass, :original_attributes, :attrs, :calls
|
67
|
+
|
68
|
+
def record_class(name)
|
69
|
+
adapter_klass.record_classes[name]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Quiver
|
2
|
+
module Adapter
|
3
|
+
module ActiveRecord
|
4
|
+
class ARecLowLevelUpdater
|
5
|
+
def initialize(adapter_klass, original_attributes)
|
6
|
+
self.adapter_klass = adapter_klass
|
7
|
+
self.failed = false
|
8
|
+
self.original_attributes = original_attributes
|
9
|
+
self.attrs = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def map(attributes, opts)
|
13
|
+
record = record_class(opts[:to])
|
14
|
+
|
15
|
+
if opts[:foreign_key]
|
16
|
+
record = record.where(opts[:foreign_key])
|
17
|
+
end
|
18
|
+
|
19
|
+
if opts[:primary]
|
20
|
+
record = record.where(
|
21
|
+
adapter_klass.primary_key_name => primary_key
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
result = record.update_all(attributes)
|
26
|
+
|
27
|
+
if result == 0
|
28
|
+
self.failed = true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def map_array(h, opts)
|
33
|
+
raise ArgumentError, 'map_array requires opts[foreign_key] to be set' unless opts[:foreign_key]
|
34
|
+
|
35
|
+
h.each do |key, items|
|
36
|
+
record = record_class(opts[:to])
|
37
|
+
query = record.where(opts[:foreign_key])
|
38
|
+
|
39
|
+
ids = record.pluck(:id)
|
40
|
+
remaining_ids = items.map { |i| i[:id] }.compact
|
41
|
+
remove_ids = ids - remaining_ids
|
42
|
+
|
43
|
+
query.where(id: remove_ids).delete_all
|
44
|
+
|
45
|
+
attrs[key] = items.map do |item|
|
46
|
+
item = item.merge(opts[:foreign_key])
|
47
|
+
|
48
|
+
if item[:id]
|
49
|
+
result = query.where(id: item[:id]).update_all(item)
|
50
|
+
|
51
|
+
if result != 1
|
52
|
+
self.failed = true
|
53
|
+
else
|
54
|
+
item
|
55
|
+
end
|
56
|
+
else
|
57
|
+
result = record.create(item)
|
58
|
+
|
59
|
+
if !result.persisted?
|
60
|
+
self.failed = true
|
61
|
+
else
|
62
|
+
result.attributes.symbolize_keys
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def success?
|
70
|
+
!failed
|
71
|
+
end
|
72
|
+
|
73
|
+
def failed!
|
74
|
+
self.failed = true
|
75
|
+
end
|
76
|
+
|
77
|
+
def result
|
78
|
+
r = original_attributes.symbolize_keys.merge(attrs.merge(
|
79
|
+
adapter_klass.primary_key_name => primary_key
|
80
|
+
).symbolize_keys)
|
81
|
+
|
82
|
+
if original_attributes[:__type__]
|
83
|
+
r.merge!(
|
84
|
+
original_attributes[:__type__][:name] => original_attributes[:__type__][:value]
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
r
|
89
|
+
end
|
90
|
+
|
91
|
+
def primary_key
|
92
|
+
original_attributes[adapter_klass.primary_key_name]
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
attr_accessor :adapter_klass, :failed, :mapper_klass, :original_attributes, :attrs
|
98
|
+
|
99
|
+
def record_class(name)
|
100
|
+
adapter_klass.record_classes[name]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Quiver
|
2
|
+
module Adapter
|
3
|
+
module FilterHelpers
|
4
|
+
def initialize(memo, filter)
|
5
|
+
self.memo = memo
|
6
|
+
self.filter_params = filter
|
7
|
+
end
|
8
|
+
|
9
|
+
def filter
|
10
|
+
filter_params.inject(memo) do |memo, (attr, filter)|
|
11
|
+
filter_attributes = filter.is_a?(Hash) ? filter : filter.filter_attributes
|
12
|
+
filter_attributes.inject(memo) do |memo, (comparator, value)|
|
13
|
+
if value.nil?
|
14
|
+
memo
|
15
|
+
else
|
16
|
+
case comparator.to_s.downcase
|
17
|
+
when 'eq'
|
18
|
+
equal_filter(memo, attr, value)
|
19
|
+
when 'not_eq'
|
20
|
+
not_equal_filter(memo, attr, value)
|
21
|
+
when 'in'
|
22
|
+
in_filter(memo, attr, value)
|
23
|
+
when 'not_in'
|
24
|
+
not_in_filter(memo, attr, value)
|
25
|
+
when 'lt'
|
26
|
+
less_than_filter(memo, attr, value)
|
27
|
+
when 'gt'
|
28
|
+
greater_than_filter(memo, attr, value)
|
29
|
+
when 'lte'
|
30
|
+
less_than_or_equal_filter(memo, attr, value)
|
31
|
+
when 'gte'
|
32
|
+
greater_than_or_equal_filter(memo, attr, value)
|
33
|
+
when 'not_lt'
|
34
|
+
greater_than_or_equal_filter(memo, attr, value)
|
35
|
+
when 'not_gt'
|
36
|
+
less_than_or_equal_filter(memo, attr, value)
|
37
|
+
when 'not_lte'
|
38
|
+
greater_than_filter(memo, attr, value)
|
39
|
+
when 'not_gte'
|
40
|
+
less_than_filter(memo, attr, value)
|
41
|
+
else
|
42
|
+
if respond_to?("#{comparator.to_s.downcase}_filter", true)
|
43
|
+
send("#{comparator.to_s.downcase}_filter", memo, attr, value)
|
44
|
+
else
|
45
|
+
memo
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_accessor :memo, :filter_params
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Quiver
|
2
|
+
module Adapter
|
3
|
+
module HelpersHelpers
|
4
|
+
def self.included(host)
|
5
|
+
host.send(:extend, SelfMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module SelfMethods
|
9
|
+
def included(host)
|
10
|
+
if !host.is_a?(Quiver::Adapter)
|
11
|
+
host.send(:include, Quiver::Adapter)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def mapper_name
|
19
|
+
@mapper_name ||= self.class.parent.name.split('::').last.underscore
|
20
|
+
end
|
21
|
+
|
22
|
+
def when_valid(model, adapter_op)
|
23
|
+
raise ArgumentError, "requires block" unless block_given?
|
24
|
+
|
25
|
+
errors = model.validate(
|
26
|
+
tags: [adapter_op],
|
27
|
+
mapper: mapper_klass.new,
|
28
|
+
model: model,
|
29
|
+
adapter: self
|
30
|
+
)
|
31
|
+
|
32
|
+
if errors.success?
|
33
|
+
current_time = Time.now.utc
|
34
|
+
model.updated_at = current_time if model.respond_to?(:updated_at=)
|
35
|
+
|
36
|
+
if adapter_op == :create
|
37
|
+
model.created_at ||= current_time if model.respond_to?(:created_at)
|
38
|
+
end
|
39
|
+
|
40
|
+
object = yield(model, errors)
|
41
|
+
end
|
42
|
+
|
43
|
+
Quiver::Mapper::MapperResult.new(object, errors, adapter_op: adapter_op)
|
44
|
+
end
|
45
|
+
|
46
|
+
def hydrate(attributes)
|
47
|
+
mapper_klass.hydrate(attributes).tap do |obj|
|
48
|
+
obj.persisted_by!(adapter_type)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Quiver
|
2
|
+
module Adapter
|
3
|
+
module MemoryAdapterFilterDefaults
|
4
|
+
include FilterHelpers
|
5
|
+
|
6
|
+
def equal_filter(memo, attr, value)
|
7
|
+
memo.select do |obj|
|
8
|
+
obj[attr.to_sym] == value
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def not_equal_filter(memo, attr, value)
|
13
|
+
memo.select do |obj|
|
14
|
+
obj[attr.to_sym] != value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def in_filter(memo, attr, value)
|
19
|
+
memo.select do |obj|
|
20
|
+
value.include?(obj[attr.to_sym])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def not_in_filter(memo, attr, value)
|
25
|
+
memo.select do |obj|
|
26
|
+
!value.include?(obj[attr.to_sym])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def less_than_filter(memo, attr, value)
|
31
|
+
memo.select do |obj|
|
32
|
+
obj[attr.to_sym] < value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def greater_than_filter(memo, attr, value)
|
37
|
+
memo.select do |obj|
|
38
|
+
obj[attr.to_sym] > value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def less_than_or_equal_filter(memo, attr, value)
|
43
|
+
memo.select do |obj|
|
44
|
+
obj[attr.to_sym] <= value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def greater_than_or_equal_filter(memo, attr, value)
|
49
|
+
memo.select do |obj|
|
50
|
+
obj[attr.to_sym] >= value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def nil_filter(memo, attr, value)
|
55
|
+
memo.select do |obj|
|
56
|
+
obj[attr.to_sym].nil? == (value == 'true' || value == true)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def not_nil_filter(memo, attr, value)
|
61
|
+
memo.select do |obj|
|
62
|
+
obj[attr.to_sym].nil? != (value == 'true' || value == true)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class MemoryAdapterFilter
|
68
|
+
include MemoryAdapterFilterDefaults
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|