foam-framework
Version:
MVC metaprogramming framework
331 lines (302 loc) • 11.1 kB
JavaScript
/**
* @license
* Copyright 2014 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
CLASS({
package: 'foam.dao',
name: 'EasyDAO',
extends: 'foam.dao.ProxyDAO',
requires: [
'MDAO',
'foam.core.dao.CloningDAO',
'foam.core.dao.MergeDAO',
'foam.core.dao.MigrationDAO',
'foam.core.dao.StorageDAO',
'foam.core.dao.SyncDAO',
'foam.core.dao.SyncTrait',
'foam.core.dao.sync.PollingSyncDAO',
'foam.core.dao.sync.SocketSyncDAO',
'foam.core.dao.VersionNoDAO',
'foam.dao.CachingDAO',
'foam.dao.ContextualizingDAO',
'foam.dao.DeDupDAO',
'foam.dao.EasyClientDAO',
'foam.dao.GUIDDAO',
'foam.dao.IDBDAO',
'foam.dao.SeqNoDAO',
'foam.dao.LoggingDAO',
'foam.dao.TimingDAO'
],
imports: [ 'document' ],
help: 'A facade for easy DAO setup.',
documentation: function() {/*
<p>If you don't know which $$DOC{ref:'DAO'} implementation to choose, $$DOC{ref:'foam.dao.EasyDAO'} is
ready to help. Simply <code>this.X.EasyDAO.create()</code> and set the flags
to indicate what behavior you're looking for. Under the hood, $$DOC{ref:'foam.dao.EasyDAO'}
will create one or more $$DOC{ref:'DAO'} instances to service your requirements.
</p>
<p>Since $$DOC{ref:'foam.dao.EasyDAO'} is a proxy, just use it like you would any other
$$DOC{ref:'DAO'}, without worrying about the internal $$DOC{ref:'DAO'} doing the
work.
</p>
*/},
properties: [
{
name: 'name',
defaultValueFn: function() { return this.model.id; },
documentation: "The developer-friendly name for this $$DOC{ref:'.'}."
},
{
model_: 'BooleanProperty',
name: 'seqNo',
defaultValue: false,
documentation: "Have $$DOC{ref:'.'} use a sequence number to index items. Note that $$DOC{ref:'.seqNo'} and $$DOC{ref:'.guid'} features are mutually exclusive."
},
{
model_: 'BooleanProperty',
name: 'guid',
label: 'GUID',
defaultValue: false,
documentation: "Have $$DOC{ref:'.'} generate guids to index items. Note that $$DOC{ref:'.seqNo'} and $$DOC{ref:'.guid'} features are mutually exclusive."
},
{
name: 'seqProperty',
type: 'Property',
documentation: "The property on your items to use to store the sequence number or guid. This is required for $$DOC{ref:'.seqNo'} or $$DOC{ref:'.guid'} mode."
},
{
model_: 'BooleanProperty',
name: 'cache',
defaultValue: false,
documentation: "Enable local caching of the $$DOC{ref:'DAO'}."
},
{
model_: 'BooleanProperty',
name: 'dedup',
defaultValue: false,
documentation: "Enable value de-duplication to save memory when caching."
},
{
model_: 'BooleanProperty',
name: 'logging',
defaultValue: false,
documentation: "Enable logging on the $$DOC{ref:'DAO'}."
},
{
model_: 'BooleanProperty',
name: 'timing',
defaultValue: false,
documentation: "Enable time tracking for concurrent $$DOC{ref:'DAO'} operations."
},
{
model_: 'BooleanProperty',
name: 'contextualize',
defaultValue: false,
documentation: "Contextualize objects on .find"
},
{
model_: 'BooleanProperty',
name: 'cloning',
defaultValue: false,
documentation: "True to clone results on select"
},
{
name: 'daoType',
defaultValue: 'foam.dao.IDBDAO',
documentation: function() { /*
<p>Selects the basic functionality this $$DOC{ref:'foam.dao.EasyDAO'} should provide.
You can specify an instance of a DAO model definition such as
$$DOC{ref:'MDAO'}, or a constant indicating your requirements.</p>
<p>Choices are:</p>
<ul>
<li>$$DOC{ref:'.ALIASES',text:'IDB'}: Use IndexDB for storage.</li>
<li>$$DOC{ref:'.ALIASES',text:'LOCAL'}: Use local storage (for Chrome Apps, this will use local, non-synced storage).</li>
<li>$$DOC{ref:'.ALIASES',text:'SYNC'}: Use synchronized storage (for Chrome Apps, this will use Chrome Sync storage).</li>
</ul>
*/}
},
{
model_: 'BooleanProperty',
name: 'autoIndex',
defaultValue: false,
documentation: "Automatically generate an index."
},
{
model_: 'ArrayProperty',
name: 'migrationRules',
subType: 'foam.core.dao.MigrationRule',
documentation: "Creates an internal $$DOC{ref:'MigrationDAO'} and applies the given array of $$DOC{ref:'MigrationRule'}."
},
{
model_: 'BooleanProperty',
name: 'syncWithServer'
},
{
model_: 'BooleanProperty',
name: 'sockets',
defaultValue: false
},
{
model_: 'StringProperty',
name: 'serverUri',
defaultValueFn: function() {
if ( this.sockets ) {
var s = this.document.location.origin + '/api';
return s.replace(/^https/, "wss").replace(/^http/, "ws");
}
return this.document.location.origin + '/api'
}
},
{
model_: 'BooleanProperty',
name: 'isServer',
defaultValue: false
},
{
name: 'syncProperty'
},
{
name: 'deletedProperty'
}
],
constants: {
// Aliases for daoType
ALIASES: {
IDB: 'foam.dao.IDBDAO',
LOCAL: 'foam.core.dao.StorageDAO', // Switches to 'ChromeStorageDAO' for Chrome Apps
SYNC: 'foam.core.dao.StorageDAO' // Switches to 'ChromeSyncStorageDAO' for Chrome Apps
}
},
methods: [
function init(args) {
/*
<p>On initialization, the $$DOC{ref:'.'} creates an appropriate chain of
internal $$DOC{ref:'DAO'} instances based on the $$DOC{ref:'.'}
property settings.</p>
<p>This process is transparent to the developer, and you can use your
$$DOC{ref:'.'} like any other $$DOC{ref:'DAO'}.</p>
*/
this.SUPER(args);
if ( window.chrome && chrome.storage ) {
this.ALIASES.LOCAL = 'foam.core.dao.ChromeStorageDAO';
this.ALIASES.SYNC = 'foam.core.dao.ChromeSyncStorageDAO';
}
var daoType = typeof this.daoType === 'string' ? this.ALIASES[this.daoType] || this.daoType : this.daoType;
var daoModel = typeof daoType === 'string' ? this.X.lookup(daoType) : daoType;
var params = { model: this.model, autoIndex: this.autoIndex };
if ( ! daoModel ) {
console.warn("EasyDAO: Unknown DAO Type. Add '" + daoType + "' to requires: list.");
}
if ( this.name ) params.name = this.name;
if ( this.seqNo || this.guid ) params.property = this.seqProperty;
var dao = daoModel.create(params, this.Y);
if ( MDAO.isInstance(dao) ) {
this.mdao = dao;
if ( this.dedup ) dao = this.DeDupDAO.create({delegate: dao});
} else {
if ( this.migrationRules && this.migrationRules.length ) {
dao = this.MigrationDAO.create({
delegate: dao,
rules: this.migrationRules,
name: this.model.id + "_" + daoModel.id + "_" + this.name
}, this.Y);
}
if ( this.cache ) {
this.mdao = this.MDAO.create(params);
dao = this.CachingDAO.create({
cache: this.dedup ?
this.mdao :
this.DeDupDAO.create({delegate: this.mdao}),
src: dao,
model: this.model});
}
}
if ( this.seqNo && this.guid ) throw "EasyDAO 'seqNo' and 'guid' features are mutually exclusive.";
if ( this.seqNo ) {
var args = {__proto__: params, delegate: dao, model: this.model};
if ( this.seqProperty ) args.property = this.seqProperty;
dao = this.SeqNoDAO.create(args);
}
if ( this.guid ) {
var args = {__proto__: params, delegate: dao, model: this.model};
if ( this.seqProperty ) args.property = this.seqProperty;
dao = this.GUIDDAO.create(args);
}
if ( this.contextualize ) dao = this.ContextualizingDAO.create({
delegate: dao
});
if ( this.cloning ) dao = this.CloningDAO.create({
delegate: dao
});
var model = this.model;
if ( this.syncWithServer && this.isServer ) throw "isServer and syncWithServer are mutually exclusive.";
if ( this.syncWithServer || this.isServer ) {
if ( ! this.syncProperty || ! this.deletedProperty ) {
if ( model.traits.indexOf('foam.core.dao.SyncTrait') != -1 ) {
this.syncProperty = model.SYNC_PROPERTY;
this.deletedProperty = model.DELETED;
} else {
throw "Syncing with server requires the foam.core.dao.SyncTrait be applied to your model.";
}
}
}
if ( this.syncWithServer ) {
var syncStrategy = this.sockets ? this.SocketSyncDAO : this.PollingSyncDAO;
dao = syncStrategy.create({
remoteDAO: this.EasyClientDAO.create({
serverUri: this.serverUri,
model: model,
sockets: this.sockets,
reconnectPeriod: 30000
}),
syncProperty: this.syncProperty,
deletedProperty: this.deletedProperty,
delegate: dao,
period: 1000
});
dao.syncRecordDAO = foam.dao.EasyDAO.create({
model: dao.SyncRecord,
cache: true,
daoType: this.daoType,
name: this.name + '_SyncRecords'
});
}
if ( this.isServer ) {
dao = this.VersionNoDAO.create({
delegate: dao,
property: this.syncProperty,
version: 2
});
}
if ( this.timing ) dao = this.TimingDAO.create({ name: this.model.plural + 'DAO', delegate: dao });
if ( this.logging ) dao = this.LoggingDAO.create({ delegate: dao });
this.delegate = dao;
},
function addIndex() {
/* <p>Only relevant if $$DOC{ref:'.cache'} is true or if $$DOC{ref:'.daoType'}
was set to $$DOC{ref:'MDAO'}, but harmless otherwise.</p>
<p>See $$DOC{ref:'MDAO.addIndex', text:'MDAO.addIndex()'}.</p> */
this.mdao && this.mdao.addIndex.apply(this.mdao, arguments);
return this;
},
function addRawIndex() {
/* <p>Only relevant if $$DOC{ref:'.cache'} is true or if $$DOC{ref:'.daoType'}
was set to $$DOC{ref:'MDAO'}, but harmless otherwise.</p>
<p>See $$DOC{ref:'MDAO.addRawIndex', text:'MDAO.addRawIndex()'}. */
this.mdao && this.mdao.addRawIndex.apply(this.mdao, arguments);
return this;
}
]
});