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.
- checksums.yaml +7 -0
 - data/LICENSE +661 -0
 - data/README.md +2 -0
 - data/Rakefile +32 -0
 - data/config/i18n/i18n.xlsx +0 -0
 - data/config/initializers/active_record/connection_adapters_postgre_sql_adapter.rb +165 -0
 - data/config/initializers/active_record/migration_without_transaction.rb +4 -0
 - data/config/initializers/active_record/migrator.rb +34 -0
 - data/config/initializers/rails/generators.rb +13 -0
 - data/config/jsonapi/settings.yml +14 -0
 - data/config/locales/pt.yml +15 -0
 - data/lib/generators/accounting_migration/accounting_migration_generator.rb +10 -0
 - data/lib/generators/accounting_migration/templates/migration.rb +42 -0
 - data/lib/generators/accounting_payroll_migration/accounting_payroll_migration_generator.rb +10 -0
 - data/lib/generators/accounting_payroll_migration/templates/migration.rb +73 -0
 - data/lib/generators/sharded_migration/sharded_migration_generator.rb +10 -0
 - data/lib/generators/sharded_migration/templates/migration.rb +45 -0
 - data/lib/sp-duh.rb +32 -0
 - data/lib/sp/duh.rb +180 -0
 - data/lib/sp/duh/adapters/pg/text_decoder/json.rb +15 -0
 - data/lib/sp/duh/adapters/pg/text_encoder/json.rb +15 -0
 - data/lib/sp/duh/db/transfer/backup.rb +71 -0
 - data/lib/sp/duh/db/transfer/restore.rb +89 -0
 - data/lib/sp/duh/engine.rb +35 -0
 - data/lib/sp/duh/exceptions.rb +70 -0
 - data/lib/sp/duh/i18n/excel_loader.rb +26 -0
 - data/lib/sp/duh/jsonapi/adapters/base.rb +168 -0
 - data/lib/sp/duh/jsonapi/adapters/db.rb +36 -0
 - data/lib/sp/duh/jsonapi/adapters/raw_db.rb +77 -0
 - data/lib/sp/duh/jsonapi/configuration.rb +167 -0
 - data/lib/sp/duh/jsonapi/doc/apidoc_documentation_format_generator.rb +286 -0
 - data/lib/sp/duh/jsonapi/doc/generator.rb +32 -0
 - data/lib/sp/duh/jsonapi/doc/schema_catalog_helper.rb +97 -0
 - data/lib/sp/duh/jsonapi/doc/victor_pinus_metadata_format_parser.rb +374 -0
 - data/lib/sp/duh/jsonapi/exceptions.rb +56 -0
 - data/lib/sp/duh/jsonapi/model/base.rb +25 -0
 - data/lib/sp/duh/jsonapi/model/concerns/attributes.rb +94 -0
 - data/lib/sp/duh/jsonapi/model/concerns/model.rb +42 -0
 - data/lib/sp/duh/jsonapi/model/concerns/persistence.rb +221 -0
 - data/lib/sp/duh/jsonapi/model/concerns/serialization.rb +59 -0
 - data/lib/sp/duh/jsonapi/parameters.rb +44 -0
 - data/lib/sp/duh/jsonapi/resource_publisher.rb +28 -0
 - data/lib/sp/duh/jsonapi/service.rb +110 -0
 - data/lib/sp/duh/migrations.rb +47 -0
 - data/lib/sp/duh/migrations/migrator.rb +41 -0
 - data/lib/sp/duh/repl.rb +193 -0
 - data/lib/sp/duh/version.rb +25 -0
 - data/lib/tasks/db_utils.rake +98 -0
 - data/lib/tasks/doc.rake +27 -0
 - data/lib/tasks/i18n.rake +23 -0
 - data/lib/tasks/oauth.rake +29 -0
 - data/lib/tasks/transfer.rake +48 -0
 - data/lib/tasks/xls2jrxml.rake +15 -0
 - data/test/jsonapi/server.rb +67 -0
 - data/test/tasks/test.rake +10 -0
 - metadata +170 -0
 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'sp-excel-loader'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module SP
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Duh
         
     | 
| 
      
 5 
     | 
    
         
            +
                module I18n
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  class ExcelLoader < ::Sp::Excel::Loader::WorkbookLoader
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    def initialize(filename, pg_connection)
         
     | 
| 
      
 10 
     | 
    
         
            +
                      super(filename)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      @connection = pg_connection
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    def clear
         
     | 
| 
      
 15 
     | 
    
         
            +
                      @connection.exec "DELETE FROM public.i18n"
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    def reload
         
     | 
| 
      
 19 
     | 
    
         
            +
                      export_table_to_pg(@connection,  'public', '', 'i18n')
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,168 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module SP
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Duh
         
     | 
| 
      
 3 
     | 
    
         
            +
                module JSONAPI
         
     | 
| 
      
 4 
     | 
    
         
            +
                  module Adapters
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                    class Base
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                      def service ; @service ; end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                      def initialize(service)
         
     | 
| 
      
 11 
     | 
    
         
            +
                        @service = service
         
     | 
| 
      
 12 
     | 
    
         
            +
                      end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                      def get(path, params = {})
         
     | 
| 
      
 15 
     | 
    
         
            +
                        request('GET', path, params)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      end
         
     | 
| 
      
 17 
     | 
    
         
            +
                      def post(path, params = {})
         
     | 
| 
      
 18 
     | 
    
         
            +
                        request('POST', path, params)
         
     | 
| 
      
 19 
     | 
    
         
            +
                      end
         
     | 
| 
      
 20 
     | 
    
         
            +
                      def patch(path, params = {})
         
     | 
| 
      
 21 
     | 
    
         
            +
                        request('PATCH', path, params)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      end
         
     | 
| 
      
 23 
     | 
    
         
            +
                      def delete(path)
         
     | 
| 
      
 24 
     | 
    
         
            +
                        request('DELETE', path, nil)
         
     | 
| 
      
 25 
     | 
    
         
            +
                      end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                      def get!(path, params = {})
         
     | 
| 
      
 28 
     | 
    
         
            +
                        request!('GET', path, params)
         
     | 
| 
      
 29 
     | 
    
         
            +
                      end
         
     | 
| 
      
 30 
     | 
    
         
            +
                      def post!(path, params = {})
         
     | 
| 
      
 31 
     | 
    
         
            +
                        request!('POST', path, params)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      end
         
     | 
| 
      
 33 
     | 
    
         
            +
                      def patch!(path, params = {})
         
     | 
| 
      
 34 
     | 
    
         
            +
                        request!('PATCH', path, params)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      end
         
     | 
| 
      
 36 
     | 
    
         
            +
                      def delete!(path)
         
     | 
| 
      
 37 
     | 
    
         
            +
                        request!('DELETE', path, nil)
         
     | 
| 
      
 38 
     | 
    
         
            +
                      end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                      def get_explicit!(exp_accounting_schema, exp_accounting_prefix, path, params = {})
         
     | 
| 
      
 41 
     | 
    
         
            +
                        explicit_request!(exp_accounting_schema, exp_accounting_prefix, 'GET', path, params)
         
     | 
| 
      
 42 
     | 
    
         
            +
                      end
         
     | 
| 
      
 43 
     | 
    
         
            +
                      def post_explicit!(exp_accounting_schema, exp_accounting_prefix, path, params = {})
         
     | 
| 
      
 44 
     | 
    
         
            +
                        explicit_request!(exp_accounting_schema, exp_accounting_prefix, 'POST', path, params)
         
     | 
| 
      
 45 
     | 
    
         
            +
                      end
         
     | 
| 
      
 46 
     | 
    
         
            +
                      def patch_explicit!(exp_accounting_schema, exp_accounting_prefix, path, params = {})
         
     | 
| 
      
 47 
     | 
    
         
            +
                        explicit_request!(exp_accounting_schema, exp_accounting_prefix, 'PATCH', path, params)
         
     | 
| 
      
 48 
     | 
    
         
            +
                      end
         
     | 
| 
      
 49 
     | 
    
         
            +
                      def delete_explicit!(exp_accounting_schema, exp_accounting_prefix, path)
         
     | 
| 
      
 50 
     | 
    
         
            +
                        explicit_request!(exp_accounting_schema, exp_accounting_prefix, 'DELETE', path, nil)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                      alias_method :put, :patch
         
     | 
| 
      
 54 
     | 
    
         
            +
                      alias_method :put!, :patch!
         
     | 
| 
      
 55 
     | 
    
         
            +
                      alias_method :put_explicit!, :patch_explicit!
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                      def unwrap_request
         
     | 
| 
      
 58 
     | 
    
         
            +
                        unwrap_response(yield)
         
     | 
| 
      
 59 
     | 
    
         
            +
                      end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                      # do_request MUST be implemented by each specialized adapter, and returns a tuple: the request status and a JSONAPI string or hash with the result
         
     | 
| 
      
 62 
     | 
    
         
            +
                      def do_request(method, path, params) ; ; end
         
     | 
| 
      
 63 
     | 
    
         
            +
                      def explicit_do_request(exp_accounting_schema, exp_accounting_prefix, method, path, params) ; ; end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                      def request(method, path, params)
         
     | 
| 
      
 66 
     | 
    
         
            +
                        # As it is now, this method is EXACTLY the same as request!()
         
     | 
| 
      
 67 
     | 
    
         
            +
                        # And it cannot be reverted without affecting lots of changes already made in the app's controllers.
         
     | 
| 
      
 68 
     | 
    
         
            +
                        # TODO: end it, or end the !() version
         
     | 
| 
      
 69 
     | 
    
         
            +
                        # begin
         
     | 
| 
      
 70 
     | 
    
         
            +
                          unwrap_request do
         
     | 
| 
      
 71 
     | 
    
         
            +
                            do_request(method, path, params)
         
     | 
| 
      
 72 
     | 
    
         
            +
                          end
         
     | 
| 
      
 73 
     | 
    
         
            +
                        # THIS CAN'T BE DONE, because the same method cannot return both a single result (in case there is NOT an error) and a pair (in case there IS an error)
         
     | 
| 
      
 74 
     | 
    
         
            +
                        # rescue SP::Duh::JSONAPI::Exceptions::GenericModelError => e
         
     | 
| 
      
 75 
     | 
    
         
            +
                        #   [
         
     | 
| 
      
 76 
     | 
    
         
            +
                        #     e.status,
         
     | 
| 
      
 77 
     | 
    
         
            +
                        #     e.result
         
     | 
| 
      
 78 
     | 
    
         
            +
                        #   ]
         
     | 
| 
      
 79 
     | 
    
         
            +
                        # rescue Exception => e
         
     | 
| 
      
 80 
     | 
    
         
            +
                        #   [
         
     | 
| 
      
 81 
     | 
    
         
            +
                        #     SP::Duh::JSONAPI::Status::ERROR,
         
     | 
| 
      
 82 
     | 
    
         
            +
                        #     get_error_response(path, e)
         
     | 
| 
      
 83 
     | 
    
         
            +
                        #   ]
         
     | 
| 
      
 84 
     | 
    
         
            +
                        # end
         
     | 
| 
      
 85 
     | 
    
         
            +
                      end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                      def request!(method, path, params)
         
     | 
| 
      
 88 
     | 
    
         
            +
                        unwrap_request do
         
     | 
| 
      
 89 
     | 
    
         
            +
                          do_request(method, path, params)
         
     | 
| 
      
 90 
     | 
    
         
            +
                        end
         
     | 
| 
      
 91 
     | 
    
         
            +
                      end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                      def explicit_request!(exp_accounting_schema, exp_accounting_prefix, method, path, params)
         
     | 
| 
      
 94 
     | 
    
         
            +
                        unwrap_request do
         
     | 
| 
      
 95 
     | 
    
         
            +
                          explicit_do_request(exp_accounting_schema, exp_accounting_prefix, method, path, params)
         
     | 
| 
      
 96 
     | 
    
         
            +
                        end
         
     | 
| 
      
 97 
     | 
    
         
            +
                      end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                      protected
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                        def url(path) ; File.join(service.url, path) ; end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                        def url_with_params_for_query(path, params)
         
     | 
| 
      
 104 
     | 
    
         
            +
                          query = params_for_query(params)
         
     | 
| 
      
 105 
     | 
    
         
            +
                          query.blank? ? url(path) : url(path) + "?" + query
         
     | 
| 
      
 106 
     | 
    
         
            +
                        end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                        def params_for_query(params)
         
     | 
| 
      
 109 
     | 
    
         
            +
                          query = ""
         
     | 
| 
      
 110 
     | 
    
         
            +
                          if !params.blank?
         
     | 
| 
      
 111 
     | 
    
         
            +
                            case
         
     | 
| 
      
 112 
     | 
    
         
            +
                              when params.is_a?(Array)
         
     | 
| 
      
 113 
     | 
    
         
            +
                                # query = params.join('&')
         
     | 
| 
      
 114 
     | 
    
         
            +
                                query = params.map{ |v| URI.encode(URI.encode(v).gsub("'","''"), "&") }.join('&')
         
     | 
| 
      
 115 
     | 
    
         
            +
                              when params.is_a?(Hash)
         
     | 
| 
      
 116 
     | 
    
         
            +
                                query = params.map do |k,v|
         
     | 
| 
      
 117 
     | 
    
         
            +
                                  if v.is_a?(String)
         
     | 
| 
      
 118 
     | 
    
         
            +
                                    "#{k}=\"#{URI.encode(URI.encode(v).gsub("'","''"), "&")}\""
         
     | 
| 
      
 119 
     | 
    
         
            +
                                  else
         
     | 
| 
      
 120 
     | 
    
         
            +
                                    "#{k}=#{v}"
         
     | 
| 
      
 121 
     | 
    
         
            +
                                  end
         
     | 
| 
      
 122 
     | 
    
         
            +
                                end.join('&')
         
     | 
| 
      
 123 
     | 
    
         
            +
                              else
         
     | 
| 
      
 124 
     | 
    
         
            +
                                query = params.to_s
         
     | 
| 
      
 125 
     | 
    
         
            +
                            end
         
     | 
| 
      
 126 
     | 
    
         
            +
                          end
         
     | 
| 
      
 127 
     | 
    
         
            +
                          query
         
     | 
| 
      
 128 
     | 
    
         
            +
                        end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                        def params_for_body(params)
         
     | 
| 
      
 131 
     | 
    
         
            +
                          params.blank? ?  '' : params.to_json.gsub("'","''")
         
     | 
| 
      
 132 
     | 
    
         
            +
                        end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                        # unwrap_response SHOULD be implemented by each specialized adapter, and returns the request result as a JSONAPI string or hash and raises an exception if there was an error
         
     | 
| 
      
 135 
     | 
    
         
            +
                        def unwrap_response(response)
         
     | 
| 
      
 136 
     | 
    
         
            +
                          # As the method request() is EXACTLY the same as request!(), and it cannot be reverted without affecting lots of changes already made in the app's controllers...
         
     | 
| 
      
 137 
     | 
    
         
            +
                          # Allow for response being both a [ status, result ] pair (as of old) OR a single result (as of now)
         
     | 
| 
      
 138 
     | 
    
         
            +
                          if response.is_a?(Array)
         
     | 
| 
      
 139 
     | 
    
         
            +
                            status = response[0].to_i
         
     | 
| 
      
 140 
     | 
    
         
            +
                            result = response[1]
         
     | 
| 
      
 141 
     | 
    
         
            +
                            result
         
     | 
| 
      
 142 
     | 
    
         
            +
                          else
         
     | 
| 
      
 143 
     | 
    
         
            +
                            response
         
     | 
| 
      
 144 
     | 
    
         
            +
                          end
         
     | 
| 
      
 145 
     | 
    
         
            +
                        end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                        def error_response(path, error)
         
     | 
| 
      
 148 
     | 
    
         
            +
                          {
         
     | 
| 
      
 149 
     | 
    
         
            +
                            errors: [
         
     | 
| 
      
 150 
     | 
    
         
            +
                              {
         
     | 
| 
      
 151 
     | 
    
         
            +
                                status: "#{SP::Duh::JSONAPI::Status::ERROR}",
         
     | 
| 
      
 152 
     | 
    
         
            +
                                code: error.message
         
     | 
| 
      
 153 
     | 
    
         
            +
                              }
         
     | 
| 
      
 154 
     | 
    
         
            +
                            ],
         
     | 
| 
      
 155 
     | 
    
         
            +
                            links: { self: url(path) },
         
     | 
| 
      
 156 
     | 
    
         
            +
                            jsonapi: { version: SP::Duh::JSONAPI::VERSION }
         
     | 
| 
      
 157 
     | 
    
         
            +
                          }
         
     | 
| 
      
 158 
     | 
    
         
            +
                        end
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                        # get_error_response MUST be implemented by each specialized adapter, and returns a JSONAPI error result as a string or hash
         
     | 
| 
      
 161 
     | 
    
         
            +
                        def get_error_response(path, error) ; ; end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                    end
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                  end
         
     | 
| 
      
 166 
     | 
    
         
            +
                end
         
     | 
| 
      
 167 
     | 
    
         
            +
              end
         
     | 
| 
      
 168 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module SP
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Duh
         
     | 
| 
      
 3 
     | 
    
         
            +
                module JSONAPI
         
     | 
| 
      
 4 
     | 
    
         
            +
                  module Adapters
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                    class Db < RawDb
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                      protected
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                        def get_error_response(path, error) ; HashWithIndifferentAccess.new(error_response(path, error)) ; end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                        def do_request(method, path, params)
         
     | 
| 
      
 13 
     | 
    
         
            +
                          process_result(do_request_on_the_db(method, path, params))
         
     | 
| 
      
 14 
     | 
    
         
            +
                        end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                        def explicit_do_request(exp_accounting_schema, exp_accounting_prefix, method, path, params)
         
     | 
| 
      
 17 
     | 
    
         
            +
                          process_result(explicit_do_request_on_the_db(exp_accounting_schema, exp_accounting_prefix, method, path, params))
         
     | 
| 
      
 18 
     | 
    
         
            +
                        end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                      private
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                        def is_error?(result) ; !result[:errors].blank? ; end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                        def process_result(result)
         
     | 
| 
      
 25 
     | 
    
         
            +
                          result = HashWithIndifferentAccess.new(result)
         
     | 
| 
      
 26 
     | 
    
         
            +
                          result[:response] = JSON.parse(result[:response])
         
     | 
| 
      
 27 
     | 
    
         
            +
                          raise SP::Duh::JSONAPI::Exceptions::GenericModelError.new(result[:response]) if is_error?(result[:response])
         
     | 
| 
      
 28 
     | 
    
         
            +
                          [ result[:http_status], result[:response] ]
         
     | 
| 
      
 29 
     | 
    
         
            +
                        end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,77 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module SP
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Duh
         
     | 
| 
      
 3 
     | 
    
         
            +
                module JSONAPI
         
     | 
| 
      
 4 
     | 
    
         
            +
                  module Adapters
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                    class RawDb < Base
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                      protected
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                        def unwrap_response(response)
         
     | 
| 
      
 11 
     | 
    
         
            +
                          # As the method request() is EXACTLY the same as request!(), and it cannot be reverted without affecting lots of changes already made in the app's controllers...
         
     | 
| 
      
 12 
     | 
    
         
            +
                          # Allow for response being both a [ status, result ] pair (as of old) OR a single result (as of now)
         
     | 
| 
      
 13 
     | 
    
         
            +
                          if response.is_a?(Array)
         
     | 
| 
      
 14 
     | 
    
         
            +
                            status = response[0].to_i
         
     | 
| 
      
 15 
     | 
    
         
            +
                            result = response[1]
         
     | 
| 
      
 16 
     | 
    
         
            +
                            raise SP::Duh::JSONAPI::Exceptions::GenericModelError.new(result) if status != SP::Duh::JSONAPI::Status::OK
         
     | 
| 
      
 17 
     | 
    
         
            +
                            result
         
     | 
| 
      
 18 
     | 
    
         
            +
                          else
         
     | 
| 
      
 19 
     | 
    
         
            +
                            # No raise here, we do not know the status...
         
     | 
| 
      
 20 
     | 
    
         
            +
                            response
         
     | 
| 
      
 21 
     | 
    
         
            +
                          end
         
     | 
| 
      
 22 
     | 
    
         
            +
                        end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                        def get_error_response(path, error) ; error_response(path, error).to_json ; end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                        def do_request(method, path, param)
         
     | 
| 
      
 27 
     | 
    
         
            +
                          process_result(do_request_on_the_db(method, path, params))
         
     | 
| 
      
 28 
     | 
    
         
            +
                        end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                        def explicit_do_request(accounting_schema, method, path, param)
         
     | 
| 
      
 31 
     | 
    
         
            +
                          process_result(explicit_do_request_on_the_db(accounting_schema, method, path, params))
         
     | 
| 
      
 32 
     | 
    
         
            +
                        end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                      private
         
     | 
| 
      
 35 
     | 
    
         
            +
                        def user_id           ; "'#{service.parameters.user_id}'" ; end
         
     | 
| 
      
 36 
     | 
    
         
            +
                        def company_id        ; "'#{service.parameters.company_id}'" ; end
         
     | 
| 
      
 37 
     | 
    
         
            +
                        def company_schema    ; service.parameters.company_schema.nil? ? 'NULL' : "'#{service.parameters.company_schema}'" ; end
         
     | 
| 
      
 38 
     | 
    
         
            +
                        def sharded_schema    ; service.parameters.sharded_schema.nil? ? 'NULL' : "'#{service.parameters.sharded_schema}'" ; end
         
     | 
| 
      
 39 
     | 
    
         
            +
                        def accounting_schema ; service.parameters.accounting_schema.nil? ? 'NULL' : "'#{service.parameters.accounting_schema}'" ; end
         
     | 
| 
      
 40 
     | 
    
         
            +
                        def accounting_prefix ; service.parameters.accounting_prefix.nil? ? 'NULL' : "'#{service.parameters.accounting_prefix}'" ; end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                        def process_result(result)
         
     | 
| 
      
 43 
     | 
    
         
            +
                          raise SP::Duh::JSONAPI::Exceptions::GenericModelError.new(result) if is_error?(result)
         
     | 
| 
      
 44 
     | 
    
         
            +
                          [ SP::Duh::JSONAPI::Status::OK, result ]
         
     | 
| 
      
 45 
     | 
    
         
            +
                        end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                        # Implement the JSONAPI request by direct querying of the JSONAPI function in the database
         
     | 
| 
      
 48 
     | 
    
         
            +
                        def do_request_on_the_db(method, path, params)
         
     | 
| 
      
 49 
     | 
    
         
            +
                          jsonapi_query = if method == 'GET'
         
     | 
| 
      
 50 
     | 
    
         
            +
                            %Q[ SELECT * FROM public.jsonapi('#{method}', '#{url_with_params_for_query(path, params)}', '', #{user_id}, #{company_id}, #{company_schema}, #{sharded_schema}, #{accounting_schema}, #{accounting_prefix}) ]
         
     | 
| 
      
 51 
     | 
    
         
            +
                          else
         
     | 
| 
      
 52 
     | 
    
         
            +
                            %Q[ SELECT * FROM public.jsonapi('#{method}', '#{url(path)}', '#{params_for_body(params)}', #{user_id}, #{company_id}, #{company_schema}, #{sharded_schema}, #{accounting_schema}, #{accounting_prefix}) ]
         
     | 
| 
      
 53 
     | 
    
         
            +
                          end
         
     | 
| 
      
 54 
     | 
    
         
            +
                          response = service.connection.exec jsonapi_query
         
     | 
| 
      
 55 
     | 
    
         
            +
                          response.first if response.first
         
     | 
| 
      
 56 
     | 
    
         
            +
                        end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                        def explicit_do_request_on_the_db(exp_accounting_schema, exp_accounting_prefix, method, path, params)
         
     | 
| 
      
 59 
     | 
    
         
            +
                          _accounting_schema = "'#{exp_accounting_schema}'"
         
     | 
| 
      
 60 
     | 
    
         
            +
                          _accounting_prefix = "'#{exp_accounting_prefix}'"
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                          jsonapi_query = if method == 'GET'
         
     | 
| 
      
 63 
     | 
    
         
            +
                            %Q[ SELECT * FROM public.jsonapi('#{method}', '#{url_with_params_for_query(path, params)}', '', #{user_id}, #{company_id}, #{company_schema}, #{sharded_schema}, #{_accounting_schema}, #{_accounting_prefix}) ]
         
     | 
| 
      
 64 
     | 
    
         
            +
                          else
         
     | 
| 
      
 65 
     | 
    
         
            +
                            %Q[ SELECT * FROM public.jsonapi('#{method}', '#{url(path)}', '#{params_for_body(params)}', #{user_id}, #{company_id}, #{company_schema}, #{sharded_schema}, #{_accounting_schema}, #{_accounting_prefix}) ]
         
     | 
| 
      
 66 
     | 
    
         
            +
                          end
         
     | 
| 
      
 67 
     | 
    
         
            +
                          response = service.connection.exec jsonapi_query
         
     | 
| 
      
 68 
     | 
    
         
            +
                          response.first if response.first
         
     | 
| 
      
 69 
     | 
    
         
            +
                        end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                        def is_error?(result) ; result =~ /^\s*{\s*"errors"\s*:/ ; end
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
              end
         
     | 
| 
      
 77 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,167 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module SP
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Duh
         
     | 
| 
      
 3 
     | 
    
         
            +
                module JSONAPI
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                  class Configuration
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                    CONFIGURATION_TABLE_NAME = 'public.jsonapi_config'
         
     | 
| 
      
 8 
     | 
    
         
            +
                    DEFAULT_SETTINGS_FILE = 'config/jsonapi/settings.yml'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                    @@publishers = []
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    def settings
         
     | 
| 
      
 13 
     | 
    
         
            +
                      @settings ||= {}
         
     | 
| 
      
 14 
     | 
    
         
            +
                      if @settings.blank?
         
     | 
| 
      
 15 
     | 
    
         
            +
                        load_settings_from_file(File.join(SP::Duh.root, DEFAULT_SETTINGS_FILE))
         
     | 
| 
      
 16 
     | 
    
         
            +
                      end
         
     | 
| 
      
 17 
     | 
    
         
            +
                      @settings
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    def settings=(hash)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      @settings = hash
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    def resources ; @resources || [] ; end
         
     | 
| 
      
 25 
     | 
    
         
            +
                    def resource_names ; resources.map { |r| r.keys.first } ; end
         
     | 
| 
      
 26 
     | 
    
         
            +
                    def connection ; @pg_connection ; end
         
     | 
| 
      
 27 
     | 
    
         
            +
                    def url ; @url ; end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    def publishers ; @@publishers || [] ; end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    def initialize(pg_connection, url)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      @pg_connection = pg_connection
         
     | 
| 
      
 33 
     | 
    
         
            +
                      @url = url
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    def self.add_publisher(publisher)
         
     | 
| 
      
 37 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 38 
     | 
    
         
            +
                        publisher = publisher.constantize if publisher.is_a?(String)
         
     | 
| 
      
 39 
     | 
    
         
            +
                        raise Exceptions::InvalidResourcePublisherError.new(publisher: publisher.name) if !publisher.include?(ResourcePublisher)
         
     | 
| 
      
 40 
     | 
    
         
            +
                        @@publishers << publisher
         
     | 
| 
      
 41 
     | 
    
         
            +
                      rescue StandardError => e
         
     | 
| 
      
 42 
     | 
    
         
            +
                        raise Exceptions::InvalidResourcePublisherError.new(publisher: publisher.is_a?(String) ? publisher : publisher.name)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      end
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    def setup
         
     | 
| 
      
 47 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 48 
     | 
    
         
            +
                        create_jsonapi_configuration_store()
         
     | 
| 
      
 49 
     | 
    
         
            +
                      rescue StandardError => e
         
     | 
| 
      
 50 
     | 
    
         
            +
                        raise Exceptions::GenericServiceError.new(e)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      end
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    def exists?
         
     | 
| 
      
 55 
     | 
    
         
            +
                      check = connection.exec %Q[ SELECT COUNT(*) FROM #{Configuration::CONFIGURATION_TABLE_NAME} WHERE prefix = '#{url}' ]
         
     | 
| 
      
 56 
     | 
    
         
            +
                      return check.first.values.first.to_i > 0
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    def load_from_database
         
     | 
| 
      
 60 
     | 
    
         
            +
                      @resources = []
         
     | 
| 
      
 61 
     | 
    
         
            +
                      @settings = {}
         
     | 
| 
      
 62 
     | 
    
         
            +
                      configuration = connection.exec %Q[ SELECT config FROM #{Configuration::CONFIGURATION_TABLE_NAME} WHERE prefix = '#{url}' ]
         
     | 
| 
      
 63 
     | 
    
         
            +
                      if configuration.first
         
     | 
| 
      
 64 
     | 
    
         
            +
                        configuration = JSON.parse(configuration.first['config'])
         
     | 
| 
      
 65 
     | 
    
         
            +
                        @resources = configuration['resources']
         
     | 
| 
      
 66 
     | 
    
         
            +
                        @settings = configuration.reject { |k,v| k == 'resources' }
         
     | 
| 
      
 67 
     | 
    
         
            +
                      end
         
     | 
| 
      
 68 
     | 
    
         
            +
                      @resources
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    def load_from_publishers(replace = false)
         
     | 
| 
      
 72 
     | 
    
         
            +
                      @resources = []
         
     | 
| 
      
 73 
     | 
    
         
            +
                      @settings = {}
         
     | 
| 
      
 74 
     | 
    
         
            +
                      @@publishers.each do |publisher|
         
     | 
| 
      
 75 
     | 
    
         
            +
                         add_resources_from_folder(publisher.jsonapi_resources_root, replace)
         
     | 
| 
      
 76 
     | 
    
         
            +
                      end
         
     | 
| 
      
 77 
     | 
    
         
            +
                      @resources
         
     | 
| 
      
 78 
     | 
    
         
            +
                    end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    def save
         
     | 
| 
      
 81 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 82 
     | 
    
         
            +
                        if exists?
         
     | 
| 
      
 83 
     | 
    
         
            +
                          connection.exec %Q[
         
     | 
| 
      
 84 
     | 
    
         
            +
                            UPDATE #{Configuration::CONFIGURATION_TABLE_NAME} SET config='#{definition.to_json}' WHERE prefix='#{url}';
         
     | 
| 
      
 85 
     | 
    
         
            +
                          ]
         
     | 
| 
      
 86 
     | 
    
         
            +
                        else
         
     | 
| 
      
 87 
     | 
    
         
            +
                          connection.exec %Q[
         
     | 
| 
      
 88 
     | 
    
         
            +
                            INSERT INTO #{Configuration::CONFIGURATION_TABLE_NAME} (prefix, config) VALUES ('#{url}','#{definition.to_json}');
         
     | 
| 
      
 89 
     | 
    
         
            +
                          ]
         
     | 
| 
      
 90 
     | 
    
         
            +
                        end
         
     | 
| 
      
 91 
     | 
    
         
            +
                      rescue StandardError => e
         
     | 
| 
      
 92 
     | 
    
         
            +
                        raise Exceptions::SaveConfigurationError.new(nil, e)
         
     | 
| 
      
 93 
     | 
    
         
            +
                      end
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                    def reload!
         
     | 
| 
      
 97 
     | 
    
         
            +
                      load_from_publishers(true)
         
     | 
| 
      
 98 
     | 
    
         
            +
                      save
         
     | 
| 
      
 99 
     | 
    
         
            +
                      @resources
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    def load_settings_from_file(file_name)
         
     | 
| 
      
 103 
     | 
    
         
            +
                      @settings = YAML.load_file(file_name)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                    private
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                      def create_jsonapi_configuration_store
         
     | 
| 
      
 109 
     | 
    
         
            +
                        connection.exec %Q[
         
     | 
| 
      
 110 
     | 
    
         
            +
                          CREATE TABLE IF NOT EXISTS #{Configuration::CONFIGURATION_TABLE_NAME} (
         
     | 
| 
      
 111 
     | 
    
         
            +
                            prefix varchar(64) PRIMARY KEY,
         
     | 
| 
      
 112 
     | 
    
         
            +
                            config text NOT NULL
         
     | 
| 
      
 113 
     | 
    
         
            +
                          );
         
     | 
| 
      
 114 
     | 
    
         
            +
                        ]
         
     | 
| 
      
 115 
     | 
    
         
            +
                      end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                      def definition
         
     | 
| 
      
 118 
     | 
    
         
            +
                        settings.merge(resources: resources)
         
     | 
| 
      
 119 
     | 
    
         
            +
                      end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                      def add_resources_from_folder(folder_name, replace)
         
     | 
| 
      
 122 
     | 
    
         
            +
                        @resources ||= []
         
     | 
| 
      
 123 
     | 
    
         
            +
                        # First load resources at the root folder
         
     | 
| 
      
 124 
     | 
    
         
            +
                        Dir.glob(File.join(folder_name, '*.yml')) do |configuration_file|
         
     | 
| 
      
 125 
     | 
    
         
            +
                          add_resources_from_file(configuration_file, replace)
         
     | 
| 
      
 126 
     | 
    
         
            +
                        end
         
     | 
| 
      
 127 
     | 
    
         
            +
                        # Then load resources at the inner folders
         
     | 
| 
      
 128 
     | 
    
         
            +
                        Dir.glob(File.join(folder_name, '*', '*.yml')) do |configuration_file|
         
     | 
| 
      
 129 
     | 
    
         
            +
                          add_resources_from_file(configuration_file, replace)
         
     | 
| 
      
 130 
     | 
    
         
            +
                        end
         
     | 
| 
      
 131 
     | 
    
         
            +
                        @resources
         
     | 
| 
      
 132 
     | 
    
         
            +
                      end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                      def add_resources_from_file(configuration_file, replace)
         
     | 
| 
      
 135 
     | 
    
         
            +
                        _log "Processing resources from file #{configuration_file}", "JSONAPI::Configuration"
         
     | 
| 
      
 136 
     | 
    
         
            +
                        configuration =  YAML.load_file(configuration_file)
         
     | 
| 
      
 137 
     | 
    
         
            +
                        if configuration.is_a? Hash
         
     | 
| 
      
 138 
     | 
    
         
            +
                          add_resource(configuration, configuration_file, replace)
         
     | 
| 
      
 139 
     | 
    
         
            +
                        else
         
     | 
| 
      
 140 
     | 
    
         
            +
                          if configuration.is_a? Array
         
     | 
| 
      
 141 
     | 
    
         
            +
                            configuration.each { |resource| add_resource(resource, configuration_file, replace) }
         
     | 
| 
      
 142 
     | 
    
         
            +
                          else
         
     | 
| 
      
 143 
     | 
    
         
            +
                            raise Exceptions::InvalidResourceConfigurationError.new(file: configuration_file)
         
     | 
| 
      
 144 
     | 
    
         
            +
                          end
         
     | 
| 
      
 145 
     | 
    
         
            +
                        end
         
     | 
| 
      
 146 
     | 
    
         
            +
                      end
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                      def add_resource(resource, configuration_file, replace)
         
     | 
| 
      
 149 
     | 
    
         
            +
                        raise Exceptions::InvalidResourceConfigurationError.new(file: configuration_file) if (resource.keys.count != 1)
         
     | 
| 
      
 150 
     | 
    
         
            +
                        resource_name = resource.keys[0]
         
     | 
| 
      
 151 
     | 
    
         
            +
                        _log "Processing resource #{resource_name}", "JSONAPI::Configuration"
         
     | 
| 
      
 152 
     | 
    
         
            +
                        processed = false
         
     | 
| 
      
 153 
     | 
    
         
            +
                        @resources.each_with_index do |r, i|
         
     | 
| 
      
 154 
     | 
    
         
            +
                          if r.keys.include?(resource_name)
         
     | 
| 
      
 155 
     | 
    
         
            +
                            raise Exceptions::DuplicateResourceError.new(name: resource_name) if !replace
         
     | 
| 
      
 156 
     | 
    
         
            +
                            @resources[i] = resource
         
     | 
| 
      
 157 
     | 
    
         
            +
                            processed = true
         
     | 
| 
      
 158 
     | 
    
         
            +
                            break
         
     | 
| 
      
 159 
     | 
    
         
            +
                          end
         
     | 
| 
      
 160 
     | 
    
         
            +
                        end
         
     | 
| 
      
 161 
     | 
    
         
            +
                        @resources << resource if !processed
         
     | 
| 
      
 162 
     | 
    
         
            +
                      end
         
     | 
| 
      
 163 
     | 
    
         
            +
                  end
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                end
         
     | 
| 
      
 166 
     | 
    
         
            +
              end
         
     | 
| 
      
 167 
     | 
    
         
            +
            end
         
     |