Skip to content

Commit

Permalink
Rename id method to identify; Also the creation of records with a…
Browse files Browse the repository at this point in the history
… defined identifier; Optimize id incremental creation
  • Loading branch information
wdavidw committed Mar 15, 2012
1 parent 92b4adf commit e8404e4
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 73 deletions.
63 changes: 33 additions & 30 deletions lib/Records.coffee
Expand Up @@ -223,27 +223,31 @@ module.exports = class Records extends Schema
# Get current date once if schema is temporal
date = new Date Date.now() if temporal?
# Generate new identifiers
multi.incr "#{db}:#{name}_incr" for x in records
multi.exec (err, recordIds) =>
incr = 0
for record in records then incr++ unless record[identifier]
multi.incrby "#{db}:#{name}_incr", incr
multi.exec (err, recordId) =>
recordId = recordId - incr
return callback err if err
multi = redis.multi()
for record, i in records
recordId++ unless record[identifier]
# Enrich the record with its identifier
record[identifier] = recordId = recordIds[i]
record[identifier] = recordId unless record[identifier]
# Enrich the record with a creation date
record[temporal.creation] = date if temporal?.creation? and not record[temporal.creation]?
# Enrich the record with a creation date
record[temporal.modification] = date if temporal?.modification? and not record[temporal.modification]?
# Register new identifier
multi.sadd "#{db}:#{name}_#{identifier}", recordId
multi.sadd "#{db}:#{name}_#{identifier}", record[identifier]
# Deal with Unique
for property of unique
multi.hset "#{db}:#{name}_#{property}", record[property], recordId if record[property]
multi.hset "#{db}:#{name}_#{property}", record[property], record[identifier] if record[property]
# Deal with Index
for property of index
value = record[property]
value = hash value
multi.sadd "#{db}:#{name}_#{property}:#{value}", recordId
multi.sadd "#{db}:#{name}_#{property}:#{value}", record[identifier]
#multi.zadd "#{s.db}:#{s.name}_#{property}", 0, record[property]
# Store the record
r = {}
Expand All @@ -253,7 +257,7 @@ module.exports = class Records extends Schema
# Filter null values
r[property] = value if value?
@serialize r
multi.hmset "#{db}:#{name}:#{recordId}", r
multi.hmset "#{db}:#{name}:#{record[identifier]}", r
multi.exec (err, results) =>
return callback err if err
for result in results
Expand Down Expand Up @@ -313,7 +317,7 @@ module.exports = class Records extends Schema
`options` All options are optional. Options properties include:
* `properties` Array of properties to fetch, all properties if not defined.
* `properties` Array of properties to fetch, all properties unless defined.
* `force` Force the retrieval of properties even if already present in the record objects.
* `accept_null` Skip objects if they are provided as null.
* `object` If `true`, return an object where keys are the identifier and value are the fetched records
Expand All @@ -338,7 +342,7 @@ module.exports = class Records extends Schema
if options.accept_null? and not records.some((record) -> record isnt null)
return callback null, if isArray then records else records[0]
# Retrieve records identifiers
@id records, {object: true, accept_null: options.accept_null?}, (err, records) =>
@identify records, {object: true, accept_null: options.accept_null?}, (err, records) =>
return callback err if err
cmds = []
records.forEach (record, i) ->
Expand Down Expand Up @@ -374,8 +378,8 @@ module.exports = class Records extends Schema
callback null, if isArray then records else records[0]
###
`id(records, [options], callback)`
----------------------------------
`identify(records, [options], callback)`
----------------------------------------
Extract record identifiers or set the identifier to null if its associated record could not be found.
The method doesn't hit the database to validate record values and if an id is
Expand Down Expand Up @@ -414,7 +418,7 @@ module.exports = class Records extends Schema
console.log ids
###
id: (records, options, callback) ->
identify: (records, options, callback) ->
if arguments.length is 2
callback = options
options = {}
Expand Down Expand Up @@ -447,20 +451,19 @@ module.exports = class Records extends Schema
records[i][identifier] = record
else
return callback new Error 'Invalid id, got ' + (JSON.stringify record)
# No need to hit redis if no comand are registered
if cmds.length is 0
if not options.object
finalize = ->
unless options.object
records = for record in records
if record? then record[identifier] else record
return callback null, if isArray then records else records[0]
callback null, if isArray then records else records[0]
# No need to hit redis if there is no command
return finalize() if cmds.length is 0
# Run the commands
multi = redis.multi cmds
multi.exec (err, results) =>
unless options.object
records = for record in records
record[identifier]
return callback err if err
@unserialize records
callback null, if isArray then records else records[0]
finalize()
###
`list([options], callback)`
Expand Down Expand Up @@ -566,7 +569,7 @@ module.exports = class Records extends Schema
multi.del tempkey if tempkey
multi.exec()
###
`remove(records, callback)`
---------------------------
Remove one or several records from the database. The function will also
Expand Down Expand Up @@ -598,24 +601,24 @@ module.exports = class Records extends Schema
return callback err if err
callback null, records.length
###
`update(records, [options], callback)`
--------------------------------------
Update one or several records. The records must exists in the database or
an error will be returned in the callback. The existence of a record may
be discovered through its identifier or the presence of a unique property.
`records` Record object or array of record objects.
`options` Options properties include:
* `validate` Validate the records.
`callback` Called on success or failure. Received parameters are:
* `err` Error object if any.
* `records` Records with their newly created identifier.
Records are not validated, it is the responsability of the client program calling `create` to either
call `validate` before calling `create` or to passs the `validate` options.
Expand All @@ -625,7 +628,7 @@ module.exports = class Records extends Schema
username: 'my_username'
age: 28
, (err, user) -> console.log user
###
update: (records, options, callback) ->
if arguments.length is 2
Expand All @@ -644,7 +647,7 @@ module.exports = class Records extends Schema
# 2.1 Make sure the new property is not assigned to another record
# 2.2 Erase old index & Create new index
# 3. Save the record
@id records, {object: true}, (err, records) =>
@identify records, {object: true}, (err, records) =>
return callback err if err
# Stop here if a record is invalid
for record in records
Expand Down
51 changes: 30 additions & 21 deletions test/create.coffee
Expand Up @@ -26,8 +26,8 @@ describe 'create', ->

it 'Test create # one user', (next) ->
Users.create
username: 'my_username',
email: 'my@email.com',
username: 'my_username'
email: 'my@email.com'
password: 'my_password'
, (err, user) ->
should.not.exist err
Expand All @@ -38,12 +38,12 @@ describe 'create', ->

it 'Test create # multiple users', (next) ->
Users.create [
username: 'my_username_1',
email: 'my_first@email.com',
username: 'my_username_1'
email: 'my_first@email.com'
password: 'my_password'
,
username: 'my_username_2',
email: 'my_second@email.com',
username: 'my_username_2'
email: 'my_second@email.com'
password: 'my_password'
], (err, users) ->
should.not.exist err
Expand All @@ -54,8 +54,8 @@ describe 'create', ->

it 'Test create # existing id', (next) ->
Users.create
username: 'my_username',
email: 'my@email.com',
username: 'my_username'
email: 'my@email.com'
password: 'my_password'
, (err, user) ->
should.not.exist err
Expand All @@ -76,21 +76,21 @@ describe 'create', ->
, (err, user) ->
should.not.exist err
Users.create
username: 'my_username',
email: 'my@email.com',
username: 'my_username'
email: 'my@email.com'
password: 'my_password'
, (err, user) ->
err.message.should.eql 'Record 1 already exists'
Users.clear next

it 'should only return the newly created identifiers', (next) ->
Users.create [
username: 'my_username_1',
email: 'my_first@email.com',
username: 'my_username_1'
email: 'my_first@email.com'
password: 'my_password'
,
username: 'my_username_2',
email: 'my_second@email.com',
username: 'my_username_2'
email: 'my_second@email.com'
password: 'my_password'
], identifiers: true, (err, ids) ->
should.not.exist err
Expand All @@ -100,12 +100,12 @@ describe 'create', ->

it 'should only return selected properties', (next) ->
Users.create [
username: 'my_username_1',
email: 'my_first@email.com',
username: 'my_username_1'
email: 'my_first@email.com'
password: 'my_password'
,
username: 'my_username_2',
email: 'my_second@email.com',
username: 'my_username_2'
email: 'my_second@email.com'
password: 'my_password'
], properties: ['email'], (err, users) ->
should.not.exist err
Expand All @@ -115,14 +115,23 @@ describe 'create', ->

it 'should only insert defined properties', (next) ->
Users.create
username: 'my_username_1',
email: 'my_first@email.com',
password: 'my_password'
username: 'my_username_1'
email: 'my_first@email.com'
zombie: 'e.t. maison'
, (err, user) ->
Users.get user.user_id, (err, user) ->
should.not.exist user.zombie
Users.clear next

it 'should let you pass your own identifiers', (next) ->
Users.create
user_id: 1
username: 'my_username_1'
, (err, user) ->
Users.get 1, (err, user) ->
user.username.should.equal 'my_username_1'
Users.clear next




0 comments on commit e8404e4

Please sign in to comment.