<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>dist/dataset.js</filename>
    </added>
    <added>
      <filename>dist/dataset.min.js</filename>
    </added>
    <added>
      <filename>dist/dataset.ymin.js</filename>
    </added>
    <added>
      <filename>source/dm.js</filename>
    </added>
    <added>
      <filename>source/dm/connection.js</filename>
    </added>
    <added>
      <filename>source/dm/connections/air.js</filename>
    </added>
    <added>
      <filename>source/dm/connections/gears.js</filename>
    </added>
    <added>
      <filename>source/dm/connections/html5.js</filename>
    </added>
    <added>
      <filename>source/dm/database.js</filename>
    </added>
    <added>
      <filename>source/dm/dataset.js</filename>
    </added>
    <added>
      <filename>source/dm/inflector.js</filename>
    </added>
    <added>
      <filename>source/dm/model/class_methods.js</filename>
    </added>
    <added>
      <filename>source/dm/model/instance_methods.js</filename>
    </added>
    <added>
      <filename>source/dm/model/relationships.js</filename>
    </added>
    <added>
      <filename>source/dm/schema.js</filename>
    </added>
    <added>
      <filename>source/dm/schema_dsl.js</filename>
    </added>
    <added>
      <filename>source/dm/sql.js</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,10 +1,11 @@
 Todo:
 - Add relationships:
 	- hasMany
-	- hasOne
 	- belongsTo
+	- hasOne
 	- hasAndBelongsToMany
 - WHERE clause builder
+- t.serialize('column_name') -&gt; Serializes to/from JSON???
 
 
 Thoughts and/or Ideas:</diff>
      <filename>Notes.taskpaper</filename>
    </modified>
    <modified>
      <diff>@@ -3,15 +3,20 @@ task :test do
   puts `adl test-app.xml`
 end
 
+desc &quot;Compiles all targets&quot;
+task :build=&gt;[:build_dm, :build_dataset] do
+  puts &quot;Finished.&quot;
+end
+
 desc &quot;Compiles from source scripts into dist/dm.js&quot;
-task :build do
+task :build_dm do
   puts &quot;Building dm.js...&quot;
   require 'sprockets'
   
   secretary = Sprockets::Secretary.new(
     :asset_root   =&gt; &quot;assets&quot;,
     :load_path    =&gt; [&quot;source&quot;, &quot;etc&quot;, &quot;.&quot;],
-    :source_files =&gt; [&quot;source/application.js&quot;]
+    :source_files =&gt; [&quot;source/dm.js&quot;]
   )
 
   # Generate a Sprockets::Concatenation object from the source files
@@ -28,4 +33,29 @@ task :build do
   puts 'Done.'
 end
 
+desc &quot;Compiles from source scripts into dist/dataset.js&quot;
+task :build_dataset do
+  puts &quot;Building dataset.js...&quot;
+  require 'sprockets'
+  
+  secretary = Sprockets::Secretary.new(
+    :asset_root   =&gt; &quot;assets&quot;,
+    :load_path    =&gt; [&quot;source&quot;, &quot;etc&quot;, &quot;.&quot;],
+    :source_files =&gt; [&quot;source/dataset.js&quot;]
+  )
+
+  # Generate a Sprockets::Concatenation object from the source files
+  concatenation = secretary.concatenation
+  # Write the concatenation to disk
+  concatenation.save_to(&quot;dist/dataset.js&quot;)
+  
+  puts &quot;Piping dataset.js through jsmin...&quot;
+  `cat dist/dataset.js | jsmin &gt; dist/dataset.min.js`
+
+  puts &quot;Piping dataset.js through yuicompressor...&quot;
+  `java -jar $HOME/Dev/bin/yuicompressor-2.3.5.jar -o dist/dataset.ymin.js dist/dataset.js`
+  
+  puts 'Done.'
+end
+
 task :default=&gt;:build</diff>
      <filename>Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -21,6 +21,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
+
 var DM = {
 
   AUTHOR: &quot;M@ McCray &lt;darthapo@gmail.com&gt;&quot;,
@@ -28,7 +29,157 @@ var DM = {
 
 }
 
-var Options = {
+var Inflector = {
+  Inflections: {
+    plural: [
+    [/(quiz)$/i,               &quot;$1zes&quot;  ],
+    [/^(ox)$/i,                &quot;$1en&quot;   ],
+    [/([m|l])ouse$/i,          &quot;$1ice&quot;  ],
+    [/(matr|vert|ind)ix|ex$/i, &quot;$1ices&quot; ],
+    [/(x|ch|ss|sh)$/i,         &quot;$1es&quot;   ],
+    [/([^aeiouy]|qu)y$/i,      &quot;$1ies&quot;  ],
+    [/(hive)$/i,               &quot;$1s&quot;    ],
+    [/(?:([^f])fe|([lr])f)$/i, &quot;$1$2ves&quot;],
+    [/sis$/i,                  &quot;ses&quot;    ],
+    [/([ti])um$/i,             &quot;$1a&quot;    ],
+    [/(buffal|tomat)o$/i,      &quot;$1oes&quot;  ],
+    [/(bu)s$/i,                &quot;$1ses&quot;  ],
+    [/(alias|status)$/i,       &quot;$1es&quot;   ],
+    [/(octop|vir)us$/i,        &quot;$1i&quot;    ],
+    [/(ax|test)is$/i,          &quot;$1es&quot;   ],
+    [/s$/i,                    &quot;s&quot;      ],
+    [/$/,                      &quot;s&quot;      ]
+    ],
+    singular: [
+    [/(quiz)zes$/i,                                                    &quot;$1&quot;     ],
+    [/(matr)ices$/i,                                                   &quot;$1ix&quot;   ],
+    [/(vert|ind)ices$/i,                                               &quot;$1ex&quot;   ],
+    [/^(ox)en/i,                                                       &quot;$1&quot;     ],
+    [/(alias|status)es$/i,                                             &quot;$1&quot;     ],
+    [/(octop|vir)i$/i,                                                 &quot;$1us&quot;   ],
+    [/(cris|ax|test)es$/i,                                             &quot;$1is&quot;   ],
+    [/(shoe)s$/i,                                                      &quot;$1&quot;     ],
+    [/(o)es$/i,                                                        &quot;$1&quot;     ],
+    [/(bus)es$/i,                                                      &quot;$1&quot;     ],
+    [/([m|l])ice$/i,                                                   &quot;$1ouse&quot; ],
+    [/(x|ch|ss|sh)es$/i,                                               &quot;$1&quot;     ],
+    [/(m)ovies$/i,                                                     &quot;$1ovie&quot; ],
+    [/(s)eries$/i,                                                     &quot;$1eries&quot;],
+    [/([^aeiouy]|qu)ies$/i,                                            &quot;$1y&quot;    ],
+    [/([lr])ves$/i,                                                    &quot;$1f&quot;    ],
+    [/(tive)s$/i,                                                      &quot;$1&quot;     ],
+    [/(hive)s$/i,                                                      &quot;$1&quot;     ],
+    [/([^f])ves$/i,                                                    &quot;$1fe&quot;   ],
+    [/(^analy)ses$/i,                                                  &quot;$1sis&quot;  ],
+    [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, &quot;$1$2sis&quot;],
+    [/([ti])a$/i,                                                      &quot;$1um&quot;   ],
+    [/(n)ews$/i,                                                       &quot;$1ews&quot;  ],
+    [/s$/i,                                                            &quot;&quot;       ]
+    ],
+    irregular: [
+    ['move',   'moves'   ],
+    ['sex',    'sexes'   ],
+    ['child',  'children'],
+    ['man',    'men'     ],
+    ['person', 'people'  ]
+    ],
+    uncountable: [
+    &quot;sheep&quot;,
+    &quot;fish&quot;,
+    &quot;series&quot;,
+    &quot;species&quot;,
+    &quot;money&quot;,
+    &quot;rice&quot;,
+    &quot;information&quot;,
+    &quot;equipment&quot;
+    ]
+  },
+  ordinalize: function(number) {
+    if (11 &lt;= parseInt(number) % 100 &amp;&amp; parseInt(number) % 100 &lt;= 13) {
+      return number + &quot;th&quot;;
+    } else {
+      switch (parseInt(number) % 10) {
+        case  1: return number + &quot;st&quot;;
+        case  2: return number + &quot;nd&quot;;
+        case  3: return number + &quot;rd&quot;;
+        default: return number + &quot;th&quot;;
+      }
+    }
+  },
+  pluralize: function(word) {
+    for (var i = 0; i &lt; Inflector.Inflections.uncountable.length; i++) {
+      var uncountable = Inflector.Inflections.uncountable[i];
+      if (word.toLowerCase == uncountable) {
+        return uncountable;
+      }
+    }
+    for (var i = 0; i &lt; Inflector.Inflections.irregular.length; i++) {
+      var singular = Inflector.Inflections.irregular[i][0];
+      var plural   = Inflector.Inflections.irregular[i][1];
+      if ((word.toLowerCase == singular) || (word == plural)) {
+        return plural;
+      }
+    }
+    for (var i = 0; i &lt; Inflector.Inflections.plural.length; i++) {
+      var regex          = Inflector.Inflections.plural[i][0];
+      var replace_string = Inflector.Inflections.plural[i][1];
+      if (regex.test(word)) {
+        return word.replace(regex, replace_string);
+      }
+    }
+  },
+  singularize: function(word) {
+    for (var i = 0; i &lt; Inflector.Inflections.uncountable.length; i++) {
+      var uncountable = Inflector.Inflections.uncountable[i];
+      if (word.toLowerCase == uncountable) {
+        return uncountable;
+      }
+    }
+    for (var i = 0; i &lt; Inflector.Inflections.irregular.length; i++) {
+      var singular = Inflector.Inflections.irregular[i][0];
+      var plural   = Inflector.Inflections.irregular[i][1];
+      if ((word.toLowerCase == singular) || (word == plural)) {
+        return plural;
+      }
+    }
+    for (var i = 0; i &lt; Inflector.Inflections.singular.length; i++) {
+      var regex          = Inflector.Inflections.singular[i][0];
+      var replace_string = Inflector.Inflections.singular[i][1];
+      if (regex.test(word)) {
+        return word.replace(regex, replace_string);
+      }
+    }
+  }
+}
+
+function ordinalize(number) {
+  return Inflector.ordinalize(number);
+}
+
+Object.extend(String.prototype, {
+  pluralize: function(count, plural) {
+    if (typeof count == 'undefined') {
+      return Inflector.pluralize(this);
+    } else {
+      return count + ' ' + (1 == parseInt(count) ? this : plural || Inflector.pluralize(this));
+    }
+  },
+  singularize: function(count) {
+    if (typeof count == 'undefined') {
+      return Inflector.singularize(this);
+    } else {
+      return count + &quot; &quot; + Inflector.singularize(this);
+    }
+  }
+});
+
+DM.DB = {
+  execute: function() {
+    throw &quot;No DB connection has been made!!!&quot;;
+  }
+}
+
+DM.Options = {
 
   setOptions: function(opts) {
     var defaultOpts = $H(this.options || {}),
@@ -38,6 +189,38 @@ var Options = {
 
 }
 
+DM.Database = Class.create(DM.Options, { /// EVENTS???
+
+  options: {
+    name:         '',
+    description:  '',
+    displayName:  false,
+    size:         10240,
+    preferGears:  false
+  },
+
+  initialize: function(options) {
+    this.setOptions(options);
+    this.conn = DM.ConnectionFactory.getConnection( this.options );
+    DM.DB = this;
+  },
+
+  execute: function(sql, params, callback, options) {
+    if(!sql){ throw &quot;You must provide SQL to execute&quot;; }
+
+    var callback = callback || function(){ /*console.log('No callback defined')*/ },
+        params   = params || [],
+        options  = options || {};
+
+
+    this.conn.execute(sql, params, function(results){
+      callback(results);
+    }, options);
+  }
+
+});
+
+
 DM.AirConnection = Class.create({
   initialize: function(connInfo) {
     this.type = 'air';
@@ -203,44 +386,34 @@ DM.ConnectionFactory = {
   }
 
 };
-DM.Database = Class.create(Options, { /// EVENTS???
 
-  options: {
-    name:         '',
-    description:  '',
-    displayName:  false,
-    size:         10240,
-    preferGears:  false
-  },
+DM.DeferredCallback = Class.create({
 
-  initialize: function(options) {
-    this.setOptions(options);
-    this.conn = DM.ConnectionFactory.getConnection( this.options );
-    DM.Model.DB = this;
+  initialize: function(target, callback, args) {
+    this.target = target;
+    this.current = 0;
+    this.callback = callback;
+    this.args = args;
   },
 
-  execute: function(sql, params, callback, options) {
-    if(!sql){ throw &quot;You must provide SQL to execute&quot;; }
-
-    var callback = callback || function(){ /*console.log('No callback defined')*/ },
-        params   = params || [],
-        options  = options || {};
-
-
-    this.conn.execute(sql, params, function(results){
-      callback(results);
-    }, options);
+  ping: function() {
+    this.current++;
+    if(this.current == this.target) {
+      this.callback.apply(null, this.args);
+    } else {
+      console.log(&quot;Not yet...&quot;)
+    }
   }
-
 });
 
 DM.Dataset = Class.create({
 
-  initialize: function(tableName) {
+  initialize: function(tableName, options) {
     this.tableName = tableName;
     this.conditions = [];
     this.values = [];
     this.ordering = [];
+    this.options = $H({ asModel:false }).update(options || {});
   },
 
   filter: function(col, comparator, value, cnd) {
@@ -279,9 +452,9 @@ DM.Dataset = Class.create({
 
   each: function(callback) {
     var self = this;
-    DM.Model.DB.execute(this.toSql(), this.values, function(results){
+    DM.DB.execute(this.toSql(), this.values, function(results){
       for (var i=0; i &lt; results.rows.length; i++) {
-        var row = results.rows.item(i);
+        var row = self.options.asModel ? new DM.ModelInstance(results.rows.item(i), self.options.modelKlass) : results.rows.item(i);
         callback( row, i, results );
       };
     });
@@ -291,11 +464,17 @@ DM.Dataset = Class.create({
   all: function(callback) {
     if(callback) {
       var self = this;
-      DM.Model.DB.execute(this.toSql(), this.values, function(results){
+      DM.DB.execute(this.toSql(), this.values, function(results){
         var rows = [];
-        for (var i=0; i &lt; results.rows.length; i++) {
-          rows.push( results.rows.item(i)  );
-        };
+        if(self.options.asModel) {
+          for (var i=0; i &lt; results.rows.length; i++) {
+            rows.push( new DM.ModelInstance(results.rows.item(i), self.options.modelKlass) );
+          };
+        } else {
+          for (var i=0; i &lt; results.rows.length; i++) {
+            rows.push( results.rows.item(i)  );
+          };
+        }
         callback( rows ); // As an array...
       });
     } else {
@@ -306,20 +485,61 @@ DM.Dataset = Class.create({
     return this;
   },
 
-
-  count: function(callback) {
-    return this;
+  results: function(callback) {
+    this.all(callback);
   },
 
+
+
   add: function(data, callback) {
+    var self = this,
+        fn = callback || function(){};
+    if(Object.isArray(data)) {
+      console.log('!!! Data is ARRAY!!!')
+      var updatedData = [],
+          deferedCallback = new DM.DeferredCallback(data.length, callback, [updatedData]);
+      $A(data).each(function(item){
+        var sqlInf = DM.SQL.insertForObject(item, self.tableName);
+        DM.DB.execute(sqlInf[0], sqlInf[1], function(res){
+          item.id = res.insertId;
+          updatedData.push(item);
+          deferedCallback.ping();
+        });
+      })
+    } else {
+      var sqlInf = DM.SQL.insertForObject(data, this.tableName);
+      DM.DB.execute(sqlInf[0], sqlInf[1], function(res){
+        data.id = res.insertId;
+        fn(data, res);
+      });
+    }
     return this;
   },
 
   update: function(data, callback) {
+    var self = this,
+        sqlInf = DM.SQL.updateForObject(data, this.tableName),
+        fn = callback || function(){};
+    DM.DB.execute(sqlInf[0], sqlInf[1], function(res){
+      fn(data, res);
+    });
     return this;
   },
 
   destroy: function(data, callback) {
+    var self = this,
+        sqlInf = DM.SQL.deleteForModel(data, this.tableName);
+    DM.DB.execute(sqlInf[0], sqlInf[1], function(res){
+      callback(data, res);
+    });
+    return this;
+  },
+
+  destroyAll: function(callback) {
+    var self = this;
+    this.each(function(row){
+      this.destroy(row, callback);
+    });
     return this;
   },
 
@@ -382,15 +602,153 @@ Object.extend(String.prototype, {
     return [this, '&gt;=', value];
   },
 });
+
+DM.SQL = (function(){
+
+  function query() {
+    return $A(arguments).join(' ');
+  }
+
+  function safeFields(model) {
+    return model.fields.filter(function(f){ return (f.name != 'id')})
+  }
+
+  function typeSafe(value) {
+    if(value instanceof Date) {
+      return value.getTime();
+    } else {
+      return value;
+    }
+  }
+
+  return {
+
+    createForModel: function(model) {
+      var sql = query(
+        'CREATE TABLE',
+        'IF NOT EXISTS',
+        model.table_name,
+        '(',
+          model.fields.map( function(fld){ return query(fld.name, fld.type) }).join(', '),
+        ');'
+      );
+      return sql;
+    },
+
+    createForSchema: function(dsl, table_name) {
+      dsl.table_name = table_name;
+      return this.createForModel(dsl);
+    },
+
+    updateForModel: function(model) {
+      var values = [],
+          sql = query(
+            'UPDATE',
+            model.table_name,
+            'SET',
+            safeFields(model).map(function(fld){
+                values.push(model.get(fld.name, true));
+                return query(fld.name, '=', '?')
+            }).join(', '),
+            'WHERE id = ?;'
+          );
+      values.push( model.id );
+      return [sql, values];
+    },
+
+    insertForModel: function(model) {
+      var values = [],
+          sql = query(
+            'INSERT INTO',
+            model.table_name,
+            '(',
+            safeFields(model).map(function(fld){
+                values.push( model.get(fld.name, true) );
+                return fld.name;
+            }).join(', '),
+            ') VALUES (',
+            safeFields(model).map(function(fld){
+                return '?';
+            }).join(', '),
+            &quot;);&quot;
+          );
+      return [sql, values];
+    },
+
+    deleteForModel: function(model) {
+      var sql = query(
+        &quot;DELETE FROM&quot;,
+        model.table_name,
+        &quot;WHERE id = ?;&quot;
+      );
+      return [sql, [model.id]]
+    },
+
+
+    updateForObject: function(object, table_name) {
+      if(!object.id) throw &quot;Object must have an ID to be updated...&quot;;
+      var values = [],
+          hsh = $H(object),
+          sql = query(
+            'UPDATE',
+            table_name,
+            'SET',
+            hsh.keys().without('id').map(function(fld){
+                values.push( typeSafe(hsh.get(fld)) );
+                return query(fld, '=', '?')
+            }).join(', '),
+            'WHERE id = ?;'
+          );
+      values.push( hsh.get('id') );
+      return [sql, values];
+    },
+
+    insertForObject: function(object, table_name) {
+      var values = [],
+          hsh = $H(object),
+          sql = query(
+            'INSERT INTO',
+            table_name,
+            '(',
+            hsh.keys().without('id').map(function(fld){
+                values.push( typeSafe(hsh.get(fld)) );
+                return fld;
+            }).join(', '),
+            ') VALUES (',
+            hsh.keys().without('id').map(function(fld){
+                return '?';
+            }).join(', '),
+            &quot;);&quot;
+          );
+      return [sql, values];
+    },
+
+    deleteForModel: function(object, table_name) {
+      var id = (typeof object == 'number') ? object : object.id;
+          sql = query(
+            &quot;DELETE FROM&quot;,
+            table_name,
+            &quot;WHERE id = ?;&quot;
+          );
+      return [sql, [id]];
+    }
+  }
+})();
+
 DM.ModelInstance = Class.create({
+
   initialize: function(attributes, klass) {
     this.table_name = klass.table_name;
     this.fields = klass.fields; // Array
     this.columns = klass.columns; // Hash
+    this.relationships = klass.relationships; // Array
     this.klass = klass;
     this.isDirty = false;
     this.attributes = $H(attributes || {}); // Attributes from the SQLResultSet seem to be read-only
     this.id = this.attributes.get('id') || null;
+    this.relationships.each(function(rel){
+      rel.addMethodsToInstance(this);
+    }.bind(this));
   },
 
   get: function(attribute, raw) {
@@ -451,7 +809,7 @@ DM.ModelInstance = Class.create({
     if(typeof(self.id) == 'number') {
       self.klass._handleEvent('beforeSave', this);
       var cmds = DM.SQL.updateForModel(this)
-      DM.Model.DB.execute( cmds[0], cmds[1], function(res) {
+      DM.DB.execute( cmds[0], cmds[1], function(res) {
         self.klass._handleEvent('afterSave', self);
         callback(self);
       } );
@@ -463,7 +821,7 @@ DM.ModelInstance = Class.create({
       var cmds = DM.SQL.insertForModel(this),
           sql = cmds.first(),
           values = cmds.last();
-      DM.Model.DB.execute( sql, values, function(res) {
+      DM.DB.execute( sql, values, function(res) {
         self.id = res.insertId;
         self.attributes.set('id', self.id);
         self.klass._handleEvent('afterSave', self);
@@ -483,7 +841,7 @@ DM.ModelInstance = Class.create({
       var self = this,
           cmds = DM.SQL.deleteForModel(this),
           callback = callback || function(){};
-      DM.Model.DB.execute( cmds[0], cmds[1], function(res) {
+      DM.DB.execute( cmds[0], cmds[1], function(res) {
         self.id = null;
         self.set('id', null);
         callback(self);
@@ -504,30 +862,37 @@ DM.Model = (function(){ // Closure to allow truly private methods...
       if(!model_def){ throw &quot;Model definitions missing!&quot;; }
 
       this.table_name = table_name;
+      this.model_def = model_def;
+
+      DM.Model.knownModels.set(table_name, this);
+    },
 
-      if(model_def.schema) {
+    initSchema: function() {
+      if(this.model_def.schema) {
         var dsl = new DM.Schema.DSL(this).id(); // Auto generate PK?
 
-        model_def.schema(dsl); // Exec Schema DSL
+        this.model_def.schema(dsl); // Exec Schema DSL
 
         this.fields = dsl.fields; // Array
         this.columns = dsl.columns; // Hash
         this.eventHandlers = dsl.eventHandlers;
+        this.relationships = dsl.relationships;
+
+        delete this.model_def['schema'];
 
-        delete model_def['schema'];
 
       } else {
         this.fields = [];
         this.columns = [];
         this.eventHandlers = {};
+        this.relationships = [];
       }
 
-      DM.Model.knownModels.set(table_name, this);
     },
 
     find: function(idOrWhere, callback) {
       var self = this;
-      DM.Model.DB.execute(&quot;select * from &quot;+ this.table_name +&quot; where id = &quot;+ idOrWhere +&quot;;&quot;, [], function(results){
+      DM.DB.execute(&quot;select * from &quot;+ this.table_name +&quot; where id = &quot;+ idOrWhere +&quot;;&quot;, [], function(results){
         if(results.rows.length &gt; 0) {
           var model = new DM.ModelInstance(results.rows.item(0), self);
           callback(model);
@@ -537,9 +902,28 @@ DM.Model = (function(){ // Closure to allow truly private methods...
       });
     },
 
+    findWhere: function(clause, callback) {
+      var ds = new DM.Dataset(this.table_name),
+          self = this;
+      ds.filter(clause);
+      DM.DB.execute(ds.toSql(), ds.values, function(results){
+        var models = [];
+        for (var i=0; i &lt; results.rows.length; i++) {
+          var row = results.rows.item(i);
+          models.push( new DM.ModelInstance(row, self)  );
+        };
+        callback(models);
+      });
+    },
+
+    filter: function(clause) {
+      var ds = new DM.Dataset(this.table_name, { asModel:true, modelKlass:this });
+      return ds.filter(clause);
+    },
+
     all: function(callback) { // where,
       var self = this;
-      DM.Model.DB.execute(&quot;select * from &quot;+ this.table_name +&quot;;&quot;, [], function(results){
+      DM.DB.execute(&quot;select * from &quot;+ this.table_name +&quot;;&quot;, [], function(results){
 
         var models = [];
         for (var i=0; i &lt; results.rows.length; i++) {
@@ -555,7 +939,7 @@ DM.Model = (function(){ // Closure to allow truly private methods...
       var self    = this,
           count   = 0;
 
-      DM.Model.DB.execute(&quot;select count(id) as cnt from &quot;+ this.table_name +&quot;;&quot;, [], function(results){
+      DM.DB.execute(&quot;select count(id) as cnt from &quot;+ this.table_name +&quot;;&quot;, [], function(results){
         count = results.rows.item(0)['cnt'];
         callback(count);
       });
@@ -597,11 +981,12 @@ DM.Model = (function(){ // Closure to allow truly private methods...
 DM.Model.knownModels = $H();
 
 DM.Model.createModels = function(){
-  if(DM.Model.DB) {
+  if(DM.DB) {
     DM.Model.knownModels.each(function(modelDef){ // klass, tableName
       var klass     = modelDef.value,
           tableName = modelDef.key;
-      DM.Model.DB.execute( DM.SQL.createForModel( klass ), [], function() {
+      klass.initSchema();
+      DM.DB.execute( DM.SQL.createForModel( klass ), [], function() {
         klass.tableCreated = true;
       });
     });
@@ -624,6 +1009,72 @@ var Script = new DM.Model('scripts', {
   }
 });
 */
+DM.Relationships = {
+};
+
+DM.Relationships.HasMany = Class.create({
+  initialize: function(modelKlass, options, schema) {
+    this.modelKlass = modelKlass;
+    this.options = $H(options || {});
+    this.schema = schema;
+  },
+
+  addMethodsToInstance: function(model) {
+    if(!this.modelKlass) return;
+    var self = this,
+        pkey_name = model.klass.table_name.singularize()+'_id';
+    model[this.modelKlass.table_name] = {
+      add: function(model, callback) {
+
+      },
+      all: function(callback) {
+        self.modelKlass.findWhere( pkey_name.eq(model.id), callback);
+      },
+      create: function(atts, callback) {
+        atts = $H(atts)
+        atts.set(pkey_name, model.id);
+        return self.modelKlass.create( atts.toObject() );
+      },
+      each: function(callback) {
+
+      },
+      get: function(id, callback) {
+
+      },
+      find: function(unknown, callback) {
+
+      },
+      remove: function(model, callback) {
+
+      },
+      destroy: function(model, callback) {
+
+      }
+    };
+  },
+
+  instanceMethods: {
+
+  }
+});
+
+DM.Relationships.BelongsTo = Class.create({
+  initialize: function(modelKlass, options, schema) {
+    this.modelKlass = modelKlass;
+    this.options = $H(options || {});
+    this.schema = schema;
+  },
+
+  addMethodsToInstance: function(model) {
+    model[this.modelKlass.table_name] = function(callback) {
+      return &quot;WOOT!&quot;;
+    }
+  },
+
+  instanceMethods: {
+
+  }
+});
 DM.Schema = {
 }
 
@@ -689,12 +1140,14 @@ DM.Schema.Timestamp = Class.create({
   }
 });
 
+
 DM.Schema.DSL = Class.create({
   initialize: function(model) {
     this.model = model;
     this.fields = [];
     this.dateFields = [];
     this.columns = {}; // by column name...
+    this.relationships = [];
     this.eventHandlers = {
       'beforeSave': $A([]),
       'afterSave': $A([]),
@@ -754,23 +1207,17 @@ DM.Schema.DSL = Class.create({
     return this;
   },
 
-  foreignKey: function(name, opts) {
-  },
 
   hasMany: function(model, opts) {
+    this.relationships.push( new DM.Relationships.HasMany(model, opts, this) );
   },
 
-  hasOne: function(model, opts) {
-
-  },
 
   belongsTo: function(model, opts) {
-
+    this.integer(model.table_name.singularize()+'_id', {allowNull:false});
+    this.relationships.push( new DM.Relationships.BelongsTo(model, opts, this) );
   },
 
-  hasAndBelongsToMany: function(model, opts) {
-
-  },
 
   beforeSave: function(handler) {
     this.eventHandlers['beforeSave'].push(handler);
@@ -788,74 +1235,24 @@ DM.Schema.DSL = Class.create({
     this.eventHandlers['afterCreate'].push(handler);
   }
 })
+DM.Schema._tables = $H({});
 
-DM.SQL = (function(){
-
-  function query() {
-    return $A(arguments).join(' ');
-  }
-
-  function safeFields(model) {
-    return model.fields.filter(function(f){ return (f.name != 'id')})
-  }
-
-  return {
-
-    createForModel: function(model) {
-      var sql = query(
-        'CREATE TABLE',
-        'IF NOT EXISTS',
-        model.table_name,
-        '(',
-          model.fields.map( function(fld){ return query(fld.name, fld.type) }).join(', '),
-        ');'
-      );
-      return sql;
-    },
-
-    updateForModel: function(model) {
-      var values = [],
-          sql = query(
-            'UPDATE',
-            model.table_name,
-            'SET',
-            safeFields(model).map(function(fld){
-                values.push(model.get(fld.name, true));
-                return query(fld.name, '=', '?')
-            }).join(', '),
-            'WHERE id = ?;'
-          );
-      values.push( model.id );
-      return [sql, values];
-    },
-
-    insertForModel: function(model) {
-      var values = [],
-          sql = query(
-            'INSERT INTO',
-            model.table_name,
-            '(',
-            safeFields(model).map(function(fld){
-                values.push( model.get(fld.name, true) );
-                return fld.name;
-            }).join(', '),
-            ') VALUES (',
-            safeFields(model).map(function(fld){
-                return '?';
-            }).join(', '),
-            &quot;);&quot;
-          );
-      return [sql, values];
-    },
+DM.Schema.defineTable = function(tableName, configurator) {
+  var dsl = new DM.Schema.DSL(tableName).id();
+  configurator( dsl );
+  DM.Schema._tables.set(tableName, dsl); // Auto generate PK?
+  return dsl;
+}
 
-    deleteForModel: function(model) {
-      var sql = query(
-        &quot;DELETE FROM&quot;,
-        model.table_name,
-        &quot;WHERE id = ?;&quot;
-      );
-      return [sql, [model.id]]
-    }
+DM.Schema.createAllTables = function(){
+  if(DM.DB) {
+    DM.Schema._tables.keys().each(function(tableName){
+      console.log(&quot;Creating table: &quot;+ tableName)
+      DM.DB.execute( DM.SQL.createForSchema( DM.Schema._tables.get(tableName), tableName), [], function() {
+        console.log(&quot;Table created:&quot;, tableName);
+      });
+    });
+  } else {
+    console.log(&quot;DM.Schema.createAllTables: Error: No database is defined.&quot;);
   }
-})();
-
+}</diff>
      <filename>dist/dm.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,15 @@
 
 var DM={AUTHOR:&quot;M@ McCray &lt;darthapo@gmail.com&gt;&quot;,VERSION:&quot;0.1.2&quot;,}
-var Options={setOptions:function(opts){var defaultOpts=$H(this.options||{}),overrideOpts=$H(opts||{});this.options=defaultOpts.merge(overrideOpts).toObject();}}
-DM.AirConnection=Class.create({initialize:function(connInfo){this.type='air';this.connInfo=connInfo;this.connection=new air.SQLConnection();this._dbFile=air.File.applicationStorageDirectory.resolvePath(connInfo.name);this.connection.openAsync(this._dbFile);},execute:function(sql,params,callback,options){var statement=new air.SQLStatement(),count=0;statement.sqlConnection=this.connection;statement.text=sql.replace(/(\?)/g,function(riddler){return&quot;:&quot;+count++;});$H(params).each(function(pair){statement.parameters[&quot;:&quot;+pair.key]=pair.value;});statement.addEventListener(air.SQLEvent.RESULT,function(){callback(statement.getResult(),event);});statement.addEventListener(air.SQLErrorEvent.ERROR,function(){});statement.execute();}});(function(rt){if(!rt)return;if(window.air&amp;&amp;air.Introspector)
+var Inflector={Inflections:{plural:[[/(quiz)$/i,&quot;$1zes&quot;],[/^(ox)$/i,&quot;$1en&quot;],[/([m|l])ouse$/i,&quot;$1ice&quot;],[/(matr|vert|ind)ix|ex$/i,&quot;$1ices&quot;],[/(x|ch|ss|sh)$/i,&quot;$1es&quot;],[/([^aeiouy]|qu)y$/i,&quot;$1ies&quot;],[/(hive)$/i,&quot;$1s&quot;],[/(?:([^f])fe|([lr])f)$/i,&quot;$1$2ves&quot;],[/sis$/i,&quot;ses&quot;],[/([ti])um$/i,&quot;$1a&quot;],[/(buffal|tomat)o$/i,&quot;$1oes&quot;],[/(bu)s$/i,&quot;$1ses&quot;],[/(alias|status)$/i,&quot;$1es&quot;],[/(octop|vir)us$/i,&quot;$1i&quot;],[/(ax|test)is$/i,&quot;$1es&quot;],[/s$/i,&quot;s&quot;],[/$/,&quot;s&quot;]],singular:[[/(quiz)zes$/i,&quot;$1&quot;],[/(matr)ices$/i,&quot;$1ix&quot;],[/(vert|ind)ices$/i,&quot;$1ex&quot;],[/^(ox)en/i,&quot;$1&quot;],[/(alias|status)es$/i,&quot;$1&quot;],[/(octop|vir)i$/i,&quot;$1us&quot;],[/(cris|ax|test)es$/i,&quot;$1is&quot;],[/(shoe)s$/i,&quot;$1&quot;],[/(o)es$/i,&quot;$1&quot;],[/(bus)es$/i,&quot;$1&quot;],[/([m|l])ice$/i,&quot;$1ouse&quot;],[/(x|ch|ss|sh)es$/i,&quot;$1&quot;],[/(m)ovies$/i,&quot;$1ovie&quot;],[/(s)eries$/i,&quot;$1eries&quot;],[/([^aeiouy]|qu)ies$/i,&quot;$1y&quot;],[/([lr])ves$/i,&quot;$1f&quot;],[/(tive)s$/i,&quot;$1&quot;],[/(hive)s$/i,&quot;$1&quot;],[/([^f])ves$/i,&quot;$1fe&quot;],[/(^analy)ses$/i,&quot;$1sis&quot;],[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i,&quot;$1$2sis&quot;],[/([ti])a$/i,&quot;$1um&quot;],[/(n)ews$/i,&quot;$1ews&quot;],[/s$/i,&quot;&quot;]],irregular:[['move','moves'],['sex','sexes'],['child','children'],['man','men'],['person','people']],uncountable:[&quot;sheep&quot;,&quot;fish&quot;,&quot;series&quot;,&quot;species&quot;,&quot;money&quot;,&quot;rice&quot;,&quot;information&quot;,&quot;equipment&quot;]},ordinalize:function(number){if(11&lt;=parseInt(number)%100&amp;&amp;parseInt(number)%100&lt;=13){return number+&quot;th&quot;;}else{switch(parseInt(number)%10){case 1:return number+&quot;st&quot;;case 2:return number+&quot;nd&quot;;case 3:return number+&quot;rd&quot;;default:return number+&quot;th&quot;;}}},pluralize:function(word){for(var i=0;i&lt;Inflector.Inflections.uncountable.length;i++){var uncountable=Inflector.Inflections.uncountable[i];if(word.toLowerCase==uncountable){return uncountable;}}
+for(var i=0;i&lt;Inflector.Inflections.irregular.length;i++){var singular=Inflector.Inflections.irregular[i][0];var plural=Inflector.Inflections.irregular[i][1];if((word.toLowerCase==singular)||(word==plural)){return plural;}}
+for(var i=0;i&lt;Inflector.Inflections.plural.length;i++){var regex=Inflector.Inflections.plural[i][0];var replace_string=Inflector.Inflections.plural[i][1];if(regex.test(word)){return word.replace(regex,replace_string);}}},singularize:function(word){for(var i=0;i&lt;Inflector.Inflections.uncountable.length;i++){var uncountable=Inflector.Inflections.uncountable[i];if(word.toLowerCase==uncountable){return uncountable;}}
+for(var i=0;i&lt;Inflector.Inflections.irregular.length;i++){var singular=Inflector.Inflections.irregular[i][0];var plural=Inflector.Inflections.irregular[i][1];if((word.toLowerCase==singular)||(word==plural)){return plural;}}
+for(var i=0;i&lt;Inflector.Inflections.singular.length;i++){var regex=Inflector.Inflections.singular[i][0];var replace_string=Inflector.Inflections.singular[i][1];if(regex.test(word)){return word.replace(regex,replace_string);}}}}
+function ordinalize(number){return Inflector.ordinalize(number);}
+Object.extend(String.prototype,{pluralize:function(count,plural){if(typeof count=='undefined'){return Inflector.pluralize(this);}else{return count+' '+(1==parseInt(count)?this:plural||Inflector.pluralize(this));}},singularize:function(count){if(typeof count=='undefined'){return Inflector.singularize(this);}else{return count+&quot; &quot;+Inflector.singularize(this);}}});DM.DB={execute:function(){throw&quot;No DB connection has been made!!!&quot;;}}
+DM.Options={setOptions:function(opts){var defaultOpts=$H(this.options||{}),overrideOpts=$H(opts||{});this.options=defaultOpts.merge(overrideOpts).toObject();}}
+DM.Database=Class.create(DM.Options,{options:{name:'',description:'',displayName:false,size:10240,preferGears:false},initialize:function(options){this.setOptions(options);this.conn=DM.ConnectionFactory.getConnection(this.options);DM.DB=this;},execute:function(sql,params,callback,options){if(!sql){throw&quot;You must provide SQL to execute&quot;;}
+var callback=callback||function(){},params=params||[],options=options||{};this.conn.execute(sql,params,function(results){callback(results);},options);}});DM.AirConnection=Class.create({initialize:function(connInfo){this.type='air';this.connInfo=connInfo;this.connection=new air.SQLConnection();this._dbFile=air.File.applicationStorageDirectory.resolvePath(connInfo.name);this.connection.openAsync(this._dbFile);},execute:function(sql,params,callback,options){var statement=new air.SQLStatement(),count=0;statement.sqlConnection=this.connection;statement.text=sql.replace(/(\?)/g,function(riddler){return&quot;:&quot;+count++;});$H(params).each(function(pair){statement.parameters[&quot;:&quot;+pair.key]=pair.value;});statement.addEventListener(air.SQLEvent.RESULT,function(){callback(statement.getResult(),event);});statement.addEventListener(air.SQLErrorEvent.ERROR,function(){});statement.execute();}});(function(rt){if(!rt)return;if(window.air&amp;&amp;air.Introspector)
 window.console=air.Introspector.Console;else{window.console={log:function(msg){rt.trace(msg);},info:function(msg){console.log('INFO: '+msg);}}}})(window.runtime);DM.GearsConnection=Class.create({initialize:function(connInfo){this.type='gears';this.connInfo=connInfo;if(!DM.GearsConnection.gearFactory)(function(){if(typeof GearsFactory!='undefined'){DM.GearsConnection.gearFactory=new GearsFactory();}else{try{DM.GearsConnection.gearFactory=new ActiveXObject('Gears.Factory');if(DM.GearsConnection.gearFactory.getBuildInfo().indexOf('ie_mobile')!=-1){DM.GearsConnection.gearFactory.privateSetGlobalObject(this);}}catch(e){if((typeof navigator.mimeTypes!='undefined')&amp;&amp;navigator.mimeTypes[&quot;application/x-googlegears&quot;]){DM.GearsConnection.gearFactory=document.createElement(&quot;object&quot;);DM.GearsConnection.gearFactory.style.display=&quot;none&quot;;DM.GearsConnection.gearFactory.width=0;DM.GearsConnection.gearFactory.height=0;DM.GearsConnection.gearFactory.type=&quot;application/x-googlegears&quot;;document.documentElement.appendChild(DM.GearsConnection.gearFactory);}}}
 if(!DM.GearsConnection.gearFactory){throw&quot;There was an error creating the GearsFactory!&quot;;}})();this.connection=DM.GearsConnection.gearFactory.create('beta.database');this.connection.open(connInfo.name);},execute:function(sql,params,callback,options){var results=this.connection.execute(sql,$A(params).flatten()),lastId=this.connection.lastInsertRowId,rows=[];(rows.constructor.prototype||rows.prototype).item=function(i){return this[i];}
 if(results){var names=[];for(var i=0;i&lt;results.fieldCount();i++){names.push(results.fieldName(i));}
@@ -10,25 +18,30 @@ rows.push(row);results.next();}
 results.close();}
 callback({insertId:lastId,rowsAffected:0,rows:rows});}});DM.Html5Connection=Class.create({initialize:function(connInfo){this.connInfo=connInfo;this.type='html5';this.connection=openDatabase(connInfo.name,connInfo.description,connInfo.displayName||connInfo.name,connInfo.size);},execute:function(sql,params,callback,options){this.connection.transaction(function(txn){txn.executeSql(sql,$A(params).flatten(),function(t,results){callback(results);},function(err){});});}});DM.ConnectionFactory={connectionPool:$H(),getConnection:function(connInfo){if(this.connectionPool.get(connInfo.name)){return this.connectionPool.get(connInfo.name);}
 var conn=false;if(typeof openDatabase!='undefined'){conn=new DM.Html5Connection(connInfo);}else if(typeof GearsFactory!='undefined'){conn=new DM.GearsConnection(connInfo);}else if(window.runtime&amp;&amp;typeof window.runtime.flash.data.SQLConnection!='undefined'){conn=new DM.AirConnection(connInfo);}
-if(conn){this.connectionPool.set(connInfo.name,conn);return conn;}else{this.connectionPool.set(connInfo.name,null);throw&quot;Unable to find a supported database!&quot;}}};DM.Database=Class.create(Options,{options:{name:'',description:'',displayName:false,size:10240,preferGears:false},initialize:function(options){this.setOptions(options);this.conn=DM.ConnectionFactory.getConnection(this.options);DM.Model.DB=this;},execute:function(sql,params,callback,options){if(!sql){throw&quot;You must provide SQL to execute&quot;;}
-var callback=callback||function(){},params=params||[],options=options||{};this.conn.execute(sql,params,function(results){callback(results);},options);}});DM.Dataset=Class.create({initialize:function(tableName){this.tableName=tableName;this.conditions=[];this.values=[];this.ordering=[];},filter:function(col,comparator,value,cnd){if(arguments.length==2){value=comparator;var colSegs=col.split(' ');if(colSegs.length&lt;2){throw&quot;Invalid filter syntax&quot;;}
+if(conn){this.connectionPool.set(connInfo.name,conn);return conn;}else{this.connectionPool.set(connInfo.name,null);throw&quot;Unable to find a supported database!&quot;}}};DM.DeferredCallback=Class.create({initialize:function(target,callback,args){this.target=target;this.current=0;this.callback=callback;this.args=args;},ping:function(){this.current++;if(this.current==this.target){this.callback.apply(null,this.args);}else{console.log(&quot;Not yet...&quot;)}}});DM.Dataset=Class.create({initialize:function(tableName,options){this.tableName=tableName;this.conditions=[];this.values=[];this.ordering=[];this.options=$H({asModel:false}).update(options||{});},filter:function(col,comparator,value,cnd){if(arguments.length==2){value=comparator;var colSegs=col.split(' ');if(colSegs.length&lt;2){throw&quot;Invalid filter syntax&quot;;}
 comparator=colSegs.pop();col=colSegs.join(' ');}else if(arguments.length==1){var args=$A(arguments[0]);col=args[0];comparator=args[1];value=args[2];}
 cnd=cnd||'AND';this.conditions.push({col:col,com:comparator,val:'?',cnd:cnd});this.values.push(value);return this;},where:function(col,comparator,value){return this.filter(col,comparator,value);},and:function(col,comparator,value){return this.filter(col,comparator,value,'AND');},or:function(col,comparator,value){return this.filter(col,comparator,value,'OR');},order:function(column,direction){direction=direction||'ASC';this.ordering.push(column+&quot; &quot;+direction)
-return this;},each:function(callback){var self=this;DM.Model.DB.execute(this.toSql(),this.values,function(results){for(var i=0;i&lt;results.rows.length;i++){var row=results.rows.item(i);callback(row,i,results);};});return this;},all:function(callback){if(callback){var self=this;DM.Model.DB.execute(this.toSql(),this.values,function(results){var rows=[];for(var i=0;i&lt;results.rows.length;i++){rows.push(results.rows.item(i));};callback(rows);});}else{this.conditions=[];this.values=[];this.ordering=[];}
-return this;},count:function(callback){return this;},add:function(data,callback){return this;},update:function(data,callback){return this;},destroy:function(data,callback){return this;},clone:function(){var ds=new DM.Dataset(this.tableName);ds.conditions=$A(this.conditions).clone();ds.values=$A(this.values).clone();ds.ordering=$A(this.ordering).clone();return ds;},toSql:function(cmd){var cmd=cmd||'SELECT',sql=cmd+&quot; * FROM &quot;+this.tableName;if(this.conditions.length&gt;0){sql+=&quot; WHERE &quot;;$A(this.conditions).each(function(clause,count){if(count&gt;0){sql+=clause.cnd+&quot; &quot;;}
+return this;},each:function(callback){var self=this;DM.DB.execute(this.toSql(),this.values,function(results){for(var i=0;i&lt;results.rows.length;i++){var row=self.options.asModel?new DM.ModelInstance(results.rows.item(i),self.options.modelKlass):results.rows.item(i);callback(row,i,results);};});return this;},all:function(callback){if(callback){var self=this;DM.DB.execute(this.toSql(),this.values,function(results){var rows=[];if(self.options.asModel){for(var i=0;i&lt;results.rows.length;i++){rows.push(new DM.ModelInstance(results.rows.item(i),self.options.modelKlass));};}else{for(var i=0;i&lt;results.rows.length;i++){rows.push(results.rows.item(i));};}
+callback(rows);});}else{this.conditions=[];this.values=[];this.ordering=[];}
+return this;},results:function(callback){this.all(callback);},add:function(data,callback){var self=this,fn=callback||function(){};if(Object.isArray(data)){console.log('!!! Data is ARRAY!!!')
+var updatedData=[],deferedCallback=new DM.DeferredCallback(data.length,callback,[updatedData]);$A(data).each(function(item){var sqlInf=DM.SQL.insertForObject(item,self.tableName);DM.DB.execute(sqlInf[0],sqlInf[1],function(res){item.id=res.insertId;updatedData.push(item);deferedCallback.ping();});})}else{var sqlInf=DM.SQL.insertForObject(data,this.tableName);DM.DB.execute(sqlInf[0],sqlInf[1],function(res){data.id=res.insertId;fn(data,res);});}
+return this;},update:function(data,callback){var self=this,sqlInf=DM.SQL.updateForObject(data,this.tableName),fn=callback||function(){};DM.DB.execute(sqlInf[0],sqlInf[1],function(res){fn(data,res);});return this;},destroy:function(data,callback){var self=this,sqlInf=DM.SQL.deleteForModel(data,this.tableName);DM.DB.execute(sqlInf[0],sqlInf[1],function(res){callback(data,res);});return this;},destroyAll:function(callback){var self=this;this.each(function(row){this.destroy(row,callback);});return this;},clone:function(){var ds=new DM.Dataset(this.tableName);ds.conditions=$A(this.conditions).clone();ds.values=$A(this.values).clone();ds.ordering=$A(this.ordering).clone();return ds;},toSql:function(cmd){var cmd=cmd||'SELECT',sql=cmd+&quot; * FROM &quot;+this.tableName;if(this.conditions.length&gt;0){sql+=&quot; WHERE &quot;;$A(this.conditions).each(function(clause,count){if(count&gt;0){sql+=clause.cnd+&quot; &quot;;}
 sql+=&quot;(&quot;+clause.col+&quot; &quot;+clause.com+&quot; &quot;+clause.val+&quot;) &quot;;});}
 if(this.ordering.length&gt;0){sql+=&quot; ORDER BY &quot;+this.ordering.join(', ');}
-sql+=&quot;;&quot;;return sql;},toString:function(){return this.toSql();}});Object.extend(String.prototype,{eq:function(value){return[this,'=',value];},like:function(value){return[this,'like',value];},neq:function(value){return[this,'!=',value];},lt:function(value){return[this,'&lt;',value];},gt:function(value){return[this,'&gt;',value];},lteq:function(value){return[this,'&lt;=',value];},gteq:function(value){return[this,'&gt;=',value];},});DM.ModelInstance=Class.create({initialize:function(attributes,klass){this.table_name=klass.table_name;this.fields=klass.fields;this.columns=klass.columns;this.klass=klass;this.isDirty=false;this.attributes=$H(attributes||{});this.id=this.attributes.get('id')||null;},get:function(attribute,raw){if(attribute in this.columns){if(this.columns[attribute].type=='timestamp'){return(raw)?this.attributes.get(attribute):new Date(this.attributes.get(attribute));}else{return this.attributes.get(attribute);}}else{throw(&quot;'&quot;+attribute+&quot;' is not a valid column for table &quot;+this.table_name);}},set:function(attribute,value){if(attribute in this.columns){if(this.columns[attribute].type=='timestamp'){switch(typeof(value)){case'string':value=Date.parse(value);break;case'number':value=value;break;default:value=value.getTime();}}
+sql+=&quot;;&quot;;return sql;},toString:function(){return this.toSql();}});Object.extend(String.prototype,{eq:function(value){return[this,'=',value];},like:function(value){return[this,'like',value];},neq:function(value){return[this,'!=',value];},lt:function(value){return[this,'&lt;',value];},gt:function(value){return[this,'&gt;',value];},lteq:function(value){return[this,'&lt;=',value];},gteq:function(value){return[this,'&gt;=',value];},});DM.SQL=(function(){function query(){return $A(arguments).join(' ');}
+function safeFields(model){return model.fields.filter(function(f){return(f.name!='id')})}
+function typeSafe(value){if(value instanceof Date){return value.getTime();}else{return value;}}
+return{createForModel:function(model){var sql=query('CREATE TABLE','IF NOT EXISTS',model.table_name,'(',model.fields.map(function(fld){return query(fld.name,fld.type)}).join(', '),');');return sql;},createForSchema:function(dsl,table_name){dsl.table_name=table_name;return this.createForModel(dsl);},updateForModel:function(model){var values=[],sql=query('UPDATE',model.table_name,'SET',safeFields(model).map(function(fld){values.push(model.get(fld.name,true));return query(fld.name,'=','?')}).join(', '),'WHERE id = ?;');values.push(model.id);return[sql,values];},insertForModel:function(model){var values=[],sql=query('INSERT INTO',model.table_name,'(',safeFields(model).map(function(fld){values.push(model.get(fld.name,true));return fld.name;}).join(', '),') VALUES (',safeFields(model).map(function(fld){return'?';}).join(', '),&quot;);&quot;);return[sql,values];},deleteForModel:function(model){var sql=query(&quot;DELETE FROM&quot;,model.table_name,&quot;WHERE id = ?;&quot;);return[sql,[model.id]]},updateForObject:function(object,table_name){if(!object.id)throw&quot;Object must have an ID to be updated...&quot;;var values=[],hsh=$H(object),sql=query('UPDATE',table_name,'SET',hsh.keys().without('id').map(function(fld){values.push(typeSafe(hsh.get(fld)));return query(fld,'=','?')}).join(', '),'WHERE id = ?;');values.push(hsh.get('id'));return[sql,values];},insertForObject:function(object,table_name){var values=[],hsh=$H(object),sql=query('INSERT INTO',table_name,'(',hsh.keys().without('id').map(function(fld){values.push(typeSafe(hsh.get(fld)));return fld;}).join(', '),') VALUES (',hsh.keys().without('id').map(function(fld){return'?';}).join(', '),&quot;);&quot;);return[sql,values];},deleteForModel:function(object,table_name){var id=(typeof object=='number')?object:object.id;sql=query(&quot;DELETE FROM&quot;,table_name,&quot;WHERE id = ?;&quot;);return[sql,[id]];}}})();DM.ModelInstance=Class.create({initialize:function(attributes,klass){this.table_name=klass.table_name;this.fields=klass.fields;this.columns=klass.columns;this.relationships=klass.relationships;this.klass=klass;this.isDirty=false;this.attributes=$H(attributes||{});this.id=this.attributes.get('id')||null;this.relationships.each(function(rel){rel.addMethodsToInstance(this);}.bind(this));},get:function(attribute,raw){if(attribute in this.columns){if(this.columns[attribute].type=='timestamp'){return(raw)?this.attributes.get(attribute):new Date(this.attributes.get(attribute));}else{return this.attributes.get(attribute);}}else{throw(&quot;'&quot;+attribute+&quot;' is not a valid column for table &quot;+this.table_name);}},set:function(attribute,value){if(attribute in this.columns){if(this.columns[attribute].type=='timestamp'){switch(typeof(value)){case'string':value=Date.parse(value);break;case'number':value=value;break;default:value=value.getTime();}}
 if(value!=this.attributes.get(attribute)){this.isDirty=true;this.attributes.set(attribute,value);}}else{throw(&quot;'&quot;+attribute+&quot;' is not a valid column for table &quot;+this.table_name);}
 return this;},update:function(attrs,ignoreErrors){var self=this;$H(attrs).each(function(pair){if(pair.value!=self.get(pair.key)){try{self.set(pair.key,pair.value)
 self.isDirty=true;}catch(ex){if(!ignoreErrors){throw ex;}}}});},save:function(callback){var self=this,callback=callback||function(){};if('updated_on'in this.columns){this.set('updated_on',new Date());}
 if('updated_at'in this.columns){this.set('updated_at',new Date());}
 if(typeof(self.id)=='number'){self.klass._handleEvent('beforeSave',this);var cmds=DM.SQL.updateForModel(this)
-DM.Model.DB.execute(cmds[0],cmds[1],function(res){self.klass._handleEvent('afterSave',self);callback(self);});}else{if('created_on'in this.columns){this.set('created_on',new Date());}
+DM.DB.execute(cmds[0],cmds[1],function(res){self.klass._handleEvent('afterSave',self);callback(self);});}else{if('created_on'in this.columns){this.set('created_on',new Date());}
 if('created_at'in this.columns){this.set('created_at',new Date());}
-self.klass._handleEvent('beforeCreate',self);self.klass._handleEvent('beforeSave',self);var cmds=DM.SQL.insertForModel(this),sql=cmds.first(),values=cmds.last();DM.Model.DB.execute(sql,values,function(res){self.id=res.insertId;self.attributes.set('id',self.id);self.klass._handleEvent('afterSave',self);self.klass._handleEvent('afterCreate',self);callback(self);});}},reload:function(callback){if(typeof(this.id)=='number'){}},destroy:function(callback){if(typeof(this.id)=='number'){var self=this,cmds=DM.SQL.deleteForModel(this),callback=callback||function(){};DM.Model.DB.execute(cmds[0],cmds[1],function(res){self.id=null;self.set('id',null);callback(self);});}},toString:function(){return&quot;[#Model:&quot;+this.table_name+&quot; id=\&quot;&quot;+this.id+&quot;\&quot;]&quot;;}});DM.Model=(function(){return Class.create({initialize:function(table_name,model_def){if(!model_def){throw&quot;Model definitions missing!&quot;;}
-this.table_name=table_name;if(model_def.schema){var dsl=new DM.Schema.DSL(this).id();model_def.schema(dsl);this.fields=dsl.fields;this.columns=dsl.columns;this.eventHandlers=dsl.eventHandlers;delete model_def['schema'];}else{this.fields=[];this.columns=[];this.eventHandlers={};}
-DM.Model.knownModels.set(table_name,this);},find:function(idOrWhere,callback){var self=this;DM.Model.DB.execute(&quot;select * from &quot;+this.table_name+&quot; where id = &quot;+idOrWhere+&quot;;&quot;,[],function(results){if(results.rows.length&gt;0){var model=new DM.ModelInstance(results.rows.item(0),self);callback(model);}else{throw(&quot;find( &quot;+idOrWhere+&quot; ) returned 0 results.&quot;);}});},all:function(callback){var self=this;DM.Model.DB.execute(&quot;select * from &quot;+this.table_name+&quot;;&quot;,[],function(results){var models=[];for(var i=0;i&lt;results.rows.length;i++){var row=results.rows.item(i);models.push(new DM.ModelInstance(row,self));};callback(models);})},count:function(callback){var self=this,count=0;DM.Model.DB.execute(&quot;select count(id) as cnt from &quot;+this.table_name+&quot;;&quot;,[],function(results){count=results.rows.item(0)['cnt'];callback(count);});},destroyAll:function(callback){var self=this,callback=callback||function(){};self.all(function(models){var modelCount=models.length,currentCount=1;models.each(function(mdl){mdl.destroy(function(){currentCount++;if(currentCount==modelCount){callback(models);}})});})},create:function(attributes){return new DM.ModelInstance((attributes||{}),this);},_handleEvent:function(evt,model){if(evt in this.eventHandlers){this.eventHandlers[evt].each(function(handler){handler(model);});}}})})();DM.Model.knownModels=$H();DM.Model.createModels=function(){if(DM.Model.DB){DM.Model.knownModels.each(function(modelDef){var klass=modelDef.value,tableName=modelDef.key;DM.Model.DB.execute(DM.SQL.createForModel(klass),[],function(){klass.tableCreated=true;});});}else{console.log(&quot;DM.Model.createModels: Error: No database is defined.&quot;);}};DM.Schema={}
+self.klass._handleEvent('beforeCreate',self);self.klass._handleEvent('beforeSave',self);var cmds=DM.SQL.insertForModel(this),sql=cmds.first(),values=cmds.last();DM.DB.execute(sql,values,function(res){self.id=res.insertId;self.attributes.set('id',self.id);self.klass._handleEvent('afterSave',self);self.klass._handleEvent('afterCreate',self);callback(self);});}},reload:function(callback){if(typeof(this.id)=='number'){}},destroy:function(callback){if(typeof(this.id)=='number'){var self=this,cmds=DM.SQL.deleteForModel(this),callback=callback||function(){};DM.DB.execute(cmds[0],cmds[1],function(res){self.id=null;self.set('id',null);callback(self);});}},toString:function(){return&quot;[#Model:&quot;+this.table_name+&quot; id=\&quot;&quot;+this.id+&quot;\&quot;]&quot;;}});DM.Model=(function(){return Class.create({initialize:function(table_name,model_def){if(!model_def){throw&quot;Model definitions missing!&quot;;}
+this.table_name=table_name;this.model_def=model_def;DM.Model.knownModels.set(table_name,this);},initSchema:function(){if(this.model_def.schema){var dsl=new DM.Schema.DSL(this).id();this.model_def.schema(dsl);this.fields=dsl.fields;this.columns=dsl.columns;this.eventHandlers=dsl.eventHandlers;this.relationships=dsl.relationships;delete this.model_def['schema'];}else{this.fields=[];this.columns=[];this.eventHandlers={};this.relationships=[];}},find:function(idOrWhere,callback){var self=this;DM.DB.execute(&quot;select * from &quot;+this.table_name+&quot; where id = &quot;+idOrWhere+&quot;;&quot;,[],function(results){if(results.rows.length&gt;0){var model=new DM.ModelInstance(results.rows.item(0),self);callback(model);}else{throw(&quot;find( &quot;+idOrWhere+&quot; ) returned 0 results.&quot;);}});},findWhere:function(clause,callback){var ds=new DM.Dataset(this.table_name),self=this;ds.filter(clause);DM.DB.execute(ds.toSql(),ds.values,function(results){var models=[];for(var i=0;i&lt;results.rows.length;i++){var row=results.rows.item(i);models.push(new DM.ModelInstance(row,self));};callback(models);});},filter:function(clause){var ds=new DM.Dataset(this.table_name,{asModel:true,modelKlass:this});return ds.filter(clause);},all:function(callback){var self=this;DM.DB.execute(&quot;select * from &quot;+this.table_name+&quot;;&quot;,[],function(results){var models=[];for(var i=0;i&lt;results.rows.length;i++){var row=results.rows.item(i);models.push(new DM.ModelInstance(row,self));};callback(models);})},count:function(callback){var self=this,count=0;DM.DB.execute(&quot;select count(id) as cnt from &quot;+this.table_name+&quot;;&quot;,[],function(results){count=results.rows.item(0)['cnt'];callback(count);});},destroyAll:function(callback){var self=this,callback=callback||function(){};self.all(function(models){var modelCount=models.length,currentCount=1;models.each(function(mdl){mdl.destroy(function(){currentCount++;if(currentCount==modelCount){callback(models);}})});})},create:function(attributes){return new DM.ModelInstance((attributes||{}),this);},_handleEvent:function(evt,model){if(evt in this.eventHandlers){this.eventHandlers[evt].each(function(handler){handler(model);});}}})})();DM.Model.knownModels=$H();DM.Model.createModels=function(){if(DM.DB){DM.Model.knownModels.each(function(modelDef){var klass=modelDef.value,tableName=modelDef.key;klass.initSchema();DM.DB.execute(DM.SQL.createForModel(klass),[],function(){klass.tableCreated=true;});});}else{console.log(&quot;DM.Model.createModels: Error: No database is defined.&quot;);}};DM.Relationships={};DM.Relationships.HasMany=Class.create({initialize:function(modelKlass,options,schema){this.modelKlass=modelKlass;this.options=$H(options||{});this.schema=schema;},addMethodsToInstance:function(model){if(!this.modelKlass)return;var self=this,pkey_name=model.klass.table_name.singularize()+'_id';model[this.modelKlass.table_name]={add:function(model,callback){},all:function(callback){self.modelKlass.findWhere(pkey_name.eq(model.id),callback);},create:function(atts,callback){atts=$H(atts)
+atts.set(pkey_name,model.id);return self.modelKlass.create(atts.toObject());},each:function(callback){},get:function(id,callback){},find:function(unknown,callback){},remove:function(model,callback){},destroy:function(model,callback){}};},instanceMethods:{}});DM.Relationships.BelongsTo=Class.create({initialize:function(modelKlass,options,schema){this.modelKlass=modelKlass;this.options=$H(options||{});this.schema=schema;},addMethodsToInstance:function(model){model[this.modelKlass.table_name]=function(callback){return&quot;WOOT!&quot;;}},instanceMethods:{}});DM.Schema={}
 DM.Schema.Text=Class.create({initialize:function(name,opts){opts=opts||{};this.name=name;this.type='text';this.defaultValue=opts.defaultValue;this.allowNull=opts.allowNull;if(opts.notNull)
 this.allowNull=!opts.notNull;}});DM.Schema.Integer=Class.create({initialize:function(name,opts){opts=opts||{};this.name=name;this.type='integer'
 this.defaultValue=(opts.primaryKey)?undefined:opts.defaultValue;this.allowNull=opts.allowNull;if(opts.notNull)
@@ -36,10 +49,10 @@ this.allowNull=!opts.notNull;if(opts.primaryKey)
 this.type=' INTEGER PRIMARY KEY AUTOINCREMENT'}});DM.Schema.Float=Class.create({initialize:function(name,opts){opts=opts||{};this.name=name;this.type='real';this.defaultValue=opts.defaultValue;this.allowNull=opts.allowNull;if(opts.notNull)
 this.allowNull=!opts.notNull;}});DM.Schema.Blob=Class.create({initialize:function(name,opts){opts=opts||{};this.name=name;this.type='blob';this.defaultValue=opts.defaultValue;this.allowNull=opts.allowNull;if(opts.notNull)
 this.allowNull=!opts.notNull;}});DM.Schema.Timestamp=Class.create({initialize:function(name,opts){opts=opts||{};this.name=name;this.type='timestamp';this.defaultValue=opts.defaultValue;this.allowNull=opts.allowNull;if(opts.notNull)
-this.allowNull=!opts.notNull;}});DM.Schema.DSL=Class.create({initialize:function(model){this.model=model;this.fields=[];this.dateFields=[];this.columns={};this.eventHandlers={'beforeSave':$A([]),'afterSave':$A([]),'beforeCreate':$A([]),'afterCreate':$A([])}},id:function(name,opts){var pk=name||'id',fld=new DM.Schema.Integer(pk,{primaryKey:true});this.fields.push(fld);this.columns[pk]=fld;return this;},text:function(name,opts){var fld=new DM.Schema.Text(name,opts);this.fields.push(fld)
+this.allowNull=!opts.notNull;}});DM.Schema.DSL=Class.create({initialize:function(model){this.model=model;this.fields=[];this.dateFields=[];this.columns={};this.relationships=[];this.eventHandlers={'beforeSave':$A([]),'afterSave':$A([]),'beforeCreate':$A([]),'afterCreate':$A([])}},id:function(name,opts){var pk=name||'id',fld=new DM.Schema.Integer(pk,{primaryKey:true});this.fields.push(fld);this.columns[pk]=fld;return this;},text:function(name,opts){var fld=new DM.Schema.Text(name,opts);this.fields.push(fld)
 this.columns[name]=fld;return this;},blob:function(name,opts){var fld=new DM.Schema.Blob(name,opts);this.fields.push(fld)
 this.columns[name]=fld;return this;},timestamp:function(name,opts){var field=new DM.Schema.Timestamp(name,opts)
-this.fields.push(field);this.dateFields.push(field);this.columns[name]=field;return this;},integer:function(name,opts){var fld=new DM.Schema.Integer(name,opts);this.fields.push(fld);this.columns[name]=fld;return this;},'float':function(name,opts){var fld=new DM.Schema.Float(name,opts);this.fields.push(fld);this.columns[name]=fld;return this;},timestamps:function(onOrAt){onOrAt=onOrAt||'on';this.timestamp('created_'+onOrAt,{defaultValue:'NOW'});this.timestamp('updated_'+onOrAt,{defaultValue:'NOW'});return this;},foreignKey:function(name,opts){},hasMany:function(model,opts){},hasOne:function(model,opts){},belongsTo:function(model,opts){},hasAndBelongsToMany:function(model,opts){},beforeSave:function(handler){this.eventHandlers['beforeSave'].push(handler);},afterSave:function(handler){this.eventHandlers['afterSave'].push(handler);},beforeCreate:function(handler){this.eventHandlers['beforeCreate'].push(handler);},afterCreate:function(handler){this.eventHandlers['afterCreate'].push(handler);}})
-DM.SQL=(function(){function query(){return $A(arguments).join(' ');}
-function safeFields(model){return model.fields.filter(function(f){return(f.name!='id')})}
-return{createForModel:function(model){var sql=query('CREATE TABLE','IF NOT EXISTS',model.table_name,'(',model.fields.map(function(fld){return query(fld.name,fld.type)}).join(', '),');');return sql;},updateForModel:function(model){var values=[],sql=query('UPDATE',model.table_name,'SET',safeFields(model).map(function(fld){values.push(model.get(fld.name,true));return query(fld.name,'=','?')}).join(', '),'WHERE id = ?;');values.push(model.id);return[sql,values];},insertForModel:function(model){var values=[],sql=query('INSERT INTO',model.table_name,'(',safeFields(model).map(function(fld){values.push(model.get(fld.name,true));return fld.name;}).join(', '),') VALUES (',safeFields(model).map(function(fld){return'?';}).join(', '),&quot;);&quot;);return[sql,values];},deleteForModel:function(model){var sql=query(&quot;DELETE FROM&quot;,model.table_name,&quot;WHERE id = ?;&quot;);return[sql,[model.id]]}}})();
\ No newline at end of file
+this.fields.push(field);this.dateFields.push(field);this.columns[name]=field;return this;},integer:function(name,opts){var fld=new DM.Schema.Integer(name,opts);this.fields.push(fld);this.columns[name]=fld;return this;},'float':function(name,opts){var fld=new DM.Schema.Float(name,opts);this.fields.push(fld);this.columns[name]=fld;return this;},timestamps:function(onOrAt){onOrAt=onOrAt||'on';this.timestamp('created_'+onOrAt,{defaultValue:'NOW'});this.timestamp('updated_'+onOrAt,{defaultValue:'NOW'});return this;},hasMany:function(model,opts){this.relationships.push(new DM.Relationships.HasMany(model,opts,this));},belongsTo:function(model,opts){this.integer(model.table_name.singularize()+'_id',{allowNull:false});this.relationships.push(new DM.Relationships.BelongsTo(model,opts,this));},beforeSave:function(handler){this.eventHandlers['beforeSave'].push(handler);},afterSave:function(handler){this.eventHandlers['afterSave'].push(handler);},beforeCreate:function(handler){this.eventHandlers['beforeCreate'].push(handler);},afterCreate:function(handler){this.eventHandlers['afterCreate'].push(handler);}})
+DM.Schema._tables=$H({});DM.Schema.defineTable=function(tableName,configurator){var dsl=new DM.Schema.DSL(tableName).id();configurator(dsl);DM.Schema._tables.set(tableName,dsl);return dsl;}
+DM.Schema.createAllTables=function(){if(DM.DB){DM.Schema._tables.keys().each(function(tableName){console.log(&quot;Creating table: &quot;+tableName)
+DM.DB.execute(DM.SQL.createForSchema(DM.Schema._tables.get(tableName),tableName),[],function(){console.log(&quot;Table created:&quot;,tableName);});});}else{console.log(&quot;DM.Schema.createAllTables: Error: No database is defined.&quot;);}}
\ No newline at end of file</diff>
      <filename>dist/dm.min.js</filename>
    </modified>
    <modified>
      <diff>@@ -1 +1 @@
-var DM={AUTHOR:&quot;M@ McCray &lt;darthapo@gmail.com&gt;&quot;,VERSION:&quot;0.1.2&quot;,};var Options={setOptions:function(C){var A=$H(this.options||{}),B=$H(C||{});this.options=A.merge(B).toObject()}};DM.AirConnection=Class.create({initialize:function(A){this.type=&quot;air&quot;;this.connInfo=A;this.connection=new air.SQLConnection();this._dbFile=air.File.applicationStorageDirectory.resolvePath(A.name);this.connection.openAsync(this._dbFile)},execute:function(E,D,F,A){var C=new air.SQLStatement(),B=0;C.sqlConnection=this.connection;C.text=E.replace(/(\?)/g,function(G){return&quot;:&quot;+B++});$H(D).each(function(G){C.parameters[&quot;:&quot;+G.key]=G.value});C.addEventListener(air.SQLEvent.RESULT,function(){F(C.getResult(),event)});C.addEventListener(air.SQLErrorEvent.ERROR,function(){});C.execute()}});(function(A){if(!A){return }if(window.air&amp;&amp;air.Introspector){window.console=air.Introspector.Console}else{window.console={log:function(B){A.trace(B)},info:function(B){console.log(&quot;INFO: &quot;+B)}}}})(window.runtime);DM.GearsConnection=Class.create({initialize:function(A){this.type=&quot;gears&quot;;this.connInfo=A;if(!DM.GearsConnection.gearFactory){(function(){if(typeof GearsFactory!=&quot;undefined&quot;){DM.GearsConnection.gearFactory=new GearsFactory()}else{try{DM.GearsConnection.gearFactory=new ActiveXObject(&quot;Gears.Factory&quot;);if(DM.GearsConnection.gearFactory.getBuildInfo().indexOf(&quot;ie_mobile&quot;)!=-1){DM.GearsConnection.gearFactory.privateSetGlobalObject(this)}}catch(B){if((typeof navigator.mimeTypes!=&quot;undefined&quot;)&amp;&amp;navigator.mimeTypes[&quot;application/x-googlegears&quot;]){DM.GearsConnection.gearFactory=document.createElement(&quot;object&quot;);DM.GearsConnection.gearFactory.style.display=&quot;none&quot;;DM.GearsConnection.gearFactory.width=0;DM.GearsConnection.gearFactory.height=0;DM.GearsConnection.gearFactory.type=&quot;application/x-googlegears&quot;;document.documentElement.appendChild(DM.GearsConnection.gearFactory)}}}if(!DM.GearsConnection.gearFactory){throw&quot;There was an error creating the GearsFactory!&quot;}})()}this.connection=DM.GearsConnection.gearFactory.create(&quot;beta.database&quot;);this.connection.open(A.name)},execute:function(H,B,F,J){var D=this.connection.execute(H,$A(B).flatten()),A=this.connection.lastInsertRowId,I=[];(I.constructor.prototype||I.prototype).item=function(K){return this[K]};if(D){var E=[];for(var C=0;C&lt;D.fieldCount();C++){E.push(D.fieldName(C))}while(D.isValidRow()){var G={};for(var C=0;C&lt;E.length;C++){G[E[C]]=D.field(C)}I.push(G);D.next()}D.close()}F({insertId:A,rowsAffected:0,rows:I})}});DM.Html5Connection=Class.create({initialize:function(A){this.connInfo=A;this.type=&quot;html5&quot;;this.connection=openDatabase(A.name,A.description,A.displayName||A.name,A.size)},execute:function(C,B,D,A){this.connection.transaction(function(E){E.executeSql(C,$A(B).flatten(),function(G,F){D(F)},function(F){})})}});DM.ConnectionFactory={connectionPool:$H(),getConnection:function(B){if(this.connectionPool.get(B.name)){return this.connectionPool.get(B.name)}var A=false;if(typeof openDatabase!=&quot;undefined&quot;){A=new DM.Html5Connection(B)}else{if(typeof GearsFactory!=&quot;undefined&quot;){A=new DM.GearsConnection(B)}else{if(window.runtime&amp;&amp;typeof window.runtime.flash.data.SQLConnection!=&quot;undefined&quot;){A=new DM.AirConnection(B)}}}if(A){this.connectionPool.set(B.name,A);return A}else{this.connectionPool.set(B.name,null);throw&quot;Unable to find a supported database!&quot;}}};DM.Database=Class.create(Options,{options:{name:&quot;&quot;,description:&quot;&quot;,displayName:false,size:10240,preferGears:false},initialize:function(A){this.setOptions(A);this.conn=DM.ConnectionFactory.getConnection(this.options);DM.Model.DB=this},execute:function(C,B,D,A){if(!C){throw&quot;You must provide SQL to execute&quot;}var D=D||function(){},B=B||[],A=A||{};this.conn.execute(C,B,function(E){D(E)},A)}});DM.Dataset=Class.create({initialize:function(A){this.tableName=A;this.conditions=[];this.values=[];this.ordering=[]},filter:function(D,A,E,F){if(arguments.length==2){E=A;var C=D.split(&quot; &quot;);if(C.length&lt;2){throw&quot;Invalid filter syntax&quot;}A=C.pop();D=C.join(&quot; &quot;)}else{if(arguments.length==1){var B=$A(arguments[0]);D=B[0];A=B[1];E=B[2]}}F=F||&quot;AND&quot;;this.conditions.push({col:D,com:A,val:&quot;?&quot;,cnd:F});this.values.push(E);return this},where:function(B,A,C){return this.filter(B,A,C)},and:function(B,A,C){return this.filter(B,A,C,&quot;AND&quot;)},or:function(B,A,C){return this.filter(B,A,C,&quot;OR&quot;)},order:function(A,B){B=B||&quot;ASC&quot;;this.ordering.push(A+&quot; &quot;+B);return this},each:function(B){var A=this;DM.Model.DB.execute(this.toSql(),this.values,function(D){for(var C=0;C&lt;D.rows.length;C++){var E=D.rows.item(C);B(E,C,D)}});return this},all:function(B){if(B){var A=this;DM.Model.DB.execute(this.toSql(),this.values,function(D){var E=[];for(var C=0;C&lt;D.rows.length;C++){E.push(D.rows.item(C))}B(E)})}else{this.conditions=[];this.values=[];this.ordering=[]}return this},count:function(A){return this},add:function(A,B){return this},update:function(A,B){return this},destroy:function(A,B){return this},clone:function(){var A=new DM.Dataset(this.tableName);A.conditions=$A(this.conditions).clone();A.values=$A(this.values).clone();A.ordering=$A(this.ordering).clone();return A},toSql:function(A){var A=A||&quot;SELECT&quot;,B=A+&quot; * FROM &quot;+this.tableName;if(this.conditions.length&gt;0){B+=&quot; WHERE &quot;;$A(this.conditions).each(function(D,C){if(C&gt;0){B+=D.cnd+&quot; &quot;}B+=&quot;(&quot;+D.col+&quot; &quot;+D.com+&quot; &quot;+D.val+&quot;) &quot;})}if(this.ordering.length&gt;0){B+=&quot; ORDER BY &quot;+this.ordering.join(&quot;, &quot;)}B+=&quot;;&quot;;return B},toString:function(){return this.toSql()}});Object.extend(String.prototype,{eq:function(A){return[this,&quot;=&quot;,A]},like:function(A){return[this,&quot;like&quot;,A]},neq:function(A){return[this,&quot;!=&quot;,A]},lt:function(A){return[this,&quot;&lt;&quot;,A]},gt:function(A){return[this,&quot;&gt;&quot;,A]},lteq:function(A){return[this,&quot;&lt;=&quot;,A]},gteq:function(A){return[this,&quot;&gt;=&quot;,A]},});DM.ModelInstance=Class.create({initialize:function(B,A){this.table_name=A.table_name;this.fields=A.fields;this.columns=A.columns;this.klass=A;this.isDirty=false;this.attributes=$H(B||{});this.id=this.attributes.get(&quot;id&quot;)||null},get:function(B,A){if(B in this.columns){if(this.columns[B].type==&quot;timestamp&quot;){return(A)?this.attributes.get(B):new Date(this.attributes.get(B))}else{return this.attributes.get(B)}}else{throw (&quot;'&quot;+B+&quot;' is not a valid column for table &quot;+this.table_name)}},set:function(A,B){if(A in this.columns){if(this.columns[A].type==&quot;timestamp&quot;){switch(typeof (B)){case&quot;string&quot;:B=Date.parse(B);break;case&quot;number&quot;:B=B;break;default:B=B.getTime()}}if(B!=this.attributes.get(A)){this.isDirty=true;this.attributes.set(A,B)}}else{throw (&quot;'&quot;+A+&quot;' is not a valid column for table &quot;+this.table_name)}return this},update:function(B,C){var A=this;$H(B).each(function(E){if(E.value!=A.get(E.key)){try{A.set(E.key,E.value);A.isDirty=true}catch(D){if(!C){throw D}}}})},save:function(E){var C=this,E=E||function(){};if(&quot;updated_on&quot; in this.columns){this.set(&quot;updated_on&quot;,new Date())}if(&quot;updated_at&quot; in this.columns){this.set(&quot;updated_at&quot;,new Date())}if(typeof (C.id)==&quot;number&quot;){C.klass._handleEvent(&quot;beforeSave&quot;,this);var A=DM.SQL.updateForModel(this);DM.Model.DB.execute(A[0],A[1],function(F){C.klass._handleEvent(&quot;afterSave&quot;,C);E(C)})}else{if(&quot;created_on&quot; in this.columns){this.set(&quot;created_on&quot;,new Date())}if(&quot;created_at&quot; in this.columns){this.set(&quot;created_at&quot;,new Date())}C.klass._handleEvent(&quot;beforeCreate&quot;,C);C.klass._handleEvent(&quot;beforeSave&quot;,C);var A=DM.SQL.insertForModel(this),D=A.first(),B=A.last();DM.Model.DB.execute(D,B,function(F){C.id=F.insertId;C.attributes.set(&quot;id&quot;,C.id);C.klass._handleEvent(&quot;afterSave&quot;,C);C.klass._handleEvent(&quot;afterCreate&quot;,C);E(C)})}},reload:function(A){if(typeof (this.id)==&quot;number&quot;){}},destroy:function(C){if(typeof (this.id)==&quot;number&quot;){var B=this,A=DM.SQL.deleteForModel(this),C=C||function(){};DM.Model.DB.execute(A[0],A[1],function(D){B.id=null;B.set(&quot;id&quot;,null);C(B)})}},toString:function(){return&quot;[#Model:&quot;+this.table_name+' id=&quot;'+this.id+'&quot;]'}});DM.Model=(function(){return Class.create({initialize:function(A,C){if(!C){throw&quot;Model definitions missing!&quot;}this.table_name=A;if(C.schema){var B=new DM.Schema.DSL(this).id();C.schema(B);this.fields=B.fields;this.columns=B.columns;this.eventHandlers=B.eventHandlers;delete C.schema}else{this.fields=[];this.columns=[];this.eventHandlers={}}DM.Model.knownModels.set(A,this)},find:function(C,B){var A=this;DM.Model.DB.execute(&quot;select * from &quot;+this.table_name+&quot; where id = &quot;+C+&quot;;&quot;,[],function(E){if(E.rows.length&gt;0){var D=new DM.ModelInstance(E.rows.item(0),A);B(D)}else{throw (&quot;find( &quot;+C+&quot; ) returned 0 results.&quot;)}})},all:function(B){var A=this;DM.Model.DB.execute(&quot;select * from &quot;+this.table_name+&quot;;&quot;,[],function(D){var F=[];for(var C=0;C&lt;D.rows.length;C++){var E=D.rows.item(C);F.push(new DM.ModelInstance(E,A))}B(F)})},count:function(C){var A=this,B=0;DM.Model.DB.execute(&quot;select count(id) as cnt from &quot;+this.table_name+&quot;;&quot;,[],function(D){B=D.rows.item(0)[&quot;cnt&quot;];C(B)})},destroyAll:function(B){var A=this,B=B||function(){};A.all(function(E){var C=E.length,D=1;E.each(function(F){F.destroy(function(){D++;if(D==C){B(E)}})})})},create:function(A){return new DM.ModelInstance((A||{}),this)},_handleEvent:function(A,B){if(A in this.eventHandlers){this.eventHandlers[A].each(function(C){C(B)})}}})})();DM.Model.knownModels=$H();DM.Model.createModels=function(){if(DM.Model.DB){DM.Model.knownModels.each(function(C){var A=C.value,B=C.key;DM.Model.DB.execute(DM.SQL.createForModel(A),[],function(){A.tableCreated=true})})}else{console.log(&quot;DM.Model.createModels: Error: No database is defined.&quot;)}};DM.Schema={};DM.Schema.Text=Class.create({initialize:function(A,B){B=B||{};this.name=A;this.type=&quot;text&quot;;this.defaultValue=B.defaultValue;this.allowNull=B.allowNull;if(B.notNull){this.allowNull=!B.notNull}}});DM.Schema.Integer=Class.create({initialize:function(A,B){B=B||{};this.name=A;this.type=&quot;integer&quot;;this.defaultValue=(B.primaryKey)?undefined:B.defaultValue;this.allowNull=B.allowNull;if(B.notNull){this.allowNull=!B.notNull}if(B.primaryKey){this.type=&quot; INTEGER PRIMARY KEY AUTOINCREMENT&quot;}}});DM.Schema.Float=Class.create({initialize:function(A,B){B=B||{};this.name=A;this.type=&quot;real&quot;;this.defaultValue=B.defaultValue;this.allowNull=B.allowNull;if(B.notNull){this.allowNull=!B.notNull}}});DM.Schema.Blob=Class.create({initialize:function(A,B){B=B||{};this.name=A;this.type=&quot;blob&quot;;this.defaultValue=B.defaultValue;this.allowNull=B.allowNull;if(B.notNull){this.allowNull=!B.notNull}}});DM.Schema.Timestamp=Class.create({initialize:function(A,B){B=B||{};this.name=A;this.type=&quot;timestamp&quot;;this.defaultValue=B.defaultValue;this.allowNull=B.allowNull;if(B.notNull){this.allowNull=!B.notNull}}});DM.Schema.DSL=Class.create({initialize:function(A){this.model=A;this.fields=[];this.dateFields=[];this.columns={};this.eventHandlers={beforeSave:$A([]),afterSave:$A([]),beforeCreate:$A([]),afterCreate:$A([])}},id:function(A,D){var C=A||&quot;id&quot;,B=new DM.Schema.Integer(C,{primaryKey:true});this.fields.push(B);this.columns[C]=B;return this},text:function(A,C){var B=new DM.Schema.Text(A,C);this.fields.push(B);this.columns[A]=B;return this},blob:function(A,C){var B=new DM.Schema.Blob(A,C);this.fields.push(B);this.columns[A]=B;return this},timestamp:function(A,B){var C=new DM.Schema.Timestamp(A,B);this.fields.push(C);this.dateFields.push(C);this.columns[A]=C;return this},integer:function(A,C){var B=new DM.Schema.Integer(A,C);this.fields.push(B);this.columns[A]=B;return this},&quot;float&quot;:function(A,C){var B=new DM.Schema.Float(A,C);this.fields.push(B);this.columns[A]=B;return this},timestamps:function(A){A=A||&quot;on&quot;;this.timestamp(&quot;created_&quot;+A,{defaultValue:&quot;NOW&quot;});this.timestamp(&quot;updated_&quot;+A,{defaultValue:&quot;NOW&quot;});return this},foreignKey:function(A,B){},hasMany:function(A,B){},hasOne:function(A,B){},belongsTo:function(A,B){},hasAndBelongsToMany:function(A,B){},beforeSave:function(A){this.eventHandlers.beforeSave.push(A)},afterSave:function(A){this.eventHandlers.afterSave.push(A)},beforeCreate:function(A){this.eventHandlers.beforeCreate.push(A)},afterCreate:function(A){this.eventHandlers.afterCreate.push(A)}});DM.SQL=(function(){function A(){return $A(arguments).join(&quot; &quot;)}function B(C){return C.fields.filter(function(D){return(D.name!=&quot;id&quot;)})}return{createForModel:function(C){var D=A(&quot;CREATE TABLE&quot;,&quot;IF NOT EXISTS&quot;,C.table_name,&quot;(&quot;,C.fields.map(function(E){return A(E.name,E.type)}).join(&quot;, &quot;),&quot;);&quot;);return D},updateForModel:function(D){var C=[],E=A(&quot;UPDATE&quot;,D.table_name,&quot;SET&quot;,B(D).map(function(F){C.push(D.get(F.name,true));return A(F.name,&quot;=&quot;,&quot;?&quot;)}).join(&quot;, &quot;),&quot;WHERE id = ?;&quot;);C.push(D.id);return[E,C]},insertForModel:function(D){var C=[],E=A(&quot;INSERT INTO&quot;,D.table_name,&quot;(&quot;,B(D).map(function(F){C.push(D.get(F.name,true));return F.name}).join(&quot;, &quot;),&quot;) VALUES (&quot;,B(D).map(function(F){return&quot;?&quot;}).join(&quot;, &quot;),&quot;);&quot;);return[E,C]},deleteForModel:function(C){var D=A(&quot;DELETE FROM&quot;,C.table_name,&quot;WHERE id = ?;&quot;);return[D,[C.id]]}}})();
\ No newline at end of file
+var DM={AUTHOR:&quot;M@ McCray &lt;darthapo@gmail.com&gt;&quot;,VERSION:&quot;0.1.2&quot;,};var Inflector={Inflections:{plural:[[/(quiz)$/i,&quot;$1zes&quot;],[/^(ox)$/i,&quot;$1en&quot;],[/([m|l])ouse$/i,&quot;$1ice&quot;],[/(matr|vert|ind)ix|ex$/i,&quot;$1ices&quot;],[/(x|ch|ss|sh)$/i,&quot;$1es&quot;],[/([^aeiouy]|qu)y$/i,&quot;$1ies&quot;],[/(hive)$/i,&quot;$1s&quot;],[/(?:([^f])fe|([lr])f)$/i,&quot;$1$2ves&quot;],[/sis$/i,&quot;ses&quot;],[/([ti])um$/i,&quot;$1a&quot;],[/(buffal|tomat)o$/i,&quot;$1oes&quot;],[/(bu)s$/i,&quot;$1ses&quot;],[/(alias|status)$/i,&quot;$1es&quot;],[/(octop|vir)us$/i,&quot;$1i&quot;],[/(ax|test)is$/i,&quot;$1es&quot;],[/s$/i,&quot;s&quot;],[/$/,&quot;s&quot;]],singular:[[/(quiz)zes$/i,&quot;$1&quot;],[/(matr)ices$/i,&quot;$1ix&quot;],[/(vert|ind)ices$/i,&quot;$1ex&quot;],[/^(ox)en/i,&quot;$1&quot;],[/(alias|status)es$/i,&quot;$1&quot;],[/(octop|vir)i$/i,&quot;$1us&quot;],[/(cris|ax|test)es$/i,&quot;$1is&quot;],[/(shoe)s$/i,&quot;$1&quot;],[/(o)es$/i,&quot;$1&quot;],[/(bus)es$/i,&quot;$1&quot;],[/([m|l])ice$/i,&quot;$1ouse&quot;],[/(x|ch|ss|sh)es$/i,&quot;$1&quot;],[/(m)ovies$/i,&quot;$1ovie&quot;],[/(s)eries$/i,&quot;$1eries&quot;],[/([^aeiouy]|qu)ies$/i,&quot;$1y&quot;],[/([lr])ves$/i,&quot;$1f&quot;],[/(tive)s$/i,&quot;$1&quot;],[/(hive)s$/i,&quot;$1&quot;],[/([^f])ves$/i,&quot;$1fe&quot;],[/(^analy)ses$/i,&quot;$1sis&quot;],[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i,&quot;$1$2sis&quot;],[/([ti])a$/i,&quot;$1um&quot;],[/(n)ews$/i,&quot;$1ews&quot;],[/s$/i,&quot;&quot;]],irregular:[[&quot;move&quot;,&quot;moves&quot;],[&quot;sex&quot;,&quot;sexes&quot;],[&quot;child&quot;,&quot;children&quot;],[&quot;man&quot;,&quot;men&quot;],[&quot;person&quot;,&quot;people&quot;]],uncountable:[&quot;sheep&quot;,&quot;fish&quot;,&quot;series&quot;,&quot;species&quot;,&quot;money&quot;,&quot;rice&quot;,&quot;information&quot;,&quot;equipment&quot;]},ordinalize:function(A){if(11&lt;=parseInt(A)%100&amp;&amp;parseInt(A)%100&lt;=13){return A+&quot;th&quot;}else{switch(parseInt(A)%10){case 1:return A+&quot;st&quot;;case 2:return A+&quot;nd&quot;;case 3:return A+&quot;rd&quot;;default:return A+&quot;th&quot;}}},pluralize:function(F){for(var C=0;C&lt;Inflector.Inflections.uncountable.length;C++){var B=Inflector.Inflections.uncountable[C];if(F.toLowerCase==B){return B}}for(var C=0;C&lt;Inflector.Inflections.irregular.length;C++){var D=Inflector.Inflections.irregular[C][0];var A=Inflector.Inflections.irregular[C][1];if((F.toLowerCase==D)||(F==A)){return A}}for(var C=0;C&lt;Inflector.Inflections.plural.length;C++){var E=Inflector.Inflections.plural[C][0];var G=Inflector.Inflections.plural[C][1];if(E.test(F)){return F.replace(E,G)}}},singularize:function(F){for(var C=0;C&lt;Inflector.Inflections.uncountable.length;C++){var B=Inflector.Inflections.uncountable[C];if(F.toLowerCase==B){return B}}for(var C=0;C&lt;Inflector.Inflections.irregular.length;C++){var D=Inflector.Inflections.irregular[C][0];var A=Inflector.Inflections.irregular[C][1];if((F.toLowerCase==D)||(F==A)){return A}}for(var C=0;C&lt;Inflector.Inflections.singular.length;C++){var E=Inflector.Inflections.singular[C][0];var G=Inflector.Inflections.singular[C][1];if(E.test(F)){return F.replace(E,G)}}}};function ordinalize(A){return Inflector.ordinalize(A)}Object.extend(String.prototype,{pluralize:function(B,A){if(typeof B==&quot;undefined&quot;){return Inflector.pluralize(this)}else{return B+&quot; &quot;+(1==parseInt(B)?this:A||Inflector.pluralize(this))}},singularize:function(A){if(typeof A==&quot;undefined&quot;){return Inflector.singularize(this)}else{return A+&quot; &quot;+Inflector.singularize(this)}}});DM.DB={execute:function(){throw&quot;No DB connection has been made!!!&quot;}};DM.Options={setOptions:function(C){var A=$H(this.options||{}),B=$H(C||{});this.options=A.merge(B).toObject()}};DM.Database=Class.create(DM.Options,{options:{name:&quot;&quot;,description:&quot;&quot;,displayName:false,size:10240,preferGears:false},initialize:function(A){this.setOptions(A);this.conn=DM.ConnectionFactory.getConnection(this.options);DM.DB=this},execute:function(C,B,D,A){if(!C){throw&quot;You must provide SQL to execute&quot;}var D=D||function(){},B=B||[],A=A||{};this.conn.execute(C,B,function(E){D(E)},A)}});DM.AirConnection=Class.create({initialize:function(A){this.type=&quot;air&quot;;this.connInfo=A;this.connection=new air.SQLConnection();this._dbFile=air.File.applicationStorageDirectory.resolvePath(A.name);this.connection.openAsync(this._dbFile)},execute:function(E,D,F,A){var C=new air.SQLStatement(),B=0;C.sqlConnection=this.connection;C.text=E.replace(/(\?)/g,function(G){return&quot;:&quot;+B++});$H(D).each(function(G){C.parameters[&quot;:&quot;+G.key]=G.value});C.addEventListener(air.SQLEvent.RESULT,function(){F(C.getResult(),event)});C.addEventListener(air.SQLErrorEvent.ERROR,function(){});C.execute()}});(function(A){if(!A){return }if(window.air&amp;&amp;air.Introspector){window.console=air.Introspector.Console}else{window.console={log:function(B){A.trace(B)},info:function(B){console.log(&quot;INFO: &quot;+B)}}}})(window.runtime);DM.GearsConnection=Class.create({initialize:function(A){this.type=&quot;gears&quot;;this.connInfo=A;if(!DM.GearsConnection.gearFactory){(function(){if(typeof GearsFactory!=&quot;undefined&quot;){DM.GearsConnection.gearFactory=new GearsFactory()}else{try{DM.GearsConnection.gearFactory=new ActiveXObject(&quot;Gears.Factory&quot;);if(DM.GearsConnection.gearFactory.getBuildInfo().indexOf(&quot;ie_mobile&quot;)!=-1){DM.GearsConnection.gearFactory.privateSetGlobalObject(this)}}catch(B){if((typeof navigator.mimeTypes!=&quot;undefined&quot;)&amp;&amp;navigator.mimeTypes[&quot;application/x-googlegears&quot;]){DM.GearsConnection.gearFactory=document.createElement(&quot;object&quot;);DM.GearsConnection.gearFactory.style.display=&quot;none&quot;;DM.GearsConnection.gearFactory.width=0;DM.GearsConnection.gearFactory.height=0;DM.GearsConnection.gearFactory.type=&quot;application/x-googlegears&quot;;document.documentElement.appendChild(DM.GearsConnection.gearFactory)}}}if(!DM.GearsConnection.gearFactory){throw&quot;There was an error creating the GearsFactory!&quot;}})()}this.connection=DM.GearsConnection.gearFactory.create(&quot;beta.database&quot;);this.connection.open(A.name)},execute:function(H,B,F,J){var D=this.connection.execute(H,$A(B).flatten()),A=this.connection.lastInsertRowId,I=[];(I.constructor.prototype||I.prototype).item=function(K){return this[K]};if(D){var E=[];for(var C=0;C&lt;D.fieldCount();C++){E.push(D.fieldName(C))}while(D.isValidRow()){var G={};for(var C=0;C&lt;E.length;C++){G[E[C]]=D.field(C)}I.push(G);D.next()}D.close()}F({insertId:A,rowsAffected:0,rows:I})}});DM.Html5Connection=Class.create({initialize:function(A){this.connInfo=A;this.type=&quot;html5&quot;;this.connection=openDatabase(A.name,A.description,A.displayName||A.name,A.size)},execute:function(C,B,D,A){this.connection.transaction(function(E){E.executeSql(C,$A(B).flatten(),function(G,F){D(F)},function(F){})})}});DM.ConnectionFactory={connectionPool:$H(),getConnection:function(B){if(this.connectionPool.get(B.name)){return this.connectionPool.get(B.name)}var A=false;if(typeof openDatabase!=&quot;undefined&quot;){A=new DM.Html5Connection(B)}else{if(typeof GearsFactory!=&quot;undefined&quot;){A=new DM.GearsConnection(B)}else{if(window.runtime&amp;&amp;typeof window.runtime.flash.data.SQLConnection!=&quot;undefined&quot;){A=new DM.AirConnection(B)}}}if(A){this.connectionPool.set(B.name,A);return A}else{this.connectionPool.set(B.name,null);throw&quot;Unable to find a supported database!&quot;}}};DM.DeferredCallback=Class.create({initialize:function(B,C,A){this.target=B;this.current=0;this.callback=C;this.args=A},ping:function(){this.current++;if(this.current==this.target){this.callback.apply(null,this.args)}else{console.log(&quot;Not yet...&quot;)}}});DM.Dataset=Class.create({initialize:function(A,B){this.tableName=A;this.conditions=[];this.values=[];this.ordering=[];this.options=$H({asModel:false}).update(B||{})},filter:function(D,A,E,F){if(arguments.length==2){E=A;var C=D.split(&quot; &quot;);if(C.length&lt;2){throw&quot;Invalid filter syntax&quot;}A=C.pop();D=C.join(&quot; &quot;)}else{if(arguments.length==1){var B=$A(arguments[0]);D=B[0];A=B[1];E=B[2]}}F=F||&quot;AND&quot;;this.conditions.push({col:D,com:A,val:&quot;?&quot;,cnd:F});this.values.push(E);return this},where:function(B,A,C){return this.filter(B,A,C)},and:function(B,A,C){return this.filter(B,A,C,&quot;AND&quot;)},or:function(B,A,C){return this.filter(B,A,C,&quot;OR&quot;)},order:function(A,B){B=B||&quot;ASC&quot;;this.ordering.push(A+&quot; &quot;+B);return this},each:function(B){var A=this;DM.DB.execute(this.toSql(),this.values,function(D){for(var C=0;C&lt;D.rows.length;C++){var E=A.options.asModel?new DM.ModelInstance(D.rows.item(C),A.options.modelKlass):D.rows.item(C);B(E,C,D)}});return this},all:function(B){if(B){var A=this;DM.DB.execute(this.toSql(),this.values,function(D){var E=[];if(A.options.asModel){for(var C=0;C&lt;D.rows.length;C++){E.push(new DM.ModelInstance(D.rows.item(C),A.options.modelKlass))}}else{for(var C=0;C&lt;D.rows.length;C++){E.push(D.rows.item(C))}}B(E)})}else{this.conditions=[];this.values=[];this.ordering=[]}return this},results:function(A){this.all(A)},add:function(E,G){var C=this,D=G||function(){};if(Object.isArray(E)){console.log(&quot;!!! Data is ARRAY!!!&quot;);var F=[],B=new DM.DeferredCallback(E.length,G,[F]);$A(E).each(function(I){var H=DM.SQL.insertForObject(I,C.tableName);DM.DB.execute(H[0],H[1],function(J){I.id=J.insertId;F.push(I);B.ping()})})}else{var A=DM.SQL.insertForObject(E,this.tableName);DM.DB.execute(A[0],A[1],function(H){E.id=H.insertId;D(E,H)})}return this},update:function(D,E){var B=this,A=DM.SQL.updateForObject(D,this.tableName),C=E||function(){};DM.DB.execute(A[0],A[1],function(F){C(D,F)});return this},destroy:function(C,D){var B=this,A=DM.SQL.deleteForModel(C,this.tableName);DM.DB.execute(A[0],A[1],function(E){D(C,E)});return this},destroyAll:function(B){var A=this;this.each(function(C){this.destroy(C,B)});return this},clone:function(){var A=new DM.Dataset(this.tableName);A.conditions=$A(this.conditions).clone();A.values=$A(this.values).clone();A.ordering=$A(this.ordering).clone();return A},toSql:function(A){var A=A||&quot;SELECT&quot;,B=A+&quot; * FROM &quot;+this.tableName;if(this.conditions.length&gt;0){B+=&quot; WHERE &quot;;$A(this.conditions).each(function(D,C){if(C&gt;0){B+=D.cnd+&quot; &quot;}B+=&quot;(&quot;+D.col+&quot; &quot;+D.com+&quot; &quot;+D.val+&quot;) &quot;})}if(this.ordering.length&gt;0){B+=&quot; ORDER BY &quot;+this.ordering.join(&quot;, &quot;)}B+=&quot;;&quot;;return B},toString:function(){return this.toSql()}});Object.extend(String.prototype,{eq:function(A){return[this,&quot;=&quot;,A]},like:function(A){return[this,&quot;like&quot;,A]},neq:function(A){return[this,&quot;!=&quot;,A]},lt:function(A){return[this,&quot;&lt;&quot;,A]},gt:function(A){return[this,&quot;&gt;&quot;,A]},lteq:function(A){return[this,&quot;&lt;=&quot;,A]},gteq:function(A){return[this,&quot;&gt;=&quot;,A]},});DM.SQL=(function(){function B(){return $A(arguments).join(&quot; &quot;)}function C(D){return D.fields.filter(function(E){return(E.name!=&quot;id&quot;)})}function A(D){if(D instanceof Date){return D.getTime()}else{return D}}return{createForModel:function(D){var E=B(&quot;CREATE TABLE&quot;,&quot;IF NOT EXISTS&quot;,D.table_name,&quot;(&quot;,D.fields.map(function(F){return B(F.name,F.type)}).join(&quot;, &quot;),&quot;);&quot;);return E},createForSchema:function(E,D){E.table_name=D;return this.createForModel(E)},updateForModel:function(E){var D=[],F=B(&quot;UPDATE&quot;,E.table_name,&quot;SET&quot;,C(E).map(function(G){D.push(E.get(G.name,true));return B(G.name,&quot;=&quot;,&quot;?&quot;)}).join(&quot;, &quot;),&quot;WHERE id = ?;&quot;);D.push(E.id);return[F,D]},insertForModel:function(E){var D=[],F=B(&quot;INSERT INTO&quot;,E.table_name,&quot;(&quot;,C(E).map(function(G){D.push(E.get(G.name,true));return G.name}).join(&quot;, &quot;),&quot;) VALUES (&quot;,C(E).map(function(G){return&quot;?&quot;}).join(&quot;, &quot;),&quot;);&quot;);return[F,D]},deleteForModel:function(D){var E=B(&quot;DELETE FROM&quot;,D.table_name,&quot;WHERE id = ?;&quot;);return[E,[D.id]]},updateForObject:function(F,D){if(!F.id){throw&quot;Object must have an ID to be updated...&quot;}var E=[],G=$H(F),H=B(&quot;UPDATE&quot;,D,&quot;SET&quot;,G.keys().without(&quot;id&quot;).map(function(I){E.push(A(G.get(I)));return B(I,&quot;=&quot;,&quot;?&quot;)}).join(&quot;, &quot;),&quot;WHERE id = ?;&quot;);E.push(G.get(&quot;id&quot;));return[H,E]},insertForObject:function(F,D){var E=[],G=$H(F),H=B(&quot;INSERT INTO&quot;,D,&quot;(&quot;,G.keys().without(&quot;id&quot;).map(function(I){E.push(A(G.get(I)));return I}).join(&quot;, &quot;),&quot;) VALUES (&quot;,G.keys().without(&quot;id&quot;).map(function(I){return&quot;?&quot;}).join(&quot;, &quot;),&quot;);&quot;);return[H,E]},deleteForModel:function(E,D){var F=(typeof E==&quot;number&quot;)?E:E.id;sql=B(&quot;DELETE FROM&quot;,D,&quot;WHERE id = ?;&quot;);return[sql,[F]]}}})();DM.ModelInstance=Class.create({initialize:function(B,A){this.table_name=A.table_name;this.fields=A.fields;this.columns=A.columns;this.relationships=A.relationships;this.klass=A;this.isDirty=false;this.attributes=$H(B||{});this.id=this.attributes.get(&quot;id&quot;)||null;this.relationships.each(function(C){C.addMethodsToInstance(this)}.bind(this))},get:function(B,A){if(B in this.columns){if(this.columns[B].type==&quot;timestamp&quot;){return(A)?this.attributes.get(B):new Date(this.attributes.get(B))}else{return this.attributes.get(B)}}else{throw (&quot;'&quot;+B+&quot;' is not a valid column for table &quot;+this.table_name)}},set:function(A,B){if(A in this.columns){if(this.columns[A].type==&quot;timestamp&quot;){switch(typeof (B)){case&quot;string&quot;:B=Date.parse(B);break;case&quot;number&quot;:B=B;break;default:B=B.getTime()}}if(B!=this.attributes.get(A)){this.isDirty=true;this.attributes.set(A,B)}}else{throw (&quot;'&quot;+A+&quot;' is not a valid column for table &quot;+this.table_name)}return this},update:function(B,C){var A=this;$H(B).each(function(E){if(E.value!=A.get(E.key)){try{A.set(E.key,E.value);A.isDirty=true}catch(D){if(!C){throw D}}}})},save:function(E){var C=this,E=E||function(){};if(&quot;updated_on&quot; in this.columns){this.set(&quot;updated_on&quot;,new Date())}if(&quot;updated_at&quot; in this.columns){this.set(&quot;updated_at&quot;,new Date())}if(typeof (C.id)==&quot;number&quot;){C.klass._handleEvent(&quot;beforeSave&quot;,this);var A=DM.SQL.updateForModel(this);DM.DB.execute(A[0],A[1],function(F){C.klass._handleEvent(&quot;afterSave&quot;,C);E(C)})}else{if(&quot;created_on&quot; in this.columns){this.set(&quot;created_on&quot;,new Date())}if(&quot;created_at&quot; in this.columns){this.set(&quot;created_at&quot;,new Date())}C.klass._handleEvent(&quot;beforeCreate&quot;,C);C.klass._handleEvent(&quot;beforeSave&quot;,C);var A=DM.SQL.insertForModel(this),D=A.first(),B=A.last();DM.DB.execute(D,B,function(F){C.id=F.insertId;C.attributes.set(&quot;id&quot;,C.id);C.klass._handleEvent(&quot;afterSave&quot;,C);C.klass._handleEvent(&quot;afterCreate&quot;,C);E(C)})}},reload:function(A){if(typeof (this.id)==&quot;number&quot;){}},destroy:function(C){if(typeof (this.id)==&quot;number&quot;){var B=this,A=DM.SQL.deleteForModel(this),C=C||function(){};DM.DB.execute(A[0],A[1],function(D){B.id=null;B.set(&quot;id&quot;,null);C(B)})}},toString:function(){return&quot;[#Model:&quot;+this.table_name+' id=&quot;'+this.id+'&quot;]'}});DM.Model=(function(){return Class.create({initialize:function(A,B){if(!B){throw&quot;Model definitions missing!&quot;}this.table_name=A;this.model_def=B;DM.Model.knownModels.set(A,this)},initSchema:function(){if(this.model_def.schema){var A=new DM.Schema.DSL(this).id();this.model_def.schema(A);this.fields=A.fields;this.columns=A.columns;this.eventHandlers=A.eventHandlers;this.relationships=A.relationships;delete this.model_def.schema}else{this.fields=[];this.columns=[];this.eventHandlers={};this.relationships=[]}},find:function(C,B){var A=this;DM.DB.execute(&quot;select * from &quot;+this.table_name+&quot; where id = &quot;+C+&quot;;&quot;,[],function(E){if(E.rows.length&gt;0){var D=new DM.ModelInstance(E.rows.item(0),A);B(D)}else{throw (&quot;find( &quot;+C+&quot; ) returned 0 results.&quot;)}})},findWhere:function(C,D){var B=new DM.Dataset(this.table_name),A=this;B.filter(C);DM.DB.execute(B.toSql(),B.values,function(F){var H=[];for(var E=0;E&lt;F.rows.length;E++){var G=F.rows.item(E);H.push(new DM.ModelInstance(G,A))}D(H)})},filter:function(B){var A=new DM.Dataset(this.table_name,{asModel:true,modelKlass:this});return A.filter(B)},all:function(B){var A=this;DM.DB.execute(&quot;select * from &quot;+this.table_name+&quot;;&quot;,[],function(D){var F=[];for(var C=0;C&lt;D.rows.length;C++){var E=D.rows.item(C);F.push(new DM.ModelInstance(E,A))}B(F)})},count:function(C){var A=this,B=0;DM.DB.execute(&quot;select count(id) as cnt from &quot;+this.table_name+&quot;;&quot;,[],function(D){B=D.rows.item(0)[&quot;cnt&quot;];C(B)})},destroyAll:function(B){var A=this,B=B||function(){};A.all(function(E){var C=E.length,D=1;E.each(function(F){F.destroy(function(){D++;if(D==C){B(E)}})})})},create:function(A){return new DM.ModelInstance((A||{}),this)},_handleEvent:function(A,B){if(A in this.eventHandlers){this.eventHandlers[A].each(function(C){C(B)})}}})})();DM.Model.knownModels=$H();DM.Model.createModels=function(){if(DM.DB){DM.Model.knownModels.each(function(C){var A=C.value,B=C.key;A.initSchema();DM.DB.execute(DM.SQL.createForModel(A),[],function(){A.tableCreated=true})})}else{console.log(&quot;DM.Model.createModels: Error: No database is defined.&quot;)}};DM.Relationships={};DM.Relationships.HasMany=Class.create({initialize:function(C,A,B){this.modelKlass=C;this.options=$H(A||{});this.schema=B},addMethodsToInstance:function(B){if(!this.modelKlass){return }var A=this,C=B.klass.table_name.singularize()+&quot;_id&quot;;B[this.modelKlass.table_name]={add:function(D,E){},all:function(D){A.modelKlass.findWhere(C.eq(B.id),D)},create:function(E,D){E=$H(E);E.set(C,B.id);return A.modelKlass.create(E.toObject())},each:function(D){},get:function(E,D){},find:function(D,E){},remove:function(D,E){},destroy:function(D,E){}}},instanceMethods:{}});DM.Relationships.BelongsTo=Class.create({initialize:function(C,A,B){this.modelKlass=C;this.options=$H(A||{});this.schema=B},addMethodsToInstance:function(A){A[this.modelKlass.table_name]=function(B){return&quot;WOOT!&quot;}},instanceMethods:{}});DM.Schema={};DM.Schema.Text=Class.create({initialize:function(A,B){B=B||{};this.name=A;this.type=&quot;text&quot;;this.defaultValue=B.defaultValue;this.allowNull=B.allowNull;if(B.notNull){this.allowNull=!B.notNull}}});DM.Schema.Integer=Class.create({initialize:function(A,B){B=B||{};this.name=A;this.type=&quot;integer&quot;;this.defaultValue=(B.primaryKey)?undefined:B.defaultValue;this.allowNull=B.allowNull;if(B.notNull){this.allowNull=!B.notNull}if(B.primaryKey){this.type=&quot; INTEGER PRIMARY KEY AUTOINCREMENT&quot;}}});DM.Schema.Float=Class.create({initialize:function(A,B){B=B||{};this.name=A;this.type=&quot;real&quot;;this.defaultValue=B.defaultValue;this.allowNull=B.allowNull;if(B.notNull){this.allowNull=!B.notNull}}});DM.Schema.Blob=Class.create({initialize:function(A,B){B=B||{};this.name=A;this.type=&quot;blob&quot;;this.defaultValue=B.defaultValue;this.allowNull=B.allowNull;if(B.notNull){this.allowNull=!B.notNull}}});DM.Schema.Timestamp=Class.create({initialize:function(A,B){B=B||{};this.name=A;this.type=&quot;timestamp&quot;;this.defaultValue=B.defaultValue;this.allowNull=B.allowNull;if(B.notNull){this.allowNull=!B.notNull}}});DM.Schema.DSL=Class.create({initialize:function(A){this.model=A;this.fields=[];this.dateFields=[];this.columns={};this.relationships=[];this.eventHandlers={beforeSave:$A([]),afterSave:$A([]),beforeCreate:$A([]),afterCreate:$A([])}},id:function(A,D){var C=A||&quot;id&quot;,B=new DM.Schema.Integer(C,{primaryKey:true});this.fields.push(B);this.columns[C]=B;return this},text:function(A,C){var B=new DM.Schema.Text(A,C);this.fields.push(B);this.columns[A]=B;return this},blob:function(A,C){var B=new DM.Schema.Blob(A,C);this.fields.push(B);this.columns[A]=B;return this},timestamp:function(A,B){var C=new DM.Schema.Timestamp(A,B);this.fields.push(C);this.dateFields.push(C);this.columns[A]=C;return this},integer:function(A,C){var B=new DM.Schema.Integer(A,C);this.fields.push(B);this.columns[A]=B;return this},&quot;float&quot;:function(A,C){var B=new DM.Schema.Float(A,C);this.fields.push(B);this.columns[A]=B;return this},timestamps:function(A){A=A||&quot;on&quot;;this.timestamp(&quot;created_&quot;+A,{defaultValue:&quot;NOW&quot;});this.timestamp(&quot;updated_&quot;+A,{defaultValue:&quot;NOW&quot;});return this},hasMany:function(A,B){this.relationships.push(new DM.Relationships.HasMany(A,B,this))},belongsTo:function(A,B){this.integer(A.table_name.singularize()+&quot;_id&quot;,{allowNull:false});this.relationships.push(new DM.Relationships.BelongsTo(A,B,this))},beforeSave:function(A){this.eventHandlers.beforeSave.push(A)},afterSave:function(A){this.eventHandlers.afterSave.push(A)},beforeCreate:function(A){this.eventHandlers.beforeCreate.push(A)},afterCreate:function(A){this.eventHandlers.afterCreate.push(A)}});DM.Schema._tables=$H({});DM.Schema.defineTable=function(B,A){var C=new DM.Schema.DSL(B).id();A(C);DM.Schema._tables.set(B,C);return C};DM.Schema.createAllTables=function(){if(DM.DB){DM.Schema._tables.keys().each(function(A){console.log(&quot;Creating table: &quot;+A);DM.DB.execute(DM.SQL.createForSchema(DM.Schema._tables.get(A),A),[],function(){console.log(&quot;Table created:&quot;,A)})})}else{console.log(&quot;DM.Schema.createAllTables: Error: No database is defined.&quot;)}};
\ No newline at end of file</diff>
      <filename>dist/dm.ymin.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,158 +1,35 @@
-// dataset.js
-DM.Dataset = Class.create({
+/* Copyright (c) 2008-2009 M@ McCray.
 
-  initialize: function(tableName) {
-    this.tableName = tableName;
-    this.conditions = [];
-    this.values = [];
-    this.ordering = [];
-  },
-  
-  filter: function(col, comparator, value, cnd) {
-    if( arguments.length == 2 ) {
-      value = comparator;
-      var colSegs = col.split(' ');
-      if(colSegs.length &lt; 2){ throw &quot;Invalid filter syntax&quot;; }
-      comparator = colSegs.pop();
-      col = colSegs.join(' '); // Would there ever be spaces?
-    } else if( arguments.length == 1) {
-      var args = $A(arguments[0]);
-      col = args[0];
-      comparator = args[1];
-      value = args[2];
-    }
-    cnd = cnd || 'AND';
-    this.conditions.push({
-      col: col,
-      com: comparator,
-      val: '?',
-      cnd: cnd
-    });
-    this.values.push(value);
-    return this;
-  },
+  REQUIRES Prototype 1.6+
 
-  // FIXME: Make where(), and(), or() all work as expected... What is expected with OR???
-  where: function(col, comparator, value) { return this.filter(col, comparator, value); },
-  and:   function(col, comparator, value) { return this.filter(col, comparator, value, 'AND'); },
-  or:    function(col, comparator, value) { return this.filter(col, comparator, value, 'OR'); },
-  
-  order: function(column, direction) {
-    direction = direction || 'ASC';
-    this.ordering.push(column +&quot; &quot;+ direction)
-    return this;
-  },
-  
-  each: function(callback) {
-    // Execute current SQL and for each result, exec the callback
-    var self = this;
-    DM.Model.DB.execute(this.toSql(), this.values, function(results){
-      for (var i=0; i &lt; results.rows.length; i++) {
-        var row = results.rows.item(i);
-        callback( row, i, results );
-      };
-    });
-    return this;
-  },
-  
-  all: function(callback) {
-    if(callback) {
-      // Execute current SQL and pass results directly to callback
-      var self = this;
-      DM.Model.DB.execute(this.toSql(), this.values, function(results){
-        var rows = [];
-        for (var i=0; i &lt; results.rows.length; i++) {
-          rows.push( results.rows.item(i)  );
-        };
-        callback( rows ); // As an array...
-      });
-    } else {
-      this.conditions = [];
-      this.values = [];
-      this.ordering = [];
-    }
-    return this;
-  },
-  
-  //FIXME: Dataset #count, #add, #update, #destroy
-  
-  count: function(callback) {
-    // Execute current SQL and pass count to callback
-    // callback( countOfCurrentRows )
-    return this;
-  },
-  
-  add: function(data, callback) {
-    return this;
-  },
-  
-  update: function(data, callback) {
-    return this;
-  },
-  
-  destroy: function(data, callback) {
-    return this;
-  },
-  
-  clone: function() {
-    var ds = new DM.Dataset(this.tableName);
-    // Calling slice() will create a cloned array...
-    ds.conditions = $A(this.conditions).clone();
-    ds.values = $A(this.values).clone();
-    ds.ordering = $A(this.ordering).clone();
-    return ds;
-  },
-  
-  toSql: function(cmd) {
-    var cmd = cmd || 'SELECT',
-        sql = cmd +&quot; * FROM &quot;+ this.tableName;
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+&quot;Software&quot;), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
 
-    // Where clauses...
-    if(this.conditions.length &gt; 0) {
-      sql += &quot; WHERE &quot;;
-      $A(this.conditions).each(function(clause, count){
-        if(count &gt; 0) { 
-          sql += clause.cnd +&quot; &quot;;
-        }
-        sql += &quot;(&quot;+ clause.col +&quot; &quot;+ clause.com +&quot; &quot;+ clause.val +&quot;) &quot;;
-      });
-    }
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
 
-    // Conditions...
-    if(this.ordering.length &gt; 0) {
-      sql += &quot; ORDER BY &quot;+ this.ordering.join(', ');
-    }
-    
-    sql += &quot;;&quot;;
+THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
 
-    return sql;
-  },
+var DM = {
+  
+  AUTHOR: &quot;&lt;%= AUTHOR %&gt;&quot;,
+  VERSION: &quot;&lt;%= VERSION %&gt;&quot;,
   
-  toString: function() {
-    return this.toSql();
-  }
-});
+}
 
-Object.extend(String.prototype, {
-  eq:function(value) {
-    return [this, '=', value];
-  },
-  like:function(value) {
-    return [this, 'like', value];
-  },
-  neq:function(value) {
-    return [this, '!=', value];
-  },
-  lt:function(value) {
-    return [this, '&lt;', value];
-  },
-  gt:function(value) {
-    return [this, '&gt;', value];
-  },
-  lteq:function(value) {
-    return [this, '&lt;=', value];
-  },
-  gteq:function(value) {
-    return [this, '&gt;=', value];
-  },
-});
\ No newline at end of file
+//= require &quot;dm/database&quot;
+//= require &quot;dm/dataset&quot;
+//= require &quot;dm/sql&quot;
+//= require &quot;dm/schema&quot;</diff>
      <filename>source/dataset.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
 &lt;html&gt;
   &lt;script src=&quot;../etc/prototype.js&quot;&gt;&lt;/script&gt;
-  &lt;script src=&quot;../dist/dm.js&quot;&gt;&lt;/script&gt;
+  &lt;script src=&quot;../dist/dataset.js&quot;&gt;&lt;/script&gt;
   &lt;script&gt;
   
   
@@ -15,8 +15,8 @@
     &quot;API&quot;: function() {
       assertDefined( typeof DM,           &quot;DM is missing&quot; );
       assertDefined( typeof DM.Database,  &quot;DM.Database is missing&quot; );
-      assertDefined( typeof DM.Schema,    &quot;DM.Schema is missing&quot; );
-      assertDefined( typeof DM.Model,     &quot;DM.Model is missing&quot; );
+      assertDefined( typeof DM.SQL,       &quot;DM.SQL is missing&quot; );
+//      assertDefined( typeof DM.Schema,    &quot;DM.Schema is missing&quot; );
     },
 
     note2: &quot;Connection...&quot;,
@@ -81,10 +81,57 @@
       ds2.order('age');
       assertEqual(&quot;SELECT * FROM items WHERE (user_id = ?)  ORDER BY age ASC;&quot;, ds2.toSql() );
       
-      var scripts = new DM.Dataset('scripts');
+      var scripts = new DM.Dataset('comments');
       scripts.each(function(row){
-//        console.log(row.title)
+        console.log(row.id +&quot;:&quot;+ row.post_id +&quot;: &quot;+row.title)
+        // console.log(typeof row);
+        // console.log(row)
+      });
+      scripts.clone().filter( 'post_id'.eq('undefined') ).each(function(row){
+        console.log(row.id +&quot;:&quot;+ row.post_id +&quot;: &quot;+row.title)
+      });
+      
+      var comments = new DM.Dataset('comments');
+      comments.add({
+        title: &quot;I'm added from DataSet code..&quot;,
+        source: &quot;Isn't that nice?&quot;,
+        created_on: new Date()
+      }, function(){
+        console.log('Comments Add Callback!')
+        
+        
       })
+    },
+    
+    'DM.Schema.defineTable': function() {
+      
+      DM.Schema.defineTable('junk', function(t){
+        t.text('body');
+      });
+      
+      DM.Schema.createAllTables();
+    },
+    
+    'Add to new table...': function() {
+      var junk = new DM.Dataset('junk');
+      junk.add({
+          body: &quot;Isn't that nice?&quot;
+        }, function(){
+          console.log('Junk Add Callback!')
+      });
+    },
+
+    'Adding an array of values to new table...': function() {
+      var junk = new DM.Dataset('junk'),
+          newData = [
+            { body:&quot;Item One&quot; },
+            { body:&quot;Item Two&quot; },
+            { body:&quot;Item Three&quot; },
+          ];
+
+      junk.add(newData, function(){
+          console.log('&gt;&gt;&gt; Junk[] Add Callback!')
+      });
     }
   };
   &lt;/script&gt;</diff>
      <filename>test/builder-tests.html</filename>
    </modified>
    <modified>
      <diff>@@ -94,5 +94,46 @@ var Tests = {
       });
     })
     
+  },
+  
+  &quot;Model Relationships&quot;: function() {
+    connectToDb()
+
+    window.Post = new DM.Model('posts', {
+       schema: function(t){ 
+         t.text('title');
+         t.text('source');
+         t.timestamps('on'); // Creates created_on &amp;&amp; updated_on
+         t.hasMany(Comment, { cascadeDelete:true });
+       },
+     });
+     window.Comment = new DM.Model('comments', {
+        schema: function(t){ 
+          t.belongsTo(Post);
+          t.text('title');
+          t.text('source');
+          t.timestamps('on'); // Creates created_on &amp;&amp; updated_on
+        },
+      });
+     
+     DM.Model.createModels(); // Need to ensure DB exists, eh?
+    
+    
+    var p = Post.create({
+      title:'A good title is priceless',
+      source: &quot;Content here, really.&quot;,
+      html: &quot;&lt;p&gt;Content here, really.&lt;/p&gt;&quot;
+    })
+    
+    p.save(function(model){
+      console.log(model)
+      assertNotNull(model.comments, &quot;Model.comments is not null&quot;)
+
+      var c = p.comments.create({title:'I am a comment', source:'And I love it here!'});
+      assertNotNull(c, &quot;New comment is not null&quot;);
+      c.save();
+    });
+    
   }
+  
 };
\ No newline at end of file</diff>
      <filename>test/tests.js</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>source/application.js</filename>
    </removed>
    <removed>
      <filename>source/connection.js</filename>
    </removed>
    <removed>
      <filename>source/connections/air.js</filename>
    </removed>
    <removed>
      <filename>source/connections/gears.js</filename>
    </removed>
    <removed>
      <filename>source/connections/html5.js</filename>
    </removed>
    <removed>
      <filename>source/database.js</filename>
    </removed>
    <removed>
      <filename>source/model/class_methods.js</filename>
    </removed>
    <removed>
      <filename>source/model/instance_methods.js</filename>
    </removed>
    <removed>
      <filename>source/model/schema.js</filename>
    </removed>
    <removed>
      <filename>source/model/schema_dsl.js</filename>
    </removed>
    <removed>
      <filename>source/model/sql.js</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>4524b6d6058e93f0c3259c73141f804fb6d41256</id>
    </parent>
  </parents>
  <author>
    <name>M@ McCray</name>
    <email>darthapo@gmail.com</email>
  </author>
  <url>http://github.com/darthapo/dm.js/commit/224978cb617ed1cfb384679c8aa12d468b398fca</url>
  <id>224978cb617ed1cfb384679c8aa12d468b398fca</id>
  <committed-date>2009-02-27T17:00:08-08:00</committed-date>
  <authored-date>2009-02-27T17:00:08-08:00</authored-date>
  <message>Restructured source, added new dist target: dataset.js</message>
  <tree>30e8f91dced17fc81e1122375e94f062a00d0fac</tree>
  <committer>
    <name>M@ McCray</name>
    <email>darthapo@gmail.com</email>
  </committer>
</commit>
