marklogic 0.0.1 → 0.0.3
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/.ruby-version +1 -1
- data/Rakefile +20 -0
- data/lib/marklogic.rb +2 -0
- data/lib/marklogic/app_server.rb +25 -0
- data/lib/marklogic/application.rb +76 -6
- data/lib/marklogic/collection.rb +13 -1
- data/lib/marklogic/connection.rb +83 -61
- data/lib/marklogic/cursor.rb +3 -3
- data/lib/marklogic/database.rb +31 -3
- data/lib/marklogic/exceptions.rb +1 -0
- data/lib/marklogic/forest.rb +16 -0
- data/lib/marklogic/persistence.rb +19 -0
- data/lib/marklogic/version.rb +1 -1
- data/marklogic.gemspec +2 -0
- data/spec/marklogic/app_server_spec.rb +10 -0
- data/spec/marklogic/application_spec.rb +14 -0
- data/spec/marklogic/connection_spec.rb +8 -0
- metadata +43 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: a18a7c658e56f1ad3d394de8120246955b35c90d
         | 
| 4 | 
            +
              data.tar.gz: 5380d8f65f962dec8c958be996194ece2724e35e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 465d4b95d2cb7b89f62b29e9462d4f44f029fc45d2a73132b117aa1bbf326d9e05bb11094cc7701c073a22fa6ff05628655c0dec7fa6751c08fcd654837b9424
         | 
| 7 | 
            +
              data.tar.gz: 01c5b4435cc0f35ed3d6c1a0e93f159b4b7c41f3ecac97d75f5db111783c0363025ddb6f0bddf48a6be0b3c6afb5ad51ffcd25fcdf3c583e79a69f49ebf5e9ec
         | 
    
        data/.ruby-version
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            2.2. | 
| 1 | 
            +
            2.2.2
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -1,6 +1,26 @@ | |
| 1 1 | 
             
            require "bundler/gem_tasks"
         | 
| 2 2 |  | 
| 3 3 | 
             
            require 'rspec/core/rake_task'
         | 
| 4 | 
            +
            require File.expand_path('../lib/marklogic/version', __FILE__)
         | 
| 5 | 
            +
             | 
| 4 6 | 
             
            RSpec::Core::RakeTask.new
         | 
| 5 7 |  | 
| 6 8 | 
             
            task :default => :spec
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            desc 'Builds the gem'
         | 
| 11 | 
            +
            task :build do
         | 
| 12 | 
            +
              sh "gem build marklogic.gemspec"
         | 
| 13 | 
            +
            end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            desc 'Builds and installs the gem'
         | 
| 16 | 
            +
            task :install => :build do
         | 
| 17 | 
            +
              sh "gem install marklogic-#{MarkLogic::Version}"
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            desc 'Tags version, pushes to remote, and pushes gem'
         | 
| 21 | 
            +
            task :release => :build do
         | 
| 22 | 
            +
              sh "git tag v#{MarkMapper::Version}"
         | 
| 23 | 
            +
              sh "git push origin master"
         | 
| 24 | 
            +
              sh "git push origin v#{MarkLogic::Version}"
         | 
| 25 | 
            +
              sh "gem push marklogic-#{MarkLogic::Version}.gem"
         | 
| 26 | 
            +
            end
         | 
    
        data/lib/marklogic.rb
    CHANGED
    
    | @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            require 'oj'
         | 
| 1 2 | 
             
            require 'active_support'
         | 
| 2 3 | 
             
            require 'active_support/core_ext/object'
         | 
| 3 4 | 
             
            require 'active_support/core_ext/string/inflections'
         | 
| @@ -6,6 +7,7 @@ require "marklogic/consts" | |
| 6 7 | 
             
            require 'marklogic/queries'
         | 
| 7 8 | 
             
            require 'marklogic/exceptions'
         | 
| 8 9 | 
             
            require 'marklogic/object_id'
         | 
| 10 | 
            +
            require 'marklogic/multipart_parser'
         | 
| 9 11 |  | 
| 10 12 | 
             
            module MarkLogic
         | 
| 11 13 | 
             
              autoload :Application, 'marklogic/application'
         | 
    
        data/lib/marklogic/app_server.rb
    CHANGED
    
    | @@ -26,6 +26,31 @@ module MarkLogic | |
| 26 26 | 
             
                  }
         | 
| 27 27 | 
             
                end
         | 
| 28 28 |  | 
| 29 | 
            +
                def self.load(server_name, group_name = "Default")
         | 
| 30 | 
            +
                  app_server = AppServer.new(server_name, 0, 'http', group_name)
         | 
| 31 | 
            +
                  app_server.load
         | 
| 32 | 
            +
                  app_server
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def load
         | 
| 36 | 
            +
                  resp = manage_connection.get(%Q{/manage/v2/servers/#{server_name}/properties?group-id=#{group_name}&format=json})
         | 
| 37 | 
            +
                  if resp.code.to_i == 200
         | 
| 38 | 
            +
                    options = Oj.load(resp.body)
         | 
| 39 | 
            +
                    options.each do |key, value|
         | 
| 40 | 
            +
                      self[key] = value
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def inspect
         | 
| 46 | 
            +
                  as_nice_string = [
         | 
| 47 | 
            +
                    "server_name: #{server_name}",
         | 
| 48 | 
            +
                    "server_type: #{server_type}",
         | 
| 49 | 
            +
                    "port: #{self['port']}"
         | 
| 50 | 
            +
                  ].join(",")
         | 
| 51 | 
            +
                  "#<#{self.class}#{as_nice_string}>"
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 29 54 | 
             
                def []=(key, value)
         | 
| 30 55 | 
             
                  @options[key] = value
         | 
| 31 56 | 
             
                end
         | 
| @@ -2,7 +2,7 @@ module MarkLogic | |
| 2 2 | 
             
              class Application
         | 
| 3 3 | 
             
                include MarkLogic::Persistence
         | 
| 4 4 |  | 
| 5 | 
            -
                attr_accessor :app_name
         | 
| 5 | 
            +
                attr_accessor :app_name, :port
         | 
| 6 6 |  | 
| 7 7 | 
             
                def initialize(app_name, options = {})
         | 
| 8 8 | 
             
                  @app_name = app_name
         | 
| @@ -157,10 +157,16 @@ module MarkLogic | |
| 157 157 | 
             
                  end
         | 
| 158 158 | 
             
                end
         | 
| 159 159 |  | 
| 160 | 
            +
                def modules_databases
         | 
| 161 | 
            +
                  app_servers.values.map do |app_server|
         | 
| 162 | 
            +
                    databases[app_server['modules-database']]
         | 
| 163 | 
            +
                  end
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
             | 
| 160 166 | 
             
                def database(name)
         | 
| 161 | 
            -
                  database = MarkLogic::Database.new(name)
         | 
| 167 | 
            +
                  database = MarkLogic::Database.new(name, self.connection)
         | 
| 162 168 | 
             
                  yield(database) if block_given?
         | 
| 163 | 
            -
                   | 
| 169 | 
            +
                  database.application = self
         | 
| 164 170 | 
             
                  databases[name] = database
         | 
| 165 171 | 
             
                end
         | 
| 166 172 |  | 
| @@ -170,8 +176,73 @@ module MarkLogic | |
| 170 176 | 
             
                  app_servers[name] = app_server
         | 
| 171 177 | 
             
                end
         | 
| 172 178 |  | 
| 179 | 
            +
                def inspect
         | 
| 180 | 
            +
                  as_nice_string = [
         | 
| 181 | 
            +
                    " app_name: #{app_name.inspect}",
         | 
| 182 | 
            +
                    " port: #{port.inspect}",
         | 
| 183 | 
            +
                    " app_servers: #{app_servers.values.each { |app_server| app_server.inspect }}"
         | 
| 184 | 
            +
                  ].join(",")
         | 
| 185 | 
            +
                  "#<#{self.class}#{as_nice_string}>"
         | 
| 186 | 
            +
                end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                def self.load(app_name, options = {})
         | 
| 189 | 
            +
                  app = Application.new(app_name, options)
         | 
| 190 | 
            +
                  app.load
         | 
| 191 | 
            +
                  app
         | 
| 192 | 
            +
                end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                def load
         | 
| 195 | 
            +
                  app_servers[app_name] = MarkLogic::AppServer.load(app_name)
         | 
| 196 | 
            +
                  @port = app_servers[app_name]['port']
         | 
| 197 | 
            +
                  load_databases
         | 
| 198 | 
            +
                  build_indexes
         | 
| 199 | 
            +
                end
         | 
| 200 | 
            +
             | 
| 173 201 | 
             
                private
         | 
| 174 202 |  | 
| 203 | 
            +
                def load_database(db_name)
         | 
| 204 | 
            +
                  db = MarkLogic::Database.load(db_name, self.connection)
         | 
| 205 | 
            +
                  db.application = self
         | 
| 206 | 
            +
                  databases[db_name] = db
         | 
| 207 | 
            +
             | 
| 208 | 
            +
                  db['forest'].each do |forest_name|
         | 
| 209 | 
            +
                    forests[forest_name] = MarkLogic::Forest.load(forest_name, nil, self.connection) unless forests.has_key?(forest_name)
         | 
| 210 | 
            +
                    forests[forest_name].database = db
         | 
| 211 | 
            +
                  end
         | 
| 212 | 
            +
                end
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                def load_databases
         | 
| 215 | 
            +
                  app_servers.each_value do |app_server|
         | 
| 216 | 
            +
                    db_name = app_server['content-database']
         | 
| 217 | 
            +
                    load_database(db_name) unless databases.has_key?(db_name)
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                    modules_db_name = app_server['modules-database']
         | 
| 220 | 
            +
                    load_database(modules_db_name) unless databases.has_key?(modules_db_name)
         | 
| 221 | 
            +
                  end
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                  triggers_database = nil
         | 
| 224 | 
            +
                  schema_database = nil
         | 
| 225 | 
            +
                  databases.each_value do |database|
         | 
| 226 | 
            +
                    if database.has_key?('triggers-database')
         | 
| 227 | 
            +
                      triggers_database = database['triggers-database']
         | 
| 228 | 
            +
                    end
         | 
| 229 | 
            +
             | 
| 230 | 
            +
                    if database.has_key?('schema-database')
         | 
| 231 | 
            +
                      schema_database = database['schema-database']
         | 
| 232 | 
            +
                    end
         | 
| 233 | 
            +
                  end
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                  if triggers_database && !databases.has_key?(triggers_database)
         | 
| 236 | 
            +
                    load_database(triggers_database)
         | 
| 237 | 
            +
                    # databases[triggers_database] = MarkLogic::Database.new(triggers_database, self.connection)
         | 
| 238 | 
            +
                  end
         | 
| 239 | 
            +
             | 
| 240 | 
            +
                  if schema_database && !databases.has_key?(schema_database)
         | 
| 241 | 
            +
                    load_database(schema_database)
         | 
| 242 | 
            +
                    # databases[schema_database] = MarkLogic::Database.new(schema_database, self.connection)
         | 
| 243 | 
            +
                  end
         | 
| 244 | 
            +
                end
         | 
| 245 | 
            +
             | 
| 175 246 | 
             
                def indexes
         | 
| 176 247 | 
             
                  @indexes ||= {}
         | 
| 177 248 | 
             
                end
         | 
| @@ -213,7 +284,6 @@ module MarkLogic | |
| 213 284 | 
             
                  schema_database = nil
         | 
| 214 285 | 
             
                  databases.each_value do |database|
         | 
| 215 286 | 
             
                    if database.has_key?('triggers-database')
         | 
| 216 | 
            -
                      logger.info "has triggers: [#{database['triggers-database']}]"
         | 
| 217 287 | 
             
                      triggers_database = database['triggers-database']
         | 
| 218 288 | 
             
                    end
         | 
| 219 289 |  | 
| @@ -222,11 +292,11 @@ module MarkLogic | |
| 222 292 | 
             
                    end
         | 
| 223 293 | 
             
                  end
         | 
| 224 294 |  | 
| 225 | 
            -
                  if triggers_database  | 
| 295 | 
            +
                  if triggers_database && !databases.has_key?(triggers_database)
         | 
| 226 296 | 
             
                    databases[triggers_database] = MarkLogic::Database.new(triggers_database, self.connection)
         | 
| 227 297 | 
             
                  end
         | 
| 228 298 |  | 
| 229 | 
            -
                  if schema_database  | 
| 299 | 
            +
                  if schema_database && !databases.has_key?(schema_database)
         | 
| 230 300 | 
             
                    databases[schema_database] = MarkLogic::Database.new(schema_database, self.connection)
         | 
| 231 301 | 
             
                  end
         | 
| 232 302 | 
             
                end
         | 
    
        data/lib/marklogic/collection.rb
    CHANGED
    
    | @@ -21,7 +21,7 @@ module MarkLogic | |
| 21 21 | 
             
                  url = "/v1/documents?uri=#{gen_uri(id)}&format=json"
         | 
| 22 22 | 
             
                  response = @database.connection.get(url)
         | 
| 23 23 | 
             
                  raise Exception.new("Invalid response: #{response.code.to_i}, #{response.body}") unless response.code.to_i == 200
         | 
| 24 | 
            -
                   | 
| 24 | 
            +
                  Oj.load(response.body)
         | 
| 25 25 | 
             
                end
         | 
| 26 26 |  | 
| 27 27 | 
             
                def save(doc)
         | 
| @@ -217,6 +217,18 @@ module MarkLogic | |
| 217 217 | 
             
                  end
         | 
| 218 218 | 
             
                end
         | 
| 219 219 |  | 
| 220 | 
            +
                def to_s
         | 
| 221 | 
            +
                  %Q{collection: #{collection}}
         | 
| 222 | 
            +
                end
         | 
| 223 | 
            +
             | 
| 224 | 
            +
                def inspect
         | 
| 225 | 
            +
                  as_nice_string = [
         | 
| 226 | 
            +
                    " collection: #{collection.inspect}",
         | 
| 227 | 
            +
                    " database: #{database.database_name.inspect}"
         | 
| 228 | 
            +
                  ].join(",")
         | 
| 229 | 
            +
                  "#<#{self.class}#{as_nice_string}>"
         | 
| 230 | 
            +
                end
         | 
| 231 | 
            +
             | 
| 220 232 | 
             
                private
         | 
| 221 233 |  | 
| 222 234 | 
             
                def doc_uri(doc)
         | 
    
        data/lib/marklogic/connection.rb
    CHANGED
    
    | @@ -2,6 +2,7 @@ require 'net/http' | |
| 2 2 | 
             
            require 'date'
         | 
| 3 3 | 
             
            require 'json'
         | 
| 4 4 | 
             
            require 'digest'
         | 
| 5 | 
            +
            require 'net/http/persistent'
         | 
| 5 6 |  | 
| 6 7 | 
             
            module Net
         | 
| 7 8 | 
             
              module HTTPHeader
         | 
| @@ -54,6 +55,11 @@ module Net | |
| 54 55 |  | 
| 55 56 | 
             
                  @header['Authorization'] = ["Basic #{encoded}"]
         | 
| 56 57 | 
             
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                # diable header capitalization for a performance gain
         | 
| 60 | 
            +
                def capitalize(name)
         | 
| 61 | 
            +
                  name
         | 
| 62 | 
            +
                end
         | 
| 57 63 | 
             
              end
         | 
| 58 64 | 
             
            end
         | 
| 59 65 |  | 
| @@ -61,6 +67,14 @@ module MarkLogic | |
| 61 67 | 
             
              class Connection
         | 
| 62 68 | 
             
                include MarkLogic::Loggable
         | 
| 63 69 |  | 
| 70 | 
            +
                NEWLINE_SPLITTER = Regexp.new("\r\n", Regexp::MULTILINE)
         | 
| 71 | 
            +
                DOUBLE_NEWLINE_SPLITTER = Regexp.new("\r\n\r\n", Regexp::MULTILINE)
         | 
| 72 | 
            +
                START_BOUNDARY_REGEX = Regexp.new("^[\r\n]+--[^-].+?[\r\n]+", Regexp::MULTILINE)
         | 
| 73 | 
            +
                END_BOUNDARY_REGEX = Regexp.new("[\r\n]+--[^-]+--[\r\n]+$", Regexp::MULTILINE)
         | 
| 74 | 
            +
                BOUNDARY_SPLITTER_REGEX = Regexp.new(%Q{[\r\n]+--[^-]+[\r\n]+}, Regexp::MULTILINE)
         | 
| 75 | 
            +
                CONTENT_TYPE_REGEX = /Content-Type:\s+(.*)$/
         | 
| 76 | 
            +
                PRIMITIVE_REGEX = /X-Primitive:\s+(.*)$/
         | 
| 77 | 
            +
             | 
| 64 78 | 
             
                attr_accessor :admin, :manage, :app_services, :username, :password, :host, :port, :request_retries
         | 
| 65 79 |  | 
| 66 80 | 
             
                def self.configure(options = {})
         | 
| @@ -118,15 +132,19 @@ module MarkLogic | |
| 118 132 | 
             
                  @username = username || self.class.default_user
         | 
| 119 133 | 
             
                  @password = password || self.class.default_password
         | 
| 120 134 | 
             
                  @request_retries = options[:request_retries] || 3
         | 
| 121 | 
            -
                  @http = Net::HTTP.new | 
| 135 | 
            +
                  @http = Net::HTTP::Persistent.new 'marklogic'
         | 
| 122 136 | 
             
                end
         | 
| 123 137 |  | 
| 124 138 | 
             
                def run_query(query, type = "javascript", options = {})
         | 
| 125 | 
            -
                  params  | 
| 126 | 
            -
             | 
| 139 | 
            +
                  # manually building the params yielded a performance improvement
         | 
| 140 | 
            +
                  params = %Q{#{type}=#{URI.encode_www_form_component(query)}}
         | 
| 141 | 
            +
                  params += %Q{&dbname=#{options[:db]}} if options[:db]
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                  headers = {
         | 
| 144 | 
            +
                    'content-type' => 'application/x-www-form-urlencoded'
         | 
| 127 145 | 
             
                  }
         | 
| 128 | 
            -
                   | 
| 129 | 
            -
             | 
| 146 | 
            +
                  response = request('/eval', 'post', headers, params)
         | 
| 147 | 
            +
             | 
| 130 148 | 
             
                    # :xquery => options[:query],
         | 
| 131 149 | 
             
                    # :locale => LOCALE,
         | 
| 132 150 | 
             
                    # :tzoffset => "-18000",
         | 
| @@ -164,14 +182,14 @@ module MarkLogic | |
| 164 182 | 
             
                end
         | 
| 165 183 |  | 
| 166 184 | 
             
                def wait_for_restart(body)
         | 
| 167 | 
            -
                  json =  | 
| 185 | 
            +
                  json = Oj.load(body)
         | 
| 168 186 | 
             
                  ts_value = json["restart"]["last-startup"][0]["value"]
         | 
| 169 187 | 
             
                  timestamp = DateTime.iso8601(ts_value).to_time
         | 
| 170 188 | 
             
                  new_timestamp = timestamp
         | 
| 171 189 |  | 
| 172 190 | 
             
                  code = nil
         | 
| 173 191 | 
             
                  logger.debug "Waiting for restart"
         | 
| 174 | 
            -
                  until code == 200  | 
| 192 | 
            +
                  until code == 200 && new_timestamp > timestamp
         | 
| 175 193 | 
             
                    begin
         | 
| 176 194 | 
             
                      rr = get(%Q{/admin/v1/timestamp})
         | 
| 177 195 | 
             
                      code = rr.code.to_i
         | 
| @@ -202,65 +220,61 @@ module MarkLogic | |
| 202 220 | 
             
                end
         | 
| 203 221 |  | 
| 204 222 | 
             
                def split_multipart(response)
         | 
| 205 | 
            -
                   | 
| 206 | 
            -
                    body = response.body
         | 
| 223 | 
            +
                  body = response.body
         | 
| 207 224 |  | 
| 208 | 
            -
             | 
| 209 | 
            -
             | 
| 210 | 
            -
             | 
| 211 | 
            -
             | 
| 225 | 
            +
                  if body.nil? || body.length == 0
         | 
| 226 | 
            +
                    response.body = nil
         | 
| 227 | 
            +
                    return
         | 
| 228 | 
            +
                  end
         | 
| 229 | 
            +
             | 
| 230 | 
            +
                  content_type = response['Content-Type']
         | 
| 231 | 
            +
                  if (content_type && content_type.match(/multipart\/mixed.*/))
         | 
| 232 | 
            +
                    boundary = $1 if content_type =~ /^.*boundary=(.*)$/
         | 
| 212 233 |  | 
| 213 | 
            -
                     | 
| 214 | 
            -
                     | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
                       | 
| 219 | 
            -
             | 
| 220 | 
            -
                       | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 223 | 
            -
             | 
| 224 | 
            -
             | 
| 225 | 
            -
             | 
| 226 | 
            -
             | 
| 227 | 
            -
             | 
| 228 | 
            -
             | 
| 229 | 
            -
                          if meta.match(/^Content-Type:.*/m)
         | 
| 230 | 
            -
                            value_content_type = $1 if meta =~ /Content-Type:\s+(.*)$/
         | 
| 231 | 
            -
                          elsif meta.match(/^X-Primitive:.*/)
         | 
| 232 | 
            -
                            type = $1 if meta =~ /X-Primitive:\s+(.*)$/
         | 
| 233 | 
            -
                          elsif meta.match(/^X-Path:.*/)
         | 
| 234 | 
            -
                            xpath = $1 if meta =~ /X-Path:\s+(.*)$/
         | 
| 235 | 
            -
                          end
         | 
| 234 | 
            +
                    body.sub!(END_BOUNDARY_REGEX, "")
         | 
| 235 | 
            +
                    body.sub!(START_BOUNDARY_REGEX, "")
         | 
| 236 | 
            +
             | 
| 237 | 
            +
                    values = []
         | 
| 238 | 
            +
                    body.split(BOUNDARY_SPLITTER_REGEX).each do |item|
         | 
| 239 | 
            +
                      splits = item.split(DOUBLE_NEWLINE_SPLITTER)
         | 
| 240 | 
            +
                      metas = splits[0]
         | 
| 241 | 
            +
                      raw_value = splits[1]
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                      value_content_type = type = nil
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                      metas.split(NEWLINE_SPLITTER).each do |meta|
         | 
| 246 | 
            +
                        if meta =~ CONTENT_TYPE_REGEX
         | 
| 247 | 
            +
                          value_content_type = $1
         | 
| 248 | 
            +
                        elsif meta =~ PRIMITIVE_REGEX
         | 
| 249 | 
            +
                          type = $1
         | 
| 236 250 | 
             
                        end
         | 
| 251 | 
            +
                      end
         | 
| 237 252 |  | 
| 238 | 
            -
             | 
| 239 | 
            -
             | 
| 253 | 
            +
                      if (value_content_type == "application/json") then
         | 
| 254 | 
            +
                        value = Oj.load(raw_value)
         | 
| 255 | 
            +
                      else
         | 
| 256 | 
            +
                        case type
         | 
| 257 | 
            +
                        when "integer"
         | 
| 258 | 
            +
                          value = raw_value.to_i
         | 
| 259 | 
            +
                        when "boolean"
         | 
| 260 | 
            +
                          value = raw_value == "true"
         | 
| 261 | 
            +
                        when "decimal"
         | 
| 262 | 
            +
                          value = raw_value.to_f
         | 
| 240 263 | 
             
                        else
         | 
| 241 | 
            -
                           | 
| 242 | 
            -
                          when "integer"
         | 
| 243 | 
            -
                            value = raw_value.to_i
         | 
| 244 | 
            -
                          when "boolean"
         | 
| 245 | 
            -
                            value = raw_value == "true"
         | 
| 246 | 
            -
                          when "decimal"
         | 
| 247 | 
            -
                            value = raw_value.to_f
         | 
| 248 | 
            -
                          else
         | 
| 249 | 
            -
                            value = raw_value
         | 
| 250 | 
            -
                          end
         | 
| 264 | 
            +
                          value = raw_value
         | 
| 251 265 | 
             
                        end
         | 
| 252 | 
            -
                        values.push(value)
         | 
| 253 266 | 
             
                      end
         | 
| 267 | 
            +
                      values.push(value)
         | 
| 268 | 
            +
                    end
         | 
| 254 269 |  | 
| 255 | 
            -
             | 
| 256 | 
            -
             | 
| 257 | 
            -
                      end
         | 
| 258 | 
            -
                      output = values
         | 
| 259 | 
            -
                    else
         | 
| 260 | 
            -
                      output = body
         | 
| 270 | 
            +
                    if (values.length == 1)
         | 
| 271 | 
            +
                      values = values[0]
         | 
| 261 272 | 
             
                    end
         | 
| 262 | 
            -
                     | 
| 273 | 
            +
                    output = values
         | 
| 274 | 
            +
                  else
         | 
| 275 | 
            +
                    output = body
         | 
| 263 276 | 
             
                  end
         | 
| 277 | 
            +
                  response.body = output
         | 
| 264 278 | 
             
                end
         | 
| 265 279 |  | 
| 266 280 | 
             
                def request(url, verb = 'get', headers = {}, body = nil, params = nil)
         | 
| @@ -281,12 +295,20 @@ module MarkLogic | |
| 281 295 | 
             
                    request.digest_auth(@username, @password, @auth)
         | 
| 282 296 | 
             
                  end
         | 
| 283 297 |  | 
| 284 | 
            -
                   | 
| 285 | 
            -
             | 
| 298 | 
            +
                  if params
         | 
| 299 | 
            +
                    # query = URI.encode_www_form(params)
         | 
| 300 | 
            +
                    # query.gsub!(/&/, sep) if sep != '&'
         | 
| 301 | 
            +
                    # self.body = query
         | 
| 302 | 
            +
                    # request['content-type'] = 'application/x-www-form-urlencoded'
         | 
| 303 | 
            +
                    request.set_form_data(params) if (params)
         | 
| 304 | 
            +
                  elsif body
         | 
| 305 | 
            +
                    request.body = body if (body)
         | 
| 306 | 
            +
                  end
         | 
| 286 307 |  | 
| 287 | 
            -
                   | 
| 308 | 
            +
                  full_url = URI("http://#{@host}:#{@port}#{url}")
         | 
| 309 | 
            +
                  response = @http.request full_url, request
         | 
| 288 310 |  | 
| 289 | 
            -
                  if (response.code.to_i == 401  | 
| 311 | 
            +
                  if (response.code.to_i == 401 && @username && @password)
         | 
| 290 312 | 
             
                    auth_method = $1.downcase if response['www-authenticate'] =~ /^(\w+) (.*)/
         | 
| 291 313 | 
             
                    if (auth_method == "basic")
         | 
| 292 314 | 
             
                      request.basic_auth(@username, @password)
         | 
| @@ -294,7 +316,7 @@ module MarkLogic | |
| 294 316 | 
             
                      @auth = request.create_digest_auth(@username, @password, response)
         | 
| 295 317 | 
             
                    end
         | 
| 296 318 |  | 
| 297 | 
            -
                    response = @http.request request
         | 
| 319 | 
            +
                    response = @http.request full_url, request
         | 
| 298 320 | 
             
                  end
         | 
| 299 321 |  | 
| 300 322 | 
             
                  # puts("#{response.code} : #{verb.upcase} => ://#{@host}:#{@port}#{url} :: #{body} #{params}")
         | 
    
        data/lib/marklogic/cursor.rb
    CHANGED
    
    | @@ -155,7 +155,7 @@ module MarkLogic | |
| 155 155 | 
             
                end
         | 
| 156 156 |  | 
| 157 157 | 
             
                def has_sort?
         | 
| 158 | 
            -
                  @options.has_key?(:sort)  | 
| 158 | 
            +
                  @options.has_key?(:sort) || @options.has_key?(:order)
         | 
| 159 159 | 
             
                end
         | 
| 160 160 |  | 
| 161 161 | 
             
                def query
         | 
| @@ -170,7 +170,7 @@ module MarkLogic | |
| 170 170 |  | 
| 171 171 | 
             
                  sorters.map do |sorter|
         | 
| 172 172 | 
             
                    name = sorter[0].to_s
         | 
| 173 | 
            -
                    direction = (sorter[1]  | 
| 173 | 
            +
                    direction = (sorter[1] && (sorter[1] == -1)) ? "descending" : "ascending"
         | 
| 174 174 |  | 
| 175 175 |  | 
| 176 176 | 
             
                    if @collection.database.has_range_index?(name)
         | 
| @@ -197,7 +197,7 @@ module MarkLogic | |
| 197 197 |  | 
| 198 198 | 
             
                  sorters.map do |sorter|
         | 
| 199 199 | 
             
                    name = sorter[0].to_s
         | 
| 200 | 
            -
                    direction = (sorter[1]  | 
| 200 | 
            +
                    direction = (sorter[1] && (sorter[1] == -1)) ? "descending" : "ascending"
         | 
| 201 201 |  | 
| 202 202 | 
             
                    unless @collection.database.has_range_index?(name)
         | 
| 203 203 | 
             
                      raise MissingIndexError.new("Missing index on #{name}")
         | 
    
        data/lib/marklogic/database.rb
    CHANGED
    
    | @@ -31,6 +31,29 @@ module MarkLogic | |
| 31 31 | 
             
                  reset_indexes
         | 
| 32 32 | 
             
                end
         | 
| 33 33 |  | 
| 34 | 
            +
                def self.load(database_name, conn = nil)
         | 
| 35 | 
            +
                  db = Database.new(database_name, conn)
         | 
| 36 | 
            +
                  db.load
         | 
| 37 | 
            +
                  db
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def load
         | 
| 41 | 
            +
                  resp = manage_connection.get(%Q{/manage/v2/databases/#{database_name}/properties?format=json})
         | 
| 42 | 
            +
                  if resp.code.to_i == 200
         | 
| 43 | 
            +
                    options = Oj.load(resp.body)
         | 
| 44 | 
            +
                    options.each do |key, value|
         | 
| 45 | 
            +
                      self[key] = value
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def inspect
         | 
| 51 | 
            +
                  as_nice_string = @options.collect do |key, value|
         | 
| 52 | 
            +
                    " #{key}: #{value.inspect}"
         | 
| 53 | 
            +
                  end.sort.join(",")
         | 
| 54 | 
            +
                  "#<#{self.class}#{as_nice_string}>"
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 34 57 | 
             
                def []=(key, value)
         | 
| 35 58 | 
             
                  @options[key] = value
         | 
| 36 59 | 
             
                end
         | 
| @@ -121,7 +144,7 @@ module MarkLogic | |
| 121 144 | 
             
                  response = manage_connection.get(%Q{/manage/v2/databases/#{database_name}/properties?format=json})
         | 
| 122 145 | 
             
                  raise Exception.new("Invalid response: #{response.code.to_i}: #{response.body}") if (response.code.to_i != 200)
         | 
| 123 146 |  | 
| 124 | 
            -
                  props =  | 
| 147 | 
            +
                  props = Oj.load(response.body)
         | 
| 125 148 |  | 
| 126 149 | 
             
                  INDEX_KEYS.each do |key|
         | 
| 127 150 | 
             
                    if props[key]
         | 
| @@ -131,7 +154,7 @@ module MarkLogic | |
| 131 154 | 
             
                        logger.debug "#{database_name}: #{local} != #{remote}"
         | 
| 132 155 | 
             
                        return true
         | 
| 133 156 | 
             
                      end
         | 
| 134 | 
            -
                    elsif @options.has_key?(key)  | 
| 157 | 
            +
                    elsif @options.has_key?(key) && @options[key] != []
         | 
| 135 158 | 
             
                      logger.debug "#{database_name}: #{key} is not on the remote end"
         | 
| 136 159 | 
             
                      return true
         | 
| 137 160 | 
             
                    end
         | 
| @@ -199,7 +222,12 @@ module MarkLogic | |
| 199 222 | 
             
                end
         | 
| 200 223 |  | 
| 201 224 | 
             
                def collections()
         | 
| 202 | 
            -
                   | 
| 225 | 
            +
                  res = connection.run_query('cts:collections()', "xquery")
         | 
| 226 | 
            +
                  if res.code.to_i == 200
         | 
| 227 | 
            +
                    return res.body || []
         | 
| 228 | 
            +
                  else
         | 
| 229 | 
            +
                    raise MissingCollectionLexiconError.new if res.body =~ /XDMP-COLLXCNNOTFOUND/
         | 
| 230 | 
            +
                  end
         | 
| 203 231 | 
             
                end
         | 
| 204 232 | 
             
              end
         | 
| 205 233 | 
             
            end
         | 
    
        data/lib/marklogic/exceptions.rb
    CHANGED
    
    
    
        data/lib/marklogic/forest.rb
    CHANGED
    
    | @@ -13,6 +13,22 @@ module MarkLogic | |
| 13 13 | 
             
                  }
         | 
| 14 14 | 
             
                end
         | 
| 15 15 |  | 
| 16 | 
            +
                def self.load(forest_name, host_name = nil, conn = nil)
         | 
| 17 | 
            +
                  db = Forest.new(forest_name, host_name, conn)
         | 
| 18 | 
            +
                  db.load
         | 
| 19 | 
            +
                  db
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def load
         | 
| 23 | 
            +
                  resp = manage_connection.get(%Q{/manage/v2/forests/#{forest_name}/properties?format=json})
         | 
| 24 | 
            +
                  if resp.code.to_i == 200
         | 
| 25 | 
            +
                    options = Oj.load(resp.body)
         | 
| 26 | 
            +
                    options.each do |key, value|
         | 
| 27 | 
            +
                      self[key] = value
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 16 32 | 
             
                def []=(key, value)
         | 
| 17 33 | 
             
                  @options[key] = value
         | 
| 18 34 | 
             
                end
         | 
| @@ -1,6 +1,25 @@ | |
| 1 1 | 
             
            module MarkLogic
         | 
| 2 2 | 
             
              module Persistence
         | 
| 3 3 | 
             
                include MarkLogic::Loggable
         | 
| 4 | 
            +
                extend ActiveSupport::Concern
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                module ClassMethods
         | 
| 7 | 
            +
                  def manage_connection=(manage_conn)
         | 
| 8 | 
            +
                    @@manage_connection = manage_conn if manage_conn
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def manage_connection
         | 
| 12 | 
            +
                    @@manage_connection ||= MarkLogic::Connection.manage_connection
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def admin_connection=(admin_conn)
         | 
| 16 | 
            +
                    @@admin_connection = admin_conn if admin_conn
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def admin_connection
         | 
| 20 | 
            +
                    @@admin_connection ||= MarkLogic::Connection.admin_connection
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 4 23 |  | 
| 5 24 | 
             
                def connection=(conn)
         | 
| 6 25 | 
             
                  @connection = conn if conn
         | 
    
        data/lib/marklogic/version.rb
    CHANGED
    
    
    
        data/marklogic.gemspec
    CHANGED
    
    | @@ -19,5 +19,7 @@ Gem::Specification.new do |spec| | |
| 19 19 | 
             
              spec.require_paths = ['lib']
         | 
| 20 20 | 
             
              spec.has_rdoc        = 'yard'
         | 
| 21 21 |  | 
| 22 | 
            +
              spec.add_runtime_dependency 'net-http-persistent', '~> 2.9', '>= 2.9.4'
         | 
| 23 | 
            +
              spec.add_runtime_dependency 'oj', '~> 2.12', '>= 2.12.2'
         | 
| 22 24 | 
             
              spec.add_runtime_dependency 'activesupport', '~> 4.2', '>= 4.2.0'
         | 
| 23 25 | 
             
            end
         | 
| @@ -18,4 +18,14 @@ describe MarkLogic::AppServer do | |
| 18 18 | 
             
                end
         | 
| 19 19 |  | 
| 20 20 | 
             
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              describe "load" do
         | 
| 23 | 
            +
                it "should load an existing config from the server" do
         | 
| 24 | 
            +
                  app = MarkLogic::AppServer.load('App-Services')
         | 
| 25 | 
            +
                  expect(app['server-name']).to eq('App-Services')
         | 
| 26 | 
            +
                  expect(app['content-database']).to eq('Documents')
         | 
| 27 | 
            +
                  expect(app['modules-database']).to eq('Modules')
         | 
| 28 | 
            +
                  expect(app['port']).to eq(8000)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 21 31 | 
             
            end
         | 
| @@ -102,4 +102,18 @@ describe MarkLogic::Application do | |
| 102 102 | 
             
                  expect(@a).to be_stale
         | 
| 103 103 | 
             
                end
         | 
| 104 104 | 
             
              end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
              describe "load" do
         | 
| 107 | 
            +
                it "should load from existing config" do
         | 
| 108 | 
            +
                  app = MarkLogic::Application.load('App-Services', connection: CONNECTION)
         | 
| 109 | 
            +
                  expect(app.port).to eq(8000)
         | 
| 110 | 
            +
                  expect(app.app_servers.count).to eq(1)
         | 
| 111 | 
            +
                  expect(app.app_servers['App-Services'].server_name).to eq('App-Services')
         | 
| 112 | 
            +
                  expect(app.content_databases.count).to eq(1)
         | 
| 113 | 
            +
                  expect(app.content_databases.first.database_name).to eq('Documents')
         | 
| 114 | 
            +
                  expect(app.content_databases.first['forest']).to eq(['Documents'])
         | 
| 115 | 
            +
                  expect(app.modules_databases.count).to eq(1)
         | 
| 116 | 
            +
                  expect(app.modules_databases.first.database_name).to eq('Modules')
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
              end
         | 
| 105 119 | 
             
            end
         | 
| @@ -104,6 +104,14 @@ describe MarkLogic::Connection do | |
| 104 104 | 
             
                it "should split properly when a crazy object is returned" do
         | 
| 105 105 | 
             
                  expect(@b.run_query(%Q{x = { stuff: [1, 2, 3], junk: false}; x}).body).to eq({"stuff" => [1, 2, 3], "junk" => false})
         | 
| 106 106 | 
             
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                it "should handle url unencoded stuff" do
         | 
| 109 | 
            +
                  expect(@b.run_query(%Q{
         | 
| 110 | 
            +
                    let $x := "Hi & stuff"
         | 
| 111 | 
            +
                    return
         | 
| 112 | 
            +
                      $x
         | 
| 113 | 
            +
                  }, 'xquery').body).to eq("Hi & stuff")
         | 
| 114 | 
            +
                end
         | 
| 107 115 | 
             
              end
         | 
| 108 116 |  | 
| 109 117 | 
             
              describe "#digest" do
         | 
    
        metadata
    CHANGED
    
    | @@ -1,15 +1,55 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: marklogic
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Paxton Hare
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2015-04- | 
| 11 | 
            +
            date: 2015-04-16 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: net-http-persistent
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '2.9'
         | 
| 20 | 
            +
                - - ">="
         | 
| 21 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 22 | 
            +
                    version: 2.9.4
         | 
| 23 | 
            +
              type: :runtime
         | 
| 24 | 
            +
              prerelease: false
         | 
| 25 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 26 | 
            +
                requirements:
         | 
| 27 | 
            +
                - - "~>"
         | 
| 28 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 29 | 
            +
                    version: '2.9'
         | 
| 30 | 
            +
                - - ">="
         | 
| 31 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 32 | 
            +
                    version: 2.9.4
         | 
| 33 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 34 | 
            +
              name: oj
         | 
| 35 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 36 | 
            +
                requirements:
         | 
| 37 | 
            +
                - - "~>"
         | 
| 38 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 39 | 
            +
                    version: '2.12'
         | 
| 40 | 
            +
                - - ">="
         | 
| 41 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 42 | 
            +
                    version: 2.12.2
         | 
| 43 | 
            +
              type: :runtime
         | 
| 44 | 
            +
              prerelease: false
         | 
| 45 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 46 | 
            +
                requirements:
         | 
| 47 | 
            +
                - - "~>"
         | 
| 48 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 49 | 
            +
                    version: '2.12'
         | 
| 50 | 
            +
                - - ">="
         | 
| 51 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 52 | 
            +
                    version: 2.12.2
         | 
| 13 53 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 54 | 
             
              name: activesupport
         | 
| 15 55 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -145,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 145 185 | 
             
                  version: '0'
         | 
| 146 186 | 
             
            requirements: []
         | 
| 147 187 | 
             
            rubyforge_project: 
         | 
| 148 | 
            -
            rubygems_version: 2.4. | 
| 188 | 
            +
            rubygems_version: 2.4.6
         | 
| 149 189 | 
             
            signing_key: 
         | 
| 150 190 | 
             
            specification_version: 4
         | 
| 151 191 | 
             
            summary: A Ruby Driver for MarkLogic
         |