diff --git a/menu.json b/menu.json index 3ef0e6d..e258aa8 100644 --- a/menu.json +++ b/menu.json @@ -11,4 +11,5 @@ , "Short Scrabble Words" , "Sublevel" , "Multilevel" -] \ No newline at end of file + , "Queue" +] diff --git a/problems/queue/problem.txt b/problems/queue/problem.txt new file mode 100644 index 0000000..71a8d9e --- /dev/null +++ b/problems/queue/problem.txt @@ -0,0 +1,61 @@ +Write a module (not a program) that provides a FIFO queue on top +of a `{bold}level{/bold}` database. Your module should expose a function +that build a queue and accept a `{bold}levelup{/bold}` instance. +This function should return an object that has the following methods: + * `push`: add an element to the end of the queue. + * `shift`: shifts an element from the front of the queue. + * `clear`: remove all value from the queue. + +`{bold}push{\bold}` accept two arguments, the value to push and +optionally a callback to know when it is finished. + +`{bold}shift{\bold}` accept one argument, an optional callback to +retrieve the value at the front of the queue. + +`{bold}clear{\bold}` accept one argument, an optional callback to +to know when it is finished. + +Remember, all callbacks follow the style of node.js: + + function cb(err, value1, value2, value3, ...) { + if (err) { + // do something + return; + } + } + +---------------------------------------------------------------------- +HINTS: + +Use this boilerplate to get started with your module file: + + function Queue(db) { + if (!(this instanceof Queue)) return new Queue(db) + + // ... + } + + module.exports = Queue + + Queue.prototype.push = function(element, callback) { + // ... + } + + Queue.prototype.shift = function(callback) { + // ... + // at some point call callback(null, element) + } + + Queue.prototype.clear = function(callback) { + // ... + } + +Before coding, think how the queue data structure can be implemented +on top of LevelUp. In particular, you want to "translate" a `push` into a +level `put`, and `shift` into a limited ranged query. + +All pushed element must be stored in separate keys, by using a growing +monotonic identifier. What problems will you encounter if you use a counter? +Instead, try using `Date.now()`. Is this the perfect solution? + +You can also use sublevel to handle the naming of the queues! diff --git a/problems/queue/setup.js b/problems/queue/setup.js new file mode 100644 index 0000000..ddeb2fa --- /dev/null +++ b/problems/queue/setup.js @@ -0,0 +1,7 @@ + +function setup(run, callback) { + console.log(arguments) +} + +module.exports = setup +module.exports.async = true diff --git a/problems/queue/solution.js b/problems/queue/solution.js new file mode 100644 index 0000000..b01a9a9 --- /dev/null +++ b/problems/queue/solution.js @@ -0,0 +1,46 @@ + +function Queue(db) { + if (!(this instanceof Queue)) return new Queue(db) + + this._db = db +} + +Queue.prototype.push = function(element, callback) { + var key = Date.now() + '!' + Math.random().toString(16).slice(2); + + this._db.put(key, element, callback) + + return this +} + +Queue.prototype.shift = function(callback) { + var stream = this._db.createReadStream({ + limit: 1 + }) + + , db = this._db + + stream.once('data', function(data) { + db.del(data.key, function(err) { + callback(err, data.value) + }) + }) + + stream.once('error', callback) + + return this +} + +Queue.prototype.clear = function(callback) { + this._db.createReadStream() + .pipe(this._db.createWriteStream({ + type: 'del' + })) + .on('close', callback) + + return this +} + +module.exports = Queue +// you can find an alternative implementation +// with more features in https://github.com/mcollina/level-queue-type