
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
datamodeljs
Advanced tools
This library handles entity like javascript objects. Allowing relationships between those objects. Also allowing bi-directional relationships. Tracking states (changed, new, deleted) of those objects.
Data Model Management Library for JavaScript
The main goal of datamodeljs is to ensure a consistent and reliable data structure when communicating with a backend service.
In all projects the data structure between backend and frontend can be considered as an interface contract. If either side changes the structure of the data - the counterpart has problems validating and handling the data.
In order to avoid long lasting debugging sessions in a JavaScript application we use datamodeljs to read in and validate the delivered data against the defined entity model classes.
A secondary goal of datamodeljs is the ability to manage entity objects and keep track of their states (e.g. newly created, marked as changed, marked for deletion)
This entity object management allows the JavaScript application to manipulate business objects on block before sending them anywhere.
In order to be able to handle complex business objects datamodeljs implements a bi-directional entity model. Examples can be seen in "Defining entity classes"
The Github page contains an interactive example and demonstrates the possibilities with datamodeljs.
Entities created with datamodeljs know their entity class name:
_className - the string representation of the entities class name (as declared with the define function)Entities created with datamodeljs also can track four different states:
_isDirty - has the entity changed on client side since it load time_isDeleted - is the entity marked for deletion on client side_isTransient - was the entity created newly on client side_isStub - is the entity referenced by another entities relationship, but the entity itself was not loaded by nowIn most cases a dirty entity leads to an PUT call in the backend. A deleted entity leads a DELETE call. A transient entity results in a POST call and a stub entity should be loaded using a GET call. Mapping this is not part of datamodeljs since it has not the goal to cover the AJAX requests. Mapping the entity states to proper AJAX requests is the applications task.
When serialising or cloning entity objects their internal object properties _className, _isDirty, _isDeleted, _isTransient and _isStub are not exposed. So using JSON.stringify before sending entites to a service ensures that no internal property is send to the service. Also cloning entity objects simply creates a new JavaScript object that has the entites properties and values set - but it is not considered an entity object anymore since the internal object properties are not cloned.
datamodeljs exposes itself to the global variable 'datamodeljs'. In case that a different symbol for datamodeljs is needed use the symbol function. This function allows you to occupy a different global name by giving a new name or releasing the last name by providing no name or an empty name.
datamodeljs.symbol([symbol:String]) : datamodeljs
Example:
// define an alternate global exposure
datamodeljs.symbol("dmjs")
// delete the former alternate global exposure and restore the old value of 'dmjs'
datamodeljs.symbol("")
datamodeljs.symbol()
datamodeljs allows the definition of different dataManager storages by using the dm function:
datamodeljs.dm(name:String) : dataManager
Example:
var myDataManager = datamodeljs.dm("mine");
// all further examples are working with this dataManager
var dm = datamodeljs.dm("default")
The dataManager created by datamodeljs enables the entity class definition and entity management. The following chapters describe the possibilities in detail:
Defining an entity class is the basic for working with entities. Entities are defined with the define function. A class definition needs at least an unique class name (cls) and its specification (spec). A parent class name is optional. If a parent class name is given, all attributes of that class will be copied into the new class name. Please be aware that this is no real extends mechanism of those classes.
dataManager.define(cls:String, [parentCls:String], spec:Object) : void
The class specification is a list of attributes following this syntax:
{
(attribute: (primary)?type(arity)? )*
};
attribute tag.
The internal properties _className, _isDirty, _isDeleted, _isTransient and _isStub are reserved and can not be used as an class attribute.primary field with the prefix @.type can be either number, boolean, string, object or any other class namearity defines this attributes relation as an arrayed relation and it can have different options
? - stands for zero or one(0..1) elements of the given type+ - stands for one or more(1..n) elements of the given type* - stands for zero or more(0..n) elements of the given typeExamples:
dm.define("AbstractData", {
id: '@number', // this is the primary field
version: 'number'
});
dm.define("Verweis", "AbstractData", { // get all attributes of AbstractData copied
verweisTyp: "string",
anzeigename: "string",
knoten: "Knoten" // relation to objects of class Knoten
});
dm.define("Knoten", "AbstractData", {
anzeigename: 'string',
kindKnoten: 'Knoten*', // Knoten can have n childs being Knoten as well
pfad: 'string'
});
Removing a class definition from the dataManager is possible with the undefine function:
dataManager.undefine(cls:String) : void
Using this function is removing the class, its specification and all entity objects from the dataManager. It is most useful when data models are loaded dynamically.
Creating objects of entities is available with the create function.
dataManager.create(cls:String, payload:Object) : entity
cls must be one of the defined class names within the dataManagerpayload is the JSON object that should be converted into an entity. The given payload is hereby validated against the entity class specificationExample:
dm.create("Verweis", {
id: 1,
version: 1,
verweisTyp: "Symbol",
anzeigename: "symbolic link",
knoten: 1 // it is sufficient to only provide the id of the related object
// the dataManager resolves the relation using the given unique id
})
The given example creates two entity objects. The first is the desired Verweis. The second object is a Knoten with id set to but the flag stub set to true. Meaning that this object is referenced somewhere but it was not yet loaded. If this objects get loaded and created later on, then the reference to this Knoten wont change, only its content will be updated and its stub flag will be set to false.
Example:
dm.create("Knoten", {
id: 1,
version: 1,
anzeigename: "Root Knoten",
kindKnoten: [], // it is ok if this array is empty since the arity is *
pfad: "/"
})
Deleting a single entity object is possible using the destroy function.
dataManager.destroy(cls:String, obj:Object, [force:Boolean]) : void
The object will be immediatly removed from the dataManager if it was marked as transient entity or if force is set to true. Otherwise it will be marked as deleted. This way the JavaScript application can still handle the deletion with a proper AJAX call.
Example:
dm.destroy("Verweis", dm.findById("Verweis", 1))
The deletion of all objects of a given entity class(cls) is possible using the destroyAll function.
dataManager.destroyAll(cls:String) : void
Example:
dm.destroyAll("Knoten")
Changing the states of an entity is the JavaScript application's task. Entity attributes can be altered as usual in JavaScript applications. The entity class name _className can not be changed or deleted from the entity object. The specific entity states _isDirty, _isDeleted, _isTransient and _isStub can only be altered to a new legal boolean value.
// entity object properties
entityObj._className : String
entityObj._isDirty : Boolean
entityObj._isDeleted : Boolean
entityObj._isTransient : Boolean
entityObj._isStub : Boolean
For backward compatibility the dataManager functions isDirty, isDeleted, isTransient and isStub still remain as decprecated functions (see documentation in release 1.1.0#tracking-and-changing-entity-object-states).
Finding entities can be reached over several ways
findAll - find all objects of a given entity classfindAllDirty - find all objects of a given entity class that are marked as dirtyfindAllDeleted - find all objects of a given entity class that are marked as deletedfindAllTransient - find all objects of a given entity class that are marked as transientfindAllStub - find all objects of a given entity class that are marked as stubfindById - find all objects of a given entity class that match the given primary keyfindByExample - find all objects of a given entity class that match a given example objectThe following finder functions only need the class name (cls) and will return an array of entity objects that match the finder.
dataManager.findAll(cls:String) : Array(entity)
dataManager.findAllDirty(cls:String) : Array(entity)
dataManager.findAllDeleted(cls:String) : Array(entity)
dataManager.findAllTransient(cls:String) : Array(entity)
dataManager.findAllStub(cls:String) : Array(entity)
Example:
dm.findAll("Verweis")
dm.findAllDirty("Knoten")
dm.findAllDeleted("Knoten")
dm.findAllTransient("Knoten")
dm.findAllStub("Knoten")
Finding entities by primary key is quite easy by providing the desired primary as additional parameter (id). The id is defined as Any since it depends on the class specification. Basically it is either a string or a number.
dataManager.findById(cls:String, id:Any) : entity
Example:
dm.findById("Verweis", 1)
Finding entities by a given example object is available via the findByExample function.
dataManager.findByExample(cls:String, example:Object) : Array(entity)
Example:
// find all Verweis entities where verweisTyp is equal to "Symbol"
dm.findByExample("Verweis", { verweisTyp: "Symbol" })
// find all Verweis entities where verweisTyp is equal to "Symbol" and knoten is equal to Knoten with id 1
dm.findByExample("Verweis", { verweisTyp: "Symbol", knoten: 1 })
Sometimes it is useful or necessary to import data into existing entity objects. The problem with this is that any existing relationship with other others or from other objects should not be influenced. Importing data fields into an existing entity is possible with the import function. A given example object (example) will hereby be merged into an existing entity object (obj).
dataManager.import(cls:String, obj:Object, example:Object) : entity
Example:
dm.import("Verweis", dm.findById("Verweis", 1), { verweisTyp: "Copy", anzeigename: "Partial change" })
This is often needed, if a JavaScript application edits entities then stores changes to any other system and gets a newly changed object as result back. In this case the old 'saved' object still exists in the dataManager and it must be updated with the new result of the service.
Since the dataManager does quite some jobs for us and a data model might be slightly huge and complex datamodeljs enables a little debugging help for developers.
dataManager.dump() : void
Using the dump function on the dataManager shows you two lists with information:
once as an arrayed list
and once as an object map allowing access by primary key
So at any time during development, application test and application runtime it should be possible to get an insight to what the dataManager handles.
FAQs
This library handles entity like javascript objects. Allowing relationships between those objects. Also allowing bi-directional relationships. Tracking states (changed, new, deleted) of those objects.
The npm package datamodeljs receives a total of 8 weekly downloads. As such, datamodeljs popularity was classified as not popular.
We found that datamodeljs demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.