ecoportal-api 0.8.5 → 0.9.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 +4 -4
- data/.gitignore +20 -20
- data/.rspec +3 -3
- data/.rubocop.yml +55 -55
- data/.travis.yml +5 -5
- data/.yardopts +10 -10
- data/CHANGELOG.md +257 -236
- data/Gemfile +6 -6
- data/LICENSE +21 -21
- data/README.md +34 -34
- data/Rakefile +27 -27
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/ecoportal-api.gemspec +36 -36
- data/lib/ecoportal/api/common/base_class.rb +33 -29
- data/lib/ecoportal/api/common/base_model.rb +195 -177
- data/lib/ecoportal/api/common/batch_operation.rb +119 -119
- data/lib/ecoportal/api/common/batch_response.rb +34 -34
- data/lib/ecoportal/api/common/client.rb +198 -196
- data/lib/ecoportal/api/common/doc_helpers.rb +29 -29
- data/lib/ecoportal/api/common/elastic_apm_integration.rb +112 -112
- data/lib/ecoportal/api/common/hash_diff.rb +41 -41
- data/lib/ecoportal/api/common/logging.rb +12 -12
- data/lib/ecoportal/api/common/response.rb +31 -31
- data/lib/ecoportal/api/common/wrapped_response.rb +54 -54
- data/lib/ecoportal/api/common.rb +18 -18
- data/lib/ecoportal/api/errors/base.rb +8 -8
- data/lib/ecoportal/api/errors/time_out.rb +8 -8
- data/lib/ecoportal/api/errors.rb +9 -9
- data/lib/ecoportal/api/internal/account.rb +99 -100
- data/lib/ecoportal/api/internal/login_provider.rb +9 -9
- data/lib/ecoportal/api/internal/login_providers.rb +33 -33
- data/lib/ecoportal/api/internal/people.rb +14 -14
- data/lib/ecoportal/api/internal/permissions.rb +14 -13
- data/lib/ecoportal/api/internal/person.rb +101 -53
- data/lib/ecoportal/api/internal/person_details.rb +9 -9
- data/lib/ecoportal/api/internal/person_schema.rb +10 -10
- data/lib/ecoportal/api/internal/person_schemas.rb +11 -11
- data/lib/ecoportal/api/internal/policy_group.rb +9 -9
- data/lib/ecoportal/api/internal/policy_groups.rb +32 -32
- data/lib/ecoportal/api/internal/preferences.rb +31 -31
- data/lib/ecoportal/api/internal/schema_field.rb +8 -8
- data/lib/ecoportal/api/internal/schema_field_value.rb +8 -8
- data/lib/ecoportal/api/internal.rb +31 -31
- data/lib/ecoportal/api/logger.rb +62 -62
- data/lib/ecoportal/api/v1/people.rb +218 -218
- data/lib/ecoportal/api/v1/person.rb +138 -135
- data/lib/ecoportal/api/v1/person_details.rb +94 -82
- data/lib/ecoportal/api/v1/person_schema.rb +53 -53
- data/lib/ecoportal/api/v1/person_schemas.rb +48 -48
- data/lib/ecoportal/api/v1/schema_field.rb +34 -34
- data/lib/ecoportal/api/v1/schema_field_value.rb +65 -65
- data/lib/ecoportal/api/v1.rb +49 -49
- data/lib/ecoportal/api/version.rb +5 -5
- data/lib/ecoportal/api.rb +16 -16
- metadata +3 -3
data/Rakefile
CHANGED
@@ -1,27 +1,27 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
require "rspec/core/rake_task"
|
3
|
-
require "yard"
|
4
|
-
require "redcarpet"
|
5
|
-
|
6
|
-
desc "run the specs"
|
7
|
-
RSpec::Core::RakeTask.new(:spec)
|
8
|
-
|
9
|
-
desc "run rspec showing backtrace"
|
10
|
-
RSpec::Core::RakeTask.new(:spec_trace) do |task|
|
11
|
-
task.rspec_opts = ['--backtrace']
|
12
|
-
end
|
13
|
-
|
14
|
-
desc "run rspec stopping on first fail, and show backtrace"
|
15
|
-
RSpec::Core::RakeTask.new(:spec_fast) do |task|
|
16
|
-
task.rspec_opts = ['--fail-fast', '--backtrace']
|
17
|
-
end
|
18
|
-
|
19
|
-
# default task name is yard
|
20
|
-
desc "Yard: generate all the documentation"
|
21
|
-
YARD::Rake::YardocTask.new(:doc) do |t|
|
22
|
-
#t.files = ['lib/**/*.rb']
|
23
|
-
end
|
24
|
-
|
25
|
-
task :default => [:spec]
|
26
|
-
task :rspec_trace => :spec_trace
|
27
|
-
task :rspec_fast => :spec_fast
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require "yard"
|
4
|
+
require "redcarpet"
|
5
|
+
|
6
|
+
desc "run the specs"
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
|
9
|
+
desc "run rspec showing backtrace"
|
10
|
+
RSpec::Core::RakeTask.new(:spec_trace) do |task|
|
11
|
+
task.rspec_opts = ['--backtrace']
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "run rspec stopping on first fail, and show backtrace"
|
15
|
+
RSpec::Core::RakeTask.new(:spec_fast) do |task|
|
16
|
+
task.rspec_opts = ['--fail-fast', '--backtrace']
|
17
|
+
end
|
18
|
+
|
19
|
+
# default task name is yard
|
20
|
+
desc "Yard: generate all the documentation"
|
21
|
+
YARD::Rake::YardocTask.new(:doc) do |t|
|
22
|
+
#t.files = ['lib/**/*.rb']
|
23
|
+
end
|
24
|
+
|
25
|
+
task :default => [:spec]
|
26
|
+
task :rspec_trace => :spec_trace
|
27
|
+
task :rspec_fast => :spec_fast
|
data/bin/console
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "ecoportal/api"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "pry"
|
14
|
-
Pry.start(__FILE__)
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "ecoportal/api"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "pry"
|
14
|
+
Pry.start(__FILE__)
|
data/bin/setup
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#!/usr/bin/env bash
|
2
|
-
set -euo pipefail
|
3
|
-
IFS=$'\n\t'
|
4
|
-
set -vx
|
5
|
-
|
6
|
-
bundle install
|
7
|
-
|
8
|
-
# Do any other automated setup that you need to do here
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
set -euo pipefail
|
3
|
+
IFS=$'\n\t'
|
4
|
+
set -vx
|
5
|
+
|
6
|
+
bundle install
|
7
|
+
|
8
|
+
# Do any other automated setup that you need to do here
|
data/ecoportal-api.gemspec
CHANGED
@@ -1,36 +1,36 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require "ecoportal/api/version"
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "ecoportal-api"
|
8
|
-
spec.version = Ecoportal::API::VERSION
|
9
|
-
spec.authors = ["Tapio Saarinen"]
|
10
|
-
spec.email = ["tapio@ecoportal.co.nz", "rien@ecoportal.co.nz", "oscar@ecoportal.co.nz", "bozydar@ecoportal.co.nz"]
|
11
|
-
|
12
|
-
spec.summary = %q{A collection of helpers for interacting with the ecoPortal MS's various APIs}
|
13
|
-
spec.homepage = "https://www.ecoportal.com"
|
14
|
-
spec.licenses = %w[MIT]
|
15
|
-
|
16
|
-
spec.required_ruby_version = '>= 2.4.4'
|
17
|
-
|
18
|
-
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
-
f.match(%r{^(test|spec|features)/})
|
20
|
-
end
|
21
|
-
spec.bindir = "exe"
|
22
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
-
spec.require_paths = ["lib"]
|
24
|
-
|
25
|
-
spec.add_development_dependency "bundler", ">= 2.2.17", "< 2.3"
|
26
|
-
spec.add_development_dependency "rspec", ">= 3.10.0", "< 3.11"
|
27
|
-
spec.add_development_dependency "rake", ">= 13.0.3", "< 13.1"
|
28
|
-
spec.add_development_dependency "yard", ">= 0.9.26", "< 0.10"
|
29
|
-
spec.add_development_dependency "redcarpet", ">= 3.5.1", "< 3.6"
|
30
|
-
spec.add_development_dependency "pry" , "~> 0.14"
|
31
|
-
|
32
|
-
spec.add_dependency 'http', '~> 4.4.1', "< 5"
|
33
|
-
spec.add_dependency 'dotenv', '>= 2.7.6', "< 2.8"
|
34
|
-
spec.add_dependency 'elastic-apm', '>= 4.0.0', "< 4.1"
|
35
|
-
spec.add_dependency 'hash-polyfill', '~> 0'
|
36
|
-
end
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "ecoportal/api/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ecoportal-api"
|
8
|
+
spec.version = Ecoportal::API::VERSION
|
9
|
+
spec.authors = ["Tapio Saarinen"]
|
10
|
+
spec.email = ["tapio@ecoportal.co.nz", "rien@ecoportal.co.nz", "oscar@ecoportal.co.nz", "bozydar@ecoportal.co.nz"]
|
11
|
+
|
12
|
+
spec.summary = %q{A collection of helpers for interacting with the ecoPortal MS's various APIs}
|
13
|
+
spec.homepage = "https://www.ecoportal.com"
|
14
|
+
spec.licenses = %w[MIT]
|
15
|
+
|
16
|
+
spec.required_ruby_version = '>= 2.4.4'
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
+
f.match(%r{^(test|spec|features)/})
|
20
|
+
end
|
21
|
+
spec.bindir = "exe"
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", ">= 2.2.17", "< 2.3"
|
26
|
+
spec.add_development_dependency "rspec", ">= 3.10.0", "< 3.11"
|
27
|
+
spec.add_development_dependency "rake", ">= 13.0.3", "< 13.1"
|
28
|
+
spec.add_development_dependency "yard", ">= 0.9.26", "< 0.10"
|
29
|
+
spec.add_development_dependency "redcarpet", ">= 3.5.1", "< 3.6"
|
30
|
+
spec.add_development_dependency "pry" , "~> 0.14"
|
31
|
+
|
32
|
+
spec.add_dependency 'http', '~> 4.4.1', "< 5"
|
33
|
+
spec.add_dependency 'dotenv', '>= 2.7.6', "< 2.8"
|
34
|
+
spec.add_dependency 'elastic-apm', '>= 4.0.0', "< 4.1"
|
35
|
+
spec.add_dependency 'hash-polyfill', '~> 0'
|
36
|
+
end
|
@@ -1,29 +1,33 @@
|
|
1
|
-
module Ecoportal
|
2
|
-
module API
|
3
|
-
module Common
|
4
|
-
module BaseClass
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
when
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module BaseClass
|
5
|
+
def redef_without_warning(const, value)
|
6
|
+
self.class.send(:remove_const, const) if self.class.const_defined?(const)
|
7
|
+
self.class.const_set(const, value)
|
8
|
+
end
|
9
|
+
|
10
|
+
def class_resolver(name, klass)
|
11
|
+
define_singleton_method(name) { resolve_class(klass) }
|
12
|
+
define_method(name) { self.class.resolve_class(klass) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def resolve_class(klass)
|
16
|
+
@resolved ||= {}
|
17
|
+
@resolved[klass] ||=
|
18
|
+
case klass
|
19
|
+
when Class
|
20
|
+
klass
|
21
|
+
when String
|
22
|
+
Kernel.const_get(klass)
|
23
|
+
when Symbol
|
24
|
+
resolve_class(self.send(klass))
|
25
|
+
else
|
26
|
+
raise "Unknown class: #{klass}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,177 +1,195 @@
|
|
1
|
-
module Ecoportal
|
2
|
-
module API
|
3
|
-
module Common
|
4
|
-
class BaseModel
|
5
|
-
class UnlinkedModel < Exception
|
6
|
-
def initialize (msg = "Something went wrong when linking the document.", from: nil, key: nil)
|
7
|
-
msg += " From: #{from}." if from
|
8
|
-
msg += " key: #{key}." if key
|
9
|
-
super(msg)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
extend BaseClass
|
14
|
-
|
15
|
-
class << self
|
16
|
-
def passthrough(*methods, to: :doc)
|
17
|
-
methods.each do |method|
|
18
|
-
method = method.to_s
|
19
|
-
define_method method do
|
20
|
-
send(to)[method]
|
21
|
-
end
|
22
|
-
define_method "#{method}=" do |value|
|
23
|
-
send(to)[method] = value
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def embeds_one(method, key: method, nullable: false, klass:)
|
29
|
-
method = method.to_s.freeze
|
30
|
-
var = "@#{method}".freeze
|
31
|
-
key = key.to_s.freeze
|
32
|
-
define_method(method) do
|
33
|
-
if instance_variable_defined?(var)
|
34
|
-
value = instance_variable_get(var)
|
35
|
-
return value unless nullable
|
36
|
-
return value if (value && doc[key]) || (!value && !doc[key])
|
37
|
-
remove_instance_variable(var)
|
38
|
-
end
|
39
|
-
doc[key] ||= {} unless nullable
|
40
|
-
return instance_variable_set(var, nil) unless doc[key]
|
41
|
-
|
42
|
-
self.class.resolve_class(klass).new(
|
43
|
-
doc[key], parent: self, key: key
|
44
|
-
).tap {|obj| instance_variable_set(var, obj)}
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
attr_reader :_parent, :_key
|
51
|
-
|
52
|
-
def initialize(doc = {}, parent: self, key: nil)
|
53
|
-
@_parent = parent
|
54
|
-
@_key = key
|
55
|
-
if !_parent || !_key
|
56
|
-
@doc = doc
|
57
|
-
@original_doc = JSON.parse(@doc.to_json)
|
58
|
-
@initial_doc = JSON.parse(@doc.to_json)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def doc
|
63
|
-
raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key) unless linked?
|
64
|
-
return @doc if is_root?
|
65
|
-
_parent.doc.dig(*[_key].flatten)
|
66
|
-
end
|
67
|
-
|
68
|
-
def original_doc
|
69
|
-
raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key) unless linked?
|
70
|
-
return @original_doc if is_root?
|
71
|
-
_parent.original_doc&.dig(*[_key].flatten)
|
72
|
-
end
|
73
|
-
|
74
|
-
def initial_doc
|
75
|
-
raise UnlinkedModel.new(from: "#{self.class}#initial_doc", key: _key) unless linked?
|
76
|
-
return @initial_doc if is_root?
|
77
|
-
_parent.initial_doc&.dig(*[_key].flatten)
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
def
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
class BaseModel
|
5
|
+
class UnlinkedModel < Exception
|
6
|
+
def initialize (msg = "Something went wrong when linking the document.", from: nil, key: nil)
|
7
|
+
msg += " From: #{from}." if from
|
8
|
+
msg += " key: #{key}." if key
|
9
|
+
super(msg)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
extend BaseClass
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def passthrough(*methods, to: :doc)
|
17
|
+
methods.each do |method|
|
18
|
+
method = method.to_s
|
19
|
+
define_method method do
|
20
|
+
send(to)[method]
|
21
|
+
end
|
22
|
+
define_method "#{method}=" do |value|
|
23
|
+
send(to)[method] = value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def embeds_one(method, key: method, nullable: false, klass:)
|
29
|
+
method = method.to_s.freeze
|
30
|
+
var = "@#{method}".freeze
|
31
|
+
key = key.to_s.freeze
|
32
|
+
define_method(method) do
|
33
|
+
if instance_variable_defined?(var)
|
34
|
+
value = instance_variable_get(var)
|
35
|
+
return value unless nullable
|
36
|
+
return value if (value && doc[key]) || (!value && !doc[key])
|
37
|
+
remove_instance_variable(var)
|
38
|
+
end
|
39
|
+
doc[key] ||= {} unless nullable
|
40
|
+
return instance_variable_set(var, nil) unless doc[key]
|
41
|
+
|
42
|
+
self.class.resolve_class(klass).new(
|
43
|
+
doc[key], parent: self, key: key
|
44
|
+
).tap {|obj| instance_variable_set(var, obj)}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_reader :_parent, :_key
|
51
|
+
|
52
|
+
def initialize(doc = {}, parent: self, key: nil)
|
53
|
+
@_parent = parent
|
54
|
+
@_key = key
|
55
|
+
if !_parent || !_key
|
56
|
+
@doc = doc
|
57
|
+
@original_doc = JSON.parse(@doc.to_json)
|
58
|
+
@initial_doc = JSON.parse(@doc.to_json)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def doc
|
63
|
+
raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key) unless linked?
|
64
|
+
return @doc if is_root?
|
65
|
+
_parent.doc.dig(*[_key].flatten)
|
66
|
+
end
|
67
|
+
|
68
|
+
def original_doc
|
69
|
+
raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key) unless linked?
|
70
|
+
return @original_doc if is_root?
|
71
|
+
_parent.original_doc&.dig(*[_key].flatten)
|
72
|
+
end
|
73
|
+
|
74
|
+
def initial_doc
|
75
|
+
raise UnlinkedModel.new(from: "#{self.class}#initial_doc", key: _key) unless linked?
|
76
|
+
return @initial_doc if is_root?
|
77
|
+
_parent.initial_doc&.dig(*[_key].flatten)
|
78
|
+
end
|
79
|
+
|
80
|
+
# It replaces `doc` by `new_doc`
|
81
|
+
# @return [Hash] `doc` before change
|
82
|
+
def replace_doc!(new_doc)
|
83
|
+
raise UnlinkedModel.new(from: "#{self.class}#replace_doc", key: _key) unless linked?
|
84
|
+
@doc.tap do
|
85
|
+
@doc = new_doc
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# It replaces `original_doc` by `new_doc`
|
90
|
+
# @return [Hash] `original_doc` before change
|
91
|
+
def replace_original_doc!(new_doc)
|
92
|
+
raise UnlinkedModel.new(from: "#{self.class}#replace_original_doc", key: _key) unless linked?
|
93
|
+
@original_doc.tap do
|
94
|
+
@original_doc = new_doc
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def as_json
|
99
|
+
doc
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_json(*args)
|
103
|
+
doc.to_json(*args)
|
104
|
+
end
|
105
|
+
|
106
|
+
def as_update(ref = :last, ignore: [])
|
107
|
+
new_doc = as_json
|
108
|
+
ref_doc = ref == :total ? initial_doc : original_doc
|
109
|
+
Common::HashDiff.diff(new_doc, ref_doc, ignore: ignore)
|
110
|
+
end
|
111
|
+
|
112
|
+
def dirty?
|
113
|
+
as_update != {}
|
114
|
+
end
|
115
|
+
|
116
|
+
# It consolidates all the changes carried by `doc` by setting it as `original_doc`.
|
117
|
+
def consolidate!
|
118
|
+
raise UnlinkedModel.new(from: "#{self.class}#consolidate!", key: _key) unless linked?
|
119
|
+
new_doc = JSON.parse(doc.to_json)
|
120
|
+
if is_root?
|
121
|
+
@original_doc = new_doc
|
122
|
+
else
|
123
|
+
dig_set(_parent.original_doc, [_key].flatten, new_doc)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# It removes all the changes carried by `doc` by restoring `original_doc` into `doc`.
|
128
|
+
# @note
|
129
|
+
# 1. When there are nullable properties, it may be required to apply `reset!` from the parent
|
130
|
+
# i.e. `parent.reset!("child")` # when parent.child is `nil`
|
131
|
+
# 2. In such a case, only immediate childs are allowed to be reset
|
132
|
+
# @param key [String, Array<String>, nil] if given, it only resets the specified property
|
133
|
+
def reset!(key = nil)
|
134
|
+
raise "'key' should be a String. Given #{key}" unless !key || key.is_a?(String)
|
135
|
+
raise UnlinkedModel.new(from: "#{self.class}#reset!", key: _key) unless linked?
|
136
|
+
|
137
|
+
if key
|
138
|
+
if self.respond_to?(key) && child = self.send(key) && child.is_a?(Ecoportal::API::Common::BaseModel)
|
139
|
+
child.reset!
|
140
|
+
else
|
141
|
+
new_doc = original_doc && original_doc[key]
|
142
|
+
dig_set(doc, [key], new_doc && JSON.parse(new_doc.to_json))
|
143
|
+
# regenerate object if new_doc is null
|
144
|
+
self.send(key) if !new_doc && self.respond_to?(key)
|
145
|
+
end
|
146
|
+
else
|
147
|
+
new_doc = JSON.parse(original_doc.to_json)
|
148
|
+
if is_root?
|
149
|
+
@doc = new_doc
|
150
|
+
else
|
151
|
+
dig_set(_parent.doc, [_key].flatten, new_doc)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def print_pretty
|
157
|
+
puts JSON.pretty_generate(as_json)
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
161
|
+
protected
|
162
|
+
|
163
|
+
def is_root?
|
164
|
+
_parent == self && !!defined?(@doc)
|
165
|
+
end
|
166
|
+
|
167
|
+
def linked?
|
168
|
+
is_root? || !!_parent.doc.dig(*[_key].flatten)
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
def dig_set(obj, keys, value)
|
174
|
+
if keys.length == 1
|
175
|
+
obj[keys.first] = value
|
176
|
+
else
|
177
|
+
dig_set(obj[keys.first], keys.slice(1..-1), value)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def set_uniq_array_keep_order(key, value)
|
182
|
+
unless value.is_a?(Array)
|
183
|
+
raise "#{key}= needs to be passed an Array, got #{value.class}"
|
184
|
+
end
|
185
|
+
ini_vals = (original_doc && original_doc[key]) || []
|
186
|
+
|
187
|
+
value = value.uniq
|
188
|
+
# preserve original order to avoid false updates
|
189
|
+
doc[key] = ((ini_vals & value) + (value - ini_vals)).compact
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|