sp-duh 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +661 -0
  3. data/README.md +2 -0
  4. data/Rakefile +32 -0
  5. data/config/i18n/i18n.xlsx +0 -0
  6. data/config/initializers/active_record/connection_adapters_postgre_sql_adapter.rb +165 -0
  7. data/config/initializers/active_record/migration_without_transaction.rb +4 -0
  8. data/config/initializers/active_record/migrator.rb +34 -0
  9. data/config/initializers/rails/generators.rb +13 -0
  10. data/config/jsonapi/settings.yml +14 -0
  11. data/config/locales/pt.yml +15 -0
  12. data/lib/generators/accounting_migration/accounting_migration_generator.rb +10 -0
  13. data/lib/generators/accounting_migration/templates/migration.rb +42 -0
  14. data/lib/generators/accounting_payroll_migration/accounting_payroll_migration_generator.rb +10 -0
  15. data/lib/generators/accounting_payroll_migration/templates/migration.rb +73 -0
  16. data/lib/generators/sharded_migration/sharded_migration_generator.rb +10 -0
  17. data/lib/generators/sharded_migration/templates/migration.rb +45 -0
  18. data/lib/sp-duh.rb +32 -0
  19. data/lib/sp/duh.rb +180 -0
  20. data/lib/sp/duh/adapters/pg/text_decoder/json.rb +15 -0
  21. data/lib/sp/duh/adapters/pg/text_encoder/json.rb +15 -0
  22. data/lib/sp/duh/db/transfer/backup.rb +71 -0
  23. data/lib/sp/duh/db/transfer/restore.rb +89 -0
  24. data/lib/sp/duh/engine.rb +35 -0
  25. data/lib/sp/duh/exceptions.rb +70 -0
  26. data/lib/sp/duh/i18n/excel_loader.rb +26 -0
  27. data/lib/sp/duh/jsonapi/adapters/base.rb +168 -0
  28. data/lib/sp/duh/jsonapi/adapters/db.rb +36 -0
  29. data/lib/sp/duh/jsonapi/adapters/raw_db.rb +77 -0
  30. data/lib/sp/duh/jsonapi/configuration.rb +167 -0
  31. data/lib/sp/duh/jsonapi/doc/apidoc_documentation_format_generator.rb +286 -0
  32. data/lib/sp/duh/jsonapi/doc/generator.rb +32 -0
  33. data/lib/sp/duh/jsonapi/doc/schema_catalog_helper.rb +97 -0
  34. data/lib/sp/duh/jsonapi/doc/victor_pinus_metadata_format_parser.rb +374 -0
  35. data/lib/sp/duh/jsonapi/exceptions.rb +56 -0
  36. data/lib/sp/duh/jsonapi/model/base.rb +25 -0
  37. data/lib/sp/duh/jsonapi/model/concerns/attributes.rb +94 -0
  38. data/lib/sp/duh/jsonapi/model/concerns/model.rb +42 -0
  39. data/lib/sp/duh/jsonapi/model/concerns/persistence.rb +221 -0
  40. data/lib/sp/duh/jsonapi/model/concerns/serialization.rb +59 -0
  41. data/lib/sp/duh/jsonapi/parameters.rb +44 -0
  42. data/lib/sp/duh/jsonapi/resource_publisher.rb +28 -0
  43. data/lib/sp/duh/jsonapi/service.rb +110 -0
  44. data/lib/sp/duh/migrations.rb +47 -0
  45. data/lib/sp/duh/migrations/migrator.rb +41 -0
  46. data/lib/sp/duh/repl.rb +193 -0
  47. data/lib/sp/duh/version.rb +25 -0
  48. data/lib/tasks/db_utils.rake +98 -0
  49. data/lib/tasks/doc.rake +27 -0
  50. data/lib/tasks/i18n.rake +23 -0
  51. data/lib/tasks/oauth.rake +29 -0
  52. data/lib/tasks/transfer.rake +48 -0
  53. data/lib/tasks/xls2jrxml.rake +15 -0
  54. data/test/jsonapi/server.rb +67 -0
  55. data/test/tasks/test.rake +10 -0
  56. metadata +170 -0
@@ -0,0 +1,56 @@
1
+ module SP
2
+ module Duh
3
+ module JSONAPI
4
+ module Exceptions
5
+
6
+ # JSONAPI service and configuration errors
7
+
8
+ class ServiceSetupError < SP::Duh::Exceptions::GenericError ; ; end
9
+ class ServiceProtocolError < SP::Duh::Exceptions::GenericDetailedError ; ; end
10
+ class InvalidResourceConfigurationError < SP::Duh::Exceptions::GenericDetailedError ; ; end
11
+ class InvalidResourcePublisherError < SP::Duh::Exceptions::GenericDetailedError ; ; end
12
+ class DuplicateResourceError < SP::Duh::Exceptions::GenericDetailedError ; ; end
13
+ class SaveConfigurationError < SP::Duh::Exceptions::GenericError ; ; end
14
+ class InvalidJSONAPIKeyError < SP::Duh::Exceptions::GenericDetailedError ; ; end
15
+
16
+ # JSONAPI model querying errors
17
+
18
+ class GenericModelError < SP::Duh::Exceptions::GenericError
19
+
20
+ attr_reader :id
21
+ attr_reader :status
22
+ attr_reader :result
23
+
24
+ def initialize(result, nested = $!)
25
+ @result = result
26
+ errors = get_result_errors()
27
+ @status = (errors.map { |error| error[:status].to_i }.max) || 403
28
+ message = errors.first[:detail]
29
+ super(message, nested)
30
+ end
31
+
32
+ def internal_error
33
+ errors = get_result_errors()
34
+ if errors.length != 1
35
+ @result.to_json
36
+ else
37
+ errors.first[:meta]['internal-error'] if errors.first[:meta]
38
+ end
39
+ end
40
+
41
+ def inspect()
42
+ description = super()
43
+ description = description + " (#{internal_error})" if internal_error
44
+ description
45
+ end
46
+
47
+ private
48
+
49
+ def get_result_errors() ; (result.is_a?(Hash) ? result : HashWithIndifferentAccess.new(JSON.parse(result)))[:errors] ; end
50
+
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,25 @@
1
+ require 'sp/duh/jsonapi/model/concerns/model'
2
+
3
+ module SP
4
+ module Duh
5
+ module JSONAPI
6
+ module Model
7
+
8
+ class Base
9
+ include ::ActiveRecord::Validations
10
+ include Concerns::Model
11
+
12
+ def self.inherited(child)
13
+ child.resource_name = child.name.demodulize.underscore.pluralize
14
+ child.autogenerated_id = true
15
+ end
16
+
17
+ def self.i18n_scope
18
+ :activerecord
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,94 @@
1
+ module SP
2
+ module Duh
3
+ module JSONAPI
4
+ module Model
5
+ module Concerns
6
+ module Attributes
7
+ extend ::ActiveSupport::Concern
8
+
9
+ included do
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ def attributes
15
+ if !@attributes && superclass.respond_to?(:attributes)
16
+ @attributes = []
17
+ @attributes += superclass.attributes
18
+ end
19
+ @attributes = [] if !@attributes
20
+ @attributes
21
+ end
22
+
23
+ def attr_accessible(name)
24
+ attributes << name if !attributes.include?(name)
25
+ attr_accessor name
26
+ end
27
+ end
28
+
29
+ def initialize(new_attributes = nil)
30
+ assign_attributes(new_attributes) if new_attributes
31
+ yield self if block_given?
32
+ end
33
+
34
+ def attributes=(new_attributes)
35
+ return unless new_attributes.is_a?(Hash)
36
+ assign_attributes(new_attributes)
37
+ end
38
+
39
+ private
40
+
41
+ def assign_attributes(new_attributes)
42
+ return if new_attributes.blank?
43
+
44
+ new_attributes = new_attributes.stringify_keys
45
+ nested_parameter_attributes = []
46
+
47
+ new_attributes.each do |k, v|
48
+ if respond_to?("#{k}=")
49
+ if v.is_a?(Hash)
50
+ nested_parameter_attributes << [ k, v ]
51
+ else
52
+ send("#{k}=", v)
53
+ end
54
+ # else
55
+ # raise(ActiveRecord::UnknownAttributeError, "unknown attribute: #{k}")
56
+ end
57
+ end
58
+
59
+ # Assign any deferred nested attributes after the base attributes have been set
60
+ nested_parameter_attributes.each do |k,v|
61
+ send("#{k}=", v)
62
+ end
63
+ end
64
+
65
+ # Returns an <tt>#inspect</tt>-like string for the value of the
66
+ # attribute +attr_name+. String attributes are truncated upto 50
67
+ # characters, and Date and Time attributes are returned in the
68
+ # <tt>:db</tt> format. Other attributes return the value of
69
+ # <tt>#inspect</tt> without modification.
70
+ #
71
+ # person = Person.create!(:name => "David Heinemeier Hansson " * 3)
72
+ #
73
+ # person.attribute_for_inspect(:name)
74
+ # # => '"David Heinemeier Hansson David Heinemeier Hansson D..."'
75
+ #
76
+ # person.attribute_for_inspect(:created_at)
77
+ # # => '"2009-01-12 04:48:57"'
78
+ def attribute_for_inspect(name)
79
+ value = self.send(name)
80
+ if value.is_a?(String) && value.length > 50
81
+ "#{value[0..50]}...".inspect
82
+ elsif value.is_a?(Date) || value.is_a?(Time)
83
+ %("#{value.to_s(:db)}")
84
+ else
85
+ value.inspect
86
+ end
87
+ end
88
+
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,42 @@
1
+ require 'active_support'
2
+ require 'active_record'
3
+
4
+ require 'sp/duh/jsonapi/model/concerns/attributes'
5
+ require 'sp/duh/jsonapi/model/concerns/serialization'
6
+ require 'sp/duh/jsonapi/model/concerns/persistence'
7
+
8
+ module SP
9
+ module Duh
10
+ module JSONAPI
11
+ module Model
12
+ module Concerns
13
+ module Model
14
+ extend ::ActiveSupport::Concern
15
+
16
+ include Attributes
17
+ include Serialization
18
+ include Persistence
19
+
20
+ included do
21
+ end
22
+
23
+ module ClassMethods
24
+
25
+ def inspect
26
+ "#{super}(#{self.attributes.join(', ')})"
27
+ end
28
+ end
29
+
30
+ # Returns the contents of the record as a nicely formatted string.
31
+ def inspect
32
+ # attrs = self.class.attributes
33
+ inspection = self.class.attributes.collect { |name| "#{name}: #{attribute_for_inspect(name)}" }.compact.join(", ")
34
+ "#<#{self.class} #{inspection}>"
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,221 @@
1
+ module SP
2
+ module Duh
3
+ module JSONAPI
4
+ module Model
5
+ module Concerns
6
+ module Persistence
7
+ extend ::ActiveSupport::Concern
8
+
9
+ included do
10
+
11
+ # Idem for data adapter configuration...
12
+ # In a similar way to ActiveRecord::Base.connection, the adapter should be defined at the base level and is inherited by all subclasses
13
+ class_attribute :adapter, instance_reader: false, instance_writer: false
14
+
15
+ self.autogenerated_id = true
16
+
17
+ attr_accessible :id
18
+ end
19
+
20
+ module ClassMethods
21
+
22
+ # Define resource configuration accessors at the class (and subclass) level (static).
23
+ # These attribute values are NOT inherited by subclasses, each subclass MUST define their own.
24
+ # Instances can access these attributes at the class level only.
25
+ attr_accessor :resource_name
26
+ attr_accessor :autogenerated_id
27
+
28
+ def find!(id, conditions = nil) ; get(id, conditions) ; end
29
+
30
+ def find_explicit!(exp_accounting_schema, exp_accounting_prefix, id, conditions = nil)
31
+ get_explicit(exp_accounting_schema, exp_accounting_prefix, id, conditions)
32
+ end
33
+
34
+ def find(id, conditions = nil)
35
+ begin
36
+ get(id, conditions)
37
+ rescue Exception => e
38
+ return nil
39
+ end
40
+ end
41
+
42
+ def query!(condition) ; get_all(condition) ; end
43
+ def query_explicit!(exp_accounting_schema, exp_accounting_prefix, condition) ; get_all_explicit(exp_accounting_schema, exp_accounting_prefix, condition) ; end
44
+
45
+ def query(condition)
46
+ begin
47
+ get_all(condition)
48
+ rescue Exception => e
49
+ nil
50
+ end
51
+ end
52
+
53
+ def first!(condition = "")
54
+ condition += (condition.blank? ? "" : "&") + "page[size]=1"
55
+ get_all(condition).first
56
+ end
57
+
58
+ def first(condition = "")
59
+ begin
60
+ condition += (condition.blank? ? "" : "&") + "page[size]=1"
61
+ get_all(condition).first
62
+ rescue Exception => e
63
+ nil
64
+ end
65
+ end
66
+
67
+ def all! ; get_all("") ; end
68
+
69
+ def all
70
+ begin
71
+ get_all("")
72
+ rescue Exception => e
73
+ nil
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def get_explicit(exp_accounting_schema, exp_accounting_prefix, id, conditions = nil)
80
+ result = self.adapter.get_explicit!(exp_accounting_schema, exp_accounting_prefix, "#{self.resource_name}/#{id.to_s}", conditions)
81
+ jsonapi_result_to_instance(result[:data], result)
82
+ end
83
+
84
+ def get(id, conditions = nil)
85
+ result = self.adapter.get("#{self.resource_name}/#{id.to_s}", conditions)
86
+ jsonapi_result_to_instance(result[:data], result)
87
+ end
88
+
89
+ def get_all(condition)
90
+ got = []
91
+ result = self.adapter.get(self.resource_name, condition)
92
+ if result
93
+ got = result[:data].map do |item|
94
+ data = { data: item }
95
+ data.merge(included: result[:included]) if result[:included]
96
+ jsonapi_result_to_instance(item, data)
97
+ end
98
+ end
99
+ got
100
+ end
101
+
102
+ def get_all_explicit(exp_accounting_schema, exp_accounting_prefix, condition)
103
+ got = []
104
+ result = self.adapter.get_explicit!(exp_accounting_schema, exp_accounting_prefix, self.resource_name, condition)
105
+ if result
106
+ got = result[:data].map do |item|
107
+ data = { data: item }
108
+ data.merge(included: result[:included]) if result[:included]
109
+ jsonapi_result_to_instance(item, data)
110
+ end
111
+ end
112
+ got
113
+ end
114
+
115
+ def jsonapi_result_to_instance(result, data)
116
+ if result
117
+ instance = self.new(result.merge(result[:attributes]).except(:attributes))
118
+ instance.send :_data=, data
119
+ end
120
+ instance
121
+ end
122
+ end
123
+
124
+ # Instance methods
125
+
126
+ def new_record?
127
+ if self.class.autogenerated_id || self.id.nil?
128
+ self.id.nil?
129
+ else
130
+ self.class.find(self.id).nil?
131
+ end
132
+ end
133
+
134
+ def save!
135
+ if new_record?
136
+ create!
137
+ else
138
+ update!
139
+ end
140
+ end
141
+
142
+ def save_explicit!(exp_accounting_schema, exp_accounting_prefix)
143
+ if new_record?
144
+ create!(exp_accounting_schema, exp_accounting_prefix)
145
+ else
146
+ update!(exp_accounting_schema, exp_accounting_prefix)
147
+ end
148
+ end
149
+
150
+ def destroy!
151
+ if !new_record?
152
+ self.class.adapter.delete(path_for_id)
153
+ end
154
+ end
155
+
156
+ def destroy_explicit!(exp_accounting_schema, exp_accounting_prefix)
157
+ if !new_record?
158
+ self.class.adapter.delete_explicit!(exp_accounting_schema, exp_accounting_prefix, path_for_id)
159
+ end
160
+ end
161
+
162
+ alias :delete! :destroy!
163
+
164
+ def create!(exp_accounting_schema = nil, exp_accounting_prefix = nil)
165
+ if self.class.autogenerated_id
166
+ params = {
167
+ data: {
168
+ type: self.class.resource_name,
169
+ attributes: get_persistent_json.reject { |k,v| k == :id || v.nil? }
170
+ }
171
+ }
172
+ else
173
+ params = {
174
+ data: {
175
+ type: self.class.resource_name,
176
+ attributes: get_persistent_json.reject { |k,v| v.nil? }
177
+ }
178
+ }
179
+ end
180
+ result = if !exp_accounting_schema.blank? || !exp_accounting_prefix.blank?
181
+ self.class.adapter.post_explicit!(exp_accounting_schema, exp_accounting_prefix, self.class.resource_name, params)
182
+ else
183
+ self.class.adapter.post(self.class.resource_name, params)
184
+ end
185
+ # Set the id to the newly created id
186
+ self.id = result[:data][:id]
187
+ end
188
+
189
+ def update!(exp_accounting_schema = nil, exp_accounting_prefix = nil)
190
+ params = {
191
+ data: {
192
+ type: self.class.resource_name,
193
+ id: self.id.to_s,
194
+ attributes: get_persistent_json.reject { |k,v| k == :id }
195
+ }
196
+ }
197
+ result = if !exp_accounting_schema.blank? || !exp_accounting_prefix.blank?
198
+ self.class.adapter.patch_explicit!(exp_accounting_schema, exp_accounting_prefix, path_for_id, params)
199
+ else
200
+ self.class.adapter.patch(path_for_id, params)
201
+ end
202
+ end
203
+
204
+ def get_persistent_json
205
+ as_json.reject { |k| !k.in?(self.class.attributes) }
206
+ end
207
+
208
+ protected
209
+
210
+ attr_accessor :_data
211
+
212
+ private
213
+
214
+ def path_for_id ; "#{self.class.resource_name}/#{self.id.to_s}" ; end
215
+
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,59 @@
1
+ module SP
2
+ module Duh
3
+ module JSONAPI
4
+ module Model
5
+ module Concerns
6
+ module Serialization
7
+ extend ::ActiveSupport::Concern
8
+
9
+ included do
10
+ end
11
+
12
+ def as_json(options = {})
13
+ root = ActiveRecord::Base.include_root_in_json
14
+ root = options[:root] if options.try(:key?, :root)
15
+ if root
16
+ root = self.class.name.underscore.gsub('/','_').to_sym
17
+ { root => serializable_hash(options) }
18
+ else
19
+ serializable_hash(options)
20
+ end
21
+ end
22
+
23
+ def from_json(json)
24
+ root = ActiveRecord::Base.include_root_in_json
25
+ hash = ActiveSupport::JSON.decode(json)
26
+ hash = hash.values.first if root
27
+ self.attributes = hash
28
+ self
29
+ end
30
+
31
+ private
32
+
33
+ alias :read_attribute_for_serialization :send
34
+
35
+ def serializable_hash(options = {})
36
+
37
+ attribute_names = self.class.attributes.sort
38
+ if only = options[:only]
39
+ attribute_names &= Array.wrap(only).map(&:to_s)
40
+ elsif except = options[:except]
41
+ attribute_names -= Array.wrap(except).map(&:to_s)
42
+ end
43
+
44
+ hash = {}
45
+ attribute_names.each { |n| hash[n] = read_attribute_for_serialization(n) }
46
+
47
+ method_names = Array.wrap(options[:methods]).select { |n| respond_to?(n) }
48
+ method_names.each { |n| hash[n] = send(n) }
49
+
50
+ hash
51
+
52
+ end
53
+
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end