Skip to content

Instantly share code, notes, and snippets.

@gbishop
Created August 13, 2010 14:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gbishop/522994 to your computer and use it in GitHub Desktop.
Save gbishop/522994 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Try Json Refs</title>
<style type="text/css">
@import "http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/resources/dojo.css";
@import "http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css";
@import "http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojox/grid/resources/Grid.css";
@import "http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojox/grid/resources/claroGrid.css";
@import "style.css";
@import "SetEditor.css";
html, body, #content {
width: 100%;
height: 100%;
overflow: hidden;
}
#editorGoesHere {
width: 400px;
height: 200px;
border: 1px solid black;
}
</style>
<script type="text/javascript">
var djConfig = {
isDebug: false,
parseOnLoad: true,
baseUrl: './',
// map local widget namespaces -> paths relative to baseUrl
modulePaths: {'editor' : '.'}
};
</script>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js"></script>
<script type="text/javascript" src="/libs/uow.js"></script>
<script type="text/javascript" src="tryJsonRefs.js"></script>
<script type="text/javascript">
dojo.require('dijit.layout.BorderContainer');
dojo.require('dijit.layout.ContentPane');
</script>
</head>
<body class="claro">
<div id="content" dojoType="dijit.layout.BorderContainer">
<div id="top" dojoType="dijit.layout.ContentPane" region="top" splitter="false">
<span>Set Editor</span>
<span class='nav_up'><img src='images/nav_up.png'/ ><a href='../index.html'>Back to Bigwords Index</a></span>
<span class='nav_back'><img src='images/nav_back.png'/ ><a href='index.html'>Back to Editor Index</a></span>
</div>
<div id="center" dojoType="dijit.layout.ContentPane" region="center">
<div id="editorGoesHere"></div>
</div>
</div>
</body>
</html>
/*
This is an experiment with Json Referencing in our uow databases which are derived from JsonRestStore.
When I run setup, it creates a database with a single record containing refs to the first record
in each game database. This is a prototype for sets in Big Words.
When I run restore, it reads the record and instantiates the refs.
From this experiment I have determined that the restoration happens when you call loadItem and
that the db's being referenced have to be open. But contrary to the examples I've seen, you don't
have to do the loadItem call on the store the ref points at; rather it is fine (thankfully) to do the
loadItem on the store containing the ref.
Further contradiction of the examples I have seen shows that for an object like:
item = { set: 'set1', game: { $ref: '/data/AlphabetSoupLessons/4c24c449229fe83f6e000062' } }
doing db.getValue(item, 'game') does NOT dereference game. It simply returns the ref.
But db.getValue(item.game, 'name') will dereference and return the name field of the game.
*/
dojo.require('dojox.grid.DataGrid');
// first a few helpers
/* let's try monkey patching MongoStore to use deferreds.
These are candidates for inclusion in MongoStore.
*/
dojo.ready(function() {
var M = uow.data.MongoStore;
// deferred version of fetch
M.prototype.Fetch = function(args) {
var def = new dojo.Deferred();
dojo.mixin(args, {
onComplete: def.callback,
onError: def.errback
});
this.fetch(args);
return def;
};
// deferred version of Save
M.prototype.Save = function() {
var def = new dojo.Deferred();
this.save({
onComplete: def.callback,
onError: def.errback
});
return def;
};
});
/* try deleting all the records in a db the async way
Note that I don't appear to need an explicit Deferred in here. Just returning the result of
the "then" method appears to be enough.
*/
function emptyDb(db) {
return db.Fetch( {query: {} } ).then(function(items) {
dojo.forEach(items, function(item) {
db.deleteItem(item);
});
});
}
/* open a store for each collection given, return the array of stores
It appears that I do need an explicit Deferred in here. I don't see how to otherwise deal
with the multiple deferred calls ending at different times. Is there some cool extension of
dojo.map to do this? Or some way to use dojo.when?
*/
function openCollections(collections) {
var def = new dojo.Deferred();
var toGo = collections.length;
var res = [];
dojo.forEach(collections, function(collection, index) {
uow.getDatabase({
database: 'BigWords',
collection: collection,
mode: 'r'
}).then(function(db) {
res[index] = db;
toGo -= 1;
if (toGo <= 0) {
def.callback(res);
}
});
});
return def;
}
/* create a reference to first item in the given stores
How should I handle empty stores? res is going to have undef for those
*/
function readFirst(stores) {
var def = new dojo.Deferred();
var toGo = stores.length;
var res = [];
dojo.forEach(stores, function(store, index) {
store.Fetch({
query: {},
count: 1
}).then(function(items) {
res[index] = store.target + items[0]._id;
toGo -= 1;
if (toGo <= 0) {
def.callback(res);
}
});
});
return def;
}
// game collections
allGames = ['TextTilesLessons', 'AlphabetSoupLessons', 'SortActivityLessons',
'SpellBinderLessons', 'WordBuilderLessons', 'SliceAndDiceLessons'];
/* the following functions are edited into the dojo.ready call at the bottom to choose which
one runs. You need to run setup first to build the store with the references.
*/
// create an array of references in a database
function setup() {
var db1;
// step 1: get the 1st db
uow.getDatabase({database: 'BigWords', collection: 'gbTry'}).then(function(db) {
db1 = db;
// step 2: empty the 1st db
return emptyDb(db1);
}).then(function() {
// step 3: open the lesson dbs
return openCollections(allGames);
}).then(function(stores) {
// step 4: create a ref to the first item in each db
return readFirst(stores);
}).then(function(items) {
// step 5: save the references in db1
dojo.forEach(items, function(item, i) {
db1.newItem({ set: 'set1', seq: i, game: { $ref: item } });
});
// step 6: save the new records
return db1.Save();
}).then(function() {
console.log('setup all done');
});
}
// read the array of references and look at them
function restore() {
var db1;
// step 1: get the 1st db
uow.getDatabase({database: 'BigWords', collection: 'gbTry'}).then(function(db) {
db1 = db;
// setp 2: open the other stores (necessary for dereferencing to work)
return openCollections(allGames);
}).then(function(stores) {
// step 3: fetch the records
return db1.Fetch({ query: { set: 'set1' } });
}).then(function(items) {
// step 4: load the individual array items
dojo.forEach(items, function(i) {
db1.loadItem( {
item: i.game,
onItem: function(item) {
console.log('loaded item', item);
}
});
});
});
};
/* experiment with getValue
Contrary to what the doc says in several places, db1.getValue(item, 'game') does NOT do the
dereference. I have to do db1.getvalue(item.game, 'name') to get the deference done. In other words
access a field in the deferred object. I can't see how the examples given in various blog posts
could possibly work given the code in getValue in dojox.data.ServiceStore.js.
*/
function tryget() {
var db1;
// step 1: get the 1st db
uow.getDatabase({database: 'BigWords', collection: 'gbTry'}).then(function(db) {
db1 = db;
// setp 2: get the other stores
return openCollections(allGames);
}).then(function(stores) {
// step 3: fetch the records
return db1.Fetch({ query: { set: 'set1' } });
}).then(function(items) {
console.log('rawrecord', items);
// get the first one
var item = items[0];
console.log('game', item.game); // shows up as a $ref
console.log('loaded', db1.isItemLoaded(item.game)); // not loaded
console.log('wrong', db1.getValue(item, 'game'));
console.log('value', db1.getValue(item.game, 'name')); // does the deref
console.log('after deref', db1.getValue(item, 'game'));
});
}
/* read the array of references and look at them with a grid
I need that formatter on game in order to force the lazy loading. The other possibility
is the dot-path extension to JsonRestStore.getValue proposed by medryx in his BeanStore. With
it we could just set field to 'game.name'
*/
function display() {
var db1;
// step 1: get the 1st db
uow.getDatabase({database: 'BigWords', collection: 'gbTry'}).then(function(db) {
db1 = db;
// setp 2: get the other stores
return openCollections(allGames);
}).then(function(stores) {
// step 3: build the grid
var grid = new dojox.grid.DataGrid( {
store: db1,
structure: [ { name: 'Set', field: 'set', width: '20%' },
{ name: 'Seq', field: 'seq', width: '20%' },
{ name: 'Name', field: 'game', width: '60%',
formatter: function(game) { return db1.getValue(game, 'name'); } } ],
query: { set: 'set1' }
} );
dojo.place(grid.domNode, 'editorGoesHere', 'only');
grid.startup();
dojo.connect(grid, 'onDblClick', function() {
var selected = grid.selection.getSelected()[0];
console.log('selected', selected);
} );
});
};
dojo.ready(display);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment