Skip to content

Commit

Permalink
Add support for expiry time to set and get
Browse files Browse the repository at this point in the history
  • Loading branch information
wezm committed Apr 5, 2011
1 parent c5955f8 commit 1165953
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 30 deletions.
39 changes: 22 additions & 17 deletions src/db.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ class DB
constructor: (@database) ->
throw new Error("default database must be passed to new") unless @database

_initRpcArgs: (options) ->
_initOptions: (options) ->
args = {}
args.DB = options.database or @database
args.xt = options.expires if options.expires?
args

open: (@host = 'localhost', @port = 1978) ->
Expand Down Expand Up @@ -73,7 +74,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to status");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
@rpcClient.call 'status', rpc_args, (error, status, output) ->
if error?
callback error, output
Expand Down Expand Up @@ -118,7 +119,8 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to set");

@restClient.put key, value, options.database or @database, (error) ->
params = this._initOptions options
@restClient.put key, value, params, (error) ->
callback error

# Add a record if it doesn't already exist
Expand All @@ -133,7 +135,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to add");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
rpc_args.key = key
rpc_args.value = value
@rpcClient.call 'add', rpc_args, (error, status, output) ->
Expand All @@ -158,7 +160,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to replace");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
rpc_args.key = key
rpc_args.value = value
@rpcClient.call 'replace', rpc_args, (error, status, output) ->
Expand All @@ -182,7 +184,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to append");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
rpc_args.key = key
rpc_args.value = value
@rpcClient.call 'append', rpc_args, (error, status, output) ->
Expand All @@ -205,7 +207,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to increment");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
rpc_args.key = key
rpc_args.num = num
@rpcClient.call 'increment', rpc_args, (error, status, output) ->
Expand All @@ -229,7 +231,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to incrementDouble");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
rpc_args.key = key
rpc_args.num = num
@rpcClient.call 'increment_double', rpc_args, (error, status, output) ->
Expand All @@ -253,7 +255,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to cas");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
rpc_args.key = key
rpc_args.oval = oval if oval?
rpc_args.nval = nval if nval?
Expand All @@ -278,7 +280,8 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to remove");

@restClient.delete key, options.database, (error) ->
params = this._initOptions options
@restClient.delete key, params, (error) ->
callback error

exists: (key, args...) ->
Expand All @@ -292,7 +295,8 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to exists");

@restClient.head key, options.database, (error, headers) ->
params = this._initOptions options
@restClient.head key, params, (error, headers) ->
callback error, headers?

# key, [database], callback
Expand All @@ -307,8 +311,9 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to get");

@restClient.get key, options.database, (error, value) ->
callback error, value
params = this._initOptions options
@restClient.get key, params, (error, value, expires) ->
callback error, value, expires

setBulk: (records, args...) ->
switch args.length
Expand All @@ -321,7 +326,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to setBulk");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
rpc_args["_#{key}"] = value for key, value of records

@rpcClient.call 'set_bulk', rpc_args, (error, status, output) ->
Expand All @@ -343,7 +348,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to removeBulk");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
rpc_args["_#{key}"] = '' for key in keys

@rpcClient.call 'remove_bulk', rpc_args, (error, status, output) ->
Expand All @@ -365,7 +370,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to getBulk");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
rpc_args["_#{key}"] = '' for key in keys

@rpcClient.call 'get_bulk', rpc_args, (error, status, output) ->
Expand Down Expand Up @@ -395,7 +400,7 @@ class DB
else
throw new Error("Invalid number of arguments (#{args.length}) to #{procedure}");

rpc_args = this._initRpcArgs options
rpc_args = this._initOptions options
if procedure == 'match_prefix'
rpc_args.prefix = pattern
else
Expand Down
39 changes: 26 additions & 13 deletions src/rest_client.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,31 @@ class RestClient

_extractArgs: (args) ->
switch args.length
when 1 then return [null, args[0]]
when 1 then return [{}, args[0]]
when 2 then return args
else
throw new Error("Invalid number of arguments (#{args.length})");

_buildPath: (database, key) ->
if database then "/#{encodeURIComponent(database)}/#{encodeURIComponent(key)}" else "/#{escape(key)}"
_expirationTime: (date_or_number) ->
if typeof date_or_number == 'number'
Math.round((Date.now() + (1000 * date_or_number)) / 1000)
else if date_or_number instanceof Date
date_or_number.toUTCString()
else
throw new Error("Invalid expires value, must be Date or Number")

_buildPath: (params, key) ->
path = "/#{encodeURIComponent(key)}"
path = "/#{encodeURIComponent(params.DB)}" + path if params.DB
path

get: (key, args...) ->
[database, callback] = this._extractArgs(args)
[params, callback] = this._extractArgs(args)

request =
host: @host
port: @port
path: this._buildPath database, key
path: this._buildPath params, key
headers:
'Content-Length': 0
'Connection': 'keep-alive'
Expand All @@ -31,6 +41,8 @@ class RestClient
# if large responses are expected it would be
# better to write to a file if over some size threshold.
content_length = parseInt(response.headers['content-length'], 10)
expires = if response.headers.hasOwnProperty 'x-kt-xt' then new Date(response.headers['x-kt-xt']) else null

value = new Buffer(content_length)
offset = 0

Expand All @@ -40,20 +52,20 @@ class RestClient

response.on 'end', ->
switch response.statusCode
when 200 then callback undefined, value
when 404 then callback undefined, null
when 200 then callback undefined, value, expires
when 404 then callback undefined, null, expires
else callback new Error("Unexpected response from server: #{response.statusCode}")
.on 'error', (error) ->
callback error

head: (key, args...) ->
[database, callback] = this._extractArgs(args)
[params, callback] = this._extractArgs(args)

options =
host: @host
port: @port
method: 'HEAD'
path: this._buildPath database, key
path: this._buildPath params, key
headers:
'Content-Length': 0
'Connection': 'keep-alive'
Expand All @@ -69,16 +81,17 @@ class RestClient
.end()

put: (key, value, args...) ->
[database, callback] = this._extractArgs(args)
[params, callback] = this._extractArgs(args)

options =
host: @host
port: @port
method: 'PUT'
path: this._buildPath database, key
path: this._buildPath params, key
headers:
'Content-Length': if typeof value == 'string' then Buffer.byteLength(value) else value.length
'Connection': 'keep-alive'
options.headers['X-Kt-Xt'] = this._expirationTime(params.xt) if params.xt?

http.request options, (response) ->
response.on 'end', ->
Expand All @@ -90,13 +103,13 @@ class RestClient
.end(value)

delete: (key, args...) ->
[database, callback] = this._extractArgs(args)
[params, callback] = this._extractArgs(args)

options =
host: @host
port: @port
method: 'DELETE'
path: this._buildPath database, key
path: this._buildPath params, key
headers:
'Content-Length': 0
'Connection': 'keep-alive'
Expand Down
9 changes: 9 additions & 0 deletions test/db_test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ module.exports =
test.ok value == null
test.done()

'allows the expiry time to be specified': (test) ->
test.expect 2
db.set 'test', 'Value', {expires: 60}, (error, output) ->
test.ifError error

db.get 'test', (error, value, expires) ->
test.ok expires instanceof Date
test.done()

add: testCase
setUp: dbClear

Expand Down

0 comments on commit 1165953

Please sign in to comment.