Modes collection

You could get multiple mode at once. It means that, in the order of provided modes, the different object identities are merged (deep up) and returned.

var myManager = deep.ocm({
	mode1:{
		test:1
	},
	mode2:{
		title:"hello world",
		test:2
	}
});

deep.log("mode1 + mode2 : ", myManager("mode1", "mode2")); 		// be careful to order
// => mode1 + mode2 : Object { test=2, title="hello world"}

deep.log("mode2 + mode1 : ", myManager("mode2", "mode1")); 		// be careful to order
// => mode2 + mode1 : Object { title="hello world", test=1 }

Remarque 'compilation' of resulted object is done only once and cached securely in manager's local closure.

The mode collection is really useful to do something like this : (see deep.store docs )

var myManager = deep.ocm({
	dev:deep.store.Collection.create(...),
	prod:deep.store.Mongo.create(...),
	"public":deep.Disallow("del","post"),
	admin:{}
});
// try to delete something in local developpement store (a memory collection here) as "public" => return error 405  
myManager("dev","public").del("my_id");  

// try to delete something in production store (a mongo here) as "admin" => do the 'del' and return no error
myManager("prod","admin").del("my_id");  

Strict compilation

Here, if you have well understoud the previous trick, you could have seen that 'admin' entry isn't necessary :

myManager("prod","admin").del("my_id"); 
is equivalent to :
myManager("prod").del("my_id"); 
You could even gives any unknown mode after 'prod' (or 'dev'), it will do the same :
myManager("prod","bloup").del("my_id"); 

It's because the manager isn't 'strict'. It compiles what it could find... without warning if there is no associated entries for certain of provided modes (it warns only it finds nothing at all).

To disallow this behaviour, simply provide an options object to OCM constructor with `'strict':true` in it.

var myManager = deep.ocm({
	dev:deep.store.Collection.create(...),
	prod:deep.store.Mongo.create(...),
	"public":deep.Disallow("del","post"),
	admin:{}
}, { strict:true });
//...
myManager("prod", "bloup").del("my_id");  // => will warn and return an empty object as there is no 'bloup' entry in ocm layer.

Remarque Even if strict :

myManager("prod","admin").del("my_id");
and
myManager("prod").del("my_id");

are equivalent in our case.

(i.e. in the example : admin is just an empty oject that doesn't modify the compiled result)

multiModes or not.

Sometimes, you want that OCM manage only single mode. (so you want to not allow to mix different modes together)

// you don't want to allow to mix 'public' and 'user' modes (there is no sens here to do so)
var myManager = deep.ocm({
	'public':deep.store.Collection.create(...),
	'user':deep.store.Mongo.create(...)
}, { multiModes:false });

//...

myManager("public","user").get(...); // => will warn and return an empty object

Mode sensibility, context and hierarchy

So... In deep.ocm, there is 4 ways to manage modes.

Through direct usage of your manager (the two first ways)

First, the way that you've already seen here : just provides mode(s) as arguments when you ask OCM compilation.
var manager =  deep.ocm({ ... });
//...
var compiled = manager("mode1", "mode2");
Secondly, you could set its current mode(s) in manager itself, and use them 'blindly' after.
var manager =  deep.ocm({ ... });
manager.modes("mode1");			// manager will hold provided mode(s) in it's local closure
//...
var compiled = manager();		// it will use the internal mode previously defined (here : 'mode1').

Through sensibleTo, deep.Modes and deep.modes

If you want to define once a mode somewhere that could be shared between different managers, you need to set, in your managers, the name(s) of the variable(s) that contain(s) your current mode(s). You set it through 'sensibleTo' property or method :
var manager = deep.ocm({ ... }, { sensibleTo:"roles" });
or
var manager = deep.ocm({ ... });
manager.sensibleTo("roles");

Through sensibleTo, deep.Modes and deep.modes

Then, when you'll ask to your manager to return something, deep OCM will look in 3 namespaces after related 'group(s)' modes. Lets explain the hierarchy between those namespaces:

  • deep.Modes(mode1, mode2, ...) : The more general but less hierarchicaly high : it holds global modes accessible from anywhere.
  • deep.modes(mode1, mode2, ...) : it start a chain that holds provided modes in its current deep.context (see [docs on deep.context](./asynch/asynch-context-management.md) and chains)
  • myOCManager.modes(mode1, mode2, ...) : The less general but more hierarchicaly high: it holds provided modes in the local ocm closure.
So, when you do
var a = manager();
deepjs will look first in manager itself after current modes.

If there is no current mode setted in manager, but there is a 'sensibleTo' property, deepjs will look in current deep.context.modes after the 'group(s)' modes, and apply it if any.

Finally, if there is no deep.context.modes that could be find with 'group(s)', it will look in deep.Modes namespace after it, and apply it if any.

If deepjs finds nothing : it will warn and return an empty object.

For full informations on deep.context and how tu use it : see [docs](./asynch/asynch-context-management.md).

Resumed

var manager = deep.ocm({ 'public':'hello public',  'user':'hello user' }, { sensibleTo:"roles" });
//...
deep.Modes("roles","public");
//...
deep.log(manager()); // will return 'hello public'  (it has found 'roles' in deep.Modes)
//...
deep.log(manager("user")); // will return : 'hello user' (it has used direct provided mode, that hides deep.Modes one)
//...
manager.modes("user");
//...
deep.log(manager()); // will return : 'hello user' (it has used manager local current mode(s), that hides deep.Modes one)
//...
deep.modes("roles", "user") // this start a chain with its own context containing modes:{ roles:'user' }
.done(function(){	
	deep.log(manager()); // will return : 'hello user' (it has used deep.context.modes.roles, that hides deep.Modes().roles);
	//...
	deep.log(manager("public")); // will return : 'hello public' (it has used direct provided mode, that hides deep.context.modes and deep.Modes)
});
//...
manager(); // will return 'hello public'  (it has found 'roles' in deep.Modes - because deep.context.modes is empty : only the chain has modified it)

modes to null

When you want to remove a modes in one of the 3 namespaces (manager.modes(), deep.modes(), deep.Modes()) : just set it to null.
deep.Modes("roles", "public");

var manager = deep.ocm(...);	// containing a 'user' and a 'public' entry

manager.sensibleTo("roles");
manager.modes("user");

manager()...; // => return 'user' entry (it has use manager current mode(s))

manager.modes(null);

manager()...; // => return 'public' entry (it has use deep.Modes().roles)

deep.Modes("roles", null);

manager()...; // => warn and produce an empty object because no modes are set to use OCM.

Modes map

When you manipulate modes through deep.Modes or deep.modes, you could provide a modes map :
deep.Modes({
	roles:["user", "otherRole"],
	env:"dev"
});
If you do it twice, the namespace are merged at first level only. It means :
deep.Modes({
	roles:["user", "otherRole"],
	env:"dev"
});

//...

deep.Modes({
	roles:["public"],
});

deep.log(deep.Modes()); // => { roles:["public"], env:"dev" }

Resumed : when modes map are merged with a namespace (either deep.Modes or deep.context.modes (through deep.modes)), it does :
for(var i in modesMap)
	namespace[i] = modesMap[i];
So you conserve OTHER modes that those gives in modesMap.

Multi sensibility

You could also use a sensibleTo collection in your manager.
var manager = deep.ocm({
	dev:deep.store.Collection.create(...),
	prod:deep.store.Mongo.create(...),
	'public':deep.AllowOnly("get", "range"),
	user:deep.Disallow("del")
}, { sensibleTo:["env", "roles"] });

deep.Modes({
	roles:"user",
	env:"dev"
});

manager()...; // will compile local memory collection (dev entry) with 'user' restrictions