vayacondios-server 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -0
- data/config/vcd-server.rb +4 -4
- data/features/events.feature +142 -2
- data/features/stashes.feature +106 -5
- data/lib/vayacondios.rb +1 -1
- data/lib/vayacondios/server/api_options.rb +5 -3
- data/lib/vayacondios/server/configuration.rb +8 -6
- data/lib/vayacondios/server/drivers/mongo.rb +13 -10
- data/lib/vayacondios/server/models/document.rb +12 -4
- data/lib/vayacondios/server/models/event.rb +22 -8
- data/lib/vayacondios/server/models/stash.rb +7 -7
- data/spec/server/api_options_spec.rb +1 -1
- data/spec/server/configuration_spec.rb +31 -10
- data/spec/server/models/document_spec.rb +50 -3
- data/vayacondios-server.gemspec +1 -1
- metadata +6 -6
    
        data/Gemfile
    CHANGED
    
    | @@ -2,6 +2,8 @@ source 'https://rubygems.org' | |
| 2 2 |  | 
| 3 3 | 
             
            # em-mongo is too loose with its dependencies; 2.0.0 bson breaks vcd
         | 
| 4 4 | 
             
            gem 'bson', '1.9.2'
         | 
| 5 | 
            +
            # cookiejar 0.3.1 has busted file permissions WTF
         | 
| 6 | 
            +
            gem 'cookiejar', '0.3.0'
         | 
| 5 7 |  | 
| 6 8 | 
             
            gemspec name: 'vayacondios-server'
         | 
| 7 9 | 
             
            gemspec name: 'vayacondios-client'
         | 
    
        data/config/vcd-server.rb
    CHANGED
    
    | @@ -10,10 +10,10 @@ | |
| 10 10 | 
             
            # The production environment uses EventMachine::Synchrony to define a
         | 
| 11 11 | 
             
            # shared pool of open connections to the database. The size of this pool
         | 
| 12 12 | 
             
            # can be on the command-line with the --database.connections option.
         | 
| 13 | 
            -
            Vayacondios::Server::DbConfig.overlay options | 
| 13 | 
            +
            Vayacondios::Server::DbConfig.overlay options
         | 
| 14 14 |  | 
| 15 15 | 
             
            environment(:production) do
         | 
| 16 | 
            -
              db_options = Vayacondios::Server::DbConfig.env | 
| 16 | 
            +
              db_options = Vayacondios::Server::DbConfig.env(:production)[:database]
         | 
| 17 17 | 
             
              driver = Vayacondios::Server::Driver.retrieve db_options[:driver]
         | 
| 18 18 | 
             
              logger.info("Opening #{db_options[:connections]} connections to #{db_options[:host]}:#{db_options[:port]} using #{driver}.")
         | 
| 19 19 | 
             
              config['db'] = EventMachine::Synchrony::ConnectionPool.new(size: db_options[:connections]) do
         | 
| @@ -23,14 +23,14 @@ end | |
| 23 23 |  | 
| 24 24 | 
             
            # The development environment uses a single database connection.
         | 
| 25 25 | 
             
            environment(:development) do
         | 
| 26 | 
            -
              db_options = Vayacondios::Server::DbConfig.env | 
| 26 | 
            +
              db_options = Vayacondios::Server::DbConfig.env(:development)[:database]
         | 
| 27 27 | 
             
              driver = Vayacondios::Server::Driver.retrieve db_options[:driver]
         | 
| 28 28 | 
             
              logger.info("Connecting to #{db_options[:host]}:#{db_options[:port]} using #{driver}.")
         | 
| 29 29 | 
             
              config['db'] = driver.connect db_options.merge(log: logger)
         | 
| 30 30 | 
             
            end
         | 
| 31 31 |  | 
| 32 32 | 
             
            environment(:test) do
         | 
| 33 | 
            -
              db_options = Vayacondios::Server::DbConfig.env | 
| 33 | 
            +
              db_options = Vayacondios::Server::DbConfig.env(:test)[:database]
         | 
| 34 34 | 
             
              driver = Vayacondios::Server::Driver.retrieve db_options[:driver]
         | 
| 35 35 | 
             
              logger.info("Connecting to #{db_options[:host]}:#{db_options[:port]} using #{driver}.")
         | 
| 36 36 | 
             
              config['db'] = driver.connect db_options.merge(log: logger)
         | 
    
        data/features/events.feature
    CHANGED
    
    | @@ -86,6 +86,146 @@ Feature: Events | |
| 86 86 | 
             
                ]
         | 
| 87 87 | 
             
                """
         | 
| 88 88 |  | 
| 89 | 
            +
              Scenario: Retrieving Existing Events with a Limit Query
         | 
| 90 | 
            +
                Given the following Event exists under topic "topic" in the database:
         | 
| 91 | 
            +
                """
         | 
| 92 | 
            +
                {
         | 
| 93 | 
            +
                  "_id": "id1",
         | 
| 94 | 
            +
                  "_t": "2012-02-13T12:34:42.452Z",
         | 
| 95 | 
            +
                  "_d": {
         | 
| 96 | 
            +
                    "alignment": "good"
         | 
| 97 | 
            +
                  }
         | 
| 98 | 
            +
                }
         | 
| 99 | 
            +
                """
         | 
| 100 | 
            +
                And   the following Event exists under topic "topic" in the database:
         | 
| 101 | 
            +
                """
         | 
| 102 | 
            +
                {
         | 
| 103 | 
            +
                  "_id": "id2",
         | 
| 104 | 
            +
                  "_t": "2012-02-13T12:34:42.452Z",
         | 
| 105 | 
            +
                  "_d": {
         | 
| 106 | 
            +
                    "alignment": "evil"
         | 
| 107 | 
            +
                  }
         | 
| 108 | 
            +
                }
         | 
| 109 | 
            +
                """
         | 
| 110 | 
            +
                When  the client sends a GET request to "/v3/organization/events/topic" with the following body:
         | 
| 111 | 
            +
                """
         | 
| 112 | 
            +
                {
         | 
| 113 | 
            +
                  "sort": "alignment",
         | 
| 114 | 
            +
                  "order": "desc",
         | 
| 115 | 
            +
                  "limit": 1
         | 
| 116 | 
            +
                }
         | 
| 117 | 
            +
                """
         | 
| 118 | 
            +
                Then  the response status should be 200
         | 
| 119 | 
            +
                And   the response body should be:
         | 
| 120 | 
            +
                """
         | 
| 121 | 
            +
                [
         | 
| 122 | 
            +
                  {
         | 
| 123 | 
            +
                    "id": "id1",
         | 
| 124 | 
            +
                    "time": "2012-02-13T12:34:42.452Z",
         | 
| 125 | 
            +
                    "alignment": "good"
         | 
| 126 | 
            +
                  }
         | 
| 127 | 
            +
                ]
         | 
| 128 | 
            +
                """
         | 
| 129 | 
            +
             | 
| 130 | 
            +
              Scenario: Retrieving Existing Events with a Sort Query
         | 
| 131 | 
            +
                Given the following Event exists under topic "topic" in the database:
         | 
| 132 | 
            +
                """
         | 
| 133 | 
            +
                {
         | 
| 134 | 
            +
                  "_id": "id1",
         | 
| 135 | 
            +
                  "_t": "2012-02-13T12:34:43.452Z",
         | 
| 136 | 
            +
                  "_d": {
         | 
| 137 | 
            +
                    "alignment": "good"
         | 
| 138 | 
            +
                  }
         | 
| 139 | 
            +
                }
         | 
| 140 | 
            +
                """
         | 
| 141 | 
            +
                And   the following Event exists under topic "topic" in the database:
         | 
| 142 | 
            +
                """
         | 
| 143 | 
            +
                {
         | 
| 144 | 
            +
                  "_id": "id2",
         | 
| 145 | 
            +
                  "_t": "2012-02-13T12:34:42.452Z",
         | 
| 146 | 
            +
                  "_d": {
         | 
| 147 | 
            +
                    "alignment": "neutral"
         | 
| 148 | 
            +
                  }
         | 
| 149 | 
            +
                }
         | 
| 150 | 
            +
                """
         | 
| 151 | 
            +
                And   the following Event exists under topic "topic" in the database:
         | 
| 152 | 
            +
                """
         | 
| 153 | 
            +
                {
         | 
| 154 | 
            +
                  "_id": "id3",
         | 
| 155 | 
            +
                  "_t": "2012-02-13T12:34:45.452Z",
         | 
| 156 | 
            +
                  "_d": {
         | 
| 157 | 
            +
                    "alignment": "evil"
         | 
| 158 | 
            +
                  }
         | 
| 159 | 
            +
                }
         | 
| 160 | 
            +
                """
         | 
| 161 | 
            +
                When  the client sends a GET request to "/v3/organization/events/topic" with the following body:
         | 
| 162 | 
            +
                """
         | 
| 163 | 
            +
                {
         | 
| 164 | 
            +
                  "sort": "alignment",
         | 
| 165 | 
            +
                  "order": "asc"
         | 
| 166 | 
            +
                }
         | 
| 167 | 
            +
                """
         | 
| 168 | 
            +
                Then  the response status should be 200
         | 
| 169 | 
            +
                And   the response body should be:
         | 
| 170 | 
            +
                """
         | 
| 171 | 
            +
                [
         | 
| 172 | 
            +
                  {
         | 
| 173 | 
            +
                    "id": "id3",
         | 
| 174 | 
            +
                    "time": "2012-02-13T12:34:45.452Z",
         | 
| 175 | 
            +
                    "alignment": "evil"
         | 
| 176 | 
            +
                  },
         | 
| 177 | 
            +
                  {
         | 
| 178 | 
            +
                    "id": "id1",
         | 
| 179 | 
            +
                    "time": "2012-02-13T12:34:43.452Z",
         | 
| 180 | 
            +
                    "alignment": "good"
         | 
| 181 | 
            +
                  },
         | 
| 182 | 
            +
                  {
         | 
| 183 | 
            +
                    "id": "id2",
         | 
| 184 | 
            +
                    "time": "2012-02-13T12:34:42.452Z",
         | 
| 185 | 
            +
                    "alignment": "neutral"
         | 
| 186 | 
            +
                  }
         | 
| 187 | 
            +
                ]
         | 
| 188 | 
            +
                """
         | 
| 189 | 
            +
             | 
| 190 | 
            +
              Scenario: Retrieving Existing Events with a Fields Query
         | 
| 191 | 
            +
                Given the following Event exists under topic "topic" in the database:
         | 
| 192 | 
            +
                """
         | 
| 193 | 
            +
                {
         | 
| 194 | 
            +
                  "_id": "id1",
         | 
| 195 | 
            +
                  "_t": "2012-02-13T12:34:42.452Z",
         | 
| 196 | 
            +
                  "_d": {
         | 
| 197 | 
            +
                    "alignment": "good"
         | 
| 198 | 
            +
                  }
         | 
| 199 | 
            +
                }
         | 
| 200 | 
            +
                """
         | 
| 201 | 
            +
                And   the following Event exists under topic "topic" in the database:
         | 
| 202 | 
            +
                """
         | 
| 203 | 
            +
                {
         | 
| 204 | 
            +
                  "_id": "id2",
         | 
| 205 | 
            +
                  "_t": "2012-02-13T12:34:42.452Z",
         | 
| 206 | 
            +
                  "_d": {
         | 
| 207 | 
            +
                    "alignment": "evil"
         | 
| 208 | 
            +
                  }
         | 
| 209 | 
            +
                }
         | 
| 210 | 
            +
                """
         | 
| 211 | 
            +
                When  the client sends a GET request to "/v3/organization/events/topic" with the following body:
         | 
| 212 | 
            +
                """
         | 
| 213 | 
            +
                {
         | 
| 214 | 
            +
                  "alignment": "good",
         | 
| 215 | 
            +
                  "fields": ["alignment", "id"]
         | 
| 216 | 
            +
                }
         | 
| 217 | 
            +
                """
         | 
| 218 | 
            +
                Then  the response status should be 200
         | 
| 219 | 
            +
                And   the response body should be:
         | 
| 220 | 
            +
                """
         | 
| 221 | 
            +
                [
         | 
| 222 | 
            +
                  {
         | 
| 223 | 
            +
                    "id": "id1",
         | 
| 224 | 
            +
                    "alignment": "good"
         | 
| 225 | 
            +
                  }
         | 
| 226 | 
            +
                ]
         | 
| 227 | 
            +
                """
         | 
| 228 | 
            +
             | 
| 89 229 | 
             
              Scenario: Creating Events
         | 
| 90 230 | 
             
                Given there are no Events under topic "topic" in the database
         | 
| 91 231 | 
             
                When  the client sends a POST request to "/v3/organization/events/topic" with no body
         | 
| @@ -136,7 +276,7 @@ Feature: Events | |
| 136 276 | 
             
                }
         | 
| 137 277 | 
             
                """
         | 
| 138 278 | 
             
                And   there are no Events under topic "topic" in the database
         | 
| 139 | 
            -
             | 
| 279 | 
            +
             | 
| 140 280 | 
             
              Scenario: Deleting Events with a Time Query
         | 
| 141 281 | 
             
                Given the following Event exists under topic "topic" in the database:
         | 
| 142 282 | 
             
                """
         | 
| @@ -157,7 +297,7 @@ Feature: Events | |
| 157 297 | 
             
                When  the client sends a DELETE request to "/v3/organization/events/topic" with the following body:
         | 
| 158 298 | 
             
                """
         | 
| 159 299 | 
             
                {
         | 
| 160 | 
            -
                  "after": "2012-01-01T00:00:00.000Z" | 
| 300 | 
            +
                  "after": "2012-01-01T00:00:00.000Z"
         | 
| 161 301 | 
             
                }
         | 
| 162 302 | 
             
                """
         | 
| 163 303 | 
             
                Then  the response status should be 200
         | 
    
        data/features/stashes.feature
    CHANGED
    
    | @@ -49,21 +49,30 @@ Feature: Stashes | |
| 49 49 | 
             
                """
         | 
| 50 50 | 
             
                {
         | 
| 51 51 | 
             
                  "_id": "topic",
         | 
| 52 | 
            -
                  "root": { | 
| 52 | 
            +
                  "root": {
         | 
| 53 53 | 
             
                    "b": 1
         | 
| 54 54 | 
             
                  }
         | 
| 55 55 | 
             
                }
         | 
| 56 56 | 
             
                """
         | 
| 57 | 
            +
                And the following Stash exists in the database:
         | 
| 58 | 
            +
                """
         | 
| 59 | 
            +
                {
         | 
| 60 | 
            +
                  "_id": "topic",
         | 
| 61 | 
            +
                  "root": {
         | 
| 62 | 
            +
                    "b": 5
         | 
| 63 | 
            +
                  }
         | 
| 64 | 
            +
                }
         | 
| 65 | 
            +
                """
         | 
| 57 66 | 
             
                When  the client sends a GET request to "/v3/organization/stashes" with the following body:
         | 
| 58 67 | 
             
                """
         | 
| 59 | 
            -
                { | 
| 60 | 
            -
                  "root.b": 1 | 
| 68 | 
            +
                {
         | 
| 69 | 
            +
                  "root.b": 1
         | 
| 61 70 | 
             
                }
         | 
| 62 71 | 
             
                """
         | 
| 63 72 | 
             
                Then  the response status should be 200
         | 
| 64 73 | 
             
                And   the response body should be:
         | 
| 65 74 | 
             
                """
         | 
| 66 | 
            -
                [ | 
| 75 | 
            +
                [
         | 
| 67 76 | 
             
                  {
         | 
| 68 77 | 
             
                    "topic": "topic",
         | 
| 69 78 | 
             
                    "root": {
         | 
| @@ -88,7 +97,7 @@ Feature: Stashes | |
| 88 97 | 
             
                """
         | 
| 89 98 | 
             
                When  the client sends a GET request to "/v3/organization/stashes" with the following body:
         | 
| 90 99 | 
             
                """
         | 
| 91 | 
            -
                { | 
| 100 | 
            +
                {
         | 
| 92 101 | 
             
                  "root.b": 1,
         | 
| 93 102 | 
             
                  "fields": ["root.a"]
         | 
| 94 103 | 
             
                }
         | 
| @@ -108,6 +117,98 @@ Feature: Stashes | |
| 108 117 | 
             
                ]
         | 
| 109 118 | 
             
                """
         | 
| 110 119 |  | 
| 120 | 
            +
              Scenario: Retrieving Stashes using Sorting
         | 
| 121 | 
            +
                Given the following Stash exists in the database:
         | 
| 122 | 
            +
                """
         | 
| 123 | 
            +
                {
         | 
| 124 | 
            +
                  "_id": "topic1",
         | 
| 125 | 
            +
                  "root": {
         | 
| 126 | 
            +
                    "a": {
         | 
| 127 | 
            +
                      "foo": 3
         | 
| 128 | 
            +
                    },
         | 
| 129 | 
            +
                    "b": 1
         | 
| 130 | 
            +
                  }
         | 
| 131 | 
            +
                }
         | 
| 132 | 
            +
                """
         | 
| 133 | 
            +
                And the following Stash exists in the database:
         | 
| 134 | 
            +
                """
         | 
| 135 | 
            +
                {
         | 
| 136 | 
            +
                  "_id": "topic2",
         | 
| 137 | 
            +
                  "root": {
         | 
| 138 | 
            +
                    "a": {
         | 
| 139 | 
            +
                      "foo": 2
         | 
| 140 | 
            +
                    },
         | 
| 141 | 
            +
                    "b": 1
         | 
| 142 | 
            +
                  }
         | 
| 143 | 
            +
                }
         | 
| 144 | 
            +
                """
         | 
| 145 | 
            +
                When  the client sends a GET request to "/v3/organization/stashes" with the following body:
         | 
| 146 | 
            +
                """
         | 
| 147 | 
            +
                {
         | 
| 148 | 
            +
                  "root.b": 1,
         | 
| 149 | 
            +
                  "sort": "root.a.foo",
         | 
| 150 | 
            +
                  "order": "asc"
         | 
| 151 | 
            +
                }
         | 
| 152 | 
            +
                """
         | 
| 153 | 
            +
                Then  the response status should be 200
         | 
| 154 | 
            +
                And   the response body should be:
         | 
| 155 | 
            +
                """
         | 
| 156 | 
            +
                [
         | 
| 157 | 
            +
                  {
         | 
| 158 | 
            +
                    "topic": "topic2",
         | 
| 159 | 
            +
                    "root": {
         | 
| 160 | 
            +
                      "a": {
         | 
| 161 | 
            +
                        "foo": 2
         | 
| 162 | 
            +
                      },
         | 
| 163 | 
            +
                      "b": 1
         | 
| 164 | 
            +
                    }
         | 
| 165 | 
            +
                  },
         | 
| 166 | 
            +
                  {
         | 
| 167 | 
            +
                    "topic": "topic1",
         | 
| 168 | 
            +
                    "root": {
         | 
| 169 | 
            +
                      "a": {
         | 
| 170 | 
            +
                        "foo": 3
         | 
| 171 | 
            +
                      },
         | 
| 172 | 
            +
                      "b": 1
         | 
| 173 | 
            +
                    }
         | 
| 174 | 
            +
                  }
         | 
| 175 | 
            +
                ]
         | 
| 176 | 
            +
                """
         | 
| 177 | 
            +
             | 
| 178 | 
            +
              Scenario: Retrieving Stashes using Limits
         | 
| 179 | 
            +
                Given the following Stash exists in the database:
         | 
| 180 | 
            +
                """
         | 
| 181 | 
            +
                {
         | 
| 182 | 
            +
                  "_id": "topic1",
         | 
| 183 | 
            +
                  "b": 1
         | 
| 184 | 
            +
                }
         | 
| 185 | 
            +
                """
         | 
| 186 | 
            +
                And the following Stash exists in the database:
         | 
| 187 | 
            +
                """
         | 
| 188 | 
            +
                {
         | 
| 189 | 
            +
                  "_id": "topic2",
         | 
| 190 | 
            +
                  "b": 1
         | 
| 191 | 
            +
                }
         | 
| 192 | 
            +
                """
         | 
| 193 | 
            +
                When  the client sends a GET request to "/v3/organization/stashes" with the following body:
         | 
| 194 | 
            +
                """
         | 
| 195 | 
            +
                {
         | 
| 196 | 
            +
                  "b": 1,
         | 
| 197 | 
            +
                  "limit": 1,
         | 
| 198 | 
            +
                  "order": "desc"
         | 
| 199 | 
            +
                }
         | 
| 200 | 
            +
                """
         | 
| 201 | 
            +
                Then  the response status should be 200
         | 
| 202 | 
            +
                And   the response body should be:
         | 
| 203 | 
            +
                """
         | 
| 204 | 
            +
                [
         | 
| 205 | 
            +
                  {
         | 
| 206 | 
            +
                    "topic": "topic2",
         | 
| 207 | 
            +
                    "b": 1
         | 
| 208 | 
            +
                  }
         | 
| 209 | 
            +
                ]
         | 
| 210 | 
            +
                """
         | 
| 211 | 
            +
             | 
| 111 212 | 
             
              Scenario: Creating Stashes without a Query
         | 
| 112 213 | 
             
                Given there are no matching Stashes in the database
         | 
| 113 214 | 
             
                When  the client sends a POST request to "/v3/organization/stashes" with no body
         | 
    
        data/lib/vayacondios.rb
    CHANGED
    
    
| @@ -29,9 +29,11 @@ module Vayacondios::Server | |
| 29 29 | 
             
                  opts.separator ''
         | 
| 30 30 | 
             
                  opts.separator 'Database options:'
         | 
| 31 31 |  | 
| 32 | 
            -
                  options[ | 
| 33 | 
            -
                   | 
| 34 | 
            -
                   | 
| 32 | 
            +
                  options[Goliath.env] ||= {}
         | 
| 33 | 
            +
                  options[Goliath.env][:database] ||= {}
         | 
| 34 | 
            +
                  db_options = options[Goliath.env][:database]
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  defaults = DbConfig.defaults[Goliath.env][:database]
         | 
| 35 37 | 
             
                  opts.on('-d', '--database.driver NAME', "Database driver (default: #{defaults[:driver]})") do |name|
         | 
| 36 38 | 
             
                    db_options[:driver] = name
         | 
| 37 39 | 
             
                  end
         | 
| @@ -2,22 +2,24 @@ module Vayacondios::Server | |
| 2 2 | 
             
              class Configuration < Vayacondios::Configuration
         | 
| 3 3 |  | 
| 4 4 | 
             
                def defaults
         | 
| 5 | 
            -
                  { 
         | 
| 6 | 
            -
                     | 
| 5 | 
            +
                  %w[development test production].inject({}) do |default_conf, type|
         | 
| 6 | 
            +
                    default_conf[type.to_sym] = {}
         | 
| 7 | 
            +
                    default_conf[type.to_sym][:database] = {
         | 
| 7 8 | 
             
                      driver:      'mongo',
         | 
| 8 9 | 
             
                      host:        'localhost',
         | 
| 9 10 | 
             
                      port:        27017,
         | 
| 10 | 
            -
                      name:         | 
| 11 | 
            +
                      name:        "vayacondios_#{type}",
         | 
| 11 12 | 
             
                      connections: 20,
         | 
| 12 13 | 
             
                    }
         | 
| 13 | 
            -
             | 
| 14 | 
            +
                    default_conf
         | 
| 15 | 
            +
                  end
         | 
| 14 16 | 
             
                end
         | 
| 15 17 |  | 
| 16 18 | 
             
                def env(handle = nil)
         | 
| 17 19 | 
             
                  handle ||= :development
         | 
| 18 20 | 
             
                  resolved_settings[handle.to_sym] || {}
         | 
| 19 | 
            -
                end | 
| 21 | 
            +
                end
         | 
| 20 22 | 
             
              end
         | 
| 21 | 
            -
             | 
| 23 | 
            +
             | 
| 22 24 | 
             
              DbConfig = Configuration.new('database.yml') unless defined? DbConfig
         | 
| 23 25 | 
             
            end
         | 
| @@ -50,10 +50,8 @@ module Vayacondios::Server | |
| 50 50 | 
             
                  sel = { }.tap do |sel|
         | 
| 51 51 | 
             
                    time = query.delete(:_t)
         | 
| 52 52 | 
             
                    sel[:_t] = time.inject({}){ |t, (k,v)| t[('$' + k.to_s).to_sym] = v ; t } if time
         | 
| 53 | 
            -
                     | 
| 54 | 
            -
             | 
| 55 | 
            -
                  end
         | 
| 56 | 
            -
                  query.merge(sel).compact_blank
         | 
| 53 | 
            +
                    sel.merge! to_dotted_hash(query)
         | 
| 54 | 
            +
                  end.compact_blank
         | 
| 57 55 | 
             
                end
         | 
| 58 56 |  | 
| 59 57 | 
             
                def to_dotted_hash(hsh, key_string = '')
         | 
| @@ -66,14 +64,19 @@ module Vayacondios::Server | |
| 66 64 | 
             
                    end
         | 
| 67 65 | 
             
                  end
         | 
| 68 66 | 
             
                end
         | 
| 69 | 
            -
             | 
| 67 | 
            +
             | 
| 70 68 | 
             
                def projector query
         | 
| 71 | 
            -
                   | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 69 | 
            +
                  order = query.delete(:order)
         | 
| 70 | 
            +
                  if order.to_s.match(/^(a|de)sc$/i)
         | 
| 71 | 
            +
                    order = order.to_sym
         | 
| 72 | 
            +
                  else
         | 
| 73 | 
            +
                    raise Error.new("Search order must be 'asc' or 'desc'. Invalid search order: #{order}")
         | 
| 75 74 | 
             
                  end
         | 
| 76 | 
            -
             | 
| 75 | 
            +
             | 
| 76 | 
            +
                  fields = query[:fields]
         | 
| 77 | 
            +
                  fields.map!{|field| field.join('.') } if fields.is_a? Array
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  query[:sort] = [query[:sort].join('.'), order]
         | 
| 77 80 | 
             
                  query
         | 
| 78 81 | 
             
                end
         | 
| 79 82 |  | 
| @@ -30,7 +30,7 @@ module Vayacondios::Server | |
| 30 30 | 
             
                def format_response result
         | 
| 31 31 | 
             
                  from_document(result.symbolize_keys.compact).external_document
         | 
| 32 32 | 
             
                end
         | 
| 33 | 
            -
             | 
| 33 | 
            +
             | 
| 34 34 | 
             
                # A class for errors that arise within documents due to internal or
         | 
| 35 35 | 
             
                # IO errors.
         | 
| 36 36 | 
             
                Error = Class.new(StandardError)
         | 
| @@ -54,7 +54,15 @@ module Vayacondios::Server | |
| 54 54 | 
             
                    params.symbolize_keys!
         | 
| 55 55 | 
             
                    opts = {}
         | 
| 56 56 | 
             
                    [:limit, :order, :sort, :fields].each{ |opt| opts[opt] = params.delete opt }
         | 
| 57 | 
            -
                    opts. | 
| 57 | 
            +
                    default_query_options.dup.merge(opts.compact).tap do |opts|
         | 
| 58 | 
            +
                      opts[:sort]   = opts[:sort].to_s.split('.')
         | 
| 59 | 
            +
                      if opts[:fields].is_a? Array
         | 
| 60 | 
            +
                        opts[:fields].map!{|field|
         | 
| 61 | 
            +
                          field = '_id' if field == 'id'
         | 
| 62 | 
            +
                          field.split('.')
         | 
| 63 | 
            +
                        }
         | 
| 64 | 
            +
                      end
         | 
| 65 | 
            +
                    end
         | 
| 58 66 | 
             
                  end
         | 
| 59 67 |  | 
| 60 68 | 
             
                  def search(params, query, &driver)
         | 
| @@ -63,7 +71,7 @@ module Vayacondios::Server | |
| 63 71 | 
             
                    result  = driver.call(action, action.filter, options)
         | 
| 64 72 | 
             
                    result.map{ |res| new.format_response res }
         | 
| 65 73 | 
             
                  end
         | 
| 66 | 
            -
             | 
| 74 | 
            +
             | 
| 67 75 | 
             
                  def create(params, document, &driver)
         | 
| 68 76 | 
             
                    action = receive(params).prepare_create(document)
         | 
| 69 77 | 
             
                    result = driver.call(action)
         | 
| @@ -76,7 +84,7 @@ module Vayacondios::Server | |
| 76 84 | 
             
                    return nil if result.nil?
         | 
| 77 85 | 
             
                    action.format_response result
         | 
| 78 86 | 
             
                  end
         | 
| 79 | 
            -
             | 
| 87 | 
            +
             | 
| 80 88 | 
             
                  def destroy(params, document, &driver)
         | 
| 81 89 | 
             
                    action = receive(params).prepare_destroy(document.symbolize_keys)
         | 
| 82 90 | 
             
                    result = driver.call(action, action.filter)
         | 
| @@ -10,7 +10,7 @@ | |
| 10 10 | 
             
            # POST /v2/coca_cola/event/ad_campaigns
         | 
| 11 11 | 
             
            # { "impresions": 23829, "errors": 29 }
         | 
| 12 12 | 
             
            # ```
         | 
| 13 | 
            -
            # | 
| 13 | 
            +
            #
         | 
| 14 14 | 
             
            # would result in a document in the `coca_cola.ad_campaigns.events`
         | 
| 15 15 | 
             
            # collection with the following structure:
         | 
| 16 16 | 
             
            #
         | 
| @@ -53,9 +53,9 @@ module Vayacondios::Server | |
| 53 53 |  | 
| 54 54 | 
             
                # The default number of events returned when searching.
         | 
| 55 55 | 
             
                LIMIT  = 50
         | 
| 56 | 
            -
             | 
| 56 | 
            +
             | 
| 57 57 | 
             
                # The default sort order when searching
         | 
| 58 | 
            -
                ORDER  = ' | 
| 58 | 
            +
                ORDER  = 'desc'
         | 
| 59 59 |  | 
| 60 60 | 
             
                # The default sort field when searching.
         | 
| 61 61 | 
             
                SORT   = 'time'
         | 
| @@ -65,7 +65,21 @@ module Vayacondios::Server | |
| 65 65 | 
             
                WINDOW = 3600
         | 
| 66 66 |  | 
| 67 67 | 
             
                def self.default_query_options
         | 
| 68 | 
            -
                  { limit: LIMIT, order: ORDER, sort: SORT } | 
| 68 | 
            +
                  { limit: LIMIT, order: ORDER, sort: SORT }
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                def self.extract_query_options! opts
         | 
| 72 | 
            +
                  query = super
         | 
| 73 | 
            +
                  if query[:sort] == ['time']
         | 
| 74 | 
            +
                    query[:sort] = ['_t']
         | 
| 75 | 
            +
                  elsif query[:sort].present?
         | 
| 76 | 
            +
                    query[:sort].unshift '_d'
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                  query[:fields].each{|field|
         | 
| 79 | 
            +
                    field.replace(['_t']) if field == ['time']
         | 
| 80 | 
            +
                    field.unshift('_d') unless %w[_id _t].include?(field.first)
         | 
| 81 | 
            +
                  } if query[:fields].present?
         | 
| 82 | 
            +
                  query
         | 
| 69 83 | 
             
                end
         | 
| 70 84 |  | 
| 71 85 | 
             
                field :time, Time   # assigned or Time.now.utc
         | 
| @@ -84,14 +98,14 @@ module Vayacondios::Server | |
| 84 98 | 
             
                  @time = format_time to_timestamp(t)
         | 
| 85 99 | 
             
                end
         | 
| 86 100 |  | 
| 87 | 
            -
                # Parses an object into a timestamp. | 
| 101 | 
            +
                # Parses an object into a timestamp.
         | 
| 88 102 | 
             
                #
         | 
| 89 103 | 
             
                # @param [String, Numeric, Time, nil] obj
         | 
| 90 104 | 
             
                # @param [Time] default the time value to return if none could be found in the `obj`
         | 
| 91 105 | 
             
                # @return [Time]
         | 
| 92 106 | 
             
                def to_timestamp(obj, default = Time.now)
         | 
| 93 107 | 
             
                  case obj
         | 
| 94 | 
            -
                  when String  then Time.parse(obj) | 
| 108 | 
            +
                  when String  then Time.parse(obj)
         | 
| 95 109 | 
             
                  when Date    then obj.to_time
         | 
| 96 110 | 
             
                  when Time    then obj
         | 
| 97 111 | 
             
                  when Numeric then Time.at(obj)
         | 
| @@ -130,7 +144,7 @@ module Vayacondios::Server | |
| 130 144 |  | 
| 131 145 | 
             
                # An event as presented to a user
         | 
| 132 146 | 
             
                def external_document
         | 
| 133 | 
            -
                  { id: id, time: time.iso8601(3) }.merge(body)
         | 
| 147 | 
            +
                  { id: id, time: (time ? time.iso8601(3) : nil) }.merge(body).compact
         | 
| 134 148 | 
             
                end
         | 
| 135 149 |  | 
| 136 150 | 
             
                # Returns a Hash that can be used for selection criteria in a query
         | 
| @@ -193,6 +207,6 @@ module Vayacondios::Server | |
| 193 207 | 
             
                def prepare_destroy query
         | 
| 194 208 | 
             
                  receive!(filter: event_filter(query))
         | 
| 195 209 | 
             
                  self
         | 
| 196 | 
            -
                end | 
| 210 | 
            +
                end
         | 
| 197 211 | 
             
              end
         | 
| 198 212 | 
             
            end
         | 
| @@ -25,15 +25,15 @@ module Vayacondios::Server | |
| 25 25 | 
             
                LIMIT = 50
         | 
| 26 26 |  | 
| 27 27 | 
             
                # The default sort order when searching.
         | 
| 28 | 
            -
                SORT  = ' | 
| 29 | 
            -
                ORDER = ' | 
| 28 | 
            +
                SORT  = '_id'
         | 
| 29 | 
            +
                ORDER = 'asc'
         | 
| 30 30 |  | 
| 31 31 | 
             
                # Returned as an acknowledgement of the request when there is no
         | 
| 32 32 | 
             
                # better option (#destroy, #update_many, &c.)
         | 
| 33 33 | 
             
                # OK = {ok: true}
         | 
| 34 34 |  | 
| 35 35 | 
             
                def self.default_query_options
         | 
| 36 | 
            -
                  { limit: LIMIT, order: ORDER, sort: SORT } | 
| 36 | 
            +
                  { limit: LIMIT, order: ORDER, sort: SORT }
         | 
| 37 37 | 
             
                end
         | 
| 38 38 |  | 
| 39 39 | 
             
                # The name of the collection this stash will store its data in.
         | 
| @@ -52,16 +52,16 @@ module Vayacondios::Server | |
| 52 52 | 
             
                    d[:topic] = doc.delete(:_id)
         | 
| 53 53 | 
             
                    doc = nil if doc.empty?
         | 
| 54 54 | 
             
                    if body.nil?
         | 
| 55 | 
            -
                      new_body = doc | 
| 55 | 
            +
                      new_body = doc
         | 
| 56 56 | 
             
                    else
         | 
| 57 57 | 
             
                      new_body = body.merge(doc || {})
         | 
| 58 | 
            -
                    end | 
| 58 | 
            +
                    end
         | 
| 59 59 | 
             
                    d[:body]  =  new_body
         | 
| 60 60 | 
             
                  end
         | 
| 61 61 | 
             
                  receive! d
         | 
| 62 62 | 
             
                  self
         | 
| 63 63 | 
             
                end
         | 
| 64 | 
            -
             | 
| 64 | 
            +
             | 
| 65 65 | 
             
                def external_document
         | 
| 66 66 | 
             
                  { topic: topic }.merge(body || {})
         | 
| 67 67 | 
             
                end
         | 
| @@ -76,7 +76,7 @@ module Vayacondios::Server | |
| 76 76 | 
             
                  if document.is_a? Hash
         | 
| 77 77 | 
             
                    document.symbolize_keys!
         | 
| 78 78 | 
             
                    raise Error.new ':topic is a reserved key and cannot be used in a stash document' if document.has_key?(:topic)
         | 
| 79 | 
            -
                  end | 
| 79 | 
            +
                  end
         | 
| 80 80 | 
             
                  if id.blank?
         | 
| 81 81 | 
             
                    raise Error.new 'If not including an Id, the document must be a Hash' unless document.is_a? Hash
         | 
| 82 82 | 
             
                    receive!(body: document)
         | 
| @@ -23,7 +23,7 @@ describe Vayacondios::Server::ApiOptions do | |
| 23 23 | 
             
                ARGV.replace %w[-d foo -h foo.com -D bar -o 1234 -n 10]
         | 
| 24 24 | 
             
                api.options_parser(parser, settings)
         | 
| 25 25 | 
             
                parser.parse!
         | 
| 26 | 
            -
                settings[:database].should eq(driver:      'foo',
         | 
| 26 | 
            +
                settings[:test][:database].should eq(driver:      'foo',
         | 
| 27 27 | 
             
                                              connections: 10,
         | 
| 28 28 | 
             
                                              host:        'foo.com',
         | 
| 29 29 | 
             
                                              name:        'bar',
         | 
| @@ -3,11 +3,31 @@ require 'spec_helper' | |
| 3 3 | 
             
            describe Vayacondios::Server::Configuration do
         | 
| 4 4 | 
             
              its(:defaults) do
         | 
| 5 5 | 
             
                should eq(development: {
         | 
| 6 | 
            -
                             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 6 | 
            +
                            database: {
         | 
| 7 | 
            +
                              driver:      'mongo',
         | 
| 8 | 
            +
                              host:        'localhost',
         | 
| 9 | 
            +
                              port:        27017,
         | 
| 10 | 
            +
                              name:        'vayacondios_development',
         | 
| 11 | 
            +
                              connections: 20,
         | 
| 12 | 
            +
                            }
         | 
| 13 | 
            +
                          },
         | 
| 14 | 
            +
                          test: {
         | 
| 15 | 
            +
                            database: {
         | 
| 16 | 
            +
                              driver:      'mongo',
         | 
| 17 | 
            +
                              host:        'localhost',
         | 
| 18 | 
            +
                              port:        27017,
         | 
| 19 | 
            +
                              name:        'vayacondios_test',
         | 
| 20 | 
            +
                              connections: 20,
         | 
| 21 | 
            +
                            }
         | 
| 22 | 
            +
                          },
         | 
| 23 | 
            +
                          production: {
         | 
| 24 | 
            +
                            database: {
         | 
| 25 | 
            +
                              driver:      'mongo',
         | 
| 26 | 
            +
                              host:        'localhost',
         | 
| 27 | 
            +
                              port:        27017,
         | 
| 28 | 
            +
                              name:        'vayacondios_production',
         | 
| 29 | 
            +
                              connections: 20,
         | 
| 30 | 
            +
                            }
         | 
| 11 31 | 
             
                          })
         | 
| 12 32 | 
             
              end
         | 
| 13 33 |  | 
| @@ -17,11 +37,12 @@ describe Vayacondios::Server::Configuration do | |
| 17 37 |  | 
| 18 38 | 
             
              context '#env' do
         | 
| 19 39 | 
             
                it 'allows hash access scoped by environment' do
         | 
| 20 | 
            -
                  subject.env(:development).should eq( | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 40 | 
            +
                  subject.env(:development).should eq(database: {
         | 
| 41 | 
            +
                                                        driver:      'mongo',
         | 
| 42 | 
            +
                                                        host:        'localhost',
         | 
| 43 | 
            +
                                                        port:        27017,
         | 
| 44 | 
            +
                                                        name:        'vayacondios_development',
         | 
| 45 | 
            +
                                                        connections: 20 })
         | 
| 25 46 | 
             
                end
         | 
| 26 47 | 
             
              end
         | 
| 27 48 | 
             
            end
         | 
| @@ -1,9 +1,56 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 |  | 
| 3 3 | 
             
            describe Vayacondios::Server::Document do
         | 
| 4 | 
            -
              
         | 
| 5 | 
            -
              let(:params){ { organization: 'organization', topic: 'topic' } }
         | 
| 6 4 |  | 
| 7 | 
            -
               | 
| 5 | 
            +
              let(:params){ {
         | 
| 6 | 
            +
                organization: 'organization',
         | 
| 7 | 
            +
                topic:        'topic',
         | 
| 8 | 
            +
                order:        'ascending',
         | 
| 9 | 
            +
                sort:         'hostname.internal',
         | 
| 10 | 
            +
                fields:       ['id', 'hostname.internal']
         | 
| 11 | 
            +
              } }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              subject(:document){ described_class.receive(params) }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              context '.extract_query_options!' do
         | 
| 16 | 
            +
                let(:model) do
         | 
| 17 | 
            +
                  klass = Class.new(document.class) do
         | 
| 18 | 
            +
                    def self.default_query_options
         | 
| 19 | 
            +
                      { limit: 5, order: 'descending', sort: 'time' }
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                let(:options) do
         | 
| 25 | 
            +
                  model.extract_query_options! params
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                it 'removes projection params' do
         | 
| 29 | 
            +
                  options.should have_key :limit
         | 
| 30 | 
            +
                  options.should have_key :sort
         | 
| 31 | 
            +
                  options.should have_key :order
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  params.should_not have_key :limit
         | 
| 34 | 
            +
                  params.should_not have_key :sort
         | 
| 35 | 
            +
                  params.should_not have_key :order
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  params.should have_key :organization
         | 
| 38 | 
            +
                  params.should have_key :topic
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                it 'uses defaults' do
         | 
| 42 | 
            +
                  options.should have_key :sort
         | 
| 43 | 
            +
                  options[:limit].should eq 5
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                it 'uses params when provided' do
         | 
| 47 | 
            +
                  options.should have_key :limit
         | 
| 48 | 
            +
                  options.should have_key :order
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  options[:sort].should eq ['hostname', 'internal']
         | 
| 51 | 
            +
                  options[:fields].should eq [['_id'], ['hostname', 'internal']]
         | 
| 52 | 
            +
                  options[:order].should eq 'ascending'
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 8 55 |  | 
| 9 56 | 
             
            end
         | 
    
        data/vayacondios-server.gemspec
    CHANGED
    
    | @@ -21,7 +21,7 @@ Gem::Specification.new do |gem| | |
| 21 21 | 
             
              gem.add_dependency('configliere',     '>= 0.4.16')
         | 
| 22 22 | 
             
              gem.add_dependency('gorillib',        '>= 0.4.2')
         | 
| 23 23 | 
             
              gem.add_dependency('multi_json',      '>= 1.3.6')
         | 
| 24 | 
            -
              gem.add_dependency('goliath-chimp',   '>= 0.0. | 
| 24 | 
            +
              gem.add_dependency('goliath-chimp',   '>= 0.0.3')
         | 
| 25 25 |  | 
| 26 26 | 
             
              gem.add_dependency('eventmachine',    '~> 1.0')
         | 
| 27 27 | 
             
              gem.add_dependency('goliath',         '~> 1.0')
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: vayacondios-server
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.3. | 
| 4 | 
            +
              version: 0.3.2
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -12,7 +12,7 @@ authors: | |
| 12 12 | 
             
            autorequire: 
         | 
| 13 13 | 
             
            bindir: bin
         | 
| 14 14 | 
             
            cert_chain: []
         | 
| 15 | 
            -
            date: 2014- | 
| 15 | 
            +
            date: 2014-03-11 00:00:00.000000000 Z
         | 
| 16 16 | 
             
            dependencies:
         | 
| 17 17 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 18 18 | 
             
              name: configliere
         | 
| @@ -69,7 +69,7 @@ dependencies: | |
| 69 69 | 
             
                requirements:
         | 
| 70 70 | 
             
                - - ! '>='
         | 
| 71 71 | 
             
                  - !ruby/object:Gem::Version
         | 
| 72 | 
            -
                    version: 0.0. | 
| 72 | 
            +
                    version: 0.0.3
         | 
| 73 73 | 
             
              type: :runtime
         | 
| 74 74 | 
             
              prerelease: false
         | 
| 75 75 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| @@ -77,7 +77,7 @@ dependencies: | |
| 77 77 | 
             
                requirements:
         | 
| 78 78 | 
             
                - - ! '>='
         | 
| 79 79 | 
             
                  - !ruby/object:Gem::Version
         | 
| 80 | 
            -
                    version: 0.0. | 
| 80 | 
            +
                    version: 0.0.3
         | 
| 81 81 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 82 82 | 
             
              name: eventmachine
         | 
| 83 83 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -251,7 +251,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 251 251 | 
             
                  version: '0'
         | 
| 252 252 | 
             
                  segments:
         | 
| 253 253 | 
             
                  - 0
         | 
| 254 | 
            -
                  hash:  | 
| 254 | 
            +
                  hash: -1277258498442787077
         | 
| 255 255 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 256 256 | 
             
              none: false
         | 
| 257 257 | 
             
              requirements:
         | 
| @@ -260,7 +260,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 260 260 | 
             
                  version: '0'
         | 
| 261 261 | 
             
                  segments:
         | 
| 262 262 | 
             
                  - 0
         | 
| 263 | 
            -
                  hash:  | 
| 263 | 
            +
                  hash: -1277258498442787077
         | 
| 264 264 | 
             
            requirements: []
         | 
| 265 265 | 
             
            rubyforge_project: 
         | 
| 266 266 | 
             
            rubygems_version: 1.8.23
         |