diff --git a/.gitignore b/.gitignore
index b3fa805..c85e9a7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,15 @@
-Properties
-bin
-obj
+Properties/
+bin/
+obj/
*.suo
*.user
*.sublime*
-node_modules
\ No newline at end of file
+node_modules/
+.vs
+*.dat
+.idea
+*.tmp
+coverage/
+typings/DefinitelyTyped/**/*.d.ts
+.tscache
+dist/test/
\ No newline at end of file
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..dce4b6a
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,22 @@
+{
+ "bitwise": false,
+ "curly": false,
+ "eqeqeq": false,
+ "forin": false,
+ "freeze": true,
+ "immed": false,
+ "newcap": true,
+ "noarg": true,
+ "noempty": true,
+ "plusplus": false,
+ "undef": true,
+ "unused": true,
+ "maxcomplexity": 40,
+ "asi": false,
+ "boss": true,
+ "debug": false,
+ "eqnull": false,
+ "evil": false,
+
+ "node": true
+}
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..c2fc0aa
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,20 @@
+.travis.yml
+test/
+dist/test/
+example/
+doc/
+benchmarks/
+.settings/
+.git/
+.idea/
+.vs/
+.tscache/
+obj/
+bin/
+CHANGELOG
+Gruntfile.js
+*.njsproj
+.jshintrc
+.gitattributes
+.gitignore
+typings/DefinitelyTyped
\ No newline at end of file
diff --git a/.settings/launch.json b/.settings/launch.json
new file mode 100644
index 0000000..4d7318c
--- /dev/null
+++ b/.settings/launch.json
@@ -0,0 +1,31 @@
+{
+ "version": "0.1.0",
+ "configurations": [
+ {
+ "name": "Run Tests",
+ "type": "node",
+ "program": "node_modules/mocha/bin/mocha",
+ "stopOnEntry": false,
+ "args": ["--debug"],
+ "cwd": ".",
+ "runtimeExecutable": null,
+ "env": { }
+ },
+ {
+ "name": "Run Benchmark",
+ "type": "node",
+ "program": "benchmarks/mongodb.js",
+ "stopOnEntry": true,
+ "args": ["--debug"],
+ "cwd": ".",
+ "runtimeExecutable": null,
+ "env": { }
+ },
+ {
+ "name": "Attach",
+ "type": "node",
+ "address": "localhost",
+ "port": 5858
+ }
+ ]
+}
diff --git a/.settings/tasks.json b/.settings/tasks.json
new file mode 100644
index 0000000..e59acfd
--- /dev/null
+++ b/.settings/tasks.json
@@ -0,0 +1,82 @@
+// Available variables which can be used inside of strings.
+// ${workspaceRoot}: the root folder of the team
+// ${file}: the current opened file
+// ${fileBasename}: the current opened file's basename
+// ${fileDirname}: the current opened file's dirname
+// ${fileExtname}: the current opened file's extension
+// ${cwd}: the current working directory of the spawned process
+{
+ "version": "0.1.0",
+ "command": "npm",
+ "showOutput": "silent",
+
+ "windows": {
+ "command": "npm.cmd"
+ },
+
+ "tasks": [
+ {
+ "taskName": "build",
+ "args": ["run"],
+ "isBuildCommand": true,
+ "problemMatcher": ["$tsc", {
+ "fileLocation": "relative",
+ "owner": "typescript",
+ "pattern": {
+ "regexp": "^([^(]+)\\((\\d+,\\d+)\\)\\: (error|warning) TS(\\d+): (.*)$",
+ "file": 1,
+ "location": 2,
+ "code": 3,
+ "severity": 4,
+ "message": 5
+ }
+ }, {
+ "fileLocation": "relative",
+ "owner": "typescript",
+ "pattern": {
+ "regexp": "^(error|warning) TS(\\d+): File '([^']+)'.*$",
+ "file": 3,
+ "location": 2,
+ "code": 2,
+ "severity": 1,
+ "message": 3
+ }
+ }]
+ },
+ {
+ "taskName": "test",
+ "args": [],
+ "isTestCommand": true,
+ "problemMatcher": {
+ "owner": "mocha",
+ "pattern": {
+ "regexp": "^\\s*(\\d+)\\)\\s*(.+)\\:$",
+ "file": 1,
+ "message": 2
+ }
+ }
+ },
+ {
+ "taskName": "lint",
+ "args": ["run", "lint", "--", "${file}", "--exclude"],
+ "problemMatcher": "$jshint"
+ },
+ {
+ "taskName": "install",
+ "args": []
+ },
+ {
+ "taskName": "update",
+ "args": []
+ },
+ {
+ "taskName": "benchmark",
+ "args": ["run"],
+ "showOutput": "always"
+ },
+ {
+ "taskName": "publish",
+ "args": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 8a6bd3e..55b5b04 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,33 @@
language: node_js
node_js:
- - "0.8"
- "0.10"
- - "0.11"
services:
- mongodb
+
env:
- - CI_SERVER=1
\ No newline at end of file
+ - CI_SERVER=1
+
+addons:
+ code_climate:
+ repo_token: 9c90177b42d39905ca635b1f6226580dab5799f87f172b66bab4e8df77b67a13
+
+before_install:
+ - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
+ - echo 'deb http://repo.mongodb.org/apt/ubuntu precise/mongodb-org/3.0 multiverse' | sudo tee /etc/apt/sources.list.d/mongodb-org-3.0.list
+ - echo 'deb http://repo.mongodb.org/apt/ubuntu precise/mongodb-org/3.1 multiverse' | sudo tee /etc/apt/sources.list.d/mongodb-org-3.1.list
+ - sudo apt-get update
+ - sudo apt-get install -y mongodb-org mongodb-org-server mongodb-org-shell mongodb-org-tools
+
+before_script:
+ - "until nc -z localhost 27017; do echo Waiting for MongoDB; sleep 1; done"
+ - "mongo --version"
+ - gulp build
+
+script:
+ - gulp ci
+
+after_script:
+ - gulp coverage
+ - coveralls < coverage/lcov.info
+ - codeclimate < coverage/lcov.info
\ No newline at end of file
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..6ad3734
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,21 @@
+# v4.0.0
+ - Removed automatic schema extensions
+ This was done for two reasons, firstly it simplifies the process of loading documents from the database a small amount.
+ The bigger reason is pure performance. Not only do we cut down on the number of properties which need to be defined
+ on new instances (if they aren't in the static schema) but by preventing modifications to the object structure we
+ prevent V8 from de-optimizing the code.
+ - Instance original object is no longer cloned
+ This should result in a small performance boost and shouldn't break any existing code (unless it was doing weird stuff
+ with the private API... you haven't been messing with the private API have you?)
+ - Removed support for the event emitter implementation
+ With the adoption of promises, its use has become less pronounced and its removal will further simplify the codebase
+ and help boost performance.
+ - All hook signatures have been changed
+ The first argument has become the value which was previously `this`. This should enable more explicit code and support
+ for TypeScript.
+ - Model options `preprocessors` renamed to `transforms`
+ Makes it a little bit more clear what these are to be used for
+ - Caching infrastructure updated
+ We've separated the cache implementations (get/set/clear) from the logic dictating how to cache something (can/key)
+ to make implementing the two parts easier. The cache implementation is now set on the core while the model provides
+ the cache controller dictating how caching is performed.
\ No newline at end of file
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..0c0b54f
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,137 @@
+var tsconfig = require('./tsconfig.json');
+
+module.exports = function (grunt) {
+ "use strict";
+
+ grunt.initConfig({
+ ts: {
+ options: tsconfig.compilerOptions,
+
+ dev: {
+ src: tsconfig.files,
+ options: {
+ watch: 'lib',
+ fast: 'never'
+ }
+ },
+ test: {
+ src: tsconfig.files,
+ options: {
+ sourceMap: true,
+ fast: 'never'
+ }
+ },
+ release: {
+ src: ["index.ts", "lib/**/*.ts"],
+ options: {
+ sourceMap: false,
+ fast: 'never'
+ }
+ }
+ },
+ mochacli: {
+ options: {
+ require: ["test/support/chai", "test/support/config"],
+ files: "test/*.js",
+ timeout: '10s'
+ },
+
+ default: {
+
+ }
+ },
+ mocha_istanbul: {
+ coverage: {
+ src: 'test',
+ root: 'lib',
+ options: {
+ mask: '*.js',
+ reportFormats: ['lcovonly', 'html'],
+ timeout: '10s',
+ require: ["test/support/chai", "test/support/config"],
+ check: {
+ lines: 75,
+ statements: 75
+ }
+ }
+ },
+
+ coveralls: {
+ src: 'test',
+ root: 'lib',
+ options: {
+ mask: '*.js',
+ coverage: true,
+ reportFormats: ['lcovonly'],
+ timeout: '10s',
+ require: ["test/support/chai", "test/support/config"]
+ }
+ }
+ },
+
+ clean: {
+ definitions: ["*.d.ts", "!iridium.d.ts", "!_references.d.ts", "benchmarks/**/*.d.ts", "example/**/*.d.ts", "lib/**/*.d.ts", "test/**/*.d.ts"],
+ sourceMaps: ["*.map", "benchmarks/**/*.map", "example/**/*.map", "lib/**/*.map", "test/**/*.map"],
+ compiledFiles: ["*.js", "!Gruntfile.js", "benchmarks/**/*.js", "example/**/*.js", "lib/**/*.js", "test/**/*.js"],
+ coverage: ["coverage"]
+ },
+
+ _release: {
+ options: {
+ tagName: "v<%= version %>",
+ commitMessage: "v<%= version %>"
+ }
+ },
+
+ 'string-replace': {
+ packageDependencies: {
+ files: { "_references.d.ts": "_references.d.ts" },
+ options: {
+ replacements: [{
+ pattern: /(\/\/\/ )/gi,
+ replacement: '//$1'
+ }]
+ }
+ },
+ developmentDependencies: {
+ files: { "_references.d.ts": "_references.d.ts" },
+ options: {
+ replacements: [{
+ pattern: /\/\/(\/\/\/ )/gi,
+ replacement: '$1'
+ }]
+ }
+ }
+ }
+ });
+
+ grunt.event.on('coverage', function (lcovcontent, done) {
+ require('coveralls').handleInput(lcovcontent, function (err) {
+ if (err) return done(err);
+ done();
+ });
+ });
+
+ grunt.loadNpmTasks("grunt-ts");
+ grunt.loadNpmTasks("grunt-mocha-cli");
+ grunt.loadNpmTasks("grunt-mocha-istanbul");
+ grunt.loadNpmTasks("grunt-contrib-clean");
+ grunt.loadNpmTasks("grunt-release");
+ grunt.loadNpmTasks("grunt-string-replace");
+
+ grunt.renameTask('release', '_release');
+
+ grunt.registerTask("default", ["clean", "ts:dev"]);
+ grunt.registerTask("test", ["clean", "ts:test", "mochacli"]);
+ grunt.registerTask("coverage", ["clean", "ts:test", "mocha_istanbul:coverage"]);
+ grunt.registerTask("coveralls", ["clean", "ts:test", "mocha_istanbul:coveralls"]);
+ grunt.registerTask("build", ["clean", "ts:release"]);
+ grunt.registerTask("build:package", ["clean", "ts:release", "string-replace:packageDependencies"]);
+ grunt.registerTask("clean:package", ["string-replace:developmentDependencies"]);
+
+ grunt.registerTask("release", ["build:package", "_release", "clean:package"]);
+ grunt.registerTask("release:prerelease", ["build:package", "_release:prerelease", "clean:package"]);
+ grunt.registerTask("release:patch", ["build:package", "_release:patch", "clean:package"]);
+ grunt.registerTask("release:minor", ["build:package", "_release:minor", "clean:package"]);
+ grunt.registerTask("release:major", ["build:package", "_release:major", "clean:package"]);
+};
\ No newline at end of file
diff --git a/Iridium.njsproj b/Iridium.njsproj
index 23b2921..e8711c9 100644
--- a/Iridium.njsproj
+++ b/Iridium.njsproj
@@ -3,64 +3,148 @@
Debug
2.0
- {a2511e8c-33be-4b8d-8203-70d403aa446a}
+ {e9a19872-d84f-418a-8332-3ded543fb1fa}
ShowAllFiles
- index.js
+ node_modules\mocha\bin\mocha
.
.
{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}
+ true
+ CommonJS
+ true
11.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ C:\Program Files\iojs\iojs.exe
+ False
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Code
+ Mocha
+
+
+ Code
+ Mocha
+
+
+ Code
+ Mocha
+
+
+ Code
+ Mocha
+
+
+ Mocha
+
+
+ Code
+ Mocha
+
+
+ Mocha
+
+
+ Code
+ Mocha
+
+
+ Mocha
+
+
+
+ Mocha
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+
+
diff --git a/Iridium.sln b/Iridium.sln
index 9bd8174..3e496f8 100644
--- a/Iridium.sln
+++ b/Iridium.sln
@@ -1,9 +1,9 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.21005.1
+# Visual Studio 14
+VisualStudioVersion = 14.0.22609.0
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "Iridium", "Iridium.njsproj", "{A2511E8C-33BE-4B8D-8203-70D403AA446A}"
+Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "Iridium", "Iridium.njsproj", "{E9A19872-D84F-418A-8332-3DED543FB1FA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -11,10 +11,10 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {A2511E8C-33BE-4B8D-8203-70D403AA446A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A2511E8C-33BE-4B8D-8203-70D403AA446A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A2511E8C-33BE-4B8D-8203-70D403AA446A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A2511E8C-33BE-4B8D-8203-70D403AA446A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E9A19872-D84F-418A-8332-3DED543FB1FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E9A19872-D84F-418A-8332-3DED543FB1FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E9A19872-D84F-418A-8332-3DED543FB1FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E9A19872-D84F-418A-8332-3DED543FB1FA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/README.md b/README.md
index d6786d4..79195e2 100644
--- a/README.md
+++ b/README.md
@@ -1,489 +1,268 @@
-# Iridium [![Build Status](https://travis-ci.org/SierraSoftworks/Iridium.png?branch=master)](https://travis-ci.org/SierraSoftworks/Iridium) [![](https://badge.fury.io/js/iridium.png)](https://npmjs.org/package/iridium)
-**A bare metal ORM for MongoDB**
+# Iridium
+**A High Performance, IDE Friendly ODM for MongoDB**
-
+[![NPM Module](https://badge.fury.io/js/iridium.png)](https://npmjs.org/package/iridium)
+[![Build Status](https://travis-ci.org/SierraSoftworks/Iridium.png?branch=master)](https://travis-ci.org/SierraSoftworks/Iridium)
+[![Coverage Status](https://coveralls.io/repos/SierraSoftworks/Iridium/badge.svg?branch=master)](https://coveralls.io/r/SierraSoftworks/Iridium?branch=typescript)
+[![Code Climate](https://codeclimate.com/github/SierraSoftworks/Iridium/badges/gpa.svg)](https://codeclimate.com/github/SierraSoftworks/Iridium)
+[![Test Coverage](https://codeclimate.com/github/SierraSoftworks/Iridium/badges/coverage.svg)](https://codeclimate.com/github/SierraSoftworks/Iridium)
-Iridium was designed to alleviate many of the issues often present in modern ORMs, especially those designed for NoSQL datastores like MongoDB. Namely, these include a high level of bloat and an excessive amount of documentation - vastly raising the barrier to entry. On the flip side of the coin, they also tend to abstract core database functionality away from the developer to the extent that they end up jumping through unnecessary hoops just to get the results they're looking for.
-Iridium hopes to solve these issues by providing a bare bones ORM targeted at power users, and those looking for an exceptionally low overhead. It provides much of the indispensable functionality found in ORMs without the fluff.
+Iridium is designed to offer a high performance, easy to use and above all, editor friendly ODM for MongoDB on Node.js.
+Rather than adopting the "re-implement everything" approach often favoured by ODMs like Mongoose and friends, requiring
+you to learn an entirely new API and locking you into a specific coding style, Iridium tries to offer an incredibly
+lightweight implementation which makes your life easier where it counts and gets out of your way when you want to do
+anything more complex.
-## Features
- - **Crazy Lightweight**
- We've build Iridium from the ground up to minimize its memory footprint and performance overhead, we're fairly confident that you'll be hard pressed to find an ORM as fast with the same number of features. Don't believe us? Take a look at the Benchmarks section where we pit it against the *Native MongoDB Driver!*.
- - **Flexible Schema Validation**
- MongoDB's greatest strength is its ability to support dynamic schemas, we think that's a great idea but sometimes it's necessary to be able to validate aspects of your models. That's where Iridium's validation framework comes in - with an intuitive schema design framework with support for optional and dynamic fields, you'll never find yourself stuck again.
- - **Powerful Transforms**
- Anyone familiar with MongoDB knows the headaches that ObjectID causes due to its custom datatype. We also know that sometimes custom datatypes are unavoidable, or preferable for storage - though not necessarily ideal for processing. Iridium allows you to define a set of up-down transforms which are applied to parts of your model so that your code doesn't need to worry about these inconsistencies, and you can get down to writing the code you want to.
- - **Express Support**
- Everyone who has written code using Node.js knows about Express, to help make your life easier we've included support right out of the box for Express.
- - **Powerful Models**
- Iridium's models are designed to exist as individual files or modules within your application, this helps simplify management of your models and separates database design code from your application code. In addition to this, Iridium supports virtual properties, extension methods, transforms, client side property renaming and validations in an easy to understand and implement package.
- - **Caching Support**
- High performance web applications depend on accessing your data as quickly as possible, Iridium provides support for automated inline caching through any key-value store, allowing you to ensure that you can build the fastest application possible.
- - **Plugin Framework**
- Iridium allows the creation and use of plugins which can extend models and reduce duplicated code across models for common behavioural use cases. Plugins can provide custom validation, manipulate models at creation time and have the opportunity to extend instances when they are created.
- - **Automatic Query Generation**
- We understand that sometimes you don't want to structure your own queries - it's a hassle which you could do without especially when working with arrays. Thankfully, Iridium includes a powerful differential query generator which automatically generates the query necessary to store your changes without you raising a finger.
- - **[A+ Promises](https://github.com/petkaantonov/bluebird) Built In**
- We know how horrible it is having to manually wrap your favourite libraries before you can use them with promises, so we've decided to include support for the incredibly fast [Bluebird](https://github.com/petkaantonov/bluebird) promises library out of the box! (Iridium actually uses it internally as the primary handler, delegating back to callbacks for compatibility, don't tell anybody.)
-
-## Installation
-Iridium is available using *npm*, which means you can install it locally using `npm install iridium` or add it to your project's *package.json* file to have it installed automatically whenever you run `npm install`.
-
-We make use of the [Semantic Versioning](http://semver.org/) guidelines for our versioning system, as such we highly recommend you stick to a single major version of Iridium when developing an application. This can easily be handled through your *package.json* file by doing the following.
+It also means that, if you're familiar with the MongoDB CLI you should find working with Iridium very natural, with all database
+methods returning promises for their results and sensible, type annotated results being provided if you wish to make use of them.
-```javascript
-{
- // ...
- "dependencies": {
- "iridium": "4.x"
- }
-}
-```
-
-## Example
-```javascript
-var iridium = require('iridium');
-
-var database = new iridium({
- database: 'demo'
-});
-
-database.register('User', new iridium.Model(database, 'user', {
- firstname: String,
- lastname: String,
- since: Date,
- clown: Boolean,
- houses: [{
- address: String,
- colour: /Red|White|Blue|Green|Pink/
- }]
-}));
-
-database.connect(function(err, db) {
- if(err) throw err;
-
- // at this point database == db
-
- db.User.create({
- firstname: 'Billy',
- lastname: 'Bob',
- since: new Date(),
- clown: true,
- houses: [
- { address: 'The middle of nowhere', colour: 'Red' }
- ]
- }, function(err, user) {
- if(err) throw err;
-
- console.log(JSON.stringify(user));
- });
-});
-```
-
-## Benchmarks
-Since Iridium claims to be ultra-lightweight, we thought we'd share some benchmarks with you - keep in mind that in the interest of fairness we are doing our best to compare apples with apples here, so when benchmarking against the MongoDB native driver we are running Iridium queries with `{ wrap: false }`, which disables wrapping of documents in `Instance` objects - though they still pass through the validation and preprocessing frameworks, and trigger hooks.
-
-Keep in mind that benchmarks only tell half of the story, performance will vary depending on how your application is configured, the system you run it on (these benchmarks were conducted on an ANCIENT laptop that was lying around) and a number of other factors.
-
-### Iridium vs. MongoDB Driver
-As you can see, with `wrap: false`, Iridium is within a few milliseconds of the native MongoDB driver in many queries, despite adding an additional layer of security (validation) and ease of use (preprocessing). You can view the source code for this benchmark under *benchmarks/mongodb.js*.
-
-```
-> MongoDB 10000 Inserts { w: 1 }
-> => 652ms
-> Iridium 10000 Inserts { w: 1, wrap: false }
-> => 725ms
-> MongoDB find()
-> => 230ms
-> Iridium find() { wrap: false }
-> => 311ms
-> MongoDB remove()
-> => 216ms
-> Iridium remove()
-> => 213ms
-```
-
-## Core
-The Iridium core (that sounds WAY cooler than I intended when I came up with the name) is where you create a database connection and register any models to be used by the database. Registration of models is optional, however it makes accessing them easier.
+## Features
+ - **Built with TypeScript** and designed for ease of use, you'll be hard pressed to find another Node.js ORM as easy to pick
+ up and learn when combined with a supporting editor.
+ - **Promises Throughout** mean that you can easily start working with your favourite A+ compliant promise library and writing
+ more readable code. Don't think promises are the way forward? Stick with callbacks, Iridium supports both.
+ - **Fully Tested** with over 300 unit tests and over 95% test coverage, helping to ensure that Iridium always behaves the way
+ it's supposed to.
+ - **Decorator Support** helps describe your classes in an easy to understand and maintain manner, embrace ES7 with strong fallbacks
+ on ES5 compliant approaches.
+ - **Fall into Success** with Iridium's carefully designed API - which is structured to help ensure your code remains maintainable
+ regardless of how large your project becomes.
+
+## Requirements
+Iridium is built on top of a number of very modern technologies, including TypeScript 1.5, JavaScript ES6 (though we do compile
+to ES5 for compatibility with existing Node.js implementations) and the latest MongoDB Node.js Driver (version 2.0).
+
+For starters, you will need to be running MongoDB 2.6 or later in order to use Iridium - however we recommend you use MongoDB 3.0
+due to the various performance improvements they've made. If you're working with TypeScript, you will also need to use the 1.5
+compiler or risk having the Iridium type definitions break your project.
+
+## Using Iridium
+Rather than opt of the usual "Look how quickly you can do something" approach, we thought it might be useful to see
+an example which covers most of the stuff you'd need to do in Iridium. This example covers defining your own document
+interfaces, a custom schema and instance type which provides some additional methods.
+
+You'll notice that the `House` class extends Iridium's `Instance` class, which gives it methods like `save()` as well
+as change tracking when calling `save()` on the instance. If you'd prefer a lighter approach or to use your own home-grown
+implementation then you can do so by taking a look at the [Custom Instances](#custom-instances) section.
-When using Iridium, you are required to instantiate a core with a settings object which describes the database server you want to connect to. This is done by calling the core's constructor and passing an object similar to the following.
+```typescript
+///
+import {Core, Model, Instance, Collection, Index, Property, ObjectID} Iridium from 'iridium';
-```javascript
-{
- host: 'localhost', // Optional
- port: 27018, // Optional
- username: '', // Optional
- password: '', // Optional
- database: 'iridium'
+interface Colour {
+ r: number;
+ g: number;
+ b: number;
}
-```
-
-Alternatively, you can pass in a standard MongoDB URI like `mongodb://username:password@localhost:27018/iridium` in place of the configuration object, allowing Iridium to easily be used with MongoS.
-
-Once you've got a core, you need to connect it to the database. This is done by calling the core's *connect* method and giving it a callback function.
-
-
-### Registering Models
-Models can be registered with the Iridium core to provide quick access from anywhere with access to the database instance. It has the added benefit of enabling IntelliSense for these models when accessed from the database object.
-
-You are required to give each model a name by which they may be accessed, convention states that these names should begin with a capital letter to indicate that they are constructors.
-
-```javascript
-db.register('MyModel', require('./models/MyModel.js'));
-db.MyModel.get(function(err, instance) {
-
-});
-```
-
-You can also chain `register` calls to quickly load all your different models using a single line of code.
-
-```javascript
-db.register('Model1', require('./models/Model1.js')).register('Model2', require('./models/Model2.js')).connect(function(err, db) {
- if(err) throw err;
-});
-```
-
-## Database API
-We've tried to keep the Iridium API as similar to the original MongoDB Native Driver's API as possible, while still keeping it extremely easy to use. The following are a bunch of TypeScript definitions showing the different overloads available to you for Iridium's methods.
-If you don't understand TypeScript then it's easiest to think of it this way. You can use any method available from the MongoDB Native Driver using (usually) the same arguments, except the callbacks are entirely optional and a promise is always returned. On methods which select items, you can simply provide the `_id` field's value to have it automatically converted and wrapped, so doing something like `users.find('spartan563')` is entirely fine.
-
-```typescript
-interface FindFunction {
- (): promise;
- (callback: function): promise;
- (identifier: any): promise;
- (identifier: any, callback: function): promise;
- (identifier: any, options: object, callback: function): promise;
- (conditions: object): promise;
- (conditions: object, callback: function): promise;
- (conditions: object, options: object, callback: function): promise;
+interface Car {
+ make: string;
+ model: string;
+ colour: Colour;
}
-interface InsertFunction {
- (document: object): promise;
- (document: object, callback: function): promise;
- (document: object, options: object): promise;
- (document: object, options: object, callback: function): promise;
- (documents: [object]): promise;
- (documents: [object], callback: function): promise;
- (documents: [object], options: object): promise;
- (documents: [object], options: object, callback: function): promise;
+interface HouseDocument {
+ _id?: string;
+ name: string;
+
+ cars?: Car[];
}
-interface UpdateFunction {
- (conditions: object, changes: object): promise;
- (conditions: object, changes: object, callback: function): promise;
- (conditions: object, changes: object, options: object): promise;
- (conditions: object, changes: object, options: object, callback: function): promise;
+@Index({ name: 1 })
+@Collection('houses')
+class House extends Instance implements HouseDocument {
+ @ObjectID _id: string;
+ @Property(/^.+$/)
+ name: string;
+
+ @Property([{
+ make: String,
+ model: String,
+ colour: {
+ r: Number,
+ g: Number,
+ b: Number
+ }
+ }])
+ cars: Car[];
+
+ static onCreating(doc: HouseDocument) {
+ doc.cars = doc.cars || [];
+ }
+
+ addCar(make: string, model: string, colour: Colour) {
+ this.cars.push({
+ make: make,
+ model: model,
+ colour: colour
+ });
+ }
+
+ get numberOfCars() {
+ return this.cars.length;
+ }
}
-interface EnsureIndexFunction {
- (index: object): promise;
- (index: object, options: object): promise;
- (index: object, callback: function): promise;
- (index: object, options: object, callback: function): promise;
+class MyDatabase extends Core {
+ Houses = new Model(this, House);
}
-var find: FindFunction;
-var findOne: FindFunction;
-var get: FindFunction = findOne;
-
-var insert: InsertFunction;
-var create: InsertFunction = insert;
-var update: UpdateFunction;
-
-var count: FindFunction;
-var remove: FindFunction;
-
-var aggregate: function;
-
-var ensureIndex: EnsureIndexFunction;
+var myDb = new MyDatabase({ database: 'houses_test' });
+
+myDb.connect().then(() => myDb.Houses.insert({
+ name: 'My House',
+ cars: [{
+ make: 'Audi',
+ model: 'A4',
+ colour: { r: 0, g: 0, b: 0 }
+ }]
+ }))
+ .then(() => myDb.Houses.get())
+ .then((house) => {
+ house.addCar('Audi', 'S4', { r: 255, g: 255, b: 255 });
+ return house.save();
+ })
+ .then(() => myDb.close());
```
-## Models
-Iridium has been designed to make it as easy as possible to create and manage your models. To support this, models are designed to be stored within their own files - separating them from one another and keeping things logical.
-
-Each model file should export a function which accepts a reference to an Iridium Core instance, and returns the result of a model construction call.
+## Defining a Model
+Iridium models are created with a reference to their Core (which provides the database connection) and an `InstanceType` which
+is composed of a constructor function as well as a number of static properties providing configuration information for the instance.
+**JavaScript**
```javascript
-var Model = require('iridium').Model;
-module.exports = function(db) {
- var schema = {
- name: String,
- email: /.+@.+\.\w+/
- };
-
- var options = {
- methods: {
+new Model(core, InstanceType);
+```
- },
- virtuals: {
+**TypeScript**
+```typescript
+new Model(core, InstanceType);
+```
- },
- preprocessors: [],
- hooks: {
+If you're working with TypeScript, you can provide an interface for the document structure used by the database, which will allow you
+to get useful type hints when you are creating documents. You can also provide the `InstanceType` to provide useful type information
+for any instances which are retrieved from the database. This information is carried through all promises and callbacks you will use
+within Iridium and it makes your life significantly easier.
- }
- };
+Typically you will expose your models as variables on a custom Core implementation like this.
- return new Model(db, 'collectionName', schema, options);
-};
+```typescript
+class MyCore extends Core {
+ MyModel = new Model(this, MyInstanceType);
+}
```
-### Validation
-Iridium now (as of **v2.11.0**) uses [skmatc](https://sierrasoftworks.com/skmatc)(pronounced schematic) for schema validation, it allows you to quickly and easily write complex schemas in a readable manner and provides a powerful extensibility framework which you can use if you require more complex validation logic.
+## The InstanceType Constructor
+The InstanceType constructor is responsible for creating objects which represent a document retrieved from the database. It also provides
+a number of configuration details which are used to determine how Iridium works with the model.
-```javascript
-var schema = {
- username: /\w[\w\d_]{7,}/,
- email: String,
- dateOfBirth: Date,
-
- sessions: [{
- id: String,
- started: Date,
- valid: Boolean
- }]
-};
-```
+There are two approaches to defining an instance constructor - the first is to create a true wrapper like the one provided by `Iridium.Instance`
+which offers helper methods like `save()` and `remove()`, which comes in very handy for writing concise descriptive code, while the other approach
+is to simply return the document received from the database - great for performance or security purposes.
-### Methods
-Methods allow you to provide instance specific functionality in the form of callable methods on a model's instances. These methods have access to the instance, and allow you to call them directly as 1st class members.
+**TypeScript**
+```typescript
+interface Document {
+ _id?: string;
+}
-```javascript
-var options = {
- methods: {
- checkPassword: function(password) {
- return hash(password) == this.passwordHash;
- }
- }
-};
+class InstanceType {
+ constructor(model: Model, document: Document, isNew: boolean = true, isPartial: boolean = false) {
+
+ }
+
+ _id: string;
+
+ static schema: Iridium.Schema = {
+ _id: false
+ };
+
+ static collection = 'myCollection';
+}
```
-### Virtuals
-Virtuals work similarly to methods, however they represent Getter/Setter properties which also behave as first class members. The idea is that they allow you to access information which can be gathered from an instance but which you do not necessarilly wish to store in the database.
-
+**JavaScript**
```javascript
-var options = {
- virtuals: {
- forAPI: function() {
- return {
- id: this.id,
- name: this.name
- };
- },
- password: {
- get: function() { return this.passwordHash; },
- set: function(value) { this.passwordHash = hash(value); }
- }
- }
-};
-```
-
-As you can see, virtuals can either be pure getters (in which case they should not make any changes to the instance) or Getter/Setter pairs, allowing instance values to be modified.
-
-If you have no need for accessing the original database value - and it can be converted between forms losslessly, it may be preferable to make use of the preprocessor framework, as it will remove the overhead of calling a conversion function on each property access.
-
-### Hooks
-Hooks allow you to implement custom behaviour on certain events, one of the most common being the creation of a new instance. A good example of their use is the creation of a new user, where you usually receive their requested password directly. By using a hook, you can automatically convert their password into a hashed form upon creation, and save yourself the headache.
+module.exports = function(model, document, isNew, isPartial) {
+
+}
-```javascript
-var options = {
- hooks: {
- creating: function() {
- if(this.password) {
- this.passwordHash = hash(this.password);
- delete this.password;
- }
- }
- }
+module.exports.collection = 'myCollection';
+module.exports.schema = {
+ _id: false
};
```
-Other uses include the creation of default properties on models, using the *creating* hook to set the defaults if they are not present.
-
-Keep in mind that all hooks support a *done* callback if you wish to perform any kind of asynchronous operation before completing. This allows web requests, file system operations or even other database operations to be performed safely from within the hook.
-
-#### Available Hooks
- - **creating([done])**
- Called before an object is first stored in the database, `this` is set to the contents of the object being stored - allowing modification of the object prior to its insertion into the database.
- - **saving(changes[, done])**
- Called before an exisiting object is updated in the database (not called for `Model.update()`) with `this` set to the instance of the object being updated and the first argument always being the object changeset (MongoDB update syntax), allowing you to perform custom updates each time an object is saved.
- - **retrieved([done])**
- Called after an object has been retrieved from the database, but before it is wrapped into an Instance. The hook's `this` is set to the database document received - and will not have undergone any preprocessing yet.
- - **ready([done])**
- Called after an object has undergone preprocessing and has been wrapped into an Instance, allowing you to set non-persistent properties on the object (for example, retrieval time for a cache).
+### Configuration Options
+As we mentioned, configuration of a model is conducted through static properties on its constructor. These configuration options include
+the `schema` which is used to validate that all data inserted into the database through Iridium meets certain conditions, the `collection`
+which specifies the name of the MongoDB collection into which the documents are stashed and a couple of others worth noting.
-### Events
-Are you a fan of using EventEmitters? Are you too cool for school? No worries, we've got you covered. You can consume events on both models and instances using Node.js' standard event consumption functions, they behave much the same as their hook cousins with the exception that there is no way to safely manipulate the object (their call order is non-deterministic).
-
-```javascript
-// Called for all validation, hook and database errors
-model.on('error', function error(err) { });
-// Called when an object is being created in the database
-model.on('creating', function creating(document) { });
-// Called when an object is being saved to the database
-model.on('saving', function saving(instance, changes) { });
-// Called when an object is retrieved from the database/cache
-model.on('retrieved', function retrieved(instance) { });
-// Called when a new instance becomes ready
-model.on('ready', function ready(instance) { });
-
-instance.on('error', function error(err) { });
-instance.on('creating', function creating(document) { });
-instance.on('saving', function saving(instance, changes) { });
-instance.on('retrieved', function retrieved(instance) { });
-instance.on('ready', function ready(instance) { });
-```
+#### Schema
+Iridium uses [Skmatc](https://github.com/SierraSoftworks/Skmatc) for schema validation, you can read more about it on its project page but
+we'll give a quick rundown of the way you make use of it here.
-## Instances
-An instance represents a database object retrieved by Iridium, and will inherit behaviour from the model it was created to represent. In addition to this, an instance has access to a few functions for performing operations which pertain directly to that instance, including the following.
+The model's schema is defined using an object in which keys represent their document property counterparts while the values represent a validation
+rule.
-```javascript
-// Saves any changes made to the instance (only affects properties in the schema, or already retrieved from the DB)
-Instance.save().then(function complete(instance) { }, function error(err) { });
-Instance.save(function callback(err, instance) {});
-
-// Executes the requested MongoDB changes on the current instance ({ $push: { sessions: 'session_key' }} etc.)
-Instance.save(mongoChanges).then(function complete(instance) { }, function error(err) { });
-Instance.save(mongoChanges, function callback(err, instance) {});
-
-// Used for manipulating specific array elements, you can use extraConditions to select the array element to manipulate
-// For example Instance.save({ array: { $elemMatch: { id: 1 }}}, { $inc: { 'array.$.hits': 1 }});
-Instance.save(extraConditions, mongoChanges).then(function complete(instance) { }, function error(err) { });
-Instance.save(extraConditions, mongoChanges, function callback(err,instance) {})
-
-// Updates the instance's data to match the latest available data from the database
-Instance.update().then(function complete(instance) { }, function error(err) { });
-Instance.update(function callback(err, instance) {});
-
-// Removes the instance from the database
-Instance.remove().then(function complete() { }, function error(err) { });
-Instance.remove(function callback(err) {});
+**TypeScript**
+```typescript
+class InstanceType {
+ _id: string;
+ email: string;
+
+ static schema: Iridium.Schema = {
+ _id: false,
+ email: /^.+@.+$/
+ };
+}
```
-### Helpers
-The Instance object has a number of helper properties and functions available which prove useful in common use cases. These include the `document` virtual property which returns the underlying document which the Instance represents - allowing you to easily perform JSON serialization. Keep in mind that this document will have passed through the preprocessing framework. This property will be transparently overridden by Instances who's schema defines a `document` property.
-
-You will also find the `select` and `first` methods which can be used to filter an array or map for items which match certain criteria. They are based on [lodash](http://lodash.org)'s _.filter and _.first methods and by default will bind `this` to the Instance on which they are called.
-
+**JavaScript**
```javascript
-console.log(JSON.stringify(Instance.document));
-
-var session = Instance.first(Instance.sessions, function test(session) {
- return session.id == 'abcdef...';
-});
+function InstanceType() {}
-var comments = Instance.select(Instance.comments, function test(comment) {
- return comment.by = 'username';
-});
+InstanceType.schema = {
+ _id: false,
+ email: /^.+@.+$/
+};
```
-### Differential Queries
-In **v2.9.4** we added a powerful new differential query generator (codename Omnom) which allows you to easily make changes to your instances in code, and have Iridium handle the task of converting those changes to the most efficient query possible when you want to store those changes in MongoDB.
-
-Omnom allows you to do many things without needing to worry about how they are persisted to the database. These are some of the things that Omnom is well suited to handling.
-
- - Change properties or their children
- - Change the value of an array's element or its children
- - Remove elements from an array
- - Add elements to the end of an array
- - Selectively replacing an array's elements
-
-Unfortunately, there are a few limitations imposed by the way MongoDB handles queries - so when working with Iridium and Omnom we recommend you try to avoid doing the following.
-
- - Removing elements from an array while adding/changing others (will result in the array being replaced)
- - Inserting elements at the front of an array (consider reversing the array using a Concoction if you want a stack implementation that is fast)
-
-## Caching Framework
-Our caching framework allows basic queries to be served against a high performance cache, offloading requests from your database server and allowing you to more easily develop high performance applications that scale well to user demand.
-Your cache will **only** be tried for `Model.get` and `Model.findOne` requests for which the cache's `valid()` function returns true, allowing you to implement any basic cache structure you wish - including compound caches should you wish.
+### The Iridium Instance Class
+Instead of implementing your own instance constructor every time, Iridium offers a powerful and tested instance base class which provides
+a number of useful helper methods and a diff algorithm allowing you to make changes in a POCO manner.
-By default Iridium doesn't cache anything, implementing a no-op cache, but you can easily configure your own caching plugin on a per-model basis by following this example.
+To use it, simply inherit from it (if you need any computed properties or custom methods) or provide it as your instance type when instantiating
+the model.
-```javascript
-function MemoryCache() {
- this.cache = {};
+**TypeScript**
+```typescript
+class InstanceType extends Iridium.Instance {
+ _id: string;
}
-// Tells Iridium whether it can use the cache for objects that match these conditions
-MemoryCache.prototype.valid = function valid(conditions) {
- return conditions && conditions._id;
-};
-
-MemoryCache.prototype.store = function store(conditions, document, callback) {
- // Conditions are null when storing on an insert, otherwise they represent the conditions
- // that resulted in the object being retrieved from the database.
- var id = JSON.stringify(document._id);
- this.cache[id] = document;
- callback();
-};
-
-MemoryCache.prototype.fetch = function fetch(id, callback) {
- var id = JSON.stringify(conditions._id);
- callback(this.cache[id]);
-};
-
-MemoryCache.prototype.drop = function drop(conditions, callback) {
- var id = JSON.stringify(conditions._id);
- if(this.cache[id]) delete this.cache[id];
- callback();
-};
+new Iridium.Model(core, InstanceType);
```
-## Preprocessing Framework
-The preprocessing framework allows Iridium to convert values from a form better suited to your database into a form more suitable for your application in an entirely transparent manner. This is acomplished through the use of a number of preprocessors which run when retrieving an object from the database, their order is reversed when pushing an object to the database.
-
-It has been moved into its own module, Concoction, which can be used outside of Iridium - and allows you to easily extend or replace it if you wish. For more information on Concoction, visit its [project page](https://github.com/SierraSoftworks/Concoction).
-
-### Conversions
-The transforms framework provides a low-level means to convert from one value type to another by means of up/down conversion functions. The up functions are used to convert the value before it is sent UPstream to the database, while down functions are used to convert the database value into the DOWNstream value used by your application.
-
+**JavaScript**
```javascript
-var Concoction = require('concoction');
-var model = new Model(db, 'modelName', modelSchema, {
- preprocessors: [new Concoction.Convert({
- property: {
- apply: function apply(value) { return convertedValueForDatabase; },
- reverse: function reverse(value) { return convertedValueFromDatabase }
- }
- })]
- });
-```
+function InstanceType() {
+ Iridium.Instance.apply(this, arguments);
+}
-### Renames
-The renames framework allows you to access properties in a manner better suited to your application while keeping the same schema on the database side. This comes in handy when using the *_id* field for fields such as a user's username.
+require('util').inherits(InstanceType, Iridium.Instance);
-```javascript
-var Concoction = require('concoction');
-var model = new Model(db, 'modelName', modelSchema, {
- preprocessors: [new Concoction.Rename({
- _id: 'id'
- })]
- });
+new Iridium.Model(core, InstanceType);
```
-## Plugins
-Iridium allows you to use plugins which extend the functionality provided by a number of Iridium's components. These plugins can add extra functions for models and instances as well has allowing hooks to be added automatically. Plugins are imported using the `db.register(plugin)` method overload (similar to the way models are loaded), and are declared using the following layout.
+If you've used the `Iridium.Instance` constructor then you'll have a couple of useful helper methods available to you. These include `save()`, `refresh()`,
+`update()`, `remove()` and `delete()` which do more or less what it says on the can - `refresh` and `update` are synonyms for one another as are `remove` and
+`delete`.
-```javascript
-module.exports = {
- newModel: function newModel(db, collection, schema, options) {
- this.collection = collection.toLowerCase();
- this.schema._id = String,
- this.options.preprocessors = [];
- },
- newInstance: function newInstance(model, document, isNew) {
- Object.defineProperty(this, 'id', {
- get: function() { return document._id; },
- enumerable: false
- });
- }
-};
-```
+You'll also find `first()` and `select()` which allow you to select the first, or all, entr(y|ies) in a collection which match a predicate - ensuring that `this`
+maps to the instance itself within the predicate - helping to make comparisons somewhat easier within JavaScript ES5.
-## Thanks To
-I'd also like to thank [dresende](https://github.com/dresende) and [dxg](https://github.com/dxg) from the [node-orm2](https://github.com/dresende/node-orm2) project for getting me introduced to Node and giving me many of the ideas for how a good ORM should be structured. If you're looking for an easy to use and more fully featured ORM with support for SQL and NoSQL databases, I'd seriously suggest giving [node-orm2](https://github.com/dresende/node-orm2) a try.
+### Custom Instances
+If you decide to implement your own instance constructor then this is the part you'll be interested in.
\ No newline at end of file
diff --git a/README.old.md b/README.old.md
new file mode 100644
index 0000000..8b30d76
--- /dev/null
+++ b/README.old.md
@@ -0,0 +1,497 @@
+# Iridium [![Build Status](https://travis-ci.org/SierraSoftworks/Iridium.png?branch=master)](https://travis-ci.org/SierraSoftworks/Iridium) [![Coverage Status](https://coveralls.io/repos/SierraSoftworks/Iridium/badge.svg?branch=master)](https://coveralls.io/r/SierraSoftworks/Iridium?branch=typescript) [![](https://badge.fury.io/js/iridium.png)](https://npmjs.org/package/iridium) [![Code Climate](https://codeclimate.com/github/SierraSoftworks/Iridium/badges/gpa.svg)](https://codeclimate.com/github/SierraSoftworks/Iridium) [![Test Coverage](https://codeclimate.com/github/SierraSoftworks/Iridium/badges/coverage.svg)](https://codeclimate.com/github/SierraSoftworks/Iridium)
+**A bare metal ODM for MongoDB**
+
+## Version 5 Alpha
+The v5.x implementation of Iridium is not yet finished. While the API is relatively final there are still major architectural changes being made on a daily basis as we prepare v5 for stable release.
+Until then, we recommend you stick with Iridium v4.x in your applications, the documentation below covers the v4.x API and will be updated to match the v5.x API when we are ready for release.
+
+## Introduction
+Iridium isn't your traditional JavaScript ORM, it's the ORM I've always wanted and I hope you'll enjoy using it as much
+as I do. With Iridium, your models are simply JavaScript classes (if you're using ES6 or TypeScript) which means that
+you don't need to learn a new DSL just to define your database structure and that your favourite editor will be able
+to understand your code and provide useful suggestions.
+
+Iridium was designed to alleviate many of the issues often present in modern ORMs, especially those designed for NoSQL datastores like MongoDB. Namely, these include a high level of bloat and an excessive amount of documentation - vastly raising the barrier to entry. On the flip side of the coin, they also tend to abstract core database functionality away from the developer to the extent that they end up jumping through unnecessary hoops just to get the results they're looking for.
+
+Iridium hopes to solve these issues by providing a bare bones ORM targeted at power users, and those looking for an exceptionally low overhead. It provides much of the indispensable functionality found in ORMs without the fluff.
+
+## Features
+ - **Crazy Lightweight**
+ We've build Iridium from the ground up to minimize its memory footprint and performance overhead, we're fairly confident that you'll be hard pressed to find an ORM as fast with the same number of features. Don't believe us? Take a look at the Benchmarks section where we pit it against the *Native MongoDB Driver!*.
+ - **Flexible Schema Validation**
+ MongoDB's greatest strength is its ability to support dynamic schemas, we think that's a great idea but sometimes it's necessary to be able to validate aspects of your models. That's where Iridium's validation framework comes in - with an intuitive schema design framework with support for optional and dynamic fields, you'll never find yourself stuck again.
+ - **Powerful Transforms**
+ Anyone familiar with MongoDB knows the headaches that ObjectID causes due to its custom datatype. We also know that sometimes custom datatypes are unavoidable, or preferable for storage - though not necessarily ideal for processing. Iridium allows you to define a set of up-down transforms which are applied to parts of your model so that your code doesn't need to worry about these inconsistencies, and you can get down to writing the code you want to.
+ - **Express Support**
+ Everyone who has written code using Node.js knows about Express, to help make your life easier we've included support right out of the box for Express.
+ - **Powerful Models**
+ Iridium's models are designed to exist as individual files or modules within your application, this helps simplify management of your models and separates database design code from your application code. In addition to this, Iridium supports virtual properties, extension methods, transforms, client side property renaming and validations in an easy to understand and implement package.
+ - **Caching Support**
+ High performance web applications depend on accessing your data as quickly as possible, Iridium provides support for automated inline caching through any key-value store, allowing you to ensure that you can build the fastest application possible.
+ - **Plugin Framework**
+ Iridium allows the creation and use of plugins which can extend models and reduce duplicated code across models for common behavioural use cases. Plugins can provide custom validation, manipulate models at creation time and have the opportunity to extend instances when they are created.
+ - **Automatic Query Generation**
+ We understand that sometimes you don't want to structure your own queries - it's a hassle which you could do without especially when working with arrays. Thankfully, Iridium includes a powerful differential query generator which automatically generates the query necessary to store your changes without you raising a finger.
+ - **[A+ Promises](https://github.com/petkaantonov/bluebird) Built In**
+ We know how horrible it is having to manually wrap your favourite libraries before you can use them with promises, so we've decided to include support for the incredibly fast [Bluebird](https://github.com/petkaantonov/bluebird) promises library out of the box! (Iridium actually uses it internally as the primary handler, delegating back to callbacks for compatibility, don't tell anybody.)
+
+## Installation
+Iridium is available using *npm*, which means you can install it locally using `npm install iridium` or add it to your project's *package.json* file to have it installed automatically whenever you run `npm install`.
+
+We make use of the [Semantic Versioning](http://semver.org/) guidelines for our versioning system, as such we highly recommend you stick to a single major version of Iridium when developing an application. This can easily be handled through your *package.json* file by doing the following.
+
+```javascript
+{
+ // ...
+ "dependencies": {
+ "iridium": "4.x"
+ }
+}
+```
+
+## Example
+```javascript
+var iridium = require('iridium');
+
+var database = new iridium({
+ database: 'demo'
+});
+
+database.register('User', new iridium.Model(database, 'user', {
+ firstname: String,
+ lastname: String,
+ since: Date,
+ clown: Boolean,
+ houses: [{
+ address: String,
+ colour: /Red|White|Blue|Green|Pink/
+ }]
+}));
+
+database.connect(function(err, db) {
+ if(err) throw err;
+
+ // at this point database == db
+
+ db.User.create({
+ firstname: 'Billy',
+ lastname: 'Bob',
+ since: new Date(),
+ clown: true,
+ houses: [
+ { address: 'The middle of nowhere', colour: 'Red' }
+ ]
+ }, function(err, user) {
+ if(err) throw err;
+
+ console.log(JSON.stringify(user));
+ });
+});
+```
+
+## Benchmarks
+Since Iridium claims to be ultra-lightweight, we thought we'd share some benchmarks with you - keep in mind that in the interest of fairness we are doing our best to compare apples with apples here, so when benchmarking against the MongoDB native driver we are running Iridium queries with `{ wrap: false }`, which disables wrapping of documents in `Instance` objects - though they still pass through the validation and preprocessing frameworks, and trigger hooks.
+
+Keep in mind that benchmarks only tell half of the story, performance will vary depending on how your application is configured, the system you run it on (these benchmarks were conducted on an ANCIENT laptop that was lying around) and a number of other factors.
+
+### Iridium vs. MongoDB Driver
+As you can see, with `wrap: false`, Iridium is within a few milliseconds of the native MongoDB driver in many queries, despite adding an additional layer of security (validation) and ease of use (preprocessing). You can view the source code for this benchmark under *benchmarks/mongodb.js*.
+
+```
+> MongoDB 10000 Inserts { w: 1 }
+> => 652ms
+> Iridium 10000 Inserts { w: 1, wrap: false }
+> => 725ms
+> MongoDB find()
+> => 230ms
+> Iridium find() { wrap: false }
+> => 311ms
+> MongoDB remove()
+> => 216ms
+> Iridium remove()
+> => 213ms
+```
+
+## Core
+The Iridium core (that sounds WAY cooler than I intended when I came up with the name) is where you create a database connection and register any models to be used by the database. Registration of models is optional, however it makes accessing them easier.
+
+When using Iridium, you are required to instantiate a core with a settings object which describes the database server you want to connect to. This is done by calling the core's constructor and passing an object similar to the following.
+
+```javascript
+{
+ host: 'localhost', // Optional
+ port: 27018, // Optional
+ username: '', // Optional
+ password: '', // Optional
+ database: 'iridium'
+}
+```
+
+Alternatively, you can pass in a standard MongoDB URI like `mongodb://username:password@localhost:27018/iridium` in place of the configuration object, allowing Iridium to easily be used with MongoS.
+
+Once you've got a core, you need to connect it to the database. This is done by calling the core's *connect* method and giving it a callback function.
+
+
+### Registering Models
+Models can be registered with the Iridium core to provide quick access from anywhere with access to the database instance. It has the added benefit of enabling IntelliSense for these models when accessed from the database object.
+
+You are required to give each model a name by which they may be accessed, convention states that these names should begin with a capital letter to indicate that they are constructors.
+
+```javascript
+db.register('MyModel', require('./models/MyModel.js'));
+
+db.MyModel.get(function(err, instance) {
+
+});
+```
+
+You can also chain `register` calls to quickly load all your different models using a single line of code.
+
+```javascript
+db.register('Model1', require('./models/Model1.js')).register('Model2', require('./models/Model2.js')).connect(function(err, db) {
+ if(err) throw err;
+});
+```
+
+## Database API
+We've tried to keep the Iridium API as similar to the original MongoDB Native Driver's API as possible, while still keeping it extremely easy to use. The following are a bunch of TypeScript definitions showing the different overloads available to you for Iridium's methods.
+If you don't understand TypeScript then it's easiest to think of it this way. You can use any method available from the MongoDB Native Driver using (usually) the same arguments, except the callbacks are entirely optional and a promise is always returned. On methods which select items, you can simply provide the `_id` field's value to have it automatically converted and wrapped, so doing something like `users.find('spartan563')` is entirely fine.
+
+```typescript
+interface FindFunction {
+ (): promise;
+ (callback: function): promise;
+ (identifier: any): promise;
+ (identifier: any, callback: function): promise;
+ (identifier: any, options: object, callback: function): promise;
+ (conditions: object): promise;
+ (conditions: object, callback: function): promise;
+ (conditions: object, options: object, callback: function): promise;
+}
+
+interface InsertFunction {
+ (document: object): promise;
+ (document: object, callback: function): promise;
+ (document: object, options: object): promise;
+ (document: object, options: object, callback: function): promise;
+ (documents: [object]): promise;
+ (documents: [object], callback: function): promise;
+ (documents: [object], options: object): promise;
+ (documents: [object], options: object, callback: function): promise;
+}
+
+interface UpdateFunction {
+ (conditions: object, changes: object): promise;
+ (conditions: object, changes: object, callback: function): promise;
+ (conditions: object, changes: object, options: object): promise;
+ (conditions: object, changes: object, options: object, callback: function): promise;
+}
+
+interface EnsureIndexFunction {
+ (index: object): promise;
+ (index: object, options: object): promise;
+ (index: object, callback: function): promise;
+ (index: object, options: object, callback: function): promise;
+}
+
+var find: FindFunction;
+var findOne: FindFunction;
+var get: FindFunction = findOne;
+
+var insert: InsertFunction;
+var create: InsertFunction = insert;
+var update: UpdateFunction;
+
+var count: FindFunction;
+var remove: FindFunction;
+
+var aggregate: function;
+
+var ensureIndex: EnsureIndexFunction;
+```
+
+## Models
+Iridium has been designed to make it as easy as possible to create and manage your models. To support this, models are designed to be stored within their own files - separating them from one another and keeping things logical.
+
+Each model file should export a function which accepts a reference to an Iridium Core instance, and returns the result of a model construction call.
+
+```javascript
+var Model = require('iridium').Model;
+module.exports = function(db) {
+ var schema = {
+ name: String,
+ email: /.+@.+\.\w+/
+ };
+
+ var options = {
+ methods: {
+
+ },
+ virtuals: {
+
+ },
+ preprocessors: [],
+ hooks: {
+
+ }
+ };
+
+ return new Model(db, 'collectionName', schema, options);
+};
+```
+
+### Validation
+Iridium now (as of **v2.11.0**) uses [skmatc](https://sierrasoftworks.com/skmatc)(pronounced schematic) for schema validation, it allows you to quickly and easily write complex schemas in a readable manner and provides a powerful extensibility framework which you can use if you require more complex validation logic.
+
+```javascript
+var schema = {
+ username: /\w[\w\d_]{7,}/,
+ email: String,
+ dateOfBirth: Date,
+
+ sessions: [{
+ id: String,
+ started: Date,
+ valid: Boolean
+ }]
+};
+```
+
+### Methods
+Methods allow you to provide instance specific functionality in the form of callable methods on a model's instances. These methods have access to the instance, and allow you to call them directly as 1st class members.
+
+```javascript
+var options = {
+ methods: {
+ checkPassword: function(password) {
+ return hash(password) == this.passwordHash;
+ }
+ }
+};
+```
+
+### Virtuals
+Virtuals work similarly to methods, however they represent Getter/Setter properties which also behave as first class members. The idea is that they allow you to access information which can be gathered from an instance but which you do not necessarilly wish to store in the database.
+
+```javascript
+var options = {
+ virtuals: {
+ forAPI: function() {
+ return {
+ id: this.id,
+ name: this.name
+ };
+ },
+ password: {
+ get: function() { return this.passwordHash; },
+ set: function(value) { this.passwordHash = hash(value); }
+ }
+ }
+};
+```
+
+As you can see, virtuals can either be pure getters (in which case they should not make any changes to the instance) or Getter/Setter pairs, allowing instance values to be modified.
+
+If you have no need for accessing the original database value - and it can be converted between forms losslessly, it may be preferable to make use of the preprocessor framework, as it will remove the overhead of calling a conversion function on each property access.
+
+### Hooks
+Hooks allow you to implement custom behaviour on certain events, one of the most common being the creation of a new instance. A good example of their use is the creation of a new user, where you usually receive their requested password directly. By using a hook, you can automatically convert their password into a hashed form upon creation, and save yourself the headache.
+
+```javascript
+var options = {
+ hooks: {
+ creating: function() {
+ if(this.password) {
+ this.passwordHash = hash(this.password);
+ delete this.password;
+ }
+ }
+ }
+};
+```
+
+Other uses include the creation of default properties on models, using the *creating* hook to set the defaults if they are not present.
+
+Keep in mind that all hooks support a *done* callback if you wish to perform any kind of asynchronous operation before completing. This allows web requests, file system operations or even other database operations to be performed safely from within the hook.
+
+#### Available Hooks
+ - **creating([done])**
+ Called before an object is first stored in the database, `this` is set to the contents of the object being stored - allowing modification of the object prior to its insertion into the database.
+ - **saving(changes[, done])**
+ Called before an exisiting object is updated in the database (not called for `Model.update()`) with `this` set to the instance of the object being updated and the first argument always being the object changeset (MongoDB update syntax), allowing you to perform custom updates each time an object is saved.
+ - **retrieved([done])**
+ Called after an object has been retrieved from the database, but before it is wrapped into an Instance. The hook's `this` is set to the database document received - and will not have undergone any preprocessing yet.
+ - **ready([done])**
+ Called after an object has undergone preprocessing and has been wrapped into an Instance, allowing you to set non-persistent properties on the object (for example, retrieval time for a cache).
+
+### Events
+Are you a fan of using EventEmitters? Are you too cool for school? No worries, we've got you covered. You can consume events on both models and instances using Node.js' standard event consumption functions, they behave much the same as their hook cousins with the exception that there is no way to safely manipulate the object (their call order is non-deterministic).
+
+```javascript
+// Called for all validation, hook and database errors
+model.on('error', function error(err) { });
+// Called when an object is being created in the database
+model.on('creating', function creating(document) { });
+// Called when an object is being saved to the database
+model.on('saving', function saving(instance, changes) { });
+// Called when an object is retrieved from the database/cache
+model.on('retrieved', function retrieved(instance) { });
+// Called when a new instance becomes ready
+model.on('ready', function ready(instance) { });
+
+instance.on('error', function error(err) { });
+instance.on('creating', function creating(document) { });
+instance.on('saving', function saving(instance, changes) { });
+instance.on('retrieved', function retrieved(instance) { });
+instance.on('ready', function ready(instance) { });
+```
+
+## Instances
+An instance represents a database object retrieved by Iridium, and will inherit behaviour from the model it was created to represent. In addition to this, an instance has access to a few functions for performing operations which pertain directly to that instance, including the following.
+
+```javascript
+// Saves any changes made to the instance (only affects properties in the schema, or already retrieved from the DB)
+Instance.save().then(function complete(instance) { }, function error(err) { });
+Instance.save(function callback(err, instance) {});
+
+// Executes the requested MongoDB changes on the current instance ({ $push: { sessions: 'session_key' }} etc.)
+Instance.save(mongoChanges).then(function complete(instance) { }, function error(err) { });
+Instance.save(mongoChanges, function callback(err, instance) {});
+
+// Used for manipulating specific array elements, you can use extraConditions to select the array element to manipulate
+// For example Instance.save({ array: { $elemMatch: { id: 1 }}}, { $inc: { 'array.$.hits': 1 }});
+Instance.save(extraConditions, mongoChanges).then(function complete(instance) { }, function error(err) { });
+Instance.save(extraConditions, mongoChanges, function callback(err,instance) {})
+
+// Updates the instance's data to match the latest available data from the database
+Instance.update().then(function complete(instance) { }, function error(err) { });
+Instance.update(function callback(err, instance) {});
+
+// Removes the instance from the database
+Instance.remove().then(function complete() { }, function error(err) { });
+Instance.remove(function callback(err) {});
+```
+
+### Helpers
+The Instance object has a number of helper properties and functions available which prove useful in common use cases. These include the `document` virtual property which returns the underlying document which the Instance represents - allowing you to easily perform JSON serialization. Keep in mind that this document will have passed through the preprocessing framework. This property will be transparently overridden by Instances who's schema defines a `document` property.
+
+You will also find the `select` and `first` methods which can be used to filter an array or map for items which match certain criteria. They are based on [lodash](http://lodash.org)'s _.filter and _.first methods and by default will bind `this` to the Instance on which they are called.
+
+```javascript
+console.log(JSON.stringify(Instance.document));
+
+var session = Instance.first(Instance.sessions, function test(session) {
+ return session.id == 'abcdef...';
+});
+
+var comments = Instance.select(Instance.comments, function test(comment) {
+ return comment.by = 'username';
+});
+```
+
+### Differential Queries
+In **v2.9.4** we added a powerful new differential query generator (codename Omnom) which allows you to easily make changes to your instances in code, and have Iridium handle the task of converting those changes to the most efficient query possible when you want to store those changes in MongoDB.
+
+Omnom allows you to do many things without needing to worry about how they are persisted to the database. These are some of the things that Omnom is well suited to handling.
+
+ - Change properties or their children
+ - Change the value of an array's element or its children
+ - Remove elements from an array
+ - Add elements to the end of an array
+ - Selectively replacing an array's elements
+
+Unfortunately, there are a few limitations imposed by the way MongoDB handles queries - so when working with Iridium and Omnom we recommend you try to avoid doing the following.
+
+ - Removing elements from an array while adding/changing others (will result in the array being replaced)
+ - Inserting elements at the front of an array (consider reversing the array using a Concoction if you want a stack implementation that is fast)
+
+## Caching Framework
+Our caching framework allows basic queries to be served against a high performance cache, offloading requests from your database server and allowing you to more easily develop high performance applications that scale well to user demand.
+
+Your cache will **only** be tried for `Model.get` and `Model.findOne` requests for which the cache's `valid()` function returns true, allowing you to implement any basic cache structure you wish - including compound caches should you wish.
+
+By default Iridium doesn't cache anything, implementing a no-op cache, but you can easily configure your own caching plugin on a per-model basis by following this example.
+
+```javascript
+function MemoryCache() {
+ this.cache = {};
+}
+
+// Tells Iridium whether it can use the cache for objects that match these conditions
+MemoryCache.prototype.valid = function valid(conditions) {
+ return conditions && conditions._id;
+};
+
+MemoryCache.prototype.store = function store(conditions, document, callback) {
+ // Conditions are null when storing on an insert, otherwise they represent the conditions
+ // that resulted in the object being retrieved from the database.
+ var id = JSON.stringify(document._id);
+ this.cache[id] = document;
+ callback();
+};
+
+MemoryCache.prototype.fetch = function fetch(id, callback) {
+ var id = JSON.stringify(conditions._id);
+ callback(this.cache[id]);
+};
+
+MemoryCache.prototype.drop = function drop(conditions, callback) {
+ var id = JSON.stringify(conditions._id);
+ if(this.cache[id]) delete this.cache[id];
+ callback();
+};
+```
+
+## Preprocessing Framework
+The preprocessing framework allows Iridium to convert values from a form better suited to your database into a form more suitable for your application in an entirely transparent manner. This is acomplished through the use of a number of preprocessors which run when retrieving an object from the database, their order is reversed when pushing an object to the database.
+
+It has been moved into its own module, Concoction, which can be used outside of Iridium - and allows you to easily extend or replace it if you wish. For more information on Concoction, visit its [project page](https://github.com/SierraSoftworks/Concoction).
+
+### Conversions
+The transforms framework provides a low-level means to convert from one value type to another by means of up/down conversion functions. The up functions are used to convert the value before it is sent UPstream to the database, while down functions are used to convert the database value into the DOWNstream value used by your application.
+
+```javascript
+var Concoction = require('concoction');
+var model = new Model(db, 'modelName', modelSchema, {
+ preprocessors: [new Concoction.Convert({
+ property: {
+ apply: function apply(value) { return convertedValueForDatabase; },
+ reverse: function reverse(value) { return convertedValueFromDatabase }
+ }
+ })]
+ });
+```
+
+### Renames
+The renames framework allows you to access properties in a manner better suited to your application while keeping the same schema on the database side. This comes in handy when using the *_id* field for fields such as a user's username.
+
+```javascript
+var Concoction = require('concoction');
+var model = new Model(db, 'modelName', modelSchema, {
+ preprocessors: [new Concoction.Rename({
+ _id: 'id'
+ })]
+ });
+```
+
+## Plugins
+Iridium allows you to use plugins which extend the functionality provided by a number of Iridium's components. These plugins can add extra functions for models and instances as well has allowing hooks to be added automatically. Plugins are imported using the `db.register(plugin)` method overload (similar to the way models are loaded), and are declared using the following layout.
+
+```javascript
+module.exports = {
+ newModel: function newModel(db, collection, schema, options) {
+ this.collection = collection.toLowerCase();
+ this.schema._id = String,
+ this.options.preprocessors = [];
+ },
+ newInstance: function newInstance(model, document, isNew) {
+ Object.defineProperty(this, 'id', {
+ get: function() { return document._id; },
+ enumerable: false
+ });
+ }
+};
+```
+
+## Thanks To
+I'd also like to thank [dresende](https://github.com/dresende) and [dxg](https://github.com/dxg) from the [node-orm2](https://github.com/dresende/node-orm2) project for getting me introduced to Node and giving me many of the ideas for how a good ORM should be structured. If you're looking for an easy to use and more fully featured ORM with support for SQL and NoSQL databases, I'd seriously suggest giving [node-orm2](https://github.com/dresende/node-orm2) a try.
diff --git a/_references.d.ts b/_references.d.ts
new file mode 100644
index 0000000..4995816
--- /dev/null
+++ b/_references.d.ts
@@ -0,0 +1,2 @@
+///
+///
diff --git a/benchmarks/mongodb.js b/benchmarks/mongodb.js
deleted file mode 100644
index 99db7f6..0000000
--- a/benchmarks/mongodb.js
+++ /dev/null
@@ -1,143 +0,0 @@
-var async = require('async'),
- MongoClient = require('mongodb').MongoClient,
- Iridium = require('../');
-
-var objects = [];
-for(var i = 0; i < 10000; i++)
- objects.push({
- name: 'John',
- surname: 'Doe',
- birthday: new Date()
- });
-
-var iDB = new Iridium({
- database: 'iridium_bench'
-});
-
-var model = new Iridium.Model(iDB, 'iridium', {
- name: String,
- surname: String,
- birthday: Date
-});
-
-var modelWrap = new Iridium.Model(iDB, 'iridiumWrap', {
- name: String,
- surname: String,
- birthday: Date
-});
-
-iDB.register('model', model);
-
-function printTime(format, start) {
- var ms = (new Date()).getTime() - start.getTime();
- console.log(format, ms.toString() + 'ms');
-}
-
-MongoClient.connect('mongodb://localhost/iridium_bench', function(err, mDB) {
- if(err) throw err;
-
- iDB.connect(function(err) {
- if(err) throw err;
-
- // Both databases are ready, let's start testing...
-
- var mDBcol = mDB.collection('mongo');
- async.series([
- function(done) {
- mDBcol.remove({}, { w: 1 }, function(err, removed) {
- if(err) return done(err);
- return done();
- });
- },
- function(done) {
- model.remove({}, function(err, removed) {
- if(err) return done(err);
- return done();
- });
- },
- function(done) {
- console.log('MongoDB 10000 Inserts { w: 1 }');
- var start = new Date();
- mDBcol.insert(objects, { w: 1 }, function(err, inserted) {
- if(err) return done(err);
- printTime(' => %s', start);
- return done();
- });
- },
- function(done) {
- console.log('Iridium 10000 Inserts { w: 1, wrap: false }');
- var start = new Date();
- model.insert(objects, { w: 1, wrap: false }, function(err, inserted) {
- if(err) return done(err);
- printTime(' => %s', start);
- return done();
- });
- },
- function(done) {
- console.log('Iridium 10000 Inserts { w: 1, wrap: true }');
- var start = new Date();
- modelWrap.insert(objects, { w: 1, wrap: true }, function(err, inserted) {
- if(err) return done(err);
- printTime(' => %s', start);
- return done();
- });
- },
- function(done) {
- console.log('MongoDB find()');
- var start = new Date();
- mDBcol.find({}).toArray(function(err, results) {
- if(err) return done(err);
- printTime(' => %s', start);
- return done();
- });
- },
- function(done) {
- console.log('Iridium find() { wrap: false }');
- var start = new Date();
- model.find({}, { wrap: false }, function(err, results) {
- if(err) return done(err);
- printTime(' => %s', start);
- return done();
- });
- },
- function(done) {
- console.log('Iridium find() { wrap: true }');
- var start = new Date();
- modelWrap.find({}, { wrap: true }, function(err, results) {
- if(err) return done(err);
- printTime(' => %s', start);
- return done();
- });
- },
- function(done) {
- console.log('MongoDB remove()');
- var start = new Date();
- mDBcol.remove({}, function(err, results) {
- if(err) return done(err);
- printTime(' => %s', start);
- return done();
- });
- },
- function(done) {
- console.log('Iridium remove()');
- var start = new Date();
- model.remove(function(err, results) {
- if(err) return done(err);
- printTime(' => %s', start);
- return done();
- });
- },
- function(done) {
- modelWrap.remove(function(err, results) {
- if(err) return done(err);
- return done();
- });
- }
- ], function(err) {
- if(err) throw err;
-
- mDB.close();
- iDB.disconnect();
- });
- });
-});
\ No newline at end of file
diff --git a/benchmarks/mongodb.ts b/benchmarks/mongodb.ts
new file mode 100644
index 0000000..f54ce5c
--- /dev/null
+++ b/benchmarks/mongodb.ts
@@ -0,0 +1,135 @@
+///
+import Iridium = require('../index');
+import Bluebird = require('bluebird');
+import MongoDB = require('mongodb');
+import _ = require('lodash');
+import crypto = require('crypto');
+
+var intensity = 1000;
+var samples = 3;
+
+interface UserDocument {
+ _id: string;
+}
+
+class User {
+ _id: string;
+}
+
+class WrappedUser extends Iridium.Instance {
+ _id: string;
+}
+
+class IridiumDB extends Iridium.Core {
+ constructor() {
+ super({ database: 'test' });
+ }
+
+ User = new Iridium.Model(this,(model, doc) => doc, 'iridium', {
+ _id: false
+ });
+
+ UserWrapped = new Iridium.Model(this, WrappedUser, 'iridiumWrapped', {
+ _id: false
+ });
+}
+
+console.log("Running benchmark with intensity of %d, %d samples", intensity, samples);
+
+var results: { [name: string]: number } = {};
+function benchmark(name: string, prepare: (objects: UserDocument[]) => Bluebird, run: (objects: UserDocument[]) => Bluebird, compareTo?: string) {
+ return Bluebird.resolve(new Array(samples)).map(() => {
+ var objects: UserDocument[] = new Array(intensity);
+ for (var i = 0; i < objects.length; i++)
+ objects[i] = { _id: crypto.pseudoRandomBytes(16).toString('hex') };
+
+ return Bluebird.resolve().then(() => prepare(objects)).then(() => {
+ var start = new Date();
+ return Bluebird.resolve().then(() => run(objects)).then(() => {
+ var time = new Date().valueOf() - start.valueOf();
+ return time;
+ });
+ })
+ }, { concurency: 1 }).then(times => {
+ results[name] = _.reduce(times,(x, y) => x + y, 0) / times.length;
+ console.log("%s: %dms", name, results[name]);
+ if (compareTo) {
+ if (Math.abs(results[name] - results[compareTo]) / results[compareTo] < 0.1);
+ else if (results[name] > results[compareTo]) console.log(" - %dx slower than %s",(results[name] / results[compareTo]).toPrecision(2), compareTo);
+ else if (results[name] < results[compareTo]) console.log(" - %dx faster than %s",(results[name] / results[compareTo]).toPrecision(2), compareTo);
+ }
+
+ return results[name];
+ });
+}
+
+var iDB = new IridiumDB();
+iDB.connect()
+ .then(() => iDB.User.remove())
+ .then(() => iDB.UserWrapped.remove())
+ .then(() => {
+ return new Bluebird((resolve, reject) => {
+ iDB.connection.collection('mongodb').remove((err) => {
+ if (err) return reject(err);
+ return resolve(null);
+ });
+ });
+})
+ .then(() => benchmark("MongoDB insert()",() => {
+ return new Bluebird((resolve, reject) => {
+ iDB.connection.collection('mongodb').remove({},(err) => {
+ if (err) return reject(err);
+ return resolve(null);
+ });
+ });
+},(objects) => {
+ return new Bluebird((resolve, reject) => {
+ iDB.connection.collection('mongodb').insert(objects,(err, objects) => {
+ if (err) return reject(err);
+ return resolve(objects);
+ });
+ });
+ }))
+ .then(() => benchmark("Iridium insert()",() => iDB.User.remove(),(objects) => iDB.User.insert(objects), "MongoDB insert()"))
+ .then(() => benchmark("Iridium Instances insert()",() => iDB.UserWrapped.remove(),(objects) => iDB.UserWrapped.insert(objects), "MongoDB insert()"))
+
+ .then(() => benchmark("MongoDB find()",() => null,() => {
+ return new Bluebird((resolve, reject) => {
+ iDB.connection.collection('mongodb').find().toArray((err, objects: any) => {
+ if (err) return reject(err);
+ return resolve(objects);
+ });
+ });
+}))
+ .then(() => benchmark("Iridium find()",() => null,() => iDB.User.find().toArray(), "MongoDB find()"))
+ .then(() => benchmark("Iridium Instances find()",() => null,() => iDB.UserWrapped.find().toArray(), "MongoDB find()"))
+
+ .then(() => {
+ return new Bluebird((resolve, reject) => {
+ iDB.connection.collection('mongodb').remove((err, objects: any) => {
+ if (err) return reject(err);
+ return resolve(objects);
+ });
+ });
+})
+ .then(() => benchmark("MongoDB remove()",(objects) => {
+ return new Bluebird((resolve, reject) => {
+ iDB.connection.collection('mongodb').insert(objects,(err, objects) => {
+ if (err) return reject(err);
+ return resolve(objects);
+ });
+ });
+},() => {
+ return new Bluebird((resolve, reject) => {
+ iDB.connection.collection('mongodb').remove((err, objects: any) => {
+ if (err) return reject(err);
+ return resolve(objects);
+ });
+ });
+ }))
+ .then(() => iDB.User.remove())
+ .then(() => benchmark("Iridium remove()",(objects) => iDB.User.insert(objects),() => iDB.User.remove(), "MongoDB remove()"))
+ .then(() => iDB.UserWrapped.remove())
+
+ .catch((err) => console.error(err))
+ .finally(() => iDB.close());
\ No newline at end of file
diff --git a/build/build.js b/build/build.js
new file mode 100644
index 0000000..6fa1421
--- /dev/null
+++ b/build/build.js
@@ -0,0 +1,31 @@
+var gulp = require('gulp'),
+ typescript = require('gulp-typescript'),
+ sourcemaps = require('gulp-sourcemaps');
+
+var paths = require('./paths');
+
+var tsProject = {
+ module: 'commonjs',
+ target: 'es5',
+ typescript: require('typescript')
+};
+
+gulp.task('build', ['build-lib', 'build-tests']);
+
+function build(files) {
+ var tsResult = gulp.src(files, { base: paths.projectRoot })
+ .pipe(sourcemaps.init())
+ .pipe(typescript(tsProject));
+
+ return tsResult.js
+ .pipe(sourcemaps.write('.'))
+ .pipe(gulp.dest(paths.distFolder));
+}
+
+gulp.task('build-lib', function () {
+ return build(paths.buildFiles);
+});
+
+gulp.task('build-tests', function () {
+ return build(paths.testFiles);
+});
\ No newline at end of file
diff --git a/build/ci.js b/build/ci.js
new file mode 100644
index 0000000..e70b436
--- /dev/null
+++ b/build/ci.js
@@ -0,0 +1,22 @@
+var gulp = require('gulp');
+var runSequence = require('run-sequence');
+var mocha = require('gulp-mocha');
+var plumber = require('gulp-plumber');
+var path = require('path');
+
+var paths = require('./paths');
+
+gulp.task('ci', function () {
+ return runSequence('build', 'ci-test');
+});
+
+gulp.task('ci-test', function () {
+ return gulp.src(paths.builtTestFiles)
+ .pipe(plumber())
+ .pipe(mocha({
+ require: paths.testSupportFiles.map(function (file) { return path.resolve(path.dirname(__dirname), file); }),
+ timeout: 10000
+ }))
+ .once('end', function () { process.exit(); })
+ .once('error', function () { process.exit(1); });
+});
\ No newline at end of file
diff --git a/build/clean.js b/build/clean.js
new file mode 100644
index 0000000..14480ae
--- /dev/null
+++ b/build/clean.js
@@ -0,0 +1,8 @@
+var gulp = require('gulp');
+var del = require('del');
+
+var paths = require('./paths');
+
+gulp.task('clean', function (done) {
+ del(paths.cleanFiles, done);
+});
\ No newline at end of file
diff --git a/build/coverage.js b/build/coverage.js
new file mode 100644
index 0000000..416beb0
--- /dev/null
+++ b/build/coverage.js
@@ -0,0 +1,30 @@
+var gulp = require('gulp'),
+ plumber = require('gulp-plumber'),
+ istanbul = require('gulp-istanbul'),
+ mocha = require('gulp-mocha'),
+ path = require('path');
+
+var paths = require('./paths');
+
+gulp.task('coverage', function (cb) {
+ gulp.src(paths.builtFiles)
+ .pipe(istanbul())
+ .pipe(istanbul.hookRequire())
+ .on('finish', function () {
+ gulp.src(paths.builtTestFiles)
+ .pipe(plumber())
+ .pipe(mocha({
+ require: paths.testSupportFiles.map(function (file) { return path.resolve(path.dirname(__dirname), file); }),
+ timeout: 10000
+ }))
+ .pipe(istanbul.writeReports({
+ dir: paths.coverageFolder,
+ reporters: ['lcov', 'json', 'html'],
+ reportOpts: { dir: paths.coverageFolder }
+ }))
+ .pipe(istanbul.enforceThresholds({ thresholds: { global: 90 } }))
+ .once('end', function () { cb(); process.exit(); })
+ .once('error', function (err) { cb(err); process.exit(1); });
+ });
+});
+
\ No newline at end of file
diff --git a/build/default.js b/build/default.js
new file mode 100644
index 0000000..c4b969e
--- /dev/null
+++ b/build/default.js
@@ -0,0 +1,6 @@
+var gulp = require('gulp'),
+ runSequence = require('run-sequence');
+
+gulp.task('default', function () {
+ return runSequence('clean', 'build', 'test', 'watch');
+});
\ No newline at end of file
diff --git a/build/paths.js b/build/paths.js
new file mode 100644
index 0000000..6d5cb9f
--- /dev/null
+++ b/build/paths.js
@@ -0,0 +1,14 @@
+var path = require('path');
+module.exports = {
+ distFolder: path.resolve(__dirname, '../dist'),
+ projectRoot: path.dirname(__dirname),
+ coverageFolder: path.resolve(__dirname, '../coverage'),
+
+ buildFiles: ["lib/**/*.ts", "index.ts"],
+ testFiles: ["test/**/*.ts"],
+ cleanFiles: ["coverage", "dist"],
+
+ builtTestFiles: 'dist/test/*.js',
+ builtFiles: ["dist/lib/**/*.js", "dist/index.js"],
+ testSupportFiles: ['dist/test/support/chai']
+};
\ No newline at end of file
diff --git a/build/publish.js b/build/publish.js
new file mode 100644
index 0000000..aba16fd
--- /dev/null
+++ b/build/publish.js
@@ -0,0 +1,24 @@
+var gulp = require('gulp'),
+ runSequence = require('run-sequence'),
+ replace = require('gulp-replace'),
+ spawn = require('child_process').spawn;
+
+gulp.task('publish', function () {
+ return runSequence('publish-prep', 'publish-action', 'publish-clean');
+});
+
+gulp.task('publish-prep', function () {
+ return gulp.src('_references.d.ts')
+ .pipe(replace(/^\/{3}.*tsd\.d\.ts.*$/, '//$0'))
+ .pipe(gulp.dest('.'));
+});
+
+gulp.task('publish-action', function (done) {
+ spawn('npm', ['publish'], { stdio: 'inherit' }).on('close', done);
+});
+
+gulp.task('publish-clean', function () {
+ return gulp.src('_references.d.ts')
+ .pipe(replace(/^\/{2}(\/{3}.*tsd\.d\.ts.*)$/, '$1'))
+ .pipe(gulp.dest('.'));
+});
\ No newline at end of file
diff --git a/build/test.js b/build/test.js
new file mode 100644
index 0000000..64b8974
--- /dev/null
+++ b/build/test.js
@@ -0,0 +1,13 @@
+var gulp = require('gulp'),
+ mocha = require('gulp-mocha'),
+ path = require('path');
+
+var paths = require('./paths');
+
+gulp.task('test', function () {
+ return gulp.src(paths.builtTestFiles)
+ .pipe(mocha({
+ require: paths.testSupportFiles.map(function (file) { return path.resolve(path.dirname(__dirname), file); }),
+ timeout: 10000
+ }));
+});
\ No newline at end of file
diff --git a/build/version.js b/build/version.js
new file mode 100644
index 0000000..0b6910e
--- /dev/null
+++ b/build/version.js
@@ -0,0 +1,61 @@
+var gulp = require('gulp'),
+ bump = require('gulp-bump'),
+ gutil = require('gulp-util'),
+ git = require('gulp-git'),
+ minimist = require('minimist'),
+ semver = require('semver'),
+ runSequence = require('run-sequence'),
+ fs = require('fs');
+
+function getPackageJsonVersion() {
+ //We parse the json file instead of using require because require caches multiple calls so the version number won't be updated
+ return JSON.parse(fs.readFileSync('./package.json', 'utf8')).version;
+}
+
+gulp.task('version-bump', function () {
+ var args = minimist(process.argv);
+
+ var options = {};
+ if (semver.valid(args.version)) options.version = args.version;
+ else options.type = args.version;
+
+ return gulp.src(['./package.json'])
+ .pipe(bump(options).on('error', gutil.log))
+ .pipe(gulp.dest('./'));
+});
+
+gulp.task('version-commit', function () {
+ var version = getPackageJsonVersion();
+ return gulp.src('.')
+ .pipe(git.commit('Version ' + version));
+});
+
+gulp.task('version-push', function (cb) {
+ git.push('origin', 'master', cb);
+});
+
+gulp.task('version-tag', function (cb) {
+ var version = getPackageJsonVersion();
+ git.tag(version, 'Version ' + version, function (error) {
+ if (error) {
+ return cb(error);
+ }
+ git.push('origin', 'master', { args: '--tags' }, cb);
+ });
+});
+
+gulp.task('version', function (callback) {
+ runSequence(
+ 'version-bump',
+ 'version-commit',
+ 'version-push',
+ 'version-tag',
+ function (error) {
+ if (error) {
+ console.log(error.message);
+ } else {
+ console.log('Version set and comitted successfully');
+ }
+ callback(error);
+ });
+});
\ No newline at end of file
diff --git a/build/watch.js b/build/watch.js
new file mode 100644
index 0000000..9479025
--- /dev/null
+++ b/build/watch.js
@@ -0,0 +1,13 @@
+var gulp = require('gulp');
+var runSequence = require('run-sequence');
+var paths = require('./paths.js');
+
+gulp.task('watch', function () {
+ gulp.watch(paths.buildFiles, function () {
+ return runSequence('build-lib', 'test');
+ });
+
+ gulp.watch(paths.testFiles, function () {
+ return runSequence('build-tests', 'test');
+ });
+});
\ No newline at end of file
diff --git a/dist/index.js b/dist/index.js
new file mode 100644
index 0000000..117df64
--- /dev/null
+++ b/dist/index.js
@@ -0,0 +1,25 @@
+function __export(m) {
+ for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
+}
+var Core_1 = require('./lib/Core');
+exports.Core = Core_1.default;
+var Model_1 = require('./lib/Model');
+exports.Model = Model_1.default;
+var Instance_1 = require('./lib/Instance');
+exports.Instance = Instance_1.default;
+__export(require('./lib/Decorators'));
+__export(require('./lib/Plugins'));
+__export(require('./lib/Schema'));
+__export(require('./lib/Cache'));
+__export(require('./lib/CacheDirector'));
+__export(require('./lib/ModelOptions'));
+__export(require('./lib/Configuration'));
+__export(require('./lib/Hooks'));
+var MemoryCache_1 = require('./lib/caches/MemoryCache');
+exports.MemoryCache = MemoryCache_1.default;
+var NoOpCache_1 = require('./lib/caches/NoOpCache');
+exports.NoOpCache = NoOpCache_1.default;
+var IDDirector_1 = require('./lib/cacheControllers/IDDirector');
+exports.CacheOnID = IDDirector_1.default;
+
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/dist/index.js.map b/dist/index.js.map
new file mode 100644
index 0000000..ef316a3
--- /dev/null
+++ b/dist/index.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["index.ts"],"names":[],"mappings":";;;AAAA,qBAAiB,YAAY,CAAC,CAAA;AAGtB,YAAI,kBAHkB;AAC9B,sBAAkB,aAAa,CAAC,CAAA;AAElB,aAAK,mBAFa;AAChC,yBAAqB,gBAAgB,CAAC,CAAA;AACjB,gBAAQ,sBADS;AAGtC,iBAAc,kBAAkB,CAAC,EAAA;AAEjC,iBAAc,eAAe,CAAC,EAAA;AAC9B,iBAAc,cAAc,CAAC,EAAA;AAC7B,iBAAc,aAAa,CAAC,EAAA;AAC5B,iBAAc,qBAAqB,CAAC,EAAA;AACpC,iBAAc,oBAAoB,CAAC,EAAA;AACnC,iBAAc,qBAAqB,CAAC,EAAA;AACpC,iBAAc,aAAa,CAAC,EAAA;AAE5B,4BAAwB,0BAA0B,CAAC,CAAA;AAE3C,mBAAW,yBAFgC;AACnD,0BAAsB,wBAAwB,CAAC,CAAA;AAC1B,iBAAS,uBADiB;AAG/C,2BAAuB,mCAAmC,CAAC,CAAA;AACrC,iBAAS,wBAD4B;AAC1B","file":"index.js","sourcesContent":["import Core from './lib/Core';\r\nimport Model from './lib/Model';\r\nimport Instance from './lib/Instance';\r\nexport {Core, Model, Instance};\r\n\r\nexport * from './lib/Decorators';\r\n\r\nexport * from './lib/Plugins';\r\nexport * from './lib/Schema';\r\nexport * from './lib/Cache';\r\nexport * from './lib/CacheDirector';\r\nexport * from './lib/ModelOptions';\r\nexport * from './lib/Configuration';\r\nexport * from './lib/Hooks';\r\n\r\nimport MemoryCache from './lib/caches/MemoryCache';\r\nimport NoOpCache from './lib/caches/NoOpCache';\r\nexport {MemoryCache, NoOpCache};\r\n\r\nimport IDDirector from './lib/cacheControllers/IDDirector';\r\nexport {IDDirector as CacheOnID};"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/Cache.js b/dist/lib/Cache.js
new file mode 100644
index 0000000..d1bbc7d
--- /dev/null
+++ b/dist/lib/Cache.js
@@ -0,0 +1,3 @@
+
+
+//# sourceMappingURL=../lib/Cache.js.map
\ No newline at end of file
diff --git a/dist/lib/Cache.js.map b/dist/lib/Cache.js.map
new file mode 100644
index 0000000..8fe1036
--- /dev/null
+++ b/dist/lib/Cache.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/Cache.ts"],"names":[],"mappings":"AAOC","file":"lib/Cache.js","sourcesContent":["/// \r\nimport Bluebird = require('bluebird');\r\n\r\nexport interface Cache {\r\n set(key: string, value: T): void;\r\n get(key: string): Bluebird;\r\n clear(key: string): void\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/CacheDirector.js b/dist/lib/CacheDirector.js
new file mode 100644
index 0000000..fa0218f
--- /dev/null
+++ b/dist/lib/CacheDirector.js
@@ -0,0 +1,3 @@
+///
+
+//# sourceMappingURL=../lib/CacheDirector.js.map
\ No newline at end of file
diff --git a/dist/lib/CacheDirector.js.map b/dist/lib/CacheDirector.js.map
new file mode 100644
index 0000000..a6557ff
--- /dev/null
+++ b/dist/lib/CacheDirector.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/CacheDirector.ts"],"names":[],"mappings":"AAAA,AACA,4CAD4C;AAO3C","file":"lib/CacheDirector.js","sourcesContent":["/// \r\nexport interface CacheDirector {\r\n valid(object: T): boolean;\r\n buildKey(object: T): string;\r\n\r\n validQuery(conditions: any): boolean;\r\n buildQueryKey(conditions: any): string;\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/Configuration.js b/dist/lib/Configuration.js
new file mode 100644
index 0000000..01a23ff
--- /dev/null
+++ b/dist/lib/Configuration.js
@@ -0,0 +1,3 @@
+///
+
+//# sourceMappingURL=../lib/Configuration.js.map
\ No newline at end of file
diff --git a/dist/lib/Configuration.js.map b/dist/lib/Configuration.js.map
new file mode 100644
index 0000000..f15a39c
--- /dev/null
+++ b/dist/lib/Configuration.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/Configuration.ts"],"names":[],"mappings":"AAAA,AACA,4CAD4C;AAS3C","file":"lib/Configuration.js","sourcesContent":["/// \r\nexport interface Configuration {\r\n host?: string;\r\n port?: number;\r\n hosts?: { address: string; port?: number }[];\r\n database?: string;\r\n username?: string;\r\n password?: string;\r\n [key:string]: any;\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/Core.js b/dist/lib/Core.js
new file mode 100644
index 0000000..f39bfbb
--- /dev/null
+++ b/dist/lib/Core.js
@@ -0,0 +1,169 @@
+///
+var Bluebird = require('bluebird');
+var MongoDB = require('mongodb');
+var _ = require('lodash');
+var Express_1 = require('./middleware/Express');
+var NoOpCache_1 = require('./caches/NoOpCache');
+var mongoConnectAsyc = Bluebird.promisify(MongoDB.MongoClient.connect);
+var Core = (function () {
+ function Core(uri, config) {
+ this._plugins = [];
+ this._cache = new NoOpCache_1.default();
+ var args = Array.prototype.slice.call(arguments, 0);
+ uri = config = null;
+ for (var i = 0; i < args.length; i++) {
+ if (typeof args[i] == 'string')
+ uri = args[i];
+ else if (typeof args[i] == 'object')
+ config = args[i];
+ }
+ if (!uri && !config)
+ throw new Error("Expected either a URI or config object to be supplied when initializing Iridium");
+ this._url = uri;
+ this._config = config;
+ }
+ Object.defineProperty(Core.prototype, "plugins", {
+ /**
+ * Gets the plugins registered with this Iridium Core
+ * @returns {[Iridium.Plugin]}
+ */
+ get: function () {
+ return this._plugins;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Core.prototype, "settings", {
+ /**
+ * Gets the configuration specified in the construction of this
+ * Iridium Core.
+ * @returns {Iridium.Configuration}
+ */
+ get: function () {
+ return this._config;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Core.prototype, "connection", {
+ /**
+ * Gets the currently active database connection for this Iridium
+ * Core.
+ * @returns {MongoDB.Db}
+ */
+ get: function () {
+ return this._connection;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Core.prototype, "url", {
+ /**
+ * Gets the URL used to connect to MongoDB
+ * @returns {String}
+ */
+ get: function () {
+ var _this = this;
+ if (this._url)
+ return this._url;
+ var url = 'mongodb://';
+ if (this._config.username) {
+ url += this._config.username;
+ if (this._config.password)
+ url += ':' + this._config.password;
+ url += '@';
+ }
+ var hosts = [];
+ if (this._config.host) {
+ if (this._config.port)
+ hosts.push(this._config.host + ':' + this._config.port);
+ else
+ hosts.push(this._config.host);
+ }
+ if (this._config.hosts) {
+ _.each(this._config.hosts, function (host) {
+ if (host.port)
+ hosts.push(host.address + ':' + host.port);
+ else if (_this._config.port)
+ hosts.push(host.address + ':' + _this._config.port);
+ else
+ hosts.push(host.address);
+ });
+ }
+ if (hosts.length)
+ url += _.uniq(hosts).join(',');
+ else
+ url += 'localhost';
+ url += '/' + this._config.database;
+ return url;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Core.prototype, "cache", {
+ /**
+ * Gets the cache used to store objects retrieved from the database for performance reasons
+ * @returns {cache}
+ */
+ get: function () {
+ return this._cache;
+ },
+ set: function (value) {
+ this._cache = value;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ /**
+ * Registers a new plugin with this Iridium Core
+ * @param {Iridium.Plugin} plugin The plugin to register with this Iridium Core
+ * @returns {Iridium.Core}
+ */
+ Core.prototype.register = function (plugin) {
+ this.plugins.push(plugin);
+ return this;
+ };
+ /**
+ * Connects to the database server specified in the provided configuration
+ * @param {function(Error, Iridium.Core)} [callback] A callback to be triggered once the connection is established.
+ * @returns {Promise}
+ */
+ Core.prototype.connect = function (callback) {
+ var self = this;
+ return Bluebird.bind(this).then(function () {
+ if (self._connection)
+ return self._connection;
+ return mongoConnectAsyc(self.url);
+ }).then(function (db) {
+ self._connection = db;
+ return self;
+ }).nodeify(callback);
+ };
+ /**
+ * Closes the active database connection
+ * @type {Promise}
+ */
+ Core.prototype.close = function () {
+ var self = this;
+ return Bluebird.bind(this).then(function () {
+ if (!self._connection)
+ return this;
+ var conn = self._connection;
+ self._connection = null;
+ conn.close();
+ return this;
+ });
+ };
+ /**
+ * Provides an express middleware which can be used to set the req.db property
+ * to the current Iridium instance.
+ * @returns {Iridium.ExpressMiddleware}
+ */
+ Core.prototype.express = function () {
+ return Express_1.default(this);
+ };
+ return Core;
+})();
+exports.default = Core;
+
+//# sourceMappingURL=../lib/Core.js.map
\ No newline at end of file
diff --git a/dist/lib/Core.js.map b/dist/lib/Core.js.map
new file mode 100644
index 0000000..5ed979e
--- /dev/null
+++ b/dist/lib/Core.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/Core.ts"],"names":["Core","Core.constructor","Core.plugins","Core.settings","Core.connection","Core.url","Core.cache","Core.register","Core.connect","Core.close","Core.express"],"mappings":"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","file":"lib/Core.js","sourcesContent":["/// \r\nimport Bluebird = require('bluebird');\r\nimport MongoDB = require('mongodb');\r\nimport _ = require('lodash');\r\nimport http = require('http');\r\nimport events = require('events');\r\n\r\nimport {Configuration} from './Configuration';\r\nimport {Plugin} from './Plugins';\r\nimport Model from './Model';\r\nimport Instance from './Instance';\r\n\r\nimport {MiddlewareFactory} from './Middleware';\r\nimport * as ExpressMiddleware from './middleware/Express';\r\nimport ExpressMiddlewareFactory from './middleware/Express';\r\n\r\nimport {Cache} from './Cache';\r\nimport NoOpCache from './caches/NoOpCache';\r\nimport MemoryCache from './caches/MemoryCache';\r\n\r\nvar mongoConnectAsyc = Bluebird.promisify(MongoDB.MongoClient.connect);\r\n\r\nexport default class Core {\r\n /**\r\n * Creates a new Iridium Core instance connected to the specified MongoDB instance\r\n * @param {Iridium.IridiumConfiguration} config The config object defining the database to connect to\r\n * @constructs Core\r\n */\r\n constructor(config: Configuration);\r\n /**\r\n * Creates a new Iridium Core instance connected to the specified MongoDB instance\r\n * @param {String} url The URL of the MongoDB instance to connect to\r\n * @param {Iridium.IridiumConfiguration} config The config object made available as settings\r\n * @constructs Core\r\n */\r\n constructor(uri: string, config?: Configuration);\r\n constructor(uri: string | Configuration, config?: Configuration) {\r\n\r\n var args = Array.prototype.slice.call(arguments, 0);\r\n uri = config = null;\r\n for (var i = 0; i < args.length; i++) {\r\n if (typeof args[i] == 'string')\r\n uri = args[i];\r\n else if (typeof args[i] == 'object')\r\n config = args[i];\r\n }\r\n\r\n if (!uri && !config) throw new Error(\"Expected either a URI or config object to be supplied when initializing Iridium\");\r\n\r\n this._url = uri;\r\n this._config = config;\r\n }\r\n \r\n private _plugins: Plugin[] = [];\r\n private _url: string;\r\n private _config: Configuration;\r\n private _connection: MongoDB.Db;\r\n private _cache: Cache = new NoOpCache();\r\n \r\n /**\r\n * Gets the plugins registered with this Iridium Core\r\n * @returns {[Iridium.Plugin]}\r\n */\r\n get plugins(): Plugin[] {\r\n return this._plugins;\r\n }\r\n\r\n /**\r\n * Gets the configuration specified in the construction of this\r\n * Iridium Core.\r\n * @returns {Iridium.Configuration}\r\n */\r\n get settings(): Configuration {\r\n return this._config;\r\n }\r\n\r\n /**\r\n * Gets the currently active database connection for this Iridium\r\n * Core.\r\n * @returns {MongoDB.Db}\r\n */\r\n get connection(): MongoDB.Db {\r\n return this._connection;\r\n }\r\n\r\n /**\r\n * Gets the URL used to connect to MongoDB\r\n * @returns {String}\r\n */\r\n get url(): string {\r\n if (this._url) return this._url;\r\n var url: string = 'mongodb://';\r\n\r\n if (this._config.username) {\r\n url += this._config.username;\r\n if (this._config.password)\r\n url += ':' + this._config.password;\r\n url += '@';\r\n }\r\n\r\n var hosts = [];\r\n\r\n if (this._config.host) {\r\n if (this._config.port)\r\n hosts.push(this._config.host + ':' + this._config.port);\r\n else\r\n hosts.push(this._config.host);\r\n }\r\n\r\n if (this._config.hosts) {\r\n _.each(this._config.hosts, (host) => {\r\n if (host.port)\r\n hosts.push(host.address + ':' + host.port);\r\n else if(this._config.port)\r\n hosts.push(host.address + ':' + this._config.port);\r\n else\r\n hosts.push(host.address);\r\n });\r\n }\r\n\r\n if (hosts.length)\r\n url += _.uniq(hosts).join(',');\r\n else\r\n url += 'localhost';\r\n\r\n url += '/' + this._config.database;\r\n\r\n return url;\r\n }\r\n\r\n /**\r\n * Gets the cache used to store objects retrieved from the database for performance reasons\r\n * @returns {cache}\r\n */\r\n get cache(): Cache {\r\n return this._cache;\r\n }\r\n\r\n set cache(value: Cache) {\r\n this._cache = value;\r\n }\r\n\r\n /**\r\n * Registers a new plugin with this Iridium Core\r\n * @param {Iridium.Plugin} plugin The plugin to register with this Iridium Core\r\n * @returns {Iridium.Core}\r\n */\r\n register(plugin: Plugin): Core {\r\n this.plugins.push(plugin);\r\n return this;\r\n }\r\n\r\n /**\r\n * Connects to the database server specified in the provided configuration\r\n * @param {function(Error, Iridium.Core)} [callback] A callback to be triggered once the connection is established.\r\n * @returns {Promise}\r\n */\r\n connect(callback?: (err: Error, core: Core) => any): Bluebird {\r\n var self = this;\r\n return Bluebird.bind(this).then(function() {\r\n if (self._connection) return self._connection;\r\n return mongoConnectAsyc(self.url);\r\n }).then(function(db: MongoDB.Db) {\r\n self._connection = db;\r\n return self;\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Closes the active database connection\r\n * @type {Promise}\r\n */\r\n close(): Bluebird {\r\n var self = this;\r\n return Bluebird.bind(this).then(function() {\r\n if (!self._connection) return this;\r\n var conn: MongoDB.Db = self._connection;\r\n self._connection = null;\r\n conn.close();\r\n return this;\r\n });\r\n }\r\n\r\n /**\r\n * Provides an express middleware which can be used to set the req.db property\r\n * to the current Iridium instance.\r\n * @returns {Iridium.ExpressMiddleware}\r\n */\r\n express(): ExpressMiddleware.ExpressMiddleware {\r\n return ExpressMiddlewareFactory(this);\r\n }\r\n}\r\n"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/Cursor.js b/dist/lib/Cursor.js
new file mode 100644
index 0000000..f0482b0
--- /dev/null
+++ b/dist/lib/Cursor.js
@@ -0,0 +1,144 @@
+var Bluebird = require('bluebird');
+var Cursor = (function () {
+ /**
+ * Creates a new Iridium cursor which wraps a MongoDB cursor object
+ * @param {Model} model The Iridium model that this cursor belongs to
+ * @param {Object} conditions The conditions that resulte in this cursor being created
+ * @param {MongoDB.Cursor} cursor The MongoDB native cursor object to be wrapped
+ * @constructor
+ */
+ function Cursor(model, conditions, cursor) {
+ this.model = model;
+ this.conditions = conditions;
+ this.cursor = cursor;
+ }
+ /**
+ * Counts the number of documents which are matched by this cursor
+ * @param {function(Error, Number)} callback A callback which is triggered when the result is available
+ * @return {Promise} A promise which will resolve with the number of documents matched by this cursor
+ */
+ Cursor.prototype.count = function (callback) {
+ var _this = this;
+ return new Bluebird(function (resolve, reject) {
+ _this.cursor.count(true, function (err, count) {
+ if (err)
+ return reject(err);
+ return resolve(count);
+ });
+ }).nodeify(callback);
+ };
+ /**
+ * Runs the specified handler over each instance in the query results
+ * @param {function(Instance)} handler The handler which is triggered for each element in the query
+ * @param {function(Error)} callback A callback which is triggered when all operations have been dispatched
+ * @return {Promise} A promise which is resolved when all operations have been dispatched
+ */
+ Cursor.prototype.forEach = function (handler, callback) {
+ var _this = this;
+ var helpers = this.model.helpers;
+ return new Bluebird(function (resolve, reject) {
+ _this.cursor.forEach(function (item) {
+ _this.model.handlers.documentReceived(_this.conditions, item, function () { return helpers.wrapDocument.apply(helpers, arguments); }).then(handler);
+ }, function (err) {
+ if (err)
+ return reject(err);
+ return resolve(null);
+ });
+ }).nodeify(callback);
+ };
+ /**
+ * Runs the specified transform over each instance in the query results and returns the resulting transformed objects
+ * @param {function(Instance): TResult} transform A handler which is used to transform the result objects
+ * @param {function(Error, TResult[])} callback A callback which is triggered when the transformations are completed
+ * @return {Promise} A promise which is fulfilled with the results of the transformations
+ */
+ Cursor.prototype.map = function (transform, callback) {
+ var _this = this;
+ var helpers = this.model.helpers;
+ return new Bluebird(function (resolve, reject) {
+ var promises = [];
+ _this.cursor.forEach(function (item) {
+ promises.push(_this.model.handlers.documentReceived(_this.conditions, item, function () { return helpers.wrapDocument.apply(helpers, arguments); })
+ .then(transform));
+ }, function (err) {
+ if (err)
+ return reject(err);
+ return resolve(Bluebird.all(promises));
+ });
+ }).nodeify(callback);
+ };
+ /**
+ * Retrieves all matching instances and returns them in an array
+ * @param {function(Error, TInstance[])} callback A callback which is triggered with the resulting instances
+ * @return {Promise} A promise which resolves with the instances returned by the query
+ */
+ Cursor.prototype.toArray = function (callback) {
+ var _this = this;
+ var helpers = this.model.helpers;
+ return new Bluebird(function (resolve, reject) {
+ _this.cursor.toArray(function (err, results) {
+ if (err)
+ return reject(err);
+ return resolve(results);
+ });
+ }).map(function (document) {
+ return _this.model.handlers.documentReceived(_this.conditions, document, function () { return helpers.wrapDocument.apply(helpers, arguments); });
+ }).nodeify(callback);
+ };
+ /**
+ * Retrieves the next item in the results list
+ * @param {function(Error, TInstance)} callback A callback which is triggered when the next item becomes available
+ * @return {Promise} A promise which is resolved with the next item
+ */
+ Cursor.prototype.next = function (callback) {
+ var _this = this;
+ return new Bluebird(function (resolve, reject) {
+ _this.cursor.next(function (err, result) {
+ if (err)
+ return reject(err);
+ return resolve(result);
+ });
+ }).then(function (document) {
+ if (!document)
+ return Bluebird.resolve(null);
+ return _this.model.handlers.documentReceived(_this.conditions, document, function (document, isNew, isPartial) { return _this.model.helpers.wrapDocument(document, isNew, isPartial); });
+ }).nodeify(callback);
+ };
+ /**
+ * Returns a new cursor which behaves the same as this one did before any results were retrieved
+ * @return {Cursor} The new cursor which starts at the beginning of the results
+ */
+ Cursor.prototype.rewind = function () {
+ this.cursor.rewind();
+ return this;
+ };
+ /**
+ * Returns a new cursor which sorts its results by the given index expression
+ * @param {model.IndexSpecification} sortExpression The index expression dictating the sort order and direction to use
+ * @return {Cursor} The new cursor which sorts its results by the sortExpression
+ */
+ Cursor.prototype.sort = function (sortExpression) {
+ return new Cursor(this.model, this.conditions, this.cursor.sort(sortExpression));
+ };
+ /**
+ * Returns a new cursor which limits the number of returned results
+ * @param {Number} limit The maximum number of results to return
+ * @return {Cursor} The new cursor which will return a maximum number of results
+ */
+ Cursor.prototype.limit = function (limit) {
+ return new Cursor(this.model, this.conditions, this.cursor.limit(limit));
+ };
+ /**
+ * Returns a new cursor which skips a number of results before it begins
+ * returning any.
+ * @param {Number} skip The number of results to skip before the cursor beings returning
+ * @return {Cursor} The new cursor which skips a number of results
+ */
+ Cursor.prototype.skip = function (skip) {
+ return new Cursor(this.model, this.conditions, this.cursor.skip(skip));
+ };
+ return Cursor;
+})();
+exports.default = Cursor;
+
+//# sourceMappingURL=../lib/Cursor.js.map
\ No newline at end of file
diff --git a/dist/lib/Cursor.js.map b/dist/lib/Cursor.js.map
new file mode 100644
index 0000000..f201972
--- /dev/null
+++ b/dist/lib/Cursor.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/Cursor.ts"],"names":["Cursor","Cursor.constructor","Cursor.count","Cursor.forEach","Cursor.map","Cursor.toArray","Cursor.next","Cursor.rewind","Cursor.sort","Cursor.limit","Cursor.skip"],"mappings":"AAIA,IAAO,QAAQ,WAAW,UAAU,CAAC,CAAC;AAGtC;IACIA;;;;;;OAMGA;IACHA,gBAAoBA,KAAkCA,EAAUA,UAAeA,EAASA,MAAsBA;QAA1FC,UAAKA,GAALA,KAAKA,CAA6BA;QAAUA,eAAUA,GAAVA,UAAUA,CAAKA;QAASA,WAAMA,GAANA,MAAMA,CAAgBA;IAE9GA,CAACA;IAEDD;;;;OAIGA;IACHA,sBAAKA,GAALA,UAAMA,QAAmCA;QAAzCE,iBAOCA;QANGA,MAAMA,CAACA,IAAIA,QAAQA,CAASA,UAACA,OAAOA,EAAEA,MAAMA;YACxCA,KAAIA,CAACA,MAAMA,CAACA,KAAKA,CAACA,IAAIA,EAACA,UAACA,GAAGA,EAAEA,KAAKA;gBAC9BA,EAAEA,CAACA,CAACA,GAAGA,CAACA;oBAACA,MAAMA,CAACA,MAAMA,CAACA,GAAGA,CAACA,CAACA;gBAC5BA,MAAMA,CAACA,OAAOA,CAAMA,KAAKA,CAACA,CAACA;YAC/BA,CAACA,CAACA,CAACA;QACPA,CAACA,CAACA,CAACA,OAAOA,CAACA,QAAQA,CAACA,CAACA;IACzBA,CAACA;IAEDF;;;;;OAKGA;IACHA,wBAAOA,GAAPA,UAAQA,OAAsCA,EAAEA,QAAiCA;QAAjFG,iBAUCA;QATGA,IAAIA,OAAOA,GAAGA,IAAIA,CAACA,KAAKA,CAACA,OAAOA,CAACA;QACjCA,MAAMA,CAACA,IAAIA,QAAQA,CAAOA,UAACA,OAAOA,EAAEA,MAAMA;YACtCA,KAAIA,CAACA,MAAMA,CAACA,OAAOA,CAACA,UAACA,IAAeA;gBAChCA,KAAIA,CAACA,KAAKA,CAACA,QAAQA,CAACA,gBAAgBA,CAACA,KAAIA,CAACA,UAAUA,EAAEA,IAAIA,EAAEA,cAAc,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAACA,CAACA,IAAIA,CAACA,OAAOA,CAACA,CAACA;YACtJA,CAACA,EAACA,UAACA,GAAGA;gBACFA,EAAEA,CAACA,CAACA,GAAGA,CAACA;oBAACA,MAAMA,CAACA,MAAMA,CAACA,GAAGA,CAACA,CAACA;gBAC5BA,MAAMA,CAACA,OAAOA,CAACA,IAAIA,CAACA,CAACA;YACzBA,CAACA,CAACA,CAACA;QACPA,CAACA,CAACA,CAACA,OAAOA,CAACA,QAAQA,CAACA,CAACA;IACzBA,CAACA;IAEDH;;;;;OAKGA;IACHA,oBAAGA,GAAHA,UAAaA,SAA+DA,EAAEA,QAAsCA;QAApHI,iBAYCA;QAXGA,IAAIA,OAAOA,GAAGA,IAAIA,CAACA,KAAKA,CAACA,OAAOA,CAACA;QACjCA,MAAMA,CAACA,IAAIA,QAAQA,CAAYA,UAACA,OAAOA,EAAEA,MAAMA;YAC3CA,IAAIA,QAAQA,GAAwBA,EAAEA,CAACA;YACvCA,KAAIA,CAACA,MAAMA,CAACA,OAAOA,CAACA,UAACA,IAAeA;gBAChCA,QAAQA,CAACA,IAAIA,CAACA,KAAIA,CAACA,KAAKA,CAACA,QAAQA,CAACA,gBAAgBA,CAACA,KAAIA,CAACA,UAAUA,EAAEA,IAAIA,EAAEA,cAAc,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAACA;qBAC5IA,IAAIA,CAAwBA,SAASA,CAACA,CAACA,CAACA;YACjDA,CAACA,EAACA,UAACA,GAAGA;gBACFA,EAAEA,CAACA,CAACA,GAAGA,CAACA;oBAACA,MAAMA,CAACA,MAAMA,CAACA,GAAGA,CAACA,CAACA;gBAC5BA,MAAMA,CAACA,OAAOA,CAACA,QAAQA,CAACA,GAAGA,CAACA,QAAQA,CAACA,CAACA,CAACA;YAC3CA,CAACA,CAACA,CAACA;QACPA,CAACA,CAACA,CAACA,OAAOA,CAACA,QAAQA,CAACA,CAACA;IACzBA,CAACA;IAEDJ;;;;OAIGA;IACHA,wBAAOA,GAAPA,UAAQA,QAAwCA;QAAhDK,iBAUCA;QATGA,IAAIA,OAAOA,GAAGA,IAAIA,CAACA,KAAKA,CAACA,OAAOA,CAACA;QACjCA,MAAMA,CAACA,IAAIA,QAAQA,CAAcA,UAACA,OAAOA,EAAEA,MAAMA;YAC7CA,KAAIA,CAACA,MAAMA,CAACA,OAAOA,CAACA,UAACA,GAAGA,EAAEA,OAAcA;gBACpCA,EAAEA,CAACA,CAACA,GAAGA,CAACA;oBAACA,MAAMA,CAACA,MAAMA,CAACA,GAAGA,CAACA,CAACA;gBAC5BA,MAAMA,CAACA,OAAOA,CAAMA,OAAOA,CAACA,CAACA;YACjCA,CAACA,CAACA,CAACA;QACPA,CAACA,CAACA,CAACA,GAAGA,CAAuBA,UAACA,QAAQA;YAClCA,MAAMA,CAACA,KAAIA,CAACA,KAAKA,CAACA,QAAQA,CAACA,gBAAgBA,CAACA,KAAIA,CAACA,UAAUA,EAAEA,QAAQA,EAAEA,cAAc,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAACA,CAACA;QACnJA,CAACA,CAACA,CAACA,OAAOA,CAACA,QAAQA,CAACA,CAACA;IACzBA,CAACA;IAEDL;;;;OAIGA;IACHA,qBAAIA,GAAJA,UAAKA,QAAsCA;QAA3CM,iBAUCA;QATGA,MAAMA,CAACA,IAAIA,QAAQA,CAAYA,UAACA,OAAOA,EAAEA,MAAMA;YAC3CA,KAAIA,CAACA,MAAMA,CAACA,IAAIA,CAACA,UAACA,GAAGA,EAAEA,MAAWA;gBAC9BA,EAAEA,CAACA,CAACA,GAAGA,CAACA;oBAACA,MAAMA,CAACA,MAAMA,CAACA,GAAGA,CAACA,CAACA;gBAC5BA,MAAMA,CAACA,OAAOA,CAAMA,MAAMA,CAACA,CAACA;YAChCA,CAACA,CAACA,CAACA;QACPA,CAACA,CAACA,CAACA,IAAIA,CAACA,UAACA,QAAQA;YACbA,EAAEA,CAACA,CAACA,CAACA,QAAQA,CAACA;gBAACA,MAAMA,CAACA,QAAQA,CAACA,OAAOA,CAAYA,IAAIA,CAACA,CAACA;YACxDA,MAAMA,CAACA,KAAIA,CAACA,KAAKA,CAACA,QAAQA,CAACA,gBAAgBA,CAACA,KAAIA,CAACA,UAAUA,EAAEA,QAAQA,EAACA,UAACA,QAAQA,EAAEA,KAAMA,EAAEA,SAAUA,IAAKA,OAAAA,KAAIA,CAACA,KAAKA,CAACA,OAAOA,CAACA,YAAYA,CAACA,QAAQA,EAAEA,KAAKA,EAAEA,SAASA,CAACA,EAA3DA,CAA2DA,CAACA,CAACA;QACzKA,CAACA,CAACA,CAACA,OAAOA,CAACA,QAAQA,CAACA,CAACA;IACzBA,CAACA;IAEDN;;;OAGGA;IACHA,uBAAMA,GAANA;QACIO,IAAIA,CAACA,MAAMA,CAACA,MAAMA,EAAEA,CAACA;QACrBA,MAAMA,CAACA,IAAIA,CAACA;IAChBA,CAACA;IAEDP;;;;OAIGA;IACHA,qBAAIA,GAAJA,UAAKA,cAAwCA;QACzCQ,MAAMA,CAACA,IAAIA,MAAMA,CAACA,IAAIA,CAACA,KAAKA,EAAEA,IAAIA,CAACA,UAAUA,EAAEA,IAAIA,CAACA,MAAMA,CAACA,IAAIA,CAACA,cAAcA,CAACA,CAACA,CAACA;IACrFA,CAACA;IAEDR;;;;OAIGA;IACHA,sBAAKA,GAALA,UAAMA,KAAaA;QACfS,MAAMA,CAACA,IAAIA,MAAMA,CAACA,IAAIA,CAACA,KAAKA,EAAEA,IAAIA,CAACA,UAAUA,EAAEA,IAAIA,CAACA,MAAMA,CAACA,KAAKA,CAACA,KAAKA,CAACA,CAACA,CAACA;IAC7EA,CAACA;IAEDT;;;;;OAKGA;IACHA,qBAAIA,GAAJA,UAAKA,IAAYA;QACbU,MAAMA,CAACA,IAAIA,MAAMA,CAACA,IAAIA,CAACA,KAAKA,EAAEA,IAAIA,CAACA,UAAUA,EAAEA,IAAIA,CAACA,MAAMA,CAACA,IAAIA,CAACA,IAAIA,CAACA,CAACA,CAACA;IAC3EA,CAACA;IACLV,aAACA;AAADA,CAtIA,AAsICA,IAAA;AAtID,wBAsIC,CAAA","file":"lib/Cursor.js","sourcesContent":["/// \r\nimport Model from './Model';\r\nimport General = require('./General');\r\nimport MongoDB = require('mongodb');\r\nimport Bluebird = require('bluebird');\r\nimport * as Index from './Index';\r\n\r\nexport default class Cursor {\r\n /**\r\n * Creates a new Iridium cursor which wraps a MongoDB cursor object\r\n * @param {Model} model The Iridium model that this cursor belongs to\r\n * @param {Object} conditions The conditions that resulte in this cursor being created\r\n * @param {MongoDB.Cursor} cursor The MongoDB native cursor object to be wrapped\r\n * @constructor\r\n */\r\n constructor(private model: Model, private conditions: any, public cursor: MongoDB.Cursor) {\r\n\r\n }\r\n\r\n /**\r\n * Counts the number of documents which are matched by this cursor\r\n * @param {function(Error, Number)} callback A callback which is triggered when the result is available\r\n * @return {Promise} A promise which will resolve with the number of documents matched by this cursor\r\n */\r\n count(callback?: General.Callback): Bluebird {\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.count(true,(err, count) => {\r\n if (err) return reject(err);\r\n return resolve(count);\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Runs the specified handler over each instance in the query results\r\n * @param {function(Instance)} handler The handler which is triggered for each element in the query\r\n * @param {function(Error)} callback A callback which is triggered when all operations have been dispatched\r\n * @return {Promise} A promise which is resolved when all operations have been dispatched\r\n */\r\n forEach(handler: (instance: TInstance) => void, callback?: General.Callback): Bluebird {\r\n var helpers = this.model.helpers;\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.forEach((item: TDocument) => {\r\n this.model.handlers.documentReceived(this.conditions, item, function () { return helpers.wrapDocument.apply(helpers, arguments); }).then(handler);\r\n },(err) => {\r\n if (err) return reject(err);\r\n return resolve(null);\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Runs the specified transform over each instance in the query results and returns the resulting transformed objects\r\n * @param {function(Instance): TResult} transform A handler which is used to transform the result objects\r\n * @param {function(Error, TResult[])} callback A callback which is triggered when the transformations are completed\r\n * @return {Promise} A promise which is fulfilled with the results of the transformations\r\n */\r\n map(transform: (instance: TInstance) => TResult | Bluebird, callback?: General.Callback): Bluebird {\r\n var helpers = this.model.helpers;\r\n return new Bluebird((resolve, reject) => {\r\n var promises: Bluebird[] = [];\r\n this.cursor.forEach((item: TDocument) => {\r\n promises.push(this.model.handlers.documentReceived(this.conditions, item, function () { return helpers.wrapDocument.apply(helpers, arguments); })\r\n .then(<(instance) => TResult>transform));\r\n },(err) => {\r\n if (err) return reject(err);\r\n return resolve(Bluebird.all(promises));\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Retrieves all matching instances and returns them in an array\r\n * @param {function(Error, TInstance[])} callback A callback which is triggered with the resulting instances\r\n * @return {Promise} A promise which resolves with the instances returned by the query\r\n */\r\n toArray(callback?: General.Callback): Bluebird {\r\n var helpers = this.model.helpers;\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.toArray((err, results: any[]) => {\r\n if (err) return reject(err);\r\n return resolve(results);\r\n });\r\n }).map((document) => {\r\n return this.model.handlers.documentReceived(this.conditions, document, function () { return helpers.wrapDocument.apply(helpers, arguments); });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Retrieves the next item in the results list\r\n * @param {function(Error, TInstance)} callback A callback which is triggered when the next item becomes available\r\n * @return {Promise} A promise which is resolved with the next item\r\n */\r\n next(callback?: General.Callback): Bluebird {\r\n return new Bluebird((resolve, reject) => {\r\n this.cursor.next((err, result: any) => {\r\n if (err) return reject(err);\r\n return resolve(result);\r\n });\r\n }).then((document) => {\r\n if (!document) return Bluebird.resolve(null);\r\n return this.model.handlers.documentReceived(this.conditions, document,(document, isNew?, isPartial?) => this.model.helpers.wrapDocument(document, isNew, isPartial));\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Returns a new cursor which behaves the same as this one did before any results were retrieved\r\n * @return {Cursor} The new cursor which starts at the beginning of the results\r\n */\r\n rewind(): Cursor {\r\n this.cursor.rewind();\r\n return this;\r\n }\r\n\r\n /**\r\n * Returns a new cursor which sorts its results by the given index expression\r\n * @param {model.IndexSpecification} sortExpression The index expression dictating the sort order and direction to use\r\n * @return {Cursor} The new cursor which sorts its results by the sortExpression\r\n */\r\n sort(sortExpression: Index.IndexSpecification): Cursor {\r\n return new Cursor(this.model, this.conditions, this.cursor.sort(sortExpression));\r\n }\r\n\r\n /**\r\n * Returns a new cursor which limits the number of returned results\r\n * @param {Number} limit The maximum number of results to return\r\n * @return {Cursor} The new cursor which will return a maximum number of results\r\n */\r\n limit(limit: number): Cursor {\r\n return new Cursor(this.model, this.conditions, this.cursor.limit(limit));\r\n }\r\n\r\n /**\r\n * Returns a new cursor which skips a number of results before it begins\r\n * returning any.\r\n * @param {Number} skip The number of results to skip before the cursor beings returning\r\n * @return {Cursor} The new cursor which skips a number of results\r\n */\r\n skip(skip: number): Cursor {\r\n return new Cursor(this.model, this.conditions, this.cursor.skip(skip));\r\n }\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/Decorators.js b/dist/lib/Decorators.js
new file mode 100644
index 0000000..c1d0be0
--- /dev/null
+++ b/dist/lib/Decorators.js
@@ -0,0 +1,63 @@
+///
+var MongoDB = require('mongodb');
+var _ = require('lodash');
+var skmatc = require('skmatc');
+function Collection(name) {
+ return function (target) {
+ target.collection = name;
+ };
+}
+exports.Collection = Collection;
+function Index(spec, options) {
+ return function (target) {
+ target.indexes = (target.indexes || []).concat({ spec: spec, options: options || {} });
+ };
+}
+exports.Index = Index;
+function Validate(forType, validate) {
+ return function (target) {
+ target.validators = (target.validators || []).concat(skmatc.create(function (schema) { return schema === forType; }, validate));
+ };
+}
+exports.Validate = Validate;
+function Property() {
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i - 0] = arguments[_i];
+ }
+ var name = null, asType = false, required = true;
+ if (args.length > 1 && typeof args[args.length - 1] === 'boolean')
+ required = args.pop();
+ return function (target, property) {
+ if (!property)
+ name = args.shift();
+ else {
+ name = property;
+ target = target.constructor;
+ }
+ asType = args.pop() || false;
+ target.schema = _.clone(target.schema || {});
+ if (!required && typeof asType !== 'boolean')
+ target.schema[name] = { $required: required, $type: asType };
+ else
+ target.schema[name] = asType;
+ };
+}
+exports.Property = Property;
+function Transform(fromDB, toDB) {
+ return function (target, property) {
+ target.constructor.transforms = _.clone(target.constructor.transforms || {});
+ target.constructor.transforms[property] = {
+ fromDB: fromDB,
+ toDB: toDB
+ };
+ };
+}
+exports.Transform = Transform;
+function ObjectID(target, name) {
+ target.constructor.schema = _.clone(target.constructor.schema || {});
+ target.constructor.schema[name] = MongoDB.ObjectID;
+}
+exports.ObjectID = ObjectID;
+
+//# sourceMappingURL=../lib/Decorators.js.map
\ No newline at end of file
diff --git a/dist/lib/Decorators.js.map b/dist/lib/Decorators.js.map
new file mode 100644
index 0000000..cc8c35f
--- /dev/null
+++ b/dist/lib/Decorators.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/Decorators.ts"],"names":["Collection","Index","Validate","Property","Transform","ObjectID"],"mappings":"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","file":"lib/Decorators.js","sourcesContent":["/// \r\nimport MongoDB = require('mongodb');\r\nimport _ = require('lodash');\r\nimport skmatc = require('skmatc');\r\nimport Instance from './Instance';\r\nimport {Index, IndexSpecification} from './Index';\r\nimport {Schema} from './Schema';\r\nimport InstanceImplementation from './InstanceInterface';\r\n\r\nexport function Collection(name: string) {\r\n\treturn function(target: InstanceImplementation) {\r\n\t\ttarget.collection = name;\r\n\t};\r\n}\r\n\r\nexport function Index(spec: IndexSpecification, options?: MongoDB.IndexOptions) {\r\n\treturn function(target: InstanceImplementation) {\r\n\t\ttarget.indexes = (target.indexes || []).concat({ spec: spec, options: options || {} });\r\n\t}\r\n}\r\n\r\nexport function Validate(forType: any, validate: (schema: any, data: any, path: string) => Skmatc.Result) {\r\n\treturn function(target: InstanceImplementation) {\r\n\t\ttarget.validators = (target.validators || []).concat(skmatc.create(schema => schema === forType, validate));\r\n\t}\r\n}\r\n\r\nexport function Property(asType: any, required?: boolean): (target: { constructor: Function }, name: string) => void;\r\nexport function Property(name: string, asType: any, required?: boolean): (target: Function) => void;\r\nexport function Property(...args: any[]): (target: any, name?: string) => void {\r\n\tlet name = null,\r\n\t\tasType = false,\r\n\t\trequired = true;\r\n\t\r\n\tif (args.length > 1 && typeof args[args.length - 1] === 'boolean')\r\n\t\trequired = args.pop();\r\n\t\r\n\treturn function(target: any, property?: string) {\r\n\t\tif (!property) name = args.shift();\r\n\t\telse {\r\n\t\t\tname = property;\r\n\t\t\ttarget = target.constructor;\r\n\t\t}\r\n\t\tasType = args.pop() || false;\r\n\t\t\r\n\t\ttarget.schema = _.clone(target.schema || {});\r\n\t\tif(!required && typeof asType !== 'boolean') target.schema[name] = { $required: required, $type: asType };\r\n\t\telse target.schema[name] = asType;\r\n\t}\r\n}\r\n\r\nexport function Transform(fromDB: (value: any) => any, toDB: (value: any) => any) {\r\n\treturn function(target: any, property: string) {\r\n\t\ttarget.constructor.transforms = _.clone(target.constructor.transforms || {})\r\n\t\ttarget.constructor.transforms[property] = {\r\n\t\t\tfromDB: fromDB,\r\n\t\t\ttoDB: toDB\r\n\t\t};\r\n\t};\r\n}\r\n\r\nexport function ObjectID(target: { constructor: typeof Instance }, name: string) {\r\n\ttarget.constructor.schema = _.clone(target.constructor.schema || {});\r\n\ttarget.constructor.schema[name] = MongoDB.ObjectID;\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/General.js b/dist/lib/General.js
new file mode 100644
index 0000000..f88be71
--- /dev/null
+++ b/dist/lib/General.js
@@ -0,0 +1,3 @@
+///
+
+//# sourceMappingURL=../lib/General.js.map
\ No newline at end of file
diff --git a/dist/lib/General.js.map b/dist/lib/General.js.map
new file mode 100644
index 0000000..fd4eed7
--- /dev/null
+++ b/dist/lib/General.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/General.ts"],"names":[],"mappings":"AAAA,AACA,4CAD4C;AAoB3C","file":"lib/General.js","sourcesContent":["/// \r\nexport interface Callback {\r\n (err: Error, object?: T): void;\r\n}\r\n\r\nexport interface Predicate {\r\n (object: T, key?: string): boolean;\r\n}\r\n\r\nexport interface PropertyGetter {\r\n (): T;\r\n}\r\n\r\nexport interface PropertySetter {\r\n (value: T): void;\r\n}\r\n\r\nexport interface Property {\r\n get?: PropertyGetter;\r\n set?: PropertySetter;\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/Hooks.js b/dist/lib/Hooks.js
new file mode 100644
index 0000000..117b52f
--- /dev/null
+++ b/dist/lib/Hooks.js
@@ -0,0 +1,3 @@
+
+
+//# sourceMappingURL=../lib/Hooks.js.map
\ No newline at end of file
diff --git a/dist/lib/Hooks.js.map b/dist/lib/Hooks.js.map
new file mode 100644
index 0000000..91cecf9
--- /dev/null
+++ b/dist/lib/Hooks.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/Hooks.ts"],"names":[],"mappings":"AAQC","file":"lib/Hooks.js","sourcesContent":["/// \r\nimport instance = require('./Instance');\r\n\r\nexport interface Hooks {\r\n onCreating? (document: TDocument): void;\r\n onRetrieved? (document: TDocument): void;\r\n onReady? (instance: TInstance): void;\r\n onSaving? (instance: TInstance, changes: any): void;\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/Index.js b/dist/lib/Index.js
new file mode 100644
index 0000000..f99f4da
--- /dev/null
+++ b/dist/lib/Index.js
@@ -0,0 +1,3 @@
+
+
+//# sourceMappingURL=../lib/Index.js.map
\ No newline at end of file
diff --git a/dist/lib/Index.js.map b/dist/lib/Index.js.map
new file mode 100644
index 0000000..4b508f3
--- /dev/null
+++ b/dist/lib/Index.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/Index.ts"],"names":[],"mappings":"AAUC","file":"lib/Index.js","sourcesContent":["/// \r\nimport MongoDB = require('mongodb');\r\n\r\nexport interface Index {\r\n spec: IndexSpecification;\r\n options?: MongoDB.IndexOptions;\r\n}\r\n\r\nexport interface IndexSpecification {\r\n [key: string]: number;\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/Instance.js b/dist/lib/Instance.js
new file mode 100644
index 0000000..91dd02a
--- /dev/null
+++ b/dist/lib/Instance.js
@@ -0,0 +1,256 @@
+var _ = require('lodash');
+var MongoDB = require('mongodb');
+var Bluebird = require('bluebird');
+var skmatc = require('skmatc');
+var Instance = (function () {
+ /**
+ * Creates a new instance which represents the given document as a type of model
+ * @param {model.Model} model The model that the document represents
+ * @param {TSchema} document The document which should be wrapped by this instance
+ * @param {Boolean} isNew Whether the document is new (doesn't exist in the database) or not
+ * @param {Boolean} isPartial Whether the document has only a subset of its fields populated
+ * @description
+ * This class will be subclassed automatically by Iridium to create a model specific instance
+ * which takes advantage of some of v8's optimizations to boost performance significantly.
+ * The instance returned by the model, and all of this instance's methods, will be of type
+ * TInstance - which should represent the merger of TSchema and IInstance for best results.
+ */
+ function Instance(model, document, isNew, isPartial) {
+ var _this = this;
+ if (isNew === void 0) { isNew = true; }
+ if (isPartial === void 0) { isPartial = false; }
+ this._model = model;
+ this._isNew = !!isNew;
+ this._isPartial = isPartial;
+ this._original = document;
+ this._modified = _.cloneDeep(document);
+ _.each(model.core.plugins, function (plugin) {
+ if (plugin.newInstance)
+ plugin.newInstance(_this, model);
+ });
+ }
+ Object.defineProperty(Instance.prototype, "document", {
+ /**
+ * Gets the underlying document representation of this instance
+ */
+ get: function () {
+ return this._modified;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Instance.prototype.save = function () {
+ var _this = this;
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i - 0] = arguments[_i];
+ }
+ var callback = null;
+ var changes = null;
+ var conditions = {};
+ Array.prototype.slice.call(args, 0).reverse().forEach(function (arg) {
+ if (typeof arg == 'function')
+ callback = arg;
+ else if (typeof arg == 'object') {
+ if (!changes)
+ changes = arg;
+ else
+ conditions = arg;
+ }
+ });
+ return Bluebird.resolve().then(function () {
+ conditions = _.cloneDeep(conditions);
+ _.merge(conditions, { _id: _this._modified._id });
+ conditions = _this._model.helpers.transformToDB(conditions);
+ if (!changes) {
+ var validation = _this._model.helpers.validate(_this._modified);
+ if (validation.failed)
+ return Bluebird.reject(validation.error).bind(_this).nodeify(callback);
+ var original = _.cloneDeep(_this._original);
+ var modified = _.cloneDeep(_this._modified);
+ changes = _this._model.helpers.diff(original, modified);
+ }
+ if (!_.keys(changes).length)
+ return null;
+ return changes;
+ }).then(function (changes) {
+ if (!changes && !_this._isNew)
+ return changes;
+ return _this._model.handlers.savingDocument(_this, changes).then(function () { return changes; });
+ }).then(function (changes) {
+ if (!changes && !_this._isNew)
+ return false;
+ if (_this._isNew) {
+ return new Bluebird(function (resolve, reject) {
+ _this._model.collection.insertOne(_this._modified, { w: 'majority' }, function (err, doc) {
+ if (err)
+ return reject(err);
+ return resolve(!!doc);
+ });
+ });
+ }
+ else {
+ return new Bluebird(function (resolve, reject) {
+ _this._model.collection.updateOne(conditions, changes, { w: 'majority' }, function (err, changed) {
+ if (err)
+ return reject(err);
+ return resolve(changed);
+ });
+ });
+ }
+ }).then(function (changed) {
+ conditions = _this._model.helpers.convertToDB({ _id: _this._modified._id });
+ if (!changed) {
+ return _.cloneDeep(_this._modified);
+ }
+ return new Bluebird(function (resolve, reject) {
+ _this._model.collection.findOne(conditions, function (err, latest) {
+ if (err)
+ return reject(err);
+ return resolve(latest);
+ });
+ });
+ }).then(function (latest) {
+ return _this._model.handlers.documentReceived(conditions, latest, function (value) {
+ _this._isPartial = false;
+ _this._isNew = false;
+ _this._original = value;
+ _this._modified = _.clone(value);
+ return _this;
+ });
+ }).nodeify(callback);
+ };
+ /**
+ * Updates this instance to match the latest document available in the backing collection
+ * @param {function(Error, IInstance)} callback A callback which is triggered when the update completes
+ * @returns {Promise}
+ */
+ Instance.prototype.update = function (callback) {
+ return this.refresh(callback);
+ };
+ /**
+ * Updates this instance to match the latest document available in the backing collection
+ * @param {function(Error, IInstance)} callback A callback which is triggered when the update completes
+ * @returns {Promise}
+ */
+ Instance.prototype.refresh = function (callback) {
+ var _this = this;
+ var conditions = { _id: this._original._id };
+ return Bluebird.resolve().then(function () {
+ return new Bluebird(function (resolve, reject) {
+ _this._model.collection.findOne(conditions, function (err, doc) {
+ if (err)
+ return reject(err);
+ return resolve(doc);
+ });
+ });
+ }).then(function (newDocument) {
+ if (!newDocument) {
+ _this._isPartial = true;
+ _this._isNew = true;
+ _this._original = _.cloneDeep(_this._modified);
+ return _this;
+ }
+ return _this._model.handlers.documentReceived(conditions, newDocument, function (doc) {
+ _this._isNew = false;
+ _this._isPartial = false;
+ _this._original = doc;
+ _this._modified = _.cloneDeep(doc);
+ return _this;
+ });
+ }).nodeify(callback);
+ };
+ /**
+ * Removes this instance's document from the backing collection
+ * @param {function(Error, IInstance)} callback A callback which is triggered when the operation completes
+ * @returns {Promise}
+ */
+ Instance.prototype.delete = function (callback) {
+ return this.remove(callback);
+ };
+ /**
+ * Removes this instance's document from the backing collection
+ * @param {function(Error, IInstance)} callback A callback which is triggered when the operation completes
+ * @returns {Promise}
+ */
+ Instance.prototype.remove = function (callback) {
+ var _this = this;
+ var conditions = { _id: this._original._id };
+ return Bluebird.resolve().then(function () {
+ if (_this._isNew)
+ return 0;
+ return new Bluebird(function (resolve, reject) {
+ _this._model.collection.remove(conditions, { w: 'majority' }, function (err, removed) {
+ if (err)
+ return reject(err);
+ return resolve(removed);
+ });
+ });
+ }).then(function (removed) {
+ if (removed)
+ return _this._model.cache.clear(conditions);
+ return false;
+ }).then(function () {
+ _this._isNew = true;
+ return _this;
+ }).nodeify(callback);
+ };
+ Instance.prototype.first = function (collection, predicate) {
+ var _this = this;
+ var result = null;
+ _.each(collection, function (value, key) {
+ if (predicate.call(_this, value, key)) {
+ result = value;
+ return false;
+ }
+ });
+ return result;
+ };
+ Instance.prototype.select = function (collection, predicate) {
+ var _this = this;
+ var isArray = Array.isArray(collection);
+ var results = isArray ? [] : {};
+ _.each(collection, function (value, key) {
+ if (predicate.call(_this, value, key)) {
+ if (isArray)
+ results.push(value);
+ else
+ results[key] = value;
+ }
+ });
+ return results;
+ };
+ /**
+ * Gets the JSON representation of this instance
+ * @returns {TDocument}
+ */
+ Instance.prototype.toJSON = function () {
+ return this.document;
+ };
+ /**
+ * Gets a string representation of this instance
+ * @returns {String}
+ */
+ Instance.prototype.toString = function () {
+ return JSON.stringify(this.document, null, 2);
+ };
+ Instance.schema = {
+ _id: MongoDB.ObjectID
+ };
+ Instance.validators = [
+ skmatc.create(function (schema) { return schema === MongoDB.ObjectID; }, function (schema, data) {
+ return this.assert(!data || data instanceof MongoDB.ObjectID);
+ }, { name: 'ObjectID validation' })
+ ];
+ Instance.transforms = {
+ _id: {
+ fromDB: function (value) { return value._bsontype == 'ObjectID' ? new MongoDB.ObjectID(value.id).toHexString() : value; },
+ toDB: function (value) { return value && typeof value === 'string' ? new MongoDB.ObjectID(value) : value; }
+ }
+ };
+ Instance.indexes = [];
+ return Instance;
+})();
+exports.default = Instance;
+
+//# sourceMappingURL=../lib/Instance.js.map
\ No newline at end of file
diff --git a/dist/lib/Instance.js.map b/dist/lib/Instance.js.map
new file mode 100644
index 0000000..f29897d
--- /dev/null
+++ b/dist/lib/Instance.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/Instance.ts"],"names":["Instance","Instance.constructor","Instance.document","Instance.save","Instance.update","Instance.refresh","Instance.delete","Instance.remove","Instance.first","Instance.select","Instance.toJSON","Instance.toString"],"mappings":"AAUA,IAAO,CAAC,WAAW,QAAQ,CAAC,CAAC;AAC7B,IAAO,OAAO,WAAW,SAAS,CAAC,CAAC;AACpC,IAAO,QAAQ,WAAW,UAAU,CAAC,CAAC;AACtC,IAAO,MAAM,WAAW,QAAQ,CAAC,CAAC;AAElC;IACIA;;;;;;;;;;;OAWGA;IACHA,kBAAYA,KAAkCA,EAAEA,QAAmBA,EAAEA,KAAqBA,EAAEA,SAA0BA;QAb1HC,iBA4TCA;QA/SwEA,qBAAqBA,GAArBA,YAAqBA;QAAEA,yBAA0BA,GAA1BA,iBAA0BA;QAClHA,IAAIA,CAACA,MAAMA,GAAGA,KAAKA,CAACA;QAEpBA,IAAIA,CAACA,MAAMA,GAAGA,CAACA,CAACA,KAAKA,CAACA;QACtBA,IAAIA,CAACA,UAAUA,GAAGA,SAASA,CAACA;QAC5BA,IAAIA,CAACA,SAASA,GAAGA,QAAQA,CAACA;QAC1BA,IAAIA,CAACA,SAASA,GAAGA,CAACA,CAACA,SAASA,CAAYA,QAAQA,CAACA,CAACA;QAElDA,CAACA,CAACA,IAAIA,CAACA,KAAKA,CAACA,IAAIA,CAACA,OAAOA,EAACA,UAACA,MAAcA;YACrCA,EAAEA,CAACA,CAACA,MAAMA,CAACA,WAAWA,CAACA;gBAACA,MAAMA,CAACA,WAAWA,CAACA,KAAIA,EAAEA,KAAKA,CAACA,CAACA;QAC5DA,CAACA,CAACA,CAACA;IACPA,CAACA;IAWDD,sBAAIA,8BAAQA;QAHZA;;WAEGA;aACHA;YACIE,MAAMA,CAACA,IAAIA,CAACA,SAASA,CAACA;QAC1BA,CAACA;;;OAAAF;IAwDDA,uBAAIA,GAAJA;QAAAG,iBA0ECA;QA1EIA,cAAcA;aAAdA,WAAcA,CAAdA,sBAAcA,CAAdA,IAAcA;YAAdA,6BAAcA;;QACfA,IAAIA,QAAQA,GAA0BA,IAAIA,CAACA;QAC3CA,IAAIA,OAAOA,GAAQA,IAAIA,CAACA;QACxBA,IAAIA,UAAUA,GAAQA,EAAEA,CAACA;QAEzBA,KAAKA,CAACA,SAASA,CAACA,KAAKA,CAACA,IAAIA,CAACA,IAAIA,EAAEA,CAACA,CAACA,CAACA,OAAOA,EAAEA,CAACA,OAAOA,CAACA,UAACA,GAAGA;YACtDA,EAAEA,CAACA,CAACA,OAAOA,GAAGA,IAAIA,UAAUA,CAACA;gBAACA,QAAQA,GAAGA,GAAGA,CAACA;YAC7CA,IAAIA,CAACA,EAAEA,CAACA,CAACA,OAAOA,GAAGA,IAAIA,QAAQA,CAACA,CAACA,CAACA;gBAC9BA,EAAEA,CAACA,CAACA,CAACA,OAAOA,CAACA;oBAACA,OAAOA,GAAGA,GAAGA,CAACA;gBAC5BA,IAAIA;oBAACA,UAAUA,GAAGA,GAAGA,CAACA;YAC1BA,CAACA;QACLA,CAACA,CAACA,CAACA;QAEHA,MAAMA,CAACA,QAAQA,CAACA,OAAOA,EAAEA,CAACA,IAAIA,CAACA;YAC3BA,UAAUA,GAAGA,CAACA,CAACA,SAASA,CAACA,UAAUA,CAACA,CAACA;YACrCA,CAACA,CAACA,KAAKA,CAACA,UAAUA,EAAEA,EAAEA,GAAGA,EAAEA,KAAIA,CAACA,SAASA,CAACA,GAAGA,EAAEA,CAACA,CAACA;YAEjDA,UAAUA,GAAGA,KAAIA,CAACA,MAAMA,CAACA,OAAOA,CAACA,aAAaA,CAACA,UAAUA,CAACA,CAACA;YAE3DA,EAAEA,CAACA,CAACA,CAACA,OAAOA,CAACA,CAACA,CAACA;gBACXA,IAAIA,UAAUA,GAAGA,KAAIA,CAACA,MAAMA,CAACA,OAAOA,CAACA,QAAQA,CAACA,KAAIA,CAACA,SAASA,CAACA,CAACA;gBAC9DA,EAAEA,CAACA,CAACA,UAAUA,CAACA,MAAMA,CAACA;oBAACA,MAAMA,CAACA,QAAQA,CAACA,MAAMA,CAACA,UAAUA,CAACA,KAAKA,CAACA,CAACA,IAAIA,CAACA,KAAIA,CAACA,CAACA,OAAOA,CAACA,QAAQA,CAACA,CAACA;gBAE7FA,IAAIA,QAAQA,GAAGA,CAACA,CAACA,SAASA,CAACA,KAAIA,CAACA,SAASA,CAACA,CAACA;gBAC3CA,IAAIA,QAAQA,GAAGA,CAACA,CAACA,SAASA,CAACA,KAAIA,CAACA,SAASA,CAACA,CAACA;gBAE3CA,OAAOA,GAAGA,KAAIA,CAACA,MAAMA,CAACA,OAAOA,CAACA,IAAIA,CAACA,QAAQA,EAAEA,QAAQA,CAACA,CAACA;YAC3DA,CAACA;YAEDA,EAAEA,CAACA,CAACA,CAACA,CAACA,CAACA,IAAIA,CAACA,OAAOA,CAACA,CAACA,MAAMA,CAACA;gBAACA,MAAMA,CAACA,IAAIA,CAACA;YAEzCA,MAAMA,CAACA,OAAOA,CAACA;QACnBA,CAACA,CAACA,CAACA,IAAIA,CAACA,UAACA,OAAOA;YACZA,EAAEA,CAACA,CAACA,CAACA,OAAOA,IAAIA,CAACA,KAAIA,CAACA,MAAMA,CAACA;gBAACA,MAAMA,CAACA,OAAOA,CAACA;YAC7CA,MAAMA,CAACA,KAAIA,CAACA,MAAMA,CAACA,QAAQA,CAACA,cAAcA,CAAiBA,KAAIA,EAAEA,OAAOA,CAACA,CAACA,IAAIA,CAACA,cAAMA,OAAAA,OAAOA,EAAPA,CAAOA,CAACA,CAACA;QAClGA,CAACA,CAACA,CAACA,IAAIA,CAACA,UAACA,OAAOA;YACZA,EAAEA,CAACA,CAACA,CAACA,OAAOA,IAAIA,CAACA,KAAIA,CAACA,MAAMA,CAACA;gBAACA,MAAMA,CAACA,KAAKA,CAACA;YAE3CA,EAAEA,CAACA,CAACA,KAAIA,CAACA,MAAMA,CAACA,CAACA,CAACA;gBACdA,MAAMA,CAACA,IAAIA,QAAQA,CAAUA,UAACA,OAAOA,EAAEA,MAAMA;oBACzCA,KAAIA,CAACA,MAAMA,CAACA,UAAUA,CAACA,SAASA,CAACA,KAAIA,CAACA,SAASA,EAAEA,EAAEA,CAACA,EAAEA,UAAUA,EAAEA,EAAEA,UAACA,GAAGA,EAAEA,GAAGA;wBACzEA,EAAEA,CAACA,CAACA,GAAGA,CAACA;4BAACA,MAAMA,CAACA,MAAMA,CAACA,GAAGA,CAACA,CAACA;wBAC5BA,MAAMA,CAACA,OAAOA,CAAMA,CAACA,CAACA,GAAGA,CAACA,CAACA;oBAC/BA,CAACA,CAACA,CAACA;gBACPA,CAACA,CAACA,CAACA;YACPA,CAACA;YAACA,IAAIA,CAACA,CAACA;gBACJA,MAAMA,CAACA,IAAIA,QAAQA,CAAUA,UAACA,OAAmCA,EAAEA,MAAMA;oBACrEA,KAAIA,CAACA,MAAMA,CAACA,UAAUA,CAACA,SAASA,CAACA,UAAUA,EAAEA,OAAOA,EAAEA,EAAEA,CAACA,EAAEA,UAAUA,EAAEA,EAAEA,UAACA,GAAUA,EAAEA,OAAgBA;wBAClGA,EAAEA,CAACA,CAACA,GAAGA,CAACA;4BAACA,MAAMA,CAACA,MAAMA,CAACA,GAAGA,CAACA,CAACA;wBAC5BA,MAAMA,CAACA,OAAOA,CAACA,OAAOA,CAACA,CAACA;oBAC5BA,CAACA,CAACA,CAACA;gBACPA,CAACA,CAACA,CAACA;YACPA,CAACA;QACLA,CAACA,CAACA,CAACA,IAAIA,CAACA,UAACA,OAAgBA;YACrBA,UAAUA,GAAGA,KAAIA,CAACA,MAAMA,CAACA,OAAOA,CAACA,WAAWA,CAACA,EAAEA,GAAGA,EAAEA,KAAIA,CAACA,SAASA,CAACA,GAAGA,EAAEA,CAACA,CAACA;YAC1EA,EAAEA,CAACA,CAACA,CAACA,OAAOA,CAACA,CAACA,CAACA;gBACXA,MAAMA,CAACA,CAACA,CAACA,SAASA,CAACA,KAAIA,CAACA,SAASA,CAACA,CAACA;YACvCA,CAACA;YAEDA,MAAMA,CAACA,IAAIA,QAAQA,CAAYA,UAACA,OAAOA,EAAEA,MAAMA;gBAC3CA,KAAIA,CAACA,MAAMA,CAACA,UAAUA,CAACA,OAAOA,CAACA,UAAUA,EAACA,UAACA,GAAUA,EAAEA,MAAMA;oBACzDA,EAAEA,CAACA,CAACA,GAAGA,CAACA;wBAACA,MAAMA,CAACA,MAAMA,CAACA,GAAGA,CAACA,CAACA;oBAC5BA,MAAMA,CAACA,OAAOA,CAACA,MAAMA,CAACA,CAACA;gBAC3BA,CAACA,CAACA,CAACA;YACPA,CAACA,CAACA,CAACA;QACPA,CAACA,CAACA,CAACA,IAAIA,CAACA,UAACA,MAAiBA;YACtBA,MAAMA,CAACA,KAAIA,CAACA,MAAMA,CAACA,QAAQA,CAACA,gBAAgBA,CAACA,UAAUA,EAAEA,MAAMA,EAACA,UAACA,KAAKA;gBAClEA,KAAIA,CAACA,UAAUA,GAAGA,KAAKA,CAACA;gBACxBA,KAAIA,CAACA,MAAMA,GAAGA,KAAKA,CAACA;gBACpBA,KAAIA,CAACA,SAASA,GAAGA,KAAKA,CAACA;gBACvBA,KAAIA,CAACA,SAASA,GAAGA,CAACA,CAACA,KAAKA,CAAYA,KAAKA,CAACA,CAACA;gBAC3CA,MAAMA,CAAiBA,KAAIA,CAACA;YAChCA,CAACA,CAACA,CAACA;QACPA,CAACA,CAACA,CAACA,OAAOA,CAACA,QAAQA,CAACA,CAACA;IACzBA,CAACA;IAEDH;;;;OAIGA;IACHA,yBAAMA,GAANA,UAAOA,QAAsCA;QACzCI,MAAMA,CAACA,IAAIA,CAACA,OAAOA,CAACA,QAAQA,CAACA,CAACA;IAClCA,CAACA;IAEDJ;;;;OAIGA;IACHA,0BAAOA,GAAPA,UAAQA,QAAsCA;QAA9CK,iBA2BCA;QA1BGA,IAAIA,UAAUA,GAAGA,EAAEA,GAAGA,EAAEA,IAAIA,CAACA,SAASA,CAACA,GAAGA,EAAEA,CAACA;QAE7CA,MAAMA,CAACA,QAAQA,CAACA,OAAOA,EAAEA,CAACA,IAAIA,CAACA;YAC3BA,MAAMA,CAACA,IAAIA,QAAQA,CAAYA,UAACA,OAAOA,EAAEA,MAAMA;gBAC3CA,KAAIA,CAACA,MAAMA,CAACA,UAAUA,CAACA,OAAOA,CAACA,UAAUA,EAACA,UAACA,GAAUA,EAAEA,GAAQA;oBAC3DA,EAAEA,CAACA,CAACA,GAAGA,CAACA;wBAACA,MAAMA,CAACA,MAAMA,CAACA,GAAGA,CAACA,CAACA;oBAC5BA,MAAMA,CAACA,OAAOA,CAACA,GAAGA,CAACA,CAACA;gBACxBA,CAACA,CAACA,CAACA;YACPA,CAACA,CAACA,CAACA;QACPA,CAACA,CAACA,CAACA,IAAIA,CAACA,UAACA,WAAWA;YAChBA,EAAEA,CAACA,CAACA,CAACA,WAAWA,CAACA,CAACA,CAACA;gBACfA,KAAIA,CAACA,UAAUA,GAAGA,IAAIA,CAACA;gBACvBA,KAAIA,CAACA,MAAMA,GAAGA,IAAIA,CAACA;gBACnBA,KAAIA,CAACA,SAASA,GAAGA,CAACA,CAACA,SAASA,CAAYA,KAAIA,CAACA,SAASA,CAACA,CAACA;gBACxDA,MAAMA,CAA2BA,KAAIA,CAACA;YAC1CA,CAACA;YAEDA,MAAMA,CAACA,KAAIA,CAACA,MAAMA,CAACA,QAAQA,CAACA,gBAAgBA,CAACA,UAAUA,EAAEA,WAAWA,EAAEA,UAACA,GAAGA;gBACtEA,KAAIA,CAACA,MAAMA,GAAGA,KAAKA,CAACA;gBACpBA,KAAIA,CAACA,UAAUA,GAAGA,KAAKA,CAACA;gBACxBA,KAAIA,CAACA,SAASA,GAAGA,GAAGA,CAACA;gBACrBA,KAAIA,CAACA,SAASA,GAAGA,CAACA,CAACA,SAASA,CAAYA,GAAGA,CAACA,CAACA;gBAE7CA,MAAMA,CAAiBA,KAAIA,CAACA;YAChCA,CAACA,CAACA,CAACA;QACPA,CAACA,CAACA,CAACA,OAAOA,CAACA,QAAQA,CAACA,CAACA;IACzBA,CAACA;IAEDL;;;;OAIGA;IACHA,yBAAMA,GAANA,UAAOA,QAAsCA;QACzCM,MAAMA,CAACA,IAAIA,CAACA,MAAMA,CAACA,QAAQA,CAACA,CAACA;IACjCA,CAACA;IAEDN;;;;OAIGA;IACHA,yBAAMA,GAANA,UAAOA,QAAsCA;QAA7CO,iBAkBCA;QAjBGA,IAAIA,UAAUA,GAAGA,EAAEA,GAAGA,EAAEA,IAAIA,CAACA,SAASA,CAACA,GAAGA,EAAEA,CAACA;QAE7CA,MAAMA,CAACA,QAAQA,CAACA,OAAOA,EAAEA,CAACA,IAAIA,CAACA;YAC3BA,EAAEA,CAACA,CAACA,KAAIA,CAACA,MAAMA,CAACA;gBAACA,MAAMA,CAACA,CAACA,CAACA;YAC1BA,MAAMA,CAACA,IAAIA,QAAQA,CAASA,UAACA,OAAOA,EAAEA,MAAMA;gBACxCA,KAAIA,CAACA,MAAMA,CAACA,UAAUA,CAACA,MAAMA,CAACA,UAAUA,EAAEA,EAAEA,CAACA,EAAEA,UAAUA,EAAEA,EAACA,UAACA,GAAUA,EAAEA,OAAaA;oBAClFA,EAAEA,CAACA,CAACA,GAAGA,CAACA;wBAACA,MAAMA,CAACA,MAAMA,CAACA,GAAGA,CAACA,CAACA;oBAC5BA,MAAMA,CAACA,OAAOA,CAACA,OAAOA,CAACA,CAACA;gBAC5BA,CAACA,CAACA,CAACA;YACPA,CAACA,CAACA,CAACA;QACPA,CAACA,CAACA,CAACA,IAAIA,CAACA,UAACA,OAAOA;YACZA,EAAEA,CAACA,CAACA,OAAOA,CAACA;gBAACA,MAAMA,CAACA,KAAIA,CAACA,MAAMA,CAACA,KAAKA,CAACA,KAAKA,CAACA,UAAUA,CAACA,CAACA;YACxDA,MAAMA,CAACA,KAAKA,CAACA;QACjBA,CAACA,CAACA,CAACA,IAAIA,CAACA;YACJA,KAAIA,CAACA,MAAMA,GAAGA,IAAIA,CAACA;YACnBA,MAAMA,CAAiBA,KAAIA,CAACA;QAChCA,CAACA,CAACA,CAACA,OAAOA,CAACA,QAAQA,CAACA,CAACA;IACzBA,CAACA;IAgBDP,wBAAKA,GAALA,UAASA,UAAqCA,EAAEA,SAA+BA;QAA/EQ,iBAWCA;QAVGA,IAAIA,MAAMA,GAAGA,IAAIA,CAACA;QAElBA,CAACA,CAACA,IAAIA,CAACA,UAAUA,EAACA,UAACA,KAAQA,EAAEA,GAAGA;YAC5BA,EAAEA,CAACA,CAACA,SAASA,CAACA,IAAIA,CAACA,KAAIA,EAAEA,KAAKA,EAAEA,GAAGA,CAACA,CAACA,CAACA,CAACA;gBACnCA,MAAMA,GAAGA,KAAKA,CAACA;gBACfA,MAAMA,CAACA,KAAKA,CAACA;YACjBA,CAACA;QACLA,CAACA,CAACA,CAACA;QAEHA,MAAMA,CAACA,MAAMA,CAACA;IAClBA,CAACA;IAgBDR,yBAAMA,GAANA,UAAUA,UAAqCA,EAAEA,SAA+BA;QAAhFS,iBAYCA;QAXGA,IAAIA,OAAOA,GAAGA,KAAKA,CAACA,OAAOA,CAACA,UAAUA,CAACA,CAACA;QACxCA,IAAIA,OAAOA,GAAQA,OAAOA,GAAGA,EAAEA,GAAGA,EAAEA,CAACA;QAErCA,CAACA,CAACA,IAAIA,CAACA,UAAUA,EAACA,UAACA,KAAQA,EAAEA,GAAGA;YAC5BA,EAAEA,CAACA,CAACA,SAASA,CAACA,IAAIA,CAACA,KAAIA,EAAEA,KAAKA,EAAEA,GAAGA,CAACA,CAACA,CAACA,CAACA;gBACnCA,EAAEA,CAACA,CAACA,OAAOA,CAACA;oBAACA,OAAOA,CAACA,IAAIA,CAACA,KAAKA,CAACA,CAACA;gBACjCA,IAAIA;oBAACA,OAAOA,CAACA,GAAGA,CAACA,GAAGA,KAAKA,CAACA;YAC9BA,CAACA;QACLA,CAACA,CAACA,CAACA;QAEHA,MAAMA,CAACA,OAAOA,CAACA;IACnBA,CAACA;IAEDT;;;OAGGA;IACHA,yBAAMA,GAANA;QACIU,MAAMA,CAACA,IAAIA,CAACA,QAAQA,CAACA;IACzBA,CAACA;IAEDV;;;OAGGA;IACHA,2BAAQA,GAARA;QACIW,MAAMA,CAACA,IAAIA,CAACA,SAASA,CAACA,IAAIA,CAACA,QAAQA,EAAEA,IAAIA,EAAEA,CAACA,CAACA,CAACA;IAClDA,CAACA;IA3QMX,eAAMA,GAAWA;QACpBA,GAAGA,EAAEA,OAAOA,CAACA,QAAQA;KACxBA,CAACA;IAEKA,mBAAUA,GAAuBA;QACpCA,MAAMA,CAACA,MAAMA,CAACA,UAAAA,MAAMA,IAAIA,OAAAA,MAAMA,KAAKA,OAAOA,CAACA,QAAQA,EAA3BA,CAA2BA,EAAEA,UAASA,MAAMA,EAAEA,IAAIA;YACtE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,IAAI,YAAY,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClE,CAAC,EAAEA,EAAEA,IAAIA,EAAEA,qBAAqBA,EAAEA,CAACA;KACtCA,CAACA;IAEKA,mBAAUA,GAAwFA;QACrGA,GAAGA,EAAEA;YACDA,MAAMA,EAAEA,UAAAA,KAAKA,IAAIA,OAAAA,KAAKA,CAACA,SAASA,IAAIA,UAAUA,GAAGA,IAAIA,OAAOA,CAACA,QAAQA,CAACA,KAAKA,CAACA,EAAEA,CAACA,CAACA,WAAWA,EAAEA,GAAGA,KAAKA,EAApFA,CAAoFA;YACrGA,IAAIA,EAAEA,UAAAA,KAAKA,IAAIA,OAAAA,KAAKA,IAAIA,OAAOA,KAAKA,KAAKA,QAAQA,GAAGA,IAAIA,OAAOA,CAACA,QAAQA,CAACA,KAAKA,CAACA,GAAGA,KAAKA,EAAxEA,CAAwEA;SAC1FA;KACJA,CAACA;IAGKA,gBAAOA,GAA+CA,EAAEA,CAACA;IA0PpEA,eAACA;AAADA,CA5TA,AA4TCA,IAAA;AA5TD,0BA4TC,CAAA","file":"lib/Instance.js","sourcesContent":["/// \r\nimport Core from './Core';\r\nimport Model from './Model';\r\nimport {Plugin} from './Plugins';\r\nimport {CacheDirector} from './CacheDirector';\r\nimport * as General from './General';\r\nimport * as ModelInterfaces from './ModelInterfaces';\r\nimport * as Index from './Index';\r\nimport {Schema} from './Schema';\r\n\r\nimport _ = require('lodash');\r\nimport MongoDB = require('mongodb');\r\nimport Bluebird = require('bluebird');\r\nimport skmatc = require('skmatc');\r\n\r\nexport default class Instance {\r\n /**\r\n * Creates a new instance which represents the given document as a type of model\r\n * @param {model.Model} model The model that the document represents\r\n * @param {TSchema} document The document which should be wrapped by this instance\r\n * @param {Boolean} isNew Whether the document is new (doesn't exist in the database) or not\r\n * @param {Boolean} isPartial Whether the document has only a subset of its fields populated\r\n * @description\r\n * This class will be subclassed automatically by Iridium to create a model specific instance\r\n * which takes advantage of some of v8's optimizations to boost performance significantly.\r\n * The instance returned by the model, and all of this instance's methods, will be of type\r\n * TInstance - which should represent the merger of TSchema and IInstance for best results.\r\n */\r\n constructor(model: Model, document: TDocument, isNew: boolean = true, isPartial: boolean = false) {\r\n this._model = model;\r\n\r\n this._isNew = !!isNew;\r\n this._isPartial = isPartial;\r\n this._original = document;\r\n this._modified = _.cloneDeep(document);\r\n\r\n _.each(model.core.plugins,(plugin: Plugin) => {\r\n if (plugin.newInstance) plugin.newInstance(this, model);\r\n });\r\n }\r\n\r\n private _isNew: boolean;\r\n private _isPartial: boolean;\r\n private _model: Model;\r\n private _original: TDocument;\r\n private _modified: TDocument;\r\n\r\n /**\r\n * Gets the underlying document representation of this instance\r\n */\r\n get document(): TDocument {\r\n return this._modified;\r\n }\r\n\r\n [name: string]: any;\r\n\r\n static onCreating: (document: { _id?: any }) => void;\r\n static onRetrieved: (document: { _id?: any }) => void;\r\n static onReady: (instance: Instance<{ _id?: any }, Instance<{ _id?: any }, any>>) => void;\r\n static onSaving: (instance: Instance<{ _id?: any }, Instance<{ _id?: any }, any>>, changes: any) => void;\r\n \r\n static collection: string;\r\n \r\n static schema: Schema = {\r\n _id: MongoDB.ObjectID\r\n };\r\n \r\n static validators: Skmatc.Validator[] = [\r\n skmatc.create(schema => schema === MongoDB.ObjectID, function(schema, data) {\r\n return this.assert(!data || data instanceof MongoDB.ObjectID);\r\n }, { name: 'ObjectID validation' })\r\n ];\r\n \r\n static transforms: { [property: string]: { fromDB: (value: any) => any; toDB: (value: any) => any; } } = {\r\n _id: {\r\n fromDB: value => value._bsontype == 'ObjectID' ? new MongoDB.ObjectID(value.id).toHexString() : value,\r\n toDB: value => value && typeof value === 'string' ? new MongoDB.ObjectID(value) : value\r\n }\r\n };\r\n \r\n static cache: CacheDirector;\r\n static indexes: (Index.Index | Index.IndexSpecification)[] = [];\r\n static identifier: {\r\n apply(fromSource: any): any;\r\n reverse(toSource: any): any;\r\n };\r\n \r\n /**\r\n * Saves any changes to this instance, using the built in diff algorithm to write the update query.\r\n * @param {function(Error, IInstance)} callback A callback which is triggered when the save operation completes\r\n * @returns {Promise}\r\n */\r\n save(callback?: General.Callback): Bluebird;\r\n /**\r\n * Saves the given changes to this instance and updates the instance to match the latest database document.\r\n * @param {Object} changes The MongoDB changes object to be used when updating this instance\r\n * @param {function(Error, IInstance)} callback A callback which is triggered when the save operation completes\r\n * @returns {Promise}\r\n */\r\n save(changes: Object, callback?: General.Callback): Bluebird;\r\n /**\r\n * Saves the given changes to this instance and updates the instance to match the latest database document.\r\n * @param {Object} conditions The conditions under which the update will take place - these will be merged with an _id query\r\n * @param {Object} changes The MongoDB changes object to be used when updating this instance\r\n * @param {function(Error, IInstance)} callback A callback which is triggered when the save operation completes\r\n * @returns {Promise}\r\n */\r\n save(conditions: Object, changes: Object, callback?: General.Callback): Bluebird;\r\n save(...args: any[]): Bluebird {\r\n var callback: General.Callback = null;\r\n var changes: any = null;\r\n var conditions: any = {};\r\n\r\n Array.prototype.slice.call(args, 0).reverse().forEach((arg) => {\r\n if (typeof arg == 'function') callback = arg;\r\n else if (typeof arg == 'object') {\r\n if (!changes) changes = arg;\r\n else conditions = arg;\r\n }\r\n });\r\n\r\n return Bluebird.resolve().then(() => {\r\n conditions = _.cloneDeep(conditions);\r\n _.merge(conditions, { _id: this._modified._id });\r\n \r\n conditions = this._model.helpers.transformToDB(conditions);\r\n \r\n if (!changes) {\r\n var validation = this._model.helpers.validate(this._modified);\r\n if (validation.failed) return Bluebird.reject(validation.error).bind(this).nodeify(callback);\r\n\r\n var original = _.cloneDeep(this._original);\r\n var modified = _.cloneDeep(this._modified);\r\n\r\n changes = this._model.helpers.diff(original, modified);\r\n }\r\n\r\n if (!_.keys(changes).length) return null;\r\n\r\n return changes;\r\n }).then((changes) => {\r\n if (!changes && !this._isNew) return changes;\r\n return this._model.handlers.savingDocument(this, changes).then(() => changes);\r\n }).then((changes) => {\r\n if (!changes && !this._isNew) return false;\r\n\r\n if (this._isNew) {\r\n return new Bluebird((resolve, reject) => {\r\n this._model.collection.insertOne(this._modified, { w: 'majority' }, (err, doc) => {\r\n if (err) return reject(err);\r\n return resolve(!!doc);\r\n });\r\n });\r\n } else {\r\n return new Bluebird((resolve: (changed: boolean) => void, reject) => {\r\n this._model.collection.updateOne(conditions, changes, { w: 'majority' }, (err: Error, changed: boolean) => {\r\n if (err) return reject(err);\r\n return resolve(changed);\r\n });\r\n });\r\n }\r\n }).then((changed: boolean) => {\r\n conditions = this._model.helpers.convertToDB({ _id: this._modified._id });\r\n if (!changed) {\r\n return _.cloneDeep(this._modified);\r\n }\r\n\r\n return new Bluebird((resolve, reject) => {\r\n this._model.collection.findOne(conditions,(err: Error, latest) => {\r\n if (err) return reject(err);\r\n return resolve(latest);\r\n });\r\n });\r\n }).then((latest: TDocument) => {\r\n return this._model.handlers.documentReceived(conditions, latest,(value) => {\r\n this._isPartial = false;\r\n this._isNew = false;\r\n this._original = value;\r\n this._modified = _.clone(value);\r\n return this;\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Updates this instance to match the latest document available in the backing collection\r\n * @param {function(Error, IInstance)} callback A callback which is triggered when the update completes\r\n * @returns {Promise}\r\n */\r\n update(callback?: General.Callback): Bluebird {\r\n return this.refresh(callback);\r\n }\r\n\r\n /**\r\n * Updates this instance to match the latest document available in the backing collection\r\n * @param {function(Error, IInstance)} callback A callback which is triggered when the update completes\r\n * @returns {Promise}\r\n */\r\n refresh(callback?: General.Callback): Bluebird {\r\n var conditions = { _id: this._original._id };\r\n\r\n return Bluebird.resolve().then(() => {\r\n return new Bluebird((resolve, reject) => {\r\n this._model.collection.findOne(conditions,(err: Error, doc: any) => {\r\n if (err) return reject(err);\r\n return resolve(doc);\r\n });\r\n });\r\n }).then((newDocument) => {\r\n if (!newDocument) {\r\n this._isPartial = true;\r\n this._isNew = true;\r\n this._original = _.cloneDeep(this._modified);\r\n return >this;\r\n }\r\n\r\n return this._model.handlers.documentReceived(conditions, newDocument, (doc) => {\r\n this._isNew = false;\r\n this._isPartial = false;\r\n this._original = doc;\r\n this._modified = _.cloneDeep(doc);\r\n\r\n return this;\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Removes this instance's document from the backing collection\r\n * @param {function(Error, IInstance)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n delete(callback?: General.Callback): Bluebird {\r\n return this.remove(callback);\r\n }\r\n\r\n /**\r\n * Removes this instance's document from the backing collection\r\n * @param {function(Error, IInstance)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n remove(callback?: General.Callback): Bluebird {\r\n var conditions = { _id: this._original._id };\r\n\r\n return Bluebird.resolve().then(() => {\r\n if (this._isNew) return 0;\r\n return new Bluebird((resolve, reject) => {\r\n this._model.collection.remove(conditions, { w: 'majority' },(err: Error, removed?: any) => {\r\n if (err) return reject(err);\r\n return resolve(removed);\r\n });\r\n });\r\n }).then((removed) => {\r\n if (removed) return this._model.cache.clear(conditions);\r\n return false;\r\n }).then(() => {\r\n this._isNew = true;\r\n return this;\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Retrieves the first element in an enumerable collection which matches the predicate\r\n * @param {any[]} collection The collection from which to retrieve the element\r\n * @param {function(any, Number): Boolean} predicate The function which determines whether to select an element\r\n * @returns {any}\r\n */\r\n first(collection: T[], predicate: General.Predicate): T;\r\n /**\r\n * Retrieves the first element in an enumerable collection which matches the predicate\r\n * @param {Object} collection The collection from which to retrieve the element\r\n * @param {function(any, String): Boolean} predicate The function which determines whether to select an element\r\n * @returns {any}\r\n */\r\n first(collection: { [key: string]: T }, predicate: General.Predicate): T;\r\n first(collection: T[]| { [key: string]: T }, predicate: General.Predicate): T {\r\n var result = null;\r\n\r\n _.each(collection,(value: T, key) => {\r\n if (predicate.call(this, value, key)) {\r\n result = value;\r\n return false;\r\n }\r\n });\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Retrieves a number of elements from an enumerable collection which match the predicate\r\n * @param {any[]} collection The collection from which elements will be plucked\r\n * @param {function(any, Number): Boolean} predicate The function which determines the elements to be plucked\r\n * @returns {any[]}\r\n */\r\n select(collection: T[], predicate: General.Predicate): T[];\r\n /**\r\n * Retrieves a number of elements from an enumerable collection which match the predicate\r\n * @param {Object} collection The collection from which elements will be plucked\r\n * @param {function(any, String): Boolean} predicate The function which determines the elements to be plucked\r\n * @returns {Object}\r\n */\r\n select(collection: { [key: string]: T }, predicate: General.Predicate): { [key: string]: T };\r\n select(collection: T[]| { [key: string]: T }, predicate: General.Predicate): any {\r\n var isArray = Array.isArray(collection);\r\n var results: any = isArray ? [] : {};\r\n\r\n _.each(collection,(value: T, key) => {\r\n if (predicate.call(this, value, key)) {\r\n if (isArray) results.push(value);\r\n else results[key] = value;\r\n }\r\n });\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Gets the JSON representation of this instance\r\n * @returns {TDocument}\r\n */\r\n toJSON(): any {\r\n return this.document;\r\n }\r\n\r\n /**\r\n * Gets a string representation of this instance\r\n * @returns {String}\r\n */\r\n toString(): string {\r\n return JSON.stringify(this.document, null, 2);\r\n }\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/InstanceInterface.js b/dist/lib/InstanceInterface.js
new file mode 100644
index 0000000..430cbbd
--- /dev/null
+++ b/dist/lib/InstanceInterface.js
@@ -0,0 +1,3 @@
+
+
+//# sourceMappingURL=../lib/InstanceInterface.js.map
\ No newline at end of file
diff --git a/dist/lib/InstanceInterface.js.map b/dist/lib/InstanceInterface.js.map
new file mode 100644
index 0000000..5661b62
--- /dev/null
+++ b/dist/lib/InstanceInterface.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/InstanceInterface.ts"],"names":[],"mappings":"AAwBC","file":"lib/InstanceInterface.js","sourcesContent":["/// \r\nimport Iridium from './Core';\r\nimport {Schema} from './Schema';\r\nimport Model from './Model';\r\nimport * as Index from './Index';\r\nimport {CacheDirector} from './CacheDirector';\r\n\r\nexport default InstanceImplementation;\r\n\r\ninterface InstanceImplementation {\r\n new (model: Model, doc: TDocument, isNew?: boolean, isPartial?: boolean): TInstance;\r\n \r\n collection: string;\r\n schema: Schema;\r\n indexes?: (Index.Index | Index.IndexSpecification)[];\r\n \r\n onCreating? (document: TDocument): void;\r\n onRetrieved? (document: TDocument): void;\r\n onReady? (instance: TInstance): void;\r\n onSaving? (instance: TInstance, changes: any): void;\r\n\r\n cache?: CacheDirector;\r\n validators?: Skmatc.Validator[];\r\n transforms?: { [property: string]: { fromDB: (value: any) => any; toDB: (value: any) => any; } };\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/Middleware.js b/dist/lib/Middleware.js
new file mode 100644
index 0000000..33be524
--- /dev/null
+++ b/dist/lib/Middleware.js
@@ -0,0 +1,3 @@
+
+
+//# sourceMappingURL=../lib/Middleware.js.map
\ No newline at end of file
diff --git a/dist/lib/Middleware.js.map b/dist/lib/Middleware.js.map
new file mode 100644
index 0000000..4742047
--- /dev/null
+++ b/dist/lib/Middleware.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/Middleware.ts"],"names":[],"mappings":"AAKC","file":"lib/Middleware.js","sourcesContent":["/// \r\nimport Core from './Core';\r\n\r\nexport interface MiddlewareFactory {\r\n (core: Core): T;\r\n}"],"sourceRoot":"/source/"}
\ No newline at end of file
diff --git a/dist/lib/Model.js b/dist/lib/Model.js
new file mode 100644
index 0000000..8256fa7
--- /dev/null
+++ b/dist/lib/Model.js
@@ -0,0 +1,483 @@
+var Bluebird = require('bluebird');
+var _ = require('lodash');
+var Core_1 = require('./Core');
+var Instance_1 = require('./Instance');
+var Cursor_1 = require('./Cursor');
+var ModelCache_1 = require('./ModelCache');
+var ModelHelpers_1 = require('./ModelHelpers');
+var ModelHandlers_1 = require('./ModelHandlers');
+var ModelSpecificInstance_1 = require('./ModelSpecificInstance');
+/**
+ * An Iridium Model which represents a structured MongoDB collection
+ * @class
+ */
+var Model = (function () {
+ /**
+ * Creates a new Iridium model representing a given ISchema and backed by a collection whose name is specified
+ * @param {Iridium} core The Iridium core that this model should use for database access
+ * @param {ModelInterfaces.InstanceImplementation} instanceType The class which will be instantiated for each document retrieved from the database
+ * @returns {Model}
+ * @constructor
+ */
+ function Model(core, instanceType) {
+ this._hooks = {};
+ if (!(core instanceof Core_1.default))
+ throw new Error("You failed to provide a valid Iridium core for this model");
+ if (typeof instanceType != 'function')
+ throw new Error("You failed to provide a valid instance constructor for this model");
+ if (typeof instanceType.collection != 'string' || !instanceType.collection)
+ throw new Error("You failed to provide a valid collection name for this model");
+ if (!_.isPlainObject(instanceType.schema) || instanceType.schema._id === undefined)
+ throw new Error("You failed to provide a valid schema for this model");
+ this._core = core;
+ this.loadExternal(instanceType);
+ this.onNewModel();
+ this.loadInternal();
+ }
+ Model.prototype.loadExternal = function (instanceType) {
+ this._collection = instanceType.collection;
+ this._schema = instanceType.schema;
+ this._hooks = instanceType;
+ this._cacheDirector = instanceType.cache;
+ this._transforms = instanceType.transforms || {};
+ this._validators = instanceType.validators || [];
+ this._indexes = instanceType.indexes || [];
+ if (instanceType.prototype instanceof Instance_1.default)
+ this._Instance = ModelSpecificInstance_1.default(this, instanceType);
+ else
+ this._Instance = instanceType.bind(undefined, this);
+ };
+ Model.prototype.loadInternal = function () {
+ this._cache = new ModelCache_1.default(this);
+ this._helpers = new ModelHelpers_1.default(this);
+ this._handlers = new ModelHandlers_1.default(this);
+ };
+ Model.prototype.onNewModel = function () {
+ var _this = this;
+ this._core.plugins.forEach(function (plugin) { return plugin.newModel && plugin.newModel(_this); });
+ };
+ Object.defineProperty(Model.prototype, "helpers", {
+ /**
+ * Provides helper methods used by Iridium for common tasks
+ * @returns {ModelHelpers}
+ */
+ get: function () {
+ return this._helpers;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "handlers", {
+ /**
+ * Provides helper methods used by Iridium for hook delegation and common processes
+ * @returns {ModelHandlers}
+ */
+ get: function () {
+ return this._handlers;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "hooks", {
+ /**
+ * Gets the even hooks subscribed on this model for a number of different state changes
+ * @returns {Hooks}
+ */
+ get: function () {
+ return this._hooks;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "schema", {
+ /**
+ * Gets the ISchema dictating the data structure represented by this model
+ * @public
+ * @returns {schema}
+ */
+ get: function () {
+ return this._schema;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "core", {
+ /**
+ * Gets the Iridium core that this model is associated with
+ * @public
+ * @returns {Iridium}
+ */
+ get: function () {
+ return this._core;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "collection", {
+ /**
+ * Gets the underlying MongoDB collection from which this model's documents are retrieved
+ * @public
+ * @returns {Collection}
+ */
+ get: function () {
+ if (!this.core.connection)
+ throw new Error("Iridium Core not connected to a database.");
+ return this.core.connection.collection(this._collection);
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "collectionName", {
+ /**
+ * Gets the name of the underlying MongoDB collection from which this model's documents are retrieved
+ * @public
+ */
+ get: function () {
+ return this._collection;
+ },
+ /**
+ * Sets the name of the underlying MongoDB collection from which this model's documents are retrieved
+ * @public
+ */
+ set: function (value) {
+ this._collection = value;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "cacheDirector", {
+ /**
+ * Gets the cache controller which dictates which queries will be cached, and under which key
+ * @public
+ * @returns {CacheDirector}
+ */
+ get: function () {
+ return this._cacheDirector;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "cache", {
+ /**
+ * Gets the cache responsible for storing objects for quick retrieval under certain conditions
+ * @public
+ * @returns {ModelCache}
+ */
+ get: function () {
+ return this._cache;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "Instance", {
+ /**
+ * Gets the constructor responsible for creating instances for this model
+ */
+ get: function () {
+ return this._Instance;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "transforms", {
+ get: function () {
+ return this._transforms;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "validators", {
+ get: function () {
+ return this._validators;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Model.prototype, "indexes", {
+ get: function () {
+ return this._indexes;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Model.prototype.find = function (conditions, fields) {
+ conditions = conditions || {};
+ fields = fields || {};
+ if (!_.isPlainObject(conditions))
+ conditions = { _id: conditions };
+ conditions = this._helpers.convertToDB(conditions);
+ var cursor = this.collection.find(conditions, {
+ fields: fields
+ });
+ return new Cursor_1.default(this, conditions, cursor);
+ };
+ Model.prototype.get = function () {
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i - 0] = arguments[_i];
+ }
+ return this.findOne.apply(this, args);
+ };
+ Model.prototype.findOne = function () {
+ var _this = this;
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i - 0] = arguments[_i];
+ }
+ var conditions = null;
+ var options = null;
+ var callback = null;
+ for (var argI = 0; argI < args.length; argI++) {
+ if (typeof args[argI] == 'function')
+ callback = callback || args[argI];
+ else if (_.isPlainObject(args[argI])) {
+ if (conditions)
+ options = args[argI];
+ else
+ conditions = args[argI];
+ }
+ else
+ conditions = { _id: args[argI] };
+ }
+ conditions = conditions || {};
+ options = options || {};
+ _.defaults(options, {
+ cache: true
+ });
+ return Bluebird.resolve().bind(this).then(function () {
+ conditions = _this._helpers.convertToDB(conditions);
+ return _this._cache.get(conditions);
+ }).then(function (cachedDocument) {
+ if (cachedDocument)
+ return cachedDocument;
+ return new Bluebird(function (resolve, reject) {
+ _this.collection.findOne(conditions, {
+ fields: options.fields,
+ skip: options.skip,
+ sort: options.sort,
+ limit: options.limit
+ }, function (err, result) {
+ if (err)
+ return reject(err);
+ return resolve(result);
+ });
+ });
+ }).then(function (document) {
+ if (!document)
+ return null;
+ return _this._handlers.documentReceived(conditions, document, function (document, isNew, isPartial) { return _this._helpers.wrapDocument(document, isNew, isPartial); }, options);
+ }).nodeify(callback);
+ };
+ Model.prototype.create = function () {
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i - 0] = arguments[_i];
+ }
+ return this.insert.apply(this, args);
+ };
+ Model.prototype.insert = function (objs) {
+ var _this = this;
+ var args = [];
+ for (var _i = 1; _i < arguments.length; _i++) {
+ args[_i - 1] = arguments[_i];
+ }
+ var objects;
+ var options = {};
+ var callback = null;
+ if (typeof args[0] == 'function')
+ callback = args[0];
+ else {
+ options = args[0];
+ callback = args[1];
+ }
+ if (Array.isArray(objs))
+ objects = objs;
+ else
+ objects = [objs];
+ options = options || {};
+ _.defaults(options, {
+ w: 'majority',
+ forceServerObjectId: true
+ });
+ return Bluebird.resolve().then(function () {
+ var queryOptions = { w: options.w, upsert: options.upsert, new: true };
+ if (options.upsert) {
+ var docs = _this._handlers.creatingDocuments(objects);
+ return docs.map(function (object) {
+ return new Bluebird(function (resolve, reject) {
+ _this.collection.findAndModify({ _id: object._id }, ["_id"], object, queryOptions, function (err, result) {
+ if (err)
+ return reject(err);
+ return resolve(result);
+ });
+ });
+ });
+ }
+ else
+ return _this._handlers.creatingDocuments(objects).then(function (objects) { return _.chunk(objects, 1000); }).map(function (objects) {
+ return new Bluebird(function (resolve, reject) {
+ _this.collection.insertMany(objects, queryOptions, function (err, result) {
+ if (err)
+ return reject(err);
+ return resolve(result.ops);
+ });
+ });
+ }).then(function (results) { return _.flatten(results); });
+ }).map(function (inserted) {
+ return _this._handlers.documentReceived(null, inserted, function (document, isNew, isPartial) { return _this._helpers.wrapDocument(document, isNew, isPartial); }, { cache: options.cache });
+ }).then(function (results) {
+ if (Array.isArray(objs))
+ return results;
+ return results[0];
+ }).nodeify(callback);
+ };
+ Model.prototype.update = function (conditions, changes, options, callback) {
+ var _this = this;
+ if (typeof options == 'function') {
+ callback = options;
+ options = {};
+ }
+ options = options || {};
+ if (!_.isPlainObject(conditions))
+ conditions = {
+ _id: conditions
+ };
+ _.defaults(options, {
+ w: 'majority',
+ multi: true
+ });
+ return Bluebird.resolve().then(function () {
+ conditions = _this._helpers.convertToDB(conditions);
+ return new Bluebird(function (resolve, reject) {
+ _this.collection.updateMany(conditions, changes, options, function (err, response) {
+ if (err)
+ return reject(err);
+ // New MongoDB 2.6+ response type
+ if (response.result && response.result.nModified !== undefined)
+ return resolve(response.result.nModified);
+ // Legacy response type
+ return resolve(response.result.n);
+ });
+ });
+ }).nodeify(callback);
+ };
+ Model.prototype.count = function (conds, callback) {
+ var _this = this;
+ var conditions = conds;
+ if (typeof conds == 'function') {
+ callback = conds;
+ conditions = {};
+ }
+ conditions = conditions || {};
+ if (!_.isPlainObject(conditions))
+ conditions = {
+ _id: conditions
+ };
+ return Bluebird.resolve().then(function () {
+ conditions = _this._helpers.convertToDB(conditions);
+ return new Bluebird(function (resolve, reject) {
+ _this.collection.count(conditions, function (err, results) {
+ if (err)
+ return reject(err);
+ return resolve(results);
+ });
+ });
+ }).nodeify(callback);
+ };
+ Model.prototype.remove = function (conds, options, callback) {
+ var _this = this;
+ var conditions = conds;
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+ if (typeof conds == 'function') {
+ callback = conds;
+ options = {};
+ conditions = {};
+ }
+ conditions = conditions || {};
+ options = options || {};
+ _.defaults(options, {
+ w: 'majority'
+ });
+ if (!_.isPlainObject(conditions))
+ conditions = {
+ _id: conditions
+ };
+ return Bluebird.resolve().then(function () {
+ conditions = _this._helpers.convertToDB(conditions);
+ return new Bluebird(function (resolve, reject) {
+ _this.collection.remove(conditions, options, function (err, response) {
+ if (err)
+ return reject(err);
+ return resolve(response.result.n);
+ });
+ });
+ }).then(function (count) {
+ if (count === 1)
+ _this._cache.clear(conditions);
+ return Bluebird.resolve(count);
+ }).nodeify(callback);
+ };
+ Model.prototype.ensureIndex = function (specification, options, callback) {
+ var _this = this;
+ if (typeof options == 'function') {
+ callback = options;
+ options = {};
+ }
+ return new Bluebird(function (resolve, reject) {
+ _this.collection.ensureIndex(specification, options, function (err, name) {
+ if (err)
+ return reject(err);
+ return resolve(name);
+ });
+ }).nodeify(callback);
+ };
+ /**
+ * Ensures that all indexes defined in the model's options are created
+ * @param {function(Error, String[])} callback A callback which is triggered when the operation completes
+ * @returns {Promise} The names of the indexes
+ */
+ Model.prototype.ensureIndexes = function (callback) {
+ var _this = this;
+ return Bluebird.resolve(this._indexes).map(function (index) {
+ return _this.ensureIndex(index.spec || index, index.options || {});
+ }).nodeify(callback);
+ };
+ Model.prototype.dropIndex = function (specification, callback) {
+ var _this = this;
+ var index;
+ if (typeof (specification) === 'string')
+ index = specification;
+ else {
+ index = _(specification).map(function (direction, key) { return key + '_' + direction; }).reduce(function (x, y) { return x + '_' + y; });
+ }
+ return new Bluebird(function (resolve, reject) {
+ _this.collection.dropIndex(index, function (err, result) {
+ if (err)
+ return reject(err);
+ return resolve(!!result.ok);
+ });
+ }).nodeify(callback);
+ };
+ /**
+ * Removes all indexes (except for _id) from the collection
+ * @param {function(Error, Boolean)} callback A callback which is triggered when the operation completes
+ * @returns {Promise} Whether the indexes were dropped
+ */
+ Model.prototype.dropIndexes = function (callback) {
+ var _this = this;
+ return new Bluebird(function (resolve, reject) {
+ _this.collection.dropAllIndexes(function (err, count) {
+ if (err)
+ return reject(err);
+ return resolve(count);
+ });
+ }).nodeify(callback);
+ };
+ return Model;
+})();
+exports.default = Model;
+
+//# sourceMappingURL=../lib/Model.js.map
\ No newline at end of file
diff --git a/dist/lib/Model.js.map b/dist/lib/Model.js.map
new file mode 100644
index 0000000..f618f12
--- /dev/null
+++ b/dist/lib/Model.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["lib/Model.ts"],"names":["Model","Model.constructor","Model.loadExternal","Model.loadInternal","Model.onNewModel","Model.helpers","Model.handlers","Model.hooks","Model.schema","Model.core","Model.collection","Model.collectionName","Model.cacheDirector","Model.cache","Model.Instance","Model.transforms","Model.validators","Model.indexes","Model.find","Model.get","Model.findOne","Model.create","Model.insert","Model.update","Model.count","Model.remove","Model.ensureIndex","Model.ensureIndexes","Model.dropIndex","Model.dropIndexes"],"mappings":"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","file":"lib/Model.js","sourcesContent":["/// \r\nimport MongoDB = require('mongodb');\r\nimport Bluebird = require('bluebird');\r\nimport util = require('util');\r\nimport _ = require('lodash');\r\n\r\nimport Core from './Core';\r\nimport Instance from './Instance';\r\nimport {Schema} from './Schema';\r\nimport {Hooks} from './Hooks';\r\nimport {Plugin} from './Plugins';\r\nimport {Cache} from './Cache';\r\nimport {CacheDirector} from './CacheDirector';\r\nimport * as General from './General';\r\nimport Cursor from './Cursor';\r\nimport * as Index from './Index';\r\nimport * as ModelOptions from './ModelOptions';\r\n\r\nimport noOpCache from './caches/NoOpCache';\r\nimport memoryCache from './caches/MemoryCache';\r\nimport idCacheController from './cacheControllers/IDDirector';\r\n\r\nimport Omnom from './utils/Omnom';\r\nimport ModelCache from './ModelCache';\r\nimport ModelHelpers from './ModelHelpers';\r\nimport ModelHandlers from './ModelHandlers';\r\nimport * as ModelInterfaces from './ModelInterfaces';\r\nimport ModelSpecificInstance from './ModelSpecificInstance';\r\nimport InstanceImplementation from './InstanceInterface';\r\n\r\n/**\r\n * An Iridium Model which represents a structured MongoDB collection\r\n * @class\r\n */\r\nexport default class Model {\r\n /**\r\n * Creates a new Iridium model representing a given ISchema and backed by a collection whose name is specified\r\n * @param {Iridium} core The Iridium core that this model should use for database access\r\n * @param {ModelInterfaces.InstanceImplementation} instanceType The class which will be instantiated for each document retrieved from the database\r\n * @returns {Model}\r\n * @constructor\r\n */\r\n constructor(core: Core, instanceType: InstanceImplementation) {\r\n if (!(core instanceof Core)) throw new Error(\"You failed to provide a valid Iridium core for this model\");\r\n if (typeof instanceType != 'function') throw new Error(\"You failed to provide a valid instance constructor for this model\");\r\n if (typeof instanceType.collection != 'string' || !instanceType.collection) throw new Error(\"You failed to provide a valid collection name for this model\");\r\n if (!_.isPlainObject(instanceType.schema) || instanceType.schema._id === undefined) throw new Error(\"You failed to provide a valid schema for this model\");\r\n \r\n this._core = core;\r\n \r\n this.loadExternal(instanceType);\r\n this.onNewModel();\r\n this.loadInternal();\r\n }\r\n \r\n private loadExternal(instanceType: InstanceImplementation) {\r\n this._collection = instanceType.collection;\r\n this._schema = instanceType.schema;\r\n this._hooks = instanceType;\r\n this._cacheDirector = instanceType.cache;\r\n this._transforms = instanceType.transforms || {};\r\n this._validators = instanceType.validators || [];\r\n this._indexes = instanceType.indexes || [];\r\n\r\n if ((instanceType).prototype instanceof Instance)\r\n this._Instance = ModelSpecificInstance(this, instanceType);\r\n else\r\n this._Instance = instanceType.bind(undefined, this);\r\n }\r\n \r\n private loadInternal() {\r\n this._cache = new ModelCache(this);\r\n this._helpers = new ModelHelpers(this);\r\n this._handlers = new ModelHandlers(this);\r\n }\r\n \r\n private onNewModel() {\r\n this._core.plugins.forEach(plugin => plugin.newModel && plugin.newModel(this));\r\n }\r\n\r\n private _helpers: ModelHelpers;\r\n /**\r\n * Provides helper methods used by Iridium for common tasks\r\n * @returns {ModelHelpers}\r\n */\r\n get helpers(): ModelHelpers {\r\n return this._helpers;\r\n }\r\n\r\n private _handlers: ModelHandlers;\r\n /**\r\n * Provides helper methods used by Iridium for hook delegation and common processes\r\n * @returns {ModelHandlers}\r\n */\r\n get handlers(): ModelHandlers {\r\n return this._handlers;\r\n }\r\n \r\n private _hooks: Hooks = {};\r\n \r\n /**\r\n * Gets the even hooks subscribed on this model for a number of different state changes\r\n * @returns {Hooks}\r\n */\r\n get hooks(): Hooks {\r\n return this._hooks;\r\n }\r\n\r\n private _schema: Schema;\r\n /**\r\n * Gets the ISchema dictating the data structure represented by this model\r\n * @public\r\n * @returns {schema}\r\n */\r\n get schema(): Schema {\r\n return this._schema;\r\n }\r\n\r\n private _core: Core;\r\n /**\r\n * Gets the Iridium core that this model is associated with\r\n * @public\r\n * @returns {Iridium}\r\n */\r\n get core(): Core {\r\n return this._core;\r\n }\r\n\r\n private _collection: string;\r\n /**\r\n * Gets the underlying MongoDB collection from which this model's documents are retrieved\r\n * @public\r\n * @returns {Collection}\r\n */\r\n get collection(): MongoDB.Collection {\r\n if (!this.core.connection) throw new Error(\"Iridium Core not connected to a database.\");\r\n return this.core.connection.collection(this._collection);\r\n }\r\n \r\n /**\r\n * Gets the name of the underlying MongoDB collection from which this model's documents are retrieved\r\n * @public\r\n */\r\n get collectionName(): string {\r\n return this._collection;\r\n }\r\n\r\n /**\r\n * Sets the name of the underlying MongoDB collection from which this model's documents are retrieved\r\n * @public\r\n */\r\n set collectionName(value: string) {\r\n this._collection = value;\r\n }\r\n\r\n private _cacheDirector: CacheDirector;\r\n /**\r\n * Gets the cache controller which dictates which queries will be cached, and under which key\r\n * @public\r\n * @returns {CacheDirector}\r\n */\r\n get cacheDirector(): CacheDirector {\r\n return this._cacheDirector;\r\n }\r\n\r\n private _cache: ModelCache;\r\n /**\r\n * Gets the cache responsible for storing objects for quick retrieval under certain conditions\r\n * @public\r\n * @returns {ModelCache}\r\n */\r\n get cache(): ModelCache {\r\n return this._cache;\r\n }\r\n\r\n private _Instance: ModelInterfaces.ModelSpecificInstanceConstructor;\r\n\r\n /**\r\n * Gets the constructor responsible for creating instances for this model\r\n */\r\n get Instance(): ModelInterfaces.ModelSpecificInstanceConstructor {\r\n return this._Instance;\r\n }\r\n \r\n private _transforms: { [property: string]: { fromDB: (value: any) => any; toDB: (value: any) => any; } };\r\n \r\n get transforms() {\r\n return this._transforms;\r\n }\r\n \r\n private _validators: Skmatc.Validator[];\r\n \r\n get validators() {\r\n return this._validators;\r\n }\r\n \r\n private _indexes: (Index.Index | Index.IndexSpecification)[];\r\n \r\n get indexes() {\r\n return this._indexes;\r\n }\r\n \r\n /**\r\n * Retrieves all documents in the collection and wraps them as instances\r\n * @param {function(Error, TInstance[])} callback An optional callback which will be triggered when results are available\r\n * @returns {Promise}\r\n */\r\n find(): Cursor;\r\n /**\r\n * Returns all documents in the collection which match the conditions and wraps them as instances\r\n * @param {Object} conditions The MongoDB query dictating which documents to return\r\n * @returns {Promise}\r\n */\r\n find(conditions: { _id?: any, [key: string]: any } | any): Cursor;\r\n /**\r\n * Returns all documents in the collection which match the conditions\r\n * @param {Object} conditions The MongoDB query dictating which documents to return\r\n * @param {Object} fields The fields to include or exclude from the document\r\n * @returns {Promise}\r\n */\r\n find(conditions: { _id?: any, [key: string]: any } | any, fields: { [name: string]: number }): Cursor;\r\n find(conditions?: { _id?: any, [key: string]: any } | any, fields?: any): Cursor {\r\n conditions = conditions || {};\r\n fields = fields || {};\r\n\r\n if (!_.isPlainObject(conditions)) conditions = { _id: conditions };\r\n conditions = this._helpers.convertToDB(conditions);\r\n\r\n var cursor = this.collection.find(conditions, {\r\n fields: fields\r\n });\r\n\r\n return new Cursor(this, conditions, cursor);\r\n }\r\n\r\n /**\r\n * Retrieves a single document from the collection and wraps it as an instance\r\n * @param {function(Error, TInstance)} callback An optional callback which will be triggered when a result is available\r\n * @returns {Promise}\r\n */\r\n get(callback?: General.Callback): Bluebird;\r\n /**\r\n * Retrieves a single document from the collection with the given ID and wraps it as an instance\r\n * @param {any} id The document's unique _id field value in downstream format\r\n * @param {function(Error, TInstance)} callback An optional callback which will be triggered when a result is available\r\n * @returns {Promise}\r\n */\r\n get(id: any, callback?: General.Callback): Bluebird;\r\n /**\r\n * Retrieves a single document from the collection which matches the conditions\r\n * @param {Object} conditions The MongoDB query dictating which document to return\r\n * @param {function(Error, TInstance)} callback An optional callback which will be triggered when a result is available\r\n * @returns {Promise}\r\n */\r\n get(conditions: { _id?: any, [key: string]: any }, callback?: General.Callback): Bluebird;\r\n /**\r\n * Retrieves a single document from the collection with the given ID and wraps it as an instance\r\n * @param {any} id The document's unique _id field value in downstream format\r\n * @param {QueryOptions} options The options dictating how this function behaves\r\n * @param {function(Error, TInstance)} callback An optional callback which will be triggered when a result is available\r\n * @returns {Promise}\r\n */\r\n get(id: any, options: ModelOptions.QueryOptions, callback?: General.Callback): Bluebird;\r\n /**\r\n * Retrieves a single document from the collection which matches the conditions\r\n * @param {Object} conditions The MongoDB query dictating which document to return\r\n * @param {QueryOptions} options The options dictating how this function behaves\r\n * @param {function(Error, TInstance)} callback An optional callback which will be triggered when a result is available\r\n * @returns {Promise}\r\n */\r\n get(conditions: { _id?: any, [key: string]: any }, options: ModelOptions.QueryOptions, callback?: General.Callback): Bluebird;\r\n get(...args: any[]): Bluebird {\r\n return this.findOne.apply(this, args);\r\n }\r\n\r\n /**\r\n * Retrieves a single document from the collection and wraps it as an instance\r\n * @param {function(Error, TInstance)} callback An optional callback which will be triggered when a result is available\r\n * @returns {Promise}\r\n */\r\n findOne(callback?: General.Callback): Bluebird;\r\n /**\r\n * Retrieves a single document from the collection with the given ID and wraps it as an instance\r\n * @param {any} id The document's unique _id field value in downstream format\r\n * @param {function(Error, TInstance)} callback An optional callback which will be triggered when a result is available\r\n * @returns {Promise}\r\n */\r\n findOne(id: any, callback?: General.Callback): Bluebird;\r\n /**\r\n * Retrieves a single document from the collection which matches the conditions\r\n * @param {Object} conditions The MongoDB query dictating which document to return\r\n * @param {function(Error, TInstance)} callback An optional callback which will be triggered when a result is available\r\n * @returns {Promise}\r\n */\r\n findOne(conditions: { _id?: any, [key: string]: any }, callback?: General.Callback): Bluebird;\r\n /**\r\n * Retrieves a single document from the collection with the given ID and wraps it as an instance\r\n * @param {any} id The document's unique _id field value in downstream format\r\n * @param {QueryOptions} options The options dictating how this function behaves\r\n * @param {function(Error, TInstance)} callback An optional callback which will be triggered when a result is available\r\n * @returns {Promise}\r\n */\r\n findOne(id: any, options: ModelOptions.QueryOptions, callback?: General.Callback): Bluebird;\r\n /**\r\n * Retrieves a single document from the collection which matches the conditions\r\n * @param {Object} conditions The MongoDB query dictating which document to return\r\n * @param {QueryOptions} options The options dictating how this function behaves\r\n * @param {function(Error, TInstance)} callback An optional callback which will be triggered when a result is available\r\n * @returns {Promise}\r\n */\r\n findOne(conditions: { _id?: any, [key: string]: any }, options: ModelOptions.QueryOptions, callback?: General.Callback): Bluebird;\r\n findOne(...args: any[]): Bluebird {\r\n var conditions: { _id?: any, [key: string]: any } = null;\r\n var options: ModelOptions.QueryOptions = null;\r\n var callback: General.Callback = null;\r\n\r\n for (var argI = 0; argI < args.length; argI++) {\r\n if (typeof args[argI] == 'function') callback = callback || args[argI];\r\n else if (_.isPlainObject(args[argI])) {\r\n if (conditions) options = args[argI];\r\n else conditions = args[argI];\r\n }\r\n else conditions = { _id: args[argI] };\r\n }\r\n\r\n conditions = conditions || {};\r\n options = options || {};\r\n\r\n _.defaults(options, {\r\n cache: true\r\n });\r\n\r\n return Bluebird.resolve().bind(this).then(() => {\r\n conditions = this._helpers.convertToDB(conditions);\r\n\r\n return this._cache.get(conditions);\r\n }).then((cachedDocument: TDocument) => {\r\n if (cachedDocument) return cachedDocument;\r\n return new Bluebird((resolve, reject) => {\r\n this.collection.findOne(conditions, {\r\n fields: options.fields,\r\n skip: options.skip,\r\n sort: options.sort,\r\n limit: options.limit\r\n },(err, result) => {\r\n if (err) return reject(err);\r\n return resolve(result);\r\n });\r\n });\r\n }).then((document: TDocument) => {\r\n if (!document) return null;\r\n return this._handlers.documentReceived(conditions, document,(document, isNew?, isPartial?) => this._helpers.wrapDocument(document, isNew, isPartial), options);\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Inserts an object into the collection after validating it against this model's schema\r\n * @param {Object} object The object to insert into the collection\r\n * @param {function(Error, TInstance)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n create(objects: TDocument, callback?: General.Callback): Bluebird;\r\n /**\r\n * Inserts an object into the collection after validating it against this model's schema\r\n * @param {Object} object The object to insert into the collection\r\n * @param {CreateOptions} options The options dictating how this function behaves\r\n * @param {function(Error, TInstance)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n create(objects: TDocument, options: ModelOptions.CreateOptions, callback?: General.Callback): Bluebird;\r\n /**\r\n * Inserts the objects into the collection after validating them against this model's schema\r\n * @param {Object[]} objects The objects to insert into the collection\r\n * @param {function(Error, TInstance)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n create(objects: TDocument[], callback?: General.Callback): Bluebird;\r\n /**\r\n * Inserts the objects into the collection after validating them against this model's schema\r\n * @param {Object[]} objects The objects to insert into the collection\r\n * @param {CreateOptions} options The options dictating how this function behaves\r\n * @param {function(Error, TInstance)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n create(objects: TDocument[], options: ModelOptions.CreateOptions, callback?: General.Callback): Bluebird;\r\n create(...args: any[]): Bluebird {\r\n return this.insert.apply(this, args);\r\n }\r\n\r\n /**\r\n * Inserts an object into the collection after validating it against this model's schema\r\n * @param {Object} object The object to insert into the collection\r\n * @param {function(Error, TInstance)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n insert(objects: TDocument, callback?: General.Callback): Bluebird;\r\n /**\r\n * Inserts an object into the collection after validating it against this model's schema\r\n * @param {Object} object The object to insert into the collection\r\n * @param {CreateOptions} options The options dictating how this function behaves\r\n * @param {function(Error, TInstance)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n insert(objects: TDocument, options: ModelOptions.CreateOptions, callback?: General.Callback): Bluebird;\r\n /**\r\n * Inserts the objects into the collection after validating them against this model's schema\r\n * @param {Object[]} objects The objects to insert into the collection\r\n * @param {function(Error, TInstance[])} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n insert(objects: TDocument[], callback?: General.Callback): Bluebird;\r\n /**\r\n * Inserts the objects into the collection after validating them against this model's schema\r\n * @param {Object[]} objects The objects to insert into the collection\r\n * @param {CreateOptions} options The options dictating how this function behaves\r\n * @param {function(Error, TInstance[])} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n insert(objects: TDocument[], options: ModelOptions.CreateOptions, callback?: General.Callback): Bluebird;\r\n insert(objs: TDocument | TDocument[], ...args: any[]): Bluebird {\r\n var objects: TDocument[];\r\n var options: ModelOptions.CreateOptions = {};\r\n var callback: General.Callback = null;\r\n if (typeof args[0] == 'function') callback = args[0];\r\n else {\r\n options = args[0];\r\n callback = args[1];\r\n }\r\n\r\n if (Array.isArray(objs))\r\n objects = objs;\r\n else\r\n objects = [objs];\r\n\r\n options = options || {};\r\n _.defaults(options, {\r\n w: 'majority',\r\n forceServerObjectId: true\r\n });\r\n\r\n return Bluebird.resolve().then(() => {\r\n var queryOptions = { w: options.w, upsert: options.upsert, new: true };\r\n\r\n if (options.upsert) {\r\n var docs = this._handlers.creatingDocuments(objects);\r\n return docs.map((object: { _id: any; }) => {\r\n return new Bluebird((resolve, reject) => {\r\n this.collection.findAndModify({ _id: object._id }, [\"_id\"], object, queryOptions,(err, result) => {\r\n if (err) return reject(err);\r\n return resolve(result);\r\n });\r\n });\r\n });\r\n }\r\n else\r\n return this._handlers.creatingDocuments(objects).then(objects => _.chunk(objects, 1000)).map((objects: any[]) => {\r\n return new Bluebird((resolve, reject) => {\r\n this.collection.insertMany(objects, queryOptions,(err, result) => {\r\n if (err) return reject(err);\r\n return resolve(result.ops);\r\n });\r\n });\r\n }).then(results => _.flatten(results));\r\n }).map((inserted: any) => {\r\n return this._handlers.documentReceived(null, inserted,(document, isNew?, isPartial?) => this._helpers.wrapDocument(document, isNew, isPartial), { cache: options.cache });\r\n }).then((results: TInstance[]) => {\r\n if (Array.isArray(objs)) return results;\r\n return results[0];\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Updates the documents in the backing collection which match the conditions using the given update instructions\r\n * @param {Object} conditions The conditions which determine which documents will be updated\r\n * @param {Object} changes The changes to make to the documents\r\n * @param {function(Error, Number)} callback A callback which is triggered when the operation completes\r\n */\r\n update(conditions: { _id?: any, [key: string]: any } | any, changes: any, callback?: General.Callback): Bluebird;\r\n /**\r\n * Updates the documents in the backing collection which match the conditions using the given update instructions\r\n * @param {Object} conditions The conditions which determine which documents will be updated\r\n * @param {Object} changes The changes to make to the documents\r\n * @param {UpdateOptions} options The options which dictate how this function behaves\r\n * @param {function(Error, Number)} callback A callback which is triggered when the operation completes\r\n */\r\n update(conditions: { _id?: any, [key: string]: any } | any, changes: any, options: ModelOptions.UpdateOptions, callback?: General.Callback): Bluebird;\r\n update(conditions: { _id?: any, [key: string]: any } | any, changes: any, options?: ModelOptions.UpdateOptions, callback?: General.Callback): Bluebird {\r\n if (typeof options == 'function') {\r\n callback = >options;\r\n options = {};\r\n }\r\n \r\n options = options || {};\r\n\r\n if (!_.isPlainObject(conditions)) conditions = {\r\n _id: conditions\r\n };\r\n\r\n _.defaults(options, {\r\n w: 'majority',\r\n multi: true\r\n });\r\n\r\n return Bluebird.resolve().then(() => {\r\n conditions = this._helpers.convertToDB(conditions);\r\n\r\n return new Bluebird((resolve, reject) => {\r\n this.collection.updateMany(conditions, changes, options,(err, response) => {\r\n if (err) return reject(err);\r\n\r\n // New MongoDB 2.6+ response type\r\n if (response.result && response.result.nModified !== undefined) return resolve(response.result.nModified);\r\n\r\n // Legacy response type\r\n return resolve(response.result.n);\r\n });\r\n })\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Counts the number of documents in the collection\r\n * @param {function(Error, Number)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n count(callback?: General.Callback): Bluebird;\r\n /**\r\n * Counts the number of documents in the collection which match the conditions provided\r\n * @param {Object} conditions The conditions which determine whether an object is counted or not\r\n * @param {function(Error, Number)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n count(conditions: { _id?: any, [key: string]: any } | any, callback?: General.Callback): Bluebird;\r\n count(conds?: any, callback?: General.Callback): Bluebird {\r\n var conditions: { _id?: any, [key: string]: any } = <{ _id?: any, [key: string]: any }>conds;\r\n if (typeof conds == 'function') {\r\n callback = >conds;\r\n conditions = {};\r\n }\r\n\r\n conditions = conditions || {};\r\n\r\n if (!_.isPlainObject(conditions)) conditions = {\r\n _id: conditions\r\n };\r\n\r\n return Bluebird.resolve().then(() => {\r\n conditions = this._helpers.convertToDB(conditions);\r\n\r\n return new Bluebird((resolve, reject) => {\r\n this.collection.count(conditions,(err, results) => {\r\n if (err) return reject(err);\r\n return resolve(results);\r\n });\r\n });\r\n }).nodeify(callback);\r\n }\r\n\r\n /**\r\n * Removes all documents from the collection\r\n * @param {function(Error, Number)} callback A callback which is triggered when the operation completes\r\n * @returns {Promise}\r\n */\r\n remove(callback?: General.Callback