graphiti-activegraph 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +56 -0
- data/Gemfile +12 -0
- data/graphiti-activegraph.gemspec +33 -0
- data/lib/graphiti-activegraph.rb +32 -0
- data/lib/graphiti/active_graph/adapters/active_graph.rb +169 -0
- data/lib/graphiti/active_graph/adapters/active_graph/has_many_sideload.rb +15 -0
- data/lib/graphiti/active_graph/adapters/active_graph/has_one_sideload.rb +15 -0
- data/lib/graphiti/active_graph/adapters/active_graph/sideload.rb +68 -0
- data/lib/graphiti/active_graph/deserializer.rb +132 -0
- data/lib/graphiti/active_graph/query.rb +54 -0
- data/lib/graphiti/active_graph/resource.rb +72 -0
- data/lib/graphiti/active_graph/resource/persistence.rb +25 -0
- data/lib/graphiti/active_graph/resource_proxy.rb +84 -0
- data/lib/graphiti/active_graph/runner.rb +38 -0
- data/lib/graphiti/active_graph/scoping/filter.rb +38 -0
- data/lib/graphiti/active_graph/scoping/filterable.rb +12 -0
- data/lib/graphiti/active_graph/sideload_resolve.rb +23 -0
- data/lib/graphiti/active_graph/util/serializer_relationship.rb +29 -0
- data/lib/graphiti/active_graph/version.rb +5 -0
- metadata +217 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 788e448fa1ea2a64247650cb77402a7518ae543789ea8259240fdb60f7469340
|
4
|
+
data.tar.gz: 899272d03b3f1b78fa3567ae6fd02a0bb9386c39544ae8e2ff649c6de022b8ef
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4c071b303b06a2d8bd78a601b212a2f9ca546be2012fb22f064eb8389232824598d0b8d2366df7e4496d3325360aa5071b8188f703e5ca2b72c7dfd9570163e7
|
7
|
+
data.tar.gz: c4a43e4604cb2f283a79f8bc42e9c43648f9f3ae6af52981bbec3365a1ba9b1f298d3a45ce0842dd09b0e1536d8c5573da3b0f6c3db73f07c2baa282176b1896
|
data/.gitignore
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
# Used by dotenv library to load environment variables.
|
14
|
+
# .env
|
15
|
+
|
16
|
+
# Ignore Byebug command history file.
|
17
|
+
.byebug_history
|
18
|
+
|
19
|
+
## Specific to RubyMotion:
|
20
|
+
.dat*
|
21
|
+
.repl_history
|
22
|
+
build/
|
23
|
+
*.bridgesupport
|
24
|
+
build-iPhoneOS/
|
25
|
+
build-iPhoneSimulator/
|
26
|
+
|
27
|
+
## Specific to RubyMotion (use of CocoaPods):
|
28
|
+
#
|
29
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
30
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
31
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
32
|
+
#
|
33
|
+
# vendor/Pods/
|
34
|
+
|
35
|
+
## Documentation cache and generated files:
|
36
|
+
/.yardoc/
|
37
|
+
/_yardoc/
|
38
|
+
/doc/
|
39
|
+
/rdoc/
|
40
|
+
|
41
|
+
## Environment normalization:
|
42
|
+
/.bundle/
|
43
|
+
/vendor/bundle
|
44
|
+
/lib/bundler/man/
|
45
|
+
|
46
|
+
# for a library or gem, you might want to ignore these files since the code is
|
47
|
+
# intended to run in multiple environments; otherwise, check them in:
|
48
|
+
# Gemfile.lock
|
49
|
+
# .ruby-version
|
50
|
+
# .ruby-gemset
|
51
|
+
|
52
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
53
|
+
.rvmrc
|
54
|
+
|
55
|
+
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
56
|
+
# .rubocop-https?--*
|
data/Gemfile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "graphiti/active_graph/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "graphiti-activegraph"
|
7
|
+
spec.version = Graphiti::ActiveGraph::VERSION
|
8
|
+
spec.authors = ["Hardik Joshi"]
|
9
|
+
spec.email = ["hardikjoshi1991@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Easily build jsonapi.org-compatible APIs for GraphDB"
|
12
|
+
spec.homepage = "https://github.com/mrhardikjoshi/graphiti-activegraph"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
spec.required_ruby_version = "~> 2.3"
|
20
|
+
|
21
|
+
spec.add_dependency "graphiti", "~> 1.2.0"
|
22
|
+
spec.add_dependency "concurrent-ruby", "~> 1.0"
|
23
|
+
spec.add_dependency "activesupport", ">= 4.1"
|
24
|
+
spec.add_dependency "zeitwerk"
|
25
|
+
|
26
|
+
spec.add_development_dependency "faraday", "~> 0.15"
|
27
|
+
spec.add_development_dependency "kaminari", "~> 0.17"
|
28
|
+
spec.add_development_dependency "bundler"
|
29
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
30
|
+
spec.add_development_dependency "activemodel", ">= 4.1"
|
31
|
+
spec.add_development_dependency "graphiti_spec_helpers", "1.0.beta.4"
|
32
|
+
spec.add_development_dependency "standard"
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'graphiti'
|
2
|
+
require 'zeitwerk'
|
3
|
+
|
4
|
+
# Workaround for missing zeitwerk support as of jruby-9.2.13.0
|
5
|
+
module Graphiti
|
6
|
+
module ActiveGraph
|
7
|
+
module Scoping
|
8
|
+
end
|
9
|
+
module Adapters
|
10
|
+
end
|
11
|
+
module Util
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
# End workaround
|
16
|
+
|
17
|
+
loader = Zeitwerk::Loader.for_gem
|
18
|
+
loader.inflector.inflect 'version' => 'VERSION'
|
19
|
+
loader.ignore(File.expand_path('graphiti-activegraph.rb', __dir__))
|
20
|
+
loader.setup
|
21
|
+
|
22
|
+
Graphiti::Resource::Persistence.prepend Graphiti::ActiveGraph::Resource::Persistence
|
23
|
+
Graphiti::Scoping::Filter.prepend Graphiti::ActiveGraph::Scoping::Filter
|
24
|
+
Graphiti::Scoping::Filterable.prepend Graphiti::ActiveGraph::Scoping::Filterable
|
25
|
+
Graphiti::Util::SerializerRelationship.prepend Graphiti::ActiveGraph::Util::SerializerRelationship
|
26
|
+
Graphiti::Deserializer.prepend Graphiti::ActiveGraph::Deserializer
|
27
|
+
Graphiti::Query.prepend Graphiti::ActiveGraph::Query
|
28
|
+
Graphiti::Resource.prepend Graphiti::ActiveGraph::ResourceInstanceMethods
|
29
|
+
Graphiti::Resource.extend Graphiti::ActiveGraph::Resource
|
30
|
+
Graphiti::ResourceProxy.prepend Graphiti::ActiveGraph::ResourceProxy
|
31
|
+
Graphiti::Runner.prepend Graphiti::ActiveGraph::Runner
|
32
|
+
Graphiti::Scope.prepend Graphiti::ActiveGraph::SideloadResolve
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module Graphiti::ActiveGraph
|
2
|
+
module Adapters
|
3
|
+
class ActiveGraph < ::Graphiti::Adapters::Abstract
|
4
|
+
def self.sideloading_classes
|
5
|
+
{
|
6
|
+
has_many: Graphiti::ActiveGraph::Adapters::ActiveGraph::HasManySideload,
|
7
|
+
has_one: Graphiti::ActiveGraph::Adapters::ActiveGraph::HasOneSideload
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
def base_scope(model)
|
12
|
+
model.all
|
13
|
+
end
|
14
|
+
|
15
|
+
def assign_attributes(model_instance, attributes)
|
16
|
+
model_instance.before_assign_resource_attr if model_instance.respond_to?(:before_assign_resource_attr)
|
17
|
+
|
18
|
+
attributes.each_pair do |k, v|
|
19
|
+
model_instance.send(:"#{k}=", v) if model_instance.respond_to?(:"#{k}=")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def paginate(scope, current_page, per_page)
|
24
|
+
scope.skip((current_page - 1) * per_page).limit(per_page)
|
25
|
+
end
|
26
|
+
|
27
|
+
def transaction(_model_class)
|
28
|
+
::ActiveGraph::Base.transaction do
|
29
|
+
yield
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def order(scope, attribute, direction, extra_field = false)
|
34
|
+
if extra_field
|
35
|
+
scope.query.order("#{attribute} #{direction}").proxy_as(scope.model, scope.identity)
|
36
|
+
else
|
37
|
+
scope.order(attribute => direction)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def count(scope, _attr)
|
42
|
+
scope.skip(0).limit(nil).count
|
43
|
+
end
|
44
|
+
|
45
|
+
def save(model_instance)
|
46
|
+
model_instance.save
|
47
|
+
model_instance
|
48
|
+
end
|
49
|
+
|
50
|
+
def destroy(model_instance)
|
51
|
+
model_instance.destroy
|
52
|
+
model_instance
|
53
|
+
end
|
54
|
+
|
55
|
+
def resolve(scope)
|
56
|
+
scope.to_a
|
57
|
+
end
|
58
|
+
|
59
|
+
# def associate_all(parent, children, association_name, association_type)
|
60
|
+
# if association_type == :has_many
|
61
|
+
# if !parent.send(:"#{association_name}").present?
|
62
|
+
# parent.send(:"#{association_name}=", children)
|
63
|
+
# else
|
64
|
+
# parent.send(:"#{association_name}") << children
|
65
|
+
# end
|
66
|
+
# else
|
67
|
+
# parent.send(:"#{association_name}=", children)
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
|
71
|
+
def process_belongs_to(persistence, attributes)
|
72
|
+
[]
|
73
|
+
end
|
74
|
+
|
75
|
+
def process_has_many(persistence, caller_model)
|
76
|
+
[]
|
77
|
+
end
|
78
|
+
|
79
|
+
def persistence_attributes(persistence, attributes)
|
80
|
+
rel_attrs = {}
|
81
|
+
@persistence = persistence
|
82
|
+
|
83
|
+
del_empty_rels(rel_attrs) unless resource.relation_resource?
|
84
|
+
attributes_for_has_one(rel_attrs)
|
85
|
+
attributes_for_has_many(rel_attrs)
|
86
|
+
|
87
|
+
attributes.merge rel_attrs
|
88
|
+
end
|
89
|
+
|
90
|
+
def associate(parent, child, association_name, type)
|
91
|
+
end
|
92
|
+
|
93
|
+
def disassociate(parent, child, association_name, type)
|
94
|
+
parent.send(:"#{association_name}=", nil)
|
95
|
+
end
|
96
|
+
|
97
|
+
def clear_active_connections!
|
98
|
+
end
|
99
|
+
|
100
|
+
def filter_eq(scope, attribute, value)
|
101
|
+
scope.where(attribute => value)
|
102
|
+
end
|
103
|
+
alias filter_integer_eq filter_eq
|
104
|
+
alias filter_float_eq filter_eq
|
105
|
+
alias filter_big_decimal_eq filter_eq
|
106
|
+
alias filter_date_eq filter_eq
|
107
|
+
alias filter_boolean_eq filter_eq
|
108
|
+
alias filter_uuid_eq filter_eq
|
109
|
+
alias filter_enum_eq filter_eq
|
110
|
+
|
111
|
+
def filter_not_eq(scope, attribute, value)
|
112
|
+
scope.where_not(attribute => value)
|
113
|
+
end
|
114
|
+
alias filter_integer_not_eq filter_not_eq
|
115
|
+
alias filter_float_not_eq filter_not_eq
|
116
|
+
alias filter_big_decimal_not_eq filter_not_eq
|
117
|
+
alias filter_date_not_eq filter_not_eq
|
118
|
+
alias filter_boolean_not_eq filter_not_eq
|
119
|
+
alias filter_uuid_not_eq filter_not_eq
|
120
|
+
alias filter_enum_not_eq filter_not_eq
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def del_empty_rels(rel_attrs)
|
125
|
+
relationships = @persistence.instance_variable_get(:@relationships)
|
126
|
+
relationships.each do |rel_name, rel_data|
|
127
|
+
rel_attrs[rel_name] = nil if rel_data.blank?
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def attributes_for_has_one(rel_attrs)
|
132
|
+
@persistence.iterate(only: [:has_one]) do |x|
|
133
|
+
process_relationship_attrs(x, rel_attrs, false)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def attributes_for_has_many(rel_attrs)
|
138
|
+
@persistence.iterate(only: [:has_many]) do |x|
|
139
|
+
process_relationship_attrs(x, rel_attrs, true)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def process_relationship_attrs(x, rel_attrs, assign_multiple)
|
144
|
+
x[:object] = x[:resource]
|
145
|
+
.persist_with_relationships(x[:meta], x[:attributes], x[:relationships], self, x[:foreign_key])
|
146
|
+
|
147
|
+
resource = @persistence.instance_variable_get(:@resource)
|
148
|
+
meta = @persistence.instance_variable_get(:@meta)
|
149
|
+
# Relationship start/end nodes cannot be changed once persisted
|
150
|
+
unless meta[:method] == :update && resource.relation_resource?
|
151
|
+
if assign_multiple
|
152
|
+
rel_attrs[x[:foreign_key]] ||= []
|
153
|
+
rel_attrs[x[:foreign_key]] << resource_association_value(x)
|
154
|
+
else
|
155
|
+
rel_attrs[x[:foreign_key]] = resource_association_value(x)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def resource_association_value(rel_map)
|
161
|
+
if [:destroy, :disassociate].include?(rel_map[:meta][:method]) || rel_map[:attributes].blank?
|
162
|
+
nil
|
163
|
+
else
|
164
|
+
rel_map[:object]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Graphiti::ActiveGraph::Adapters::ActiveGraph::HasManySideload < Graphiti::Sideload::HasMany
|
2
|
+
include Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
3
|
+
|
4
|
+
def default_base_scope
|
5
|
+
resource_class.model.all
|
6
|
+
end
|
7
|
+
|
8
|
+
def infer_foreign_key
|
9
|
+
association_name.to_sym
|
10
|
+
end
|
11
|
+
|
12
|
+
def default_value_when_empty
|
13
|
+
[]
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Graphiti::ActiveGraph::Adapters::ActiveGraph::HasOneSideload < Graphiti::Sideload::HasOne
|
2
|
+
include Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
3
|
+
|
4
|
+
def default_base_scope
|
5
|
+
resource_class.model.all
|
6
|
+
end
|
7
|
+
|
8
|
+
def infer_foreign_key
|
9
|
+
association_name.to_sym
|
10
|
+
end
|
11
|
+
|
12
|
+
def default_value_when_empty
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
2
|
+
def self.included(base)
|
3
|
+
base.class_eval do
|
4
|
+
class_attribute :sideload_scope
|
5
|
+
end
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def sideload_scope(&blk)
|
11
|
+
self.sideload_scope = blk
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# def base_scope
|
16
|
+
# if @base_scope
|
17
|
+
# @base_scope.respond_to?(:call) ? @base_scope.call : @base_scope
|
18
|
+
# else
|
19
|
+
# resource.base_scope
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
|
23
|
+
# def load(parents, query, graph_parent)
|
24
|
+
# params, opts, proxy = nil, nil, nil
|
25
|
+
|
26
|
+
# with_error_handling Errors::SideloadParamsError do
|
27
|
+
# params = load_params(parents, query)
|
28
|
+
# params_proc&.call(params, parents, context)
|
29
|
+
# return [] if blank_query?(params)
|
30
|
+
# opts = load_options(parents, query)
|
31
|
+
# opts[:sideload] = self
|
32
|
+
# opts[:parent] = graph_parent
|
33
|
+
# end
|
34
|
+
|
35
|
+
# with_error_handling(Errors::SideloadQueryBuildingError) do
|
36
|
+
# proxy = resource.class._all(params, opts, base_scope)
|
37
|
+
# pre_load_proc&.call(proxy, parents)
|
38
|
+
# end
|
39
|
+
|
40
|
+
# proxy.to_a
|
41
|
+
# end
|
42
|
+
|
43
|
+
# def load(parents, _, _)
|
44
|
+
# child_arr = []
|
45
|
+
# @child_map = resource_with_parent_assoc(parents).each_with_object({}) do |arr, hash|
|
46
|
+
# child_obj = arr.first
|
47
|
+
# parent_uuid = arr.last
|
48
|
+
# hash[parent_uuid] ||= []
|
49
|
+
# hash[parent_uuid] << child_obj
|
50
|
+
# child_arr << child_obj
|
51
|
+
# end
|
52
|
+
|
53
|
+
# fire_assign(parents, child_arr)
|
54
|
+
# child_arr
|
55
|
+
# end
|
56
|
+
|
57
|
+
# def resource_with_parent_assoc(parents)
|
58
|
+
# parent_ids = parents.pluck(:id)
|
59
|
+
# proxy = parent_resource_class.model.as(:p).where(id: parent_ids)
|
60
|
+
# scope = self.class.sideload_scope
|
61
|
+
|
62
|
+
# if scope.present?
|
63
|
+
# scope.call(proxy)
|
64
|
+
# else
|
65
|
+
# proxy.send(association_name, :children)
|
66
|
+
# end.query.pluck(:children, p: :neo_id)
|
67
|
+
# end
|
68
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Graphiti::ActiveGraph
|
2
|
+
module Deserializer
|
3
|
+
class Conflict < StandardError
|
4
|
+
attr_reader :key, :path_value, :body_value
|
5
|
+
|
6
|
+
def initialize(key, path_value, body_value)
|
7
|
+
@key = key
|
8
|
+
@path_value = path_value
|
9
|
+
@body_value = body_value
|
10
|
+
end
|
11
|
+
|
12
|
+
def message
|
13
|
+
"Path parameter #{key} with value '#{path_value}' conflicts with payload value '#{body_value}'"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(payload, env=nil, model=nil, parent_map=nil)
|
18
|
+
super(payload)
|
19
|
+
|
20
|
+
if data.blank? && env && JsonApiNonParsableMiddleware.parsable_content?(env)
|
21
|
+
raise ArgumentError, "JSON API payload must contain the 'data' key"
|
22
|
+
end
|
23
|
+
|
24
|
+
@params = payload
|
25
|
+
@model = model
|
26
|
+
@parent_map = parent_map || {}
|
27
|
+
@env = env
|
28
|
+
end
|
29
|
+
|
30
|
+
def process_relationships(relationship_hash)
|
31
|
+
{}.tap do |hash|
|
32
|
+
relationship_hash.each_pair do |name, relationship_payload|
|
33
|
+
name = name.to_sym
|
34
|
+
data_payload = relationship_payload[:data]
|
35
|
+
hash[name] = data_payload.nil? ? process_nil_relationship(name) : process_relationship(relationship_payload[:data])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# change empty relationship as `disassociate` hash so they will be removed
|
41
|
+
def process_nil_relationship(name)
|
42
|
+
attributes = {}
|
43
|
+
method_name = :disassociate
|
44
|
+
|
45
|
+
{
|
46
|
+
meta: {
|
47
|
+
jsonapi_type: name.to_sym,
|
48
|
+
method: method_name
|
49
|
+
},
|
50
|
+
attributes: attributes,
|
51
|
+
relationships: {}
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def meta(action: nil)
|
56
|
+
results = super
|
57
|
+
return results if action.present? || @env.nil?
|
58
|
+
|
59
|
+
action = case @env['REQUEST_METHOD']
|
60
|
+
when 'POST' then :create
|
61
|
+
when 'PUT', 'PATCH' then :update
|
62
|
+
when 'DELETE' then :destroy
|
63
|
+
end
|
64
|
+
|
65
|
+
results[:method] = action
|
66
|
+
results
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_path_id_to_relationships!(params)
|
70
|
+
return params if path_relationships_updated?
|
71
|
+
detect_conflict(:id, @params[:id], attributes[:id])
|
72
|
+
path_map.each do |rel_name, path_value|
|
73
|
+
body_value = relationships.dig(rel_name, :attributes, :id)
|
74
|
+
if body_value
|
75
|
+
detect_conflict(rel_name, path_value.to_i, body_value&.to_i)
|
76
|
+
else
|
77
|
+
update_params(params, rel_name, path_value)
|
78
|
+
update_realationships(rel_name, path_value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
path_relationships_updated!
|
82
|
+
params
|
83
|
+
end
|
84
|
+
|
85
|
+
def path_relationships_updated!
|
86
|
+
@path_relationships_updated = true
|
87
|
+
end
|
88
|
+
|
89
|
+
def path_relationships_updated?
|
90
|
+
@path_relationships_updated.present?
|
91
|
+
end
|
92
|
+
|
93
|
+
def update_params(params, rel_name, path_value)
|
94
|
+
params[:data] ||= {}
|
95
|
+
params[:data][:relationships] ||= {}
|
96
|
+
params[:data][:relationships][rel_name] = {
|
97
|
+
data: {
|
98
|
+
type: rel_name.to_s,
|
99
|
+
id: path_value.to_i
|
100
|
+
}
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def update_realationships(rel_name, path_value)
|
105
|
+
relationships[rel_name] = { meta: {}, attributes: { id: path_value.to_i } }
|
106
|
+
end
|
107
|
+
|
108
|
+
def path_map
|
109
|
+
map = @params.select { |key, _| key =~ /_id$/ }.permit!.to_h
|
110
|
+
map = filter_keys(map) { |key| key.gsub(/_id$/, '').to_sym }
|
111
|
+
map = filter_keys(map) { |key| @parent_map[key] || key }
|
112
|
+
map = filter_keys_presence(map) if @model < ActiveGraph::Node
|
113
|
+
map
|
114
|
+
end
|
115
|
+
|
116
|
+
def filter_keys_presence(map)
|
117
|
+
filter_keys(map) { |key| presence(key) || presence(key.to_s.pluralize.to_sym) }
|
118
|
+
end
|
119
|
+
|
120
|
+
def filter_keys(map)
|
121
|
+
map.map { |key, v| [yield(key), v] }.select(&:first).to_h
|
122
|
+
end
|
123
|
+
|
124
|
+
def presence(key)
|
125
|
+
key if @model.associations.include?(key)
|
126
|
+
end
|
127
|
+
|
128
|
+
def detect_conflict(key, path_value, body_value)
|
129
|
+
raise Conflict.new(key, path_value, body_value) if body_value && body_value != path_value
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Graphiti::ActiveGraph
|
2
|
+
module Query
|
3
|
+
attr_reader :deep_sort
|
4
|
+
|
5
|
+
def filters
|
6
|
+
@filters ||= begin
|
7
|
+
{}.tap do |hash|
|
8
|
+
(@params[:filter] || {}).each_pair do |name, value|
|
9
|
+
name = name.to_sym
|
10
|
+
|
11
|
+
if legacy_nested?(name)
|
12
|
+
value.keys.each do |key|
|
13
|
+
filter_name = key.to_sym
|
14
|
+
filter_value = value[key]
|
15
|
+
|
16
|
+
if @resource.get_attr!(filter_name, :filterable, request: true)
|
17
|
+
hash[filter_name] = filter_value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
elsif nested?(name)
|
21
|
+
name = name.to_s.split(".").last.to_sym
|
22
|
+
validate!(name, :filterable)
|
23
|
+
hash[name] = value
|
24
|
+
else
|
25
|
+
hash[name] = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def sorts
|
33
|
+
return super unless (sort = params[:sort]) && sort.include?('.')
|
34
|
+
|
35
|
+
@deep_sort = sort_criteria(sort)
|
36
|
+
[]
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_sort_criteria_hash(hash)
|
40
|
+
hash.map { |key, value| [key.to_s.split('.').map(&:to_sym), value] }.to_h
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def sort_criteria(sort)
|
46
|
+
sort.split(',').map(&method(:sort_hash)).map(&method(:parse_sort_criteria_hash))
|
47
|
+
end
|
48
|
+
|
49
|
+
def update_include_hash(authorized_include_param)
|
50
|
+
@include_hash = authorized_include_param
|
51
|
+
@sideloads = nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Graphiti
|
2
|
+
module ActiveGraph
|
3
|
+
module Resource
|
4
|
+
def relation_resource?
|
5
|
+
config[:relation_resource] || false
|
6
|
+
end
|
7
|
+
|
8
|
+
def relationship_resource=(value)
|
9
|
+
config[:relation_resource] = value
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_preloaded_obj(obj, params)
|
13
|
+
id = params[:data].try(:[], :id) || params.delete(:id)
|
14
|
+
params[:filter] ||= {}
|
15
|
+
params[:filter][:id] = id if id
|
16
|
+
|
17
|
+
validate!(params)
|
18
|
+
runner = ::Graphiti::Runner.new(self, params)
|
19
|
+
runner.proxy(nil, single: true, raise_on_missing: false, preloaded: obj, bypass_required_filters: true)
|
20
|
+
end
|
21
|
+
|
22
|
+
def all_with_preloaded(obj_arr, params)
|
23
|
+
validate!(params)
|
24
|
+
|
25
|
+
runner = ::Graphiti::Runner.new(self, params)
|
26
|
+
runner.proxy(nil, raise_on_missing: false, preloaded: obj_arr)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module ResourceInstanceMethods
|
31
|
+
def relation_resource?
|
32
|
+
self.class.relation_resource?
|
33
|
+
end
|
34
|
+
|
35
|
+
def before_resolve(scope, query)
|
36
|
+
if query.params[:group_by].present?
|
37
|
+
scope.collect { |gp| query.params[:group_class].new(name: gp['name']) }
|
38
|
+
else
|
39
|
+
scope
|
40
|
+
end
|
41
|
+
# scope.with_associations(sideload_name_arr(query))
|
42
|
+
end
|
43
|
+
|
44
|
+
def sideload_name_arr(query)
|
45
|
+
query.sideloads.keys.map(&:to_sym)
|
46
|
+
end
|
47
|
+
|
48
|
+
def typecast(name, value, flag)
|
49
|
+
att = get_attr!(name, flag, request: true)
|
50
|
+
|
51
|
+
# in case of attribute is not declared on resource
|
52
|
+
# do not throw error, return original value without typecast
|
53
|
+
return value unless att
|
54
|
+
|
55
|
+
type_name = att[:type]
|
56
|
+
if flag == :filterable
|
57
|
+
type_name = filters[name][:type]
|
58
|
+
end
|
59
|
+
type = Graphiti::Types[type_name]
|
60
|
+
return if value.nil? && type[:kind] != "array"
|
61
|
+
begin
|
62
|
+
flag = :read if flag == :readable
|
63
|
+
flag = :write if flag == :writable
|
64
|
+
flag = :params if [:sortable, :filterable].include?(flag)
|
65
|
+
type[flag][value]
|
66
|
+
rescue => e
|
67
|
+
raise Errors::TypecastFailed.new(self, name, value, e, type_name)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Graphiti::ActiveGraph
|
2
|
+
module Resource
|
3
|
+
module Persistence
|
4
|
+
def update(update_params, meta = nil)
|
5
|
+
model_instance = nil
|
6
|
+
id = update_params[:id]
|
7
|
+
update_params = update_params.except(:id)
|
8
|
+
|
9
|
+
run_callbacks :persistence, :update, update_params, meta do
|
10
|
+
run_callbacks :attributes, :update, update_params, meta do |params|
|
11
|
+
model_instance = id ? model.find(id) : self.class._find(id: id).data
|
12
|
+
call_with_meta(:assign_attributes, model_instance, params, meta)
|
13
|
+
model_instance
|
14
|
+
end
|
15
|
+
|
16
|
+
run_callbacks :save, :update, model_instance, meta do
|
17
|
+
model_instance = call_with_meta(:save, model_instance, meta)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
model_instance
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Graphiti::ActiveGraph
|
2
|
+
module ResourceProxy
|
3
|
+
include Graphiti::ActiveGraph::SideloadResolve
|
4
|
+
attr_reader :preloaded
|
5
|
+
|
6
|
+
def initialize(resource, scope, query,
|
7
|
+
payload: nil,
|
8
|
+
single: false,
|
9
|
+
raise_on_missing: false,
|
10
|
+
preloaded: false)
|
11
|
+
@resource = resource
|
12
|
+
@scope = scope
|
13
|
+
@query = query
|
14
|
+
@payload = payload
|
15
|
+
@single = single
|
16
|
+
@raise_on_missing = raise_on_missing
|
17
|
+
@preloaded = preloaded
|
18
|
+
end
|
19
|
+
|
20
|
+
def data
|
21
|
+
return @data if @data
|
22
|
+
|
23
|
+
return super unless @preloaded
|
24
|
+
|
25
|
+
resolve_sideloads(@preloaded)
|
26
|
+
@single ? data_for_preloaded_record : data_for_preloaded_records
|
27
|
+
end
|
28
|
+
|
29
|
+
def data_for_preloaded_record
|
30
|
+
@preloaded = @preloaded.is_a?(Array) ? @preloaded[0] : @preloaded
|
31
|
+
@resource.decorate_record(@preloaded)
|
32
|
+
@data = @preloaded
|
33
|
+
end
|
34
|
+
|
35
|
+
def data_for_preloaded_records
|
36
|
+
@preloaded.each do |r|
|
37
|
+
@resource.decorate_record(r)
|
38
|
+
end
|
39
|
+
@data = @preloaded
|
40
|
+
end
|
41
|
+
|
42
|
+
def stats
|
43
|
+
@stats ||= if @query.hash[:stats] && !resource.relation_resource?
|
44
|
+
payload = ::Graphiti::Stats::Payload.new @resource,
|
45
|
+
@query,
|
46
|
+
@scope.unpaginated_object,
|
47
|
+
data
|
48
|
+
payload.generate
|
49
|
+
else
|
50
|
+
{}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def save(action: :create)
|
55
|
+
# TODO: remove this. Only used for persisting many-to-many with AR
|
56
|
+
# (see activerecord adapter)
|
57
|
+
original = Graphiti.context[:namespace]
|
58
|
+
begin
|
59
|
+
Graphiti.context[:namespace] = action
|
60
|
+
::Graphiti::RequestValidator.new(@resource, @payload.params).validate!
|
61
|
+
validator = persist {
|
62
|
+
@resource.persist_with_relationships \
|
63
|
+
@payload.meta(action: action),
|
64
|
+
@payload.attributes,
|
65
|
+
@payload.relationships
|
66
|
+
}
|
67
|
+
ensure
|
68
|
+
Graphiti.context[:namespace] = original
|
69
|
+
end
|
70
|
+
@data, success = validator.to_a
|
71
|
+
|
72
|
+
if success && !resource.relation_resource?
|
73
|
+
# If the context namespace is `update` or `create`, certain
|
74
|
+
# adapters will cause N+1 validation calls, so lets explicitly
|
75
|
+
# switch to a lookup context.
|
76
|
+
Graphiti.with_context(Graphiti.context[:object], :show) do
|
77
|
+
@scope.resolve_sideloads([@data])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
success
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Graphiti::ActiveGraph
|
2
|
+
module Runner
|
3
|
+
def initialize(resource_class, params, query = nil, action = nil)
|
4
|
+
@resource_class = resource_class
|
5
|
+
@params = params
|
6
|
+
@query = query
|
7
|
+
@action = action
|
8
|
+
|
9
|
+
validator = ::Graphiti::RequestValidator.new(jsonapi_resource, params)
|
10
|
+
|
11
|
+
validator.validate! unless params[:skip_render_val]
|
12
|
+
|
13
|
+
@deserialized_payload = validator.deserialized_payload
|
14
|
+
end
|
15
|
+
|
16
|
+
def proxy(base = nil, opts = {})
|
17
|
+
base ||= jsonapi_resource.base_scope
|
18
|
+
scope_opts = opts.slice :sideload_parent_length,
|
19
|
+
:default_paginate,
|
20
|
+
:after_resolve,
|
21
|
+
:sideload,
|
22
|
+
:parent,
|
23
|
+
:params
|
24
|
+
scope = jsonapi_scope(base, scope_opts) unless jsonapi_resource.relation_resource?
|
25
|
+
preloaded = opts[:preloaded] || (jsonapi_resource.relation_resource? && jsonapi_resource.base_scope)
|
26
|
+
options = { payload: deserialized_payload,
|
27
|
+
single: opts[:single],
|
28
|
+
raise_on_missing: opts[:raise_on_missing],
|
29
|
+
preloaded: preloaded
|
30
|
+
}
|
31
|
+
::Graphiti::ResourceProxy.new jsonapi_resource,
|
32
|
+
scope,
|
33
|
+
query,
|
34
|
+
options
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Graphiti::ActiveGraph
|
2
|
+
module Scoping
|
3
|
+
module Filter
|
4
|
+
def each_filter
|
5
|
+
filter_param.each_pair do |param_name, param_value|
|
6
|
+
filter = find_filter!(param_name)
|
7
|
+
|
8
|
+
normalize_param(filter, param_value).each do |operator, value|
|
9
|
+
operator = operator.to_s.gsub("!", "not_").to_sym
|
10
|
+
|
11
|
+
# dynamic filters errors for validating and typecasting value below
|
12
|
+
# so they are skipped here without validation or typecast
|
13
|
+
filter_map = filter.values[0]
|
14
|
+
if filter_map[:dynamic_filter]
|
15
|
+
yield filter, operator, value
|
16
|
+
next
|
17
|
+
end
|
18
|
+
validate_operator(filter, operator)
|
19
|
+
|
20
|
+
type = ::Graphiti::Types[filter_map[:type]]
|
21
|
+
unless type[:canonical_name] == :hash || !value.is_a?(String)
|
22
|
+
value = parse_string_value(filter_map, value)
|
23
|
+
end
|
24
|
+
|
25
|
+
check_deny_empty_filters!(resource, filter, value)
|
26
|
+
value = parse_string_null(filter_map, value)
|
27
|
+
validate_singular(resource, filter, value)
|
28
|
+
value = coerce_types(filter_map, param_name.to_sym, value)
|
29
|
+
validate_allowlist(resource, filter, value)
|
30
|
+
validate_denylist(resource, filter, value)
|
31
|
+
value = value[0] if filter_map[:single]
|
32
|
+
yield filter, operator, value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Graphiti::ActiveGraph
|
2
|
+
module SideloadResolve
|
3
|
+
def resolve_sideloads(parents)
|
4
|
+
@query.sideloads.each_pair do |name, q|
|
5
|
+
sideload = @resource.class.sideload(name)
|
6
|
+
next if sideload.nil? || sideload.shared_remote?
|
7
|
+
|
8
|
+
if sideload.assign_each_proc
|
9
|
+
Array.wrap(parents).each do |parent|
|
10
|
+
children = sideload.assign_each_proc.call(parent) || sideload.default_value_when_empty
|
11
|
+
|
12
|
+
# currently there is no possible way to assign association on activegraph without triggering save
|
13
|
+
# https://github.com/neo4jrb/activegraph/issues/1445
|
14
|
+
# as a workaround we are using instance variable here to store and retrive associations
|
15
|
+
# once above issue is fixed use that fix to assign the association here
|
16
|
+
# and also remove 1) this code and 2) SerializerRelationship#data_proc
|
17
|
+
parent.instance_variable_set("@graphiti_render_#{name}", { data: children })
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Graphiti::ActiveGraph
|
2
|
+
module Util
|
3
|
+
module SerializerRelationship
|
4
|
+
def data_proc
|
5
|
+
sideload_ref = @sideload
|
6
|
+
->(_) {
|
7
|
+
# use custom assigned sideload if it is specified via "assign_each_proc"
|
8
|
+
# otherwise retrieve sideload using normal getter on parent object
|
9
|
+
custom_assigned_sideload = @object.instance_variable_get("@graphiti_render_#{sideload_ref.association_name}")
|
10
|
+
records = if custom_assigned_sideload.blank?
|
11
|
+
@object.public_send(sideload_ref.association_name)
|
12
|
+
else
|
13
|
+
custom_assigned_sideload[:data]
|
14
|
+
end
|
15
|
+
|
16
|
+
if records
|
17
|
+
if records.respond_to?(:to_ary)
|
18
|
+
records.each { |r| sideload_ref.resource.decorate_record(r) }
|
19
|
+
else
|
20
|
+
sideload_ref.resource.decorate_record(records)
|
21
|
+
end
|
22
|
+
|
23
|
+
records
|
24
|
+
end
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: graphiti-activegraph
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Hardik Joshi
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-08-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: graphiti
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: concurrent-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: zeitwerk
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: faraday
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.15'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.15'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: kaminari
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.17'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.17'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: bundler
|
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: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '10.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '10.0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: activemodel
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '4.1'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '4.1'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: graphiti_spec_helpers
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 1.0.beta.4
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 1.0.beta.4
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: standard
|
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'
|
167
|
+
description:
|
168
|
+
email:
|
169
|
+
- hardikjoshi1991@gmail.com
|
170
|
+
executables: []
|
171
|
+
extensions: []
|
172
|
+
extra_rdoc_files: []
|
173
|
+
files:
|
174
|
+
- ".gitignore"
|
175
|
+
- Gemfile
|
176
|
+
- graphiti-activegraph.gemspec
|
177
|
+
- lib/graphiti-activegraph.rb
|
178
|
+
- lib/graphiti/active_graph/adapters/active_graph.rb
|
179
|
+
- lib/graphiti/active_graph/adapters/active_graph/has_many_sideload.rb
|
180
|
+
- lib/graphiti/active_graph/adapters/active_graph/has_one_sideload.rb
|
181
|
+
- lib/graphiti/active_graph/adapters/active_graph/sideload.rb
|
182
|
+
- lib/graphiti/active_graph/deserializer.rb
|
183
|
+
- lib/graphiti/active_graph/query.rb
|
184
|
+
- lib/graphiti/active_graph/resource.rb
|
185
|
+
- lib/graphiti/active_graph/resource/persistence.rb
|
186
|
+
- lib/graphiti/active_graph/resource_proxy.rb
|
187
|
+
- lib/graphiti/active_graph/runner.rb
|
188
|
+
- lib/graphiti/active_graph/scoping/filter.rb
|
189
|
+
- lib/graphiti/active_graph/scoping/filterable.rb
|
190
|
+
- lib/graphiti/active_graph/sideload_resolve.rb
|
191
|
+
- lib/graphiti/active_graph/util/serializer_relationship.rb
|
192
|
+
- lib/graphiti/active_graph/version.rb
|
193
|
+
homepage: https://github.com/mrhardikjoshi/graphiti-activegraph
|
194
|
+
licenses:
|
195
|
+
- MIT
|
196
|
+
metadata: {}
|
197
|
+
post_install_message:
|
198
|
+
rdoc_options: []
|
199
|
+
require_paths:
|
200
|
+
- lib
|
201
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
202
|
+
requirements:
|
203
|
+
- - "~>"
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '2.3'
|
206
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
207
|
+
requirements:
|
208
|
+
- - ">="
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: '0'
|
211
|
+
requirements: []
|
212
|
+
rubyforge_project:
|
213
|
+
rubygems_version: 2.7.6
|
214
|
+
signing_key:
|
215
|
+
specification_version: 4
|
216
|
+
summary: Easily build jsonapi.org-compatible APIs for GraphDB
|
217
|
+
test_files: []
|