Future Plans

We get a fair number of visits, I think. For a rarely-maintained, grassrootsy, non-commercial site. Not a lot. We had under 400 visits the last month, according to Google Analytics, though most visits last over 2 minutes, and at least half our visitors are repeat visitors.

I have to assume folks are making use of JazzRecord in some way, and that they’re visiting to refer to the documentation. I don’t see any other explanation. I’d really like to get to know the users, and find out if we can do anything to improve JazzRecord short-tern and long-term.

Long-term, for instance, I’d like to move our documentation into the source code repo and simply reference/style that nicer on the Web site. I’d also like to provide better docs and add a few more features, like the ability to add indexes in a model’s declaration. I’m still considering the implications of async support eventually, though I certainly don’t have time to support this idea at the moment. We’d still like to translate the docs into other languages, but we need volunteers.

Short-term, I’d like to add some new adapters to the codebase. I’d like to support any new runtimes that may have cropped up lately. Node.js and similar are definitely on the list. Does anyone use Jaxer still? Is there an environment you’d like to see supported? So long as SQLite or a compatible dialect of SQL is supported, and so long as a *synchronous* API of some kind exists, JazzRecord can be added with very little effort.

Please, take a moment and comment, here or on Twitter. Let us know how you use JR and what you’d like to see in the future.

ID Optional in latest JazzRecord 0.7

As of version 0.07 build 1236659271 (please find on Github), the ID column is now optional once more when using automigrations or in declaring columns on models. In actuality, allcolumns are optional in model declarations, if manual migrations are used. This is somewhat similar to the Hobo project’s automatically-generated migrations, only in reverse. (model fields are determined by migrations rather than the other way round)

Please note, however, that manual migrations require the explicit inclusion of an ID column:

  var BoxContent = new JazzRecord.Model({
    table: "box_contents",
    belongsTo: {box: boxes}
  });

  JazzRecord.createTable("boxes", {
    id: "int",
    label: "text",
    volume: "float"
  });

  JazzRecord.createTable("box_contents", {
    id: "int",
    name: "text",
    size: "float"
  });

This example shows how a minimal amount of code in the models can set up a 1 to N relationship between a Box and several BoxContent objects. At any time schema operations (like createTable() or removeColumn()) are called, the model’s definition is updated in memory, so calling save() or similar will always be up to date.

New Features in JazzRecord 0.7: Migrations and isNew()

First off, thanks to Khou Suylong of Mango Team for once again providing me with a bug find which led to a fix!

We’ve been busy once more, putting together JazzRecord 0.7, which incorporates manual migrations with all of the major features from Rails’ ActiveRecord migrations. While there are no official updated docs yet, here’s a brief list of changes:

ID must now explicitly be listed as a column for a model. If using automigrations, you must list it in the model definition. The explicit requirement for ID column may change going forward, but once we hit Version 1 (another month, perhaps) we will stand firm on the API. If using manual migrations, you may now leave out columns from the model definition entirely and rely on migrations setting the model’s column knowledge for you.

What this means is, no matter what changes you make to a db schema using migrations, the model is always aware of the current state of the schema and will allow you to create, destroy, and modify properties of records with no problem. The only thing to watch out for is validations if you have any, because they can cause problems if there are requirements which cannot be satisfied given a specific updated schema.

The following schema operations are available as of now:

JazzRecord.createTable(tableName, cols) – this creates a table using a columns object, identical the the (now optional) columns object from a model declaration.

  • JazzRecord.dropTable(tableName) – removes a table from the DB.
  • JazzRecord.renameTable(tableName) – renames a table
  • JazzRecord.addColumn(tableName, colName, colType) – adds a column of given type to a table
  • JazzRecord.removeColumn(tableName, colName) – removes a column from a table
  • JazzRecord.renameColumn(tableName, oldName, newName) – renames a given column in a table
  • JazzRecord.changeColumn(tableName, colName, colType) – changes the type of a column. This can result in data loss, as determined by how the DB converts data types

The last three functions were the trickiest, because SQLite does not provide inherent capabilities for modifying columns once they exist in a table. In order to reproduce thesefeatures, then, we have to go about slurping up all data in a table, dropping the existing table, creating a new table with the new schema, and spitting the same data back into the database, with data types changed or columns removed or changed in type. To keep this (hopefully) relatively safe, we wrap the destructive DROP operation in a transaction.

Did anyone even know JazzRecord had a JazzRecord.runTransaction(func, bind) method? I’m not sure! Calling this and passing in a function full of operations will ensure that if something goes wrong and you or some function you call throws an exception, all will revert to its pre-transaction state. Pretty cool, huh?

Making use of the schema operations is as simple as calling them anywhere, though typically you’d organize them into migrationsMigrations are now a bit streamlined, as well.

To automigrate, simply call JazzRecord.migrate() with no options, or to refresh the DB to an empty state, pass in an object with refresh property set to true:JazzRecord.migrate({refresh: true}). To optionally load fixture data, assign a fixtures object (same as the old object format) to JazzRecord.fixtures, and if it exists it will be loaded. To run migrations, simply assign to JazzRecord.migrations an object literal with numerically-named properties (starting with the number 1) each containing an object literal which has an up function and a down function. These functions should be the reverse of one another, and for an explanation of proper migration usage consult any Rails tutorial or wait for the documentation. Here’s a simple sample migration which creates a couple tables and adds a column to one of them over a few schema versions:

  JazzRecord.migrations = {
    1: {
      up: function() {
        JazzRecord.createTable("military_dudes", {
          id: "number",
          name: "text",
          title: "text",
          base_id: "number"
        });

        JazzRecord.createTable("bases", {
          id: "number",
          location_name: "text"
        });
      },
      down: function() {
        JazzRecord.dropTable("bases");
        JazzRecord.dropTable("military_dudes");
      }
    },

    2: {
      up: function() {
        JazzRecord.renameColumn("military_dudes", "title", "rank");
        JazzRecord.addColumn("bases", "state", "text");
      },
      down: function() {
        JazzRecord.removeColumn("bases", "state");
        JazzRecord.renameColumn("military_dudes", "rank", "title");
      }
    }
  };

After setting up a migrations object like this, you can call JazzRecord.migrate() standalone (to migrate to the latest version), or you can pass in a version number to reach the specified migration number. To reset to pre-migration status, call JazzRecord.migrate(0). In this way, you can evolve an application’s schema over time and can almost effortlessly jump between schema versions to diagnose problems or revert when you’ve introduced more problems than you’ve fixed! You can pretty much use migrations exactly as in Rails: changing schema and inserting/removing/updating data for existing, already-deployed applications. Soon we will add additional tools for updating multiple columns and multiple rows simultaneously, which will further add to the usefulness of migrations.

The smaller, but still useful, function introduced in JazzRecord 0.7 is Record’s isNew() function. This function, when called, will return true if a record has not been saved yet, or false if it has.

As a previous blog post stated, we are extremely interested in having our documentation translated into other languages, so please contact me at thynctank@thynctank.com if you can help with that.

Enjoy!

You Have the Pen (with which to Translate Documentation)!

Nick’s last post made me think of that fruity dance song from the early 90s (or some time around then).  This post is like a remix, except instead of empowering you I’m hoping to exploit your possible multilingualism for the sake of JazzRecord!  (And in keeping with blog titles that include exclamation points, I hereby christen yet another reckless blurt of the English language!!…)

JazzRecord is veritably an international JavaScript ORM.  It eats at the International House of Pancakes (Are there even any of these restaurants outside of the United States?) and it drives on the wrong side of the road.  It can’t help it.  It just loves multinationalism.  Actually, as of last week, Google Analytics reports that JazzRecord.org has enjoyed visitors from all seven continents!  That’s right!  Someone from Antarctica visited 3 pages and spent a whopping 14 minutes and 13 seconds on JazzRecord.org!  That’s one JavaScript ORMing penguin!!!  JazzRecord.org has hosted 72 countries‘ worth of visitors that speak 40 languages, and is particularly well read by Eurasia, and recently Brazil!  This is all very exciting news to the JazzRecord team. However, there is a problem with these demographics: I remember very little of my high school German and Spanish courses. Also, I don’t know a lick of Portuguese, Khmer, Russian, or whatever the hell it is they speak in England!  We’re hoping that this is where you come in.

The JazzRecord team is always excited to hear from developers that are using the library in other parts of the world, especially ones that speak other languages, but we’re afraid that the all-English documentation might be impeding their usage.  So, we’re calling out all fluently bilingual JazzRecord users to help us expand our documentation into other languages! If you fit this description and would like to help out, please send an email to Nick Carter (Project Leader) at thynctank at thynctank dot com or David Rivers (Web Designer/Webmaster) at david at ideogon dot com.  We can’t promise that helping us out will get you on Oprah, but we will certainly give credit where credit is due!

JazzRecord is open-source, free software, because a small group of developers devote their blood, sweat, tears, first-born, and third arms to the cause. Unlike the RIAA we believe in the power of transparency and collaboration. However, we do need you (Think like Uncle Sam is pointing you out minus all the negative connotations that the American military would conjure in the minds of our far-reaching user base)! After all, I can hit my Rosetta Stone even harder, but I don’t think my ability to describe an apple in each of the colors of the rainbow is going to get us anywhere!

JazzRecord: You Have The Power!

Since I recently held a conversation over IRC about some of how JazzRecord’s association loading and saving works, I thought I’d share it with the world as well.

The coolest two things about JazzRecord, and likewise Rails’ ActiveRecord:

* the fact they automatically load associated records as objects, based on models’ knowledge of interrelations with other models, and that associated records’ linkage is handled transparently to the user in such a way as to make total sense. The *databaseness* of working with things melts away to pure OO code.
* the fact the built in validations lend so much power and usefulness when it comes to business logic, without sacrificing readability of code.

In order to maintain the ease of use that ActiveRecord affords, I had to put JazzRecord together carefully. One thing I really wanted to maintain, which I’ve seen fall by the wayside in similar JavaScript ORMs, is the ability to simply assign new values to properties of a record object and have them be validated at save time, saved down as appropriate column/field data in the database, and even reload appropriate associated records from different tables. This requires that record objects have knowledge, or rather the ability to communicate with objects that *do* have knowledge (models), of interrelations between tables and knowledge of how to validate the properties.

Even knowledge of a record’s model and its associations is not enough to overcome the language barriers faced when porting a Ruby-language project to JavaScript: JavaScript function calls require the use of parenthesis, and because of this field name getters/setters cannot be treated as simple properties the way ActiveRecord field names are. To avoid having to unnecessarily clutter up API code with function calls for simple setting and getting of field data, JazzRecord introduces the idea that fields are simply properties of record objects – it just doesn’t care about any extraneous properties not defined within a record’s model declaration. At the time of save, and partially at the time a record is validated, a record’s data are examined in the context of those fields defined on the record’s model, and those associations defined in the same place. Any additional properties are simply ignored by JazzRecord. This stresses the importance of tying the record object to its basis, a model. Without the knowledge inherent in this connection, the record would have no way of loading associated data, and no means for validating field data. Without this connection, each record object would have to carry around its own set of validation rules and association-loading methods. And that would be slow.

An example may help to illustrate the ease of use/power combo better: Say we’re dealing with a *Home* model and a *Person* model. The relationship is 1 to N, where Person is the N end. Let’s say we also have a *Vehicle* model, which has a relationship of 1 to 1, with Vehicle belonging to Person. We’ve set up some nominal validation setup for ensuring a person’s age is an integer. Setup code will follow the usage examples.

Here’s a few things JazzRecord does or lets you do:

* Everyone knows finders: `var p = Person.findBy(”name”, “Nick”)`
* And getting and setting local column properties of the record is simple: `p.age //returns 28`, `p.age = “29yrs” //it’s my birthday!`
* Calling `isValid()` on a record object will return a boolean, as well as populating the error object with appropriate error information.
* Calling `p.save()` will also cause validation methods to run. Since this is an existing record, any *validatesAtUpdate* or *validatesAtSave* methods defined on the model will run.

Our record will fail to save because we’ve got errors: p.errors.age is an array of all errors relating to the *age* field, and it contains the helpful default string “age is not an integer”. This error message could easily be customized for use as actual presentational text to be used in an application to show users entering invalid data.

Correcting the age to a simple number and saving again will fix this and clear out the errors arrays: `p.age = 29; p.save()` This now succeeds, and indeed our p.errors object is re-initialized to an empty state.

Did you know JazzRecord will also reload all associated records? Didja even know it loaded them to begin with? Associations are easy to use. As soon as a finder returns a record, or as soon as a save finishes, your new record has not only the immediate field properties defined on its own model, but the associated data of any immediately-related records are loaded automatically. Here’s what this means:

* `p.vehicle` is an actual vehicle record. It has all the capabilities p has, such as retrieving/editing immediate fields and saving them back down. `p.vehicle.model` returns the string “Forenza”, and setting it `p.vehicle.model = “Corvette”` and saving `p.save()` will update the record accordingly. This is quite useful.
* if validations were defined for the vehicle record, they would be run prior to actually updating it.
* Records can be loaded more than 1 level deep by calling the `load(colname)` method of a record with unloaded subordinate records: `p.vehicle.load(”dealership”)`, perhaps, if a dealership association was defined and such data existed.

Upon loading the new data, all of the newly-loaded record’s immediate data is available for tinkering with, just as with the automatically-loaded association data.

Be careful! Loading associated records which are already present earlier in the scope chain may lead to unpredictable and undesirable results. Never do `p.vehicle.load(”owner”)`, for instance, as this will load a *second* instance of the same person record stored in *p*, and these two objects cannot be kept in sync. This is a language limitation and is unavoidable. **Do NOT load redundant records from earlier in the scope chain!**

The last piece of the powerful parts of JazzRecord puzzle (say that three times fast!) is auto-linking and unlinking of associations in the database based on logical user interaction in the API.

* A user can add or change a foreign-key reference manually: `vehic.person_id = 1`, or she can change it through the association property itself: `vehic.owner = Person.last()`. After calling `vehic.save()`, the association and the ID are both set correctly, no matter which was the triggering mechanism. Note that trying to assign both the key manually and the association can lead to confusion and is best avoided. If one has been set and you want to reset before setting the other, feel free to call the record’s *revert()* method. It will return to the state it was in after the last find or save operation.

* Likewise, deleting a foreign-key manually or deleting an association both work: `delete vehic.person_id` and `delete vehic.owner` work equally well. After calling `vehic.save()`, both association and foreign key will be deleted.

This is a useful concept. It allows the user to think in more abstract terms than setting keys all over the place. It works on all supported association types, even N to N. (it will delete and add records to mapping tables automatically) It *also* works from either side of an association. More on that in a second.

We’ve seen that deleting a record’s association when it “belongs to” another record is easy. But we can also link or unlink a record from the other side: `p.vehicle = Vehicle.find(3)` followed by a save will cause the original vehicle’s foreign key reference to disappear and the foreign key on the new vehicle (#3) to be set to the person’s ID. Again, powerful stuff. Deleting an association works the same: `h = Home.first(); delete h.people[0]; h.save()` causes the first Home record to be loaded, and removes the association of the first person object from the equation. The person object’s `home_id` will now be gone.

As for the models which were used in this article…

var Home = new JazzRecord.Model({
table: “homes”,
foreignKey: “home_id”,
hasMany: { people: “people”},
columns: {
address: “text”,
}
});

var Person = new JazzRecord.Model({
table: “people”,
foreignKey: “person_id”,
belongsTo: { home: “homes”},
hasOne: { vehicle: “vehicles”},
columns: {
name: “text”,
age: “number”,
home_id: “number”,
},

validate: {
atSave: function() {
this.validatesIsInt(”age”);
}
}
});

var Vehicle = new JazzRecord.Model({
table: “vehicles”,
foreignKey: “vehicle_id”,
belongsTo: { owner: “people”},
columns: {
make: “text”,
model: “text”,
person_id: “number”
}
});

More complex versions of these models are in the *example_models.js* file which comes in the zip file of source code for JazzRecord.

Working with the library functions almost identically to most general usage of Rails’ ActiveRecord, and this ease of use/identical behavior was a driving goal in its development. Because of its scope and methodology, actually sitting down to use JazzRecord may be the easiest way to learn it.

JazzRecord.org Redesigned! MSIE now exists again!!

After slacking on deploying some design improvements I made for jazzrecord.org, I finally pushed them today! JazzRecord visitors might notice the jump in version numbering from a 0.1b to 0.5. This should reflect the vast improvements to the library Nick has been making while I’ve been letting the site stagnate! (JazzRecord on Twitter has the skinny on all the juicy commits he’s been making.)

The design improvements are actually weeks old, but thanks to a certain popular browser developed by an unnamed Redmond-based software giant/Windows-peddler, the absolutely gorgeous redesign had to wait until I could procure a copy of said operating system in order to pander to the masses. This proved a more daunting task than common sense otherwise dictates, but I’ve finally been able to test and tweak and prod and poke the new design into MSIE compliance! The funny thing is that only 7.92% of our visitors use MSIE!! (And we suspect that 7% of the 7.92% are microwaves and garage openers spoofing their headers as IE!) However, I am on a job hunt right now, and I realize that the demographic of recruiters and potential employers is probably more inclined to use IE than our beloved Jazz users. I digress…

Note that curvy corner CSS progressively enhances the experience for users of modern browsers! It’s amazing how crappy the boxy corners look in comparison. (Sorry, garage openers!) However, I plan to soon implement image-based curviness, so 92.08% of you guys better bask in the privileged treatment while it lasts!

To whet your appetite for some more jazzrecord.org goodness–coming soon (I have no idea how soon): PDF documentation downloads!

JazzRecord Blog Finally Goes Live!

In tandem with design improvements I made to jazzrecord.org (which will be detailed in another post), we finally rolled out the JazzRecord.org Blog, a la WordPress! We considered doing this up in Mephisto, the self-proclaimed “best blogging system ever”, but it hasn’t been touched since April, 2008. (Perhaps it got perfect so they decided to not improve it any more? My loss, I suppose.) Therefor, I begrudgingly went along with a WordPress install. And then, we were going to wait until I skinned this bad boy to roll it out, but ya know what? I don’t think you guys have forever, and I’m a busy man. Furthermore, Google Analytics reports that visitors to jazzrecord.org are waning (although it appears that a core demographic of visitors keep on coming back!), so I decided about five minutes ago that we should just get on with it!

World, I introduce to you the Official JazzRecord Blog! Please: bookmark, absorb, subscribe to feeds, reply, read more, come back, tell your dog about us, graffiti-tag the URL onto the sides of buildings (don’t really do that), and then come back again as soon as you break out of the funny/big house!

I will continue to post info. on the status of jazzrecord.org and its documentations, etc. (and also my own contributions to the library, if I ever get time to add another 5 lines! Ha!), and my esteemed co-conspirator Nick Carter will post info. on the status of the library itself. Hopefully Jesse will contribute to the library again and post a thing or two! Or maybe he’ll post about his coffee obsession? I just noticed that Nick rolled out categories–Library, Site Changes, Uncategorized (sexy!), and Wide World of Jazz. So, I guess I’ll be posting about my love for jazz (music) too! Lucky you!! Seriously, please reply on any post that tickles your fancy or makes you scratch your head. The whole point of the blog is that we provide a discussion point with our JazzRecord ORM users! Like always, you can get ahold of us via the jazzrecord.org About page.

Without further ado, I will publish this, the first, blog for Blog.Jazzrecord.Org!!! (I promise sexy skinning soon…sorry.)