graphiti-activegraph 0.1.2
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 +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: []
|