Permalink
Browse files

Initial commit.

  • Loading branch information...
0 parents commit d724a4ee4b3506676d300638e883cff9db965f9e @coreh coreh committed Jul 25, 2011
Showing with 850 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +19 −0 LICENSE
  3. +301 −0 README.md
  4. +367 −0 ferret.js
  5. +20 −0 package.json
  6. +141 −0 test.js
@@ -0,0 +1,2 @@
+.DS_Store
+node_modules
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2011 by Marco Aurélio
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
301 README.md
@@ -0,0 +1,301 @@
+ferret.js - Adorable bindings for mongodb
+=========================================
+
+What is ferret.js?
+------------------
+
+`ferret.js` is a minimalistic wrapper around the excelent `node-mongodb-native` driver. It's pretty small (around 300 lines of code, without comments) and easy to use. Ferret's design is centered on:
+
+1. Simplicity
+2. Proper Error Handling and Recovery
+3. Orthogonality
+4. Sensible defaults
+5. Use of common idioms
+
+License
+-------
+
+Ferret is distributed under a MIT license. See the LICENSE file for more information.
+
+Installation
+============
+
+`ferret.js` can be easily installed through NPM.
+
+ npm install ferret
+
+Usage
+=====
+
+ var ferret = require('ferret')
+
+Sample Application/Quick Guide
+==============================
+
+### Hello World
+
+ ferret.find('users', {})
+ .on('each', function(user) {
+ console.log(user);
+ })
+
+This is arguably the simplest working program you can write using `ferret.js`.
+
+The code above fetches all the documents from the collection named `users`, and prints their contents.
+
+The `find` function returns an `util.EventEmitter` instance, to which you can attach event listeners. `each` is a convenience event that is fired for each result found.
+
+### 'each' versus 'success'
+
+If you want to you can bind to `success` instead of `each` to get an array with all the results:
+
+ ferret.find('users', {})
+ .on('success', function(users) {
+ for (var i = 0; i < users.length; i++) {
+ console.log(users[i]);
+ }
+ })
+
+
+### Error Handling
+
+It's probably a good idea to add some error handling to the code. This can be done by attaching a listener to the `error` event (Notice that the `on` calls are chainable):
+
+ ferret.find('users', {})
+ .on('success', function(users) {
+ for (var i = 0; i < users.length; i++) {
+ console.log(users[i]);
+ }
+ })
+ .on('error', function(err) {
+ // Do something about it
+ })
+
+### Server, Port, Database
+
+You should have noticed that we did not specify ferret which server, port or database to use.
+
+If nothing is specified, it will default to database `test` on server `127.0.0.1`, port `27017` — mongodb's default. To manually specify what you want, use the `connect` method.
+
+ ferret.connect('test', '127.0.0.1', '27017')
+
+ ferret.find('users', {})
+ .on('success', function(users) {
+
+ for (var i = 0; i < users.length; i++) {
+ console.log(users[i]);
+ }
+
+ })
+ .on('error', function(err) {
+ // Do something about it
+ })
+
+### The shared instance
+
+On the first time you call `connect`, ferret will create a shared instance. It can later be accessed by using `ferret.shared()`.
+
+`ferret.find` is actually a shorthand to `ferret.shared().find`.
+
+### Working with multiple ferret instances
+
+If you're going to use multiple databases, you can store the return value of `ferret.connect` into a variable:
+
+ var someDatabase = ferret.connect('test', '127.0.0.1', '27017')
+ var otherDatabase = ferret.connect('blah', '127.0.0.1', '27017')
+
+ someDatabase.find('users', {})
+ .on('success', function(users) {
+
+ for (var i = 0; i < users.length; i++) {
+ console.log(users[i]);
+ }
+
+ })
+ .on('error', function(err) {
+ // Do something about it
+ })
+
+### Collections
+
+Previously, we specified the collection to operate on through the first argument given to `find`.
+
+If you want to, you can use the `collection` method to specify a collection to operate on.
+
+Notice that `find` will no longer need or take a collection name as an argument:
+
+ var someDatabase = ferret.connect('test', '127.0.0.1', '27017')
+
+ var users = someDatabase.collection('users')
+
+ users.find({})
+ .on('success', function(users) {
+
+ for (var i = 0; i < users.length; i++) {
+ console.log(users[i]);
+ }
+
+ })
+ .on('error', function(err) {
+ // Do something about it
+ })
+
+
+### Query buffering and the 'ready' event
+
+You might have noticed that `connect` will return right away, and that we don't wait until the connection is estabilished to perform queries.
+
+Ferret will buffer the queries performed and wait until it connects to the server for the first time. If the connection is lost after that, ferret will no longer buffer queries, but instead report errors normally.
+
+It's really not necessary, but if you *really* want to, you can wait until the connection is estabilished by listening to the 'ready' event:
+
+ var database = ferret.connect('test', '127.0.0.1', '27017')
+
+ database.on('ready', function(){
+
+ var users = database.collection('users')
+
+ users.find({})
+ .on('success', function(users) {
+
+ for (var i = 0; i < users.length; i++) {
+ console.log(users[i]);
+ }
+
+ })
+ .on('error', function(err) {
+ // Do something about it
+ })
+
+ })
+ .on('error', function(){
+ // Could not connect to mongodb
+ })
+
+
+Design goals
+------------
+`ferret.js` was designed with the following goals in mind:
+
+1. **Simplicity** - Less code means less bugs, which is great. But simplicity is more than that: It means doing things the "obvious" way sometimes. "Clever" code is usually hard to understand, and less flexible.
+
+2. **Proper Error Handling and Recovery** - Hiding complexity is not the same as hiding the reality. `ferret.js` will attempt to automatically reconnect to mongodb in case of failure. However, it will also notify you about the operations that may fail in the mean time, so you can take the appropriate actions.
+
+3. **Orthogonality** - The same operations are provided on a consistent manner when accessing the database through different means. Ferret currently allows for access through:
+
+ * a shared connection object
+ * manually instanced connections
+ * `FerretCollection` objects
+
+4. **Sensible defaults** - `ferret.js` comes with sensible defaults built in so that you can get to your application logic up as quickly as possible. If you need a more tailored behavior, you can easily configure things later.
+
+5. **Use of Common idioms** - `ferret.js` sticks to the conventions of mongodb and of the `node-mongodb-native` driver as closely as possible, so you can easily make use of existing tutorials and documentation.
+
+
+Instance State
+--------------
+
+Each ferret instance is actually a state machine described by the following state diagram:
+
+ |
+ V
+ +-----------+
+ | start |
+ +-----------+
+ / \
+ / \
+ / \
+ / \
+ V V
+ ++======================++ ++=============++
+ || | || || error ||
+ || V || ++=============++
+ || +-----------+ ||
+ || | connected | ||
+ || +-----------+ ||
+ || | Λ ||
+ || V | ||
+ || +--------------+ ||
+ || | disconnected | ||
+ || +--------------+ ||
+ || ||
+ || ||
+ ++======================++
+ ready
+
+`ready` and `error` are both final states. `connected` and `disconnected` are sub-states of `ready`.
+
+The current state of an instance can be queried by the `Ferret#state()` method. The possible return values are:
+
+ 'start'
+ 'error'
+ 'ready+connected'
+ 'ready+disconnected'
+
+Ferret will only buffer queries in when in the `start` state.
+
+Query Events
+------------
+
+All queries return a new `EventEmitter` instance, which will later emit a `success` or `error` event, depending on the result.
+
+For convenience, the `find` query can also emit `each` and `cursor` events. `each` will iterate through the results, and `cursor` will provide you a raw `node-mongodb-native` cursor.
+
+You should not listen to both `each` and `success` at the same time, as that will not work. The same warning is also valid for `cursor` and `success`.
+
+Instance Events
+---------------
+
+`Ferret` inherits `EventEmitter`, and currently emits the following events:
+
+ 'ready'
+ 'error'
+ 'reconnect'
+ 'disconnect'
+
+API
+---
+
+This section provides a quick overview of the ferret API. For detailed descriptons of the different commands mongodb provides, please check their documentation.
+
+### Ferret Instance
+
+* **Ferret#state()** - Returns the instance's current state
+* **Ferret#find(collection_name, query[, fields[, options]])** - Find documents
+* **Ferret#findOne(collection_name, query)** - Find the first document
+* **Ferret#insert(collection_name, docs)** - Inserts one or more documents
+* **Ferret#save(collection_name, doc)** - Inserts if new, updates if existing
+* **Ferret#update(collection_name, criteria, replacement[, options])** - Updates existing documents
+* **Ferret#remove(collection_name, criteria)** - Removes existing documents
+* **Ferret#collection(name)** - Retuns a `FerretCollection` object
+
+`Ferret` inherits `EventEmitter`, so it also provides all functions the latter provides.
+
+### Ferret Module
+
+* **Ferret.connect([database_name[, host[, port]]])** - Creates a new ferret instance
+* **Ferret.shared(ferret)** - Gets (or sets, if `ferret` is specified) the shared instance
+
+For convenience, all the functions provided by `Ferret` instances are also available at the ferret module. When called, these functios will affect the shared instance.
+
+### FerretCollection
+
+`FerretCollection` objects can be obtained through the `Ferret#collection` method. They provide many of the methods the ferret instance provides, minus the `collection_name` parameter:
+
+* **FerretCollection#find(query[, fields[, options]])** - Find documents
+* **FerretCollection#findOne(query)** - Find the first document
+* **FerretCollection#insert(docs)** - Inserts one or more documents
+* **FerretCollection#save(doc)** - Inserts if new, updates if existing
+* **FerretCollection#update(criteria, replacement[, options])** - Updates existing documents
+* **FerretCollection#remove(criteria)** - Removes existing documents
+
+FAQ
+---
+
+### Why ferret?
+
+Mongoose was already taken ;-)
+
+### Does ferret provide ORM/Modelling functionality?
+
+Not yet. Stay tuned.
Oops, something went wrong.

0 comments on commit d724a4e

Please sign in to comment.