All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.dirigible.mongodb.dao.js Maven / Gradle / Ivy

There is a newer version: 7.2.0
Show newest version
/*
 * Copyright (c) 2022 SAP SE or an SAP affiliate company and Eclipse Dirigible contributors
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v20.html
 *
 * SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Eclipse Dirigible contributors
 * SPDX-License-Identifier: EPL-2.0
 */
"use strict";

var globals = require("core/v4/globals");
var mongodb = require("mongodb/client");

var mongoClient = mongodb.getClient();
var db = mongoClient.getDB();

var DAO = exports.DAO = function(orm, logCtxName, dataSourceName, databaseType){
	if(orm === undefined)
		throw Error('Illegal argument: orm['+ orm + ']');

	this.orm = require("db/v4/orm").get(orm);

	//setup loggerName
	var loggerName = logCtxName;
	if(!loggerName){
		loggerName = 'mongodb.dao';
		if(this.orm.table)
			loggerName = 'mongodb.dao.'+(this.orm.table.toLowerCase());
	}
	this.$log = require('log/v4/logging').getLogger(loggerName);
};

DAO.prototype.notify = function(event){
	var func = this[event];
	if(!this[event])
		return;
	if(typeof func !== 'function')
		throw Error('Illegal argument. Not a function: ' + func);
	var args = [].slice.call(arguments);
	func.apply(this, args.slice(1));
};

//Prepare a JSON object for insert into DB
DAO.prototype.createNoSQLEntity = function(entity) {
	var persistentItem = {};
	var mandatories = this.orm.getMandatoryProperties();
	for(var i=0; i-1) || mandatories[i].type.toUpperCase() === 'BOOLEAN')
			continue;
		var propValue = entity[propName];
		if(propValue === undefined || propValue === null){
			throw new Error('Illegal ' + propName + ' attribute value in '+this.orm.table+' entity: ' + propValue);
		}
	}
};

DAO.prototype.insert = function(_entity){

	var entities = _entity;
	if(_entity.constructor !== Array){
		entities = [_entity];
	}

	this.$log.info('Inserting {} {}', this.orm.table, (entities.length===1?'entity':'entities'));
	
	var updatedRecordCount = 0;
	var ids = [];

	for(var i=0; i0){
      			ids.push(dbEntity[this.orm.getPrimaryKey().name]);				
				this.$log.info('{}[] entity inserted', this.orm.table, dbEntity[this.orm.getPrimaryKey().name]);
			} else {
				this.$log.info('No changes incurred in {}', this.orm.table);
			}


	    } catch(e) {
	    	this.$log.error("Inserting {} {} failed", e, this.orm.table, (entities.length===1?'entity':'entities'));
	    	this.$log.info('Rolling back changes after failed {}[{}] insert. ', this.orm.table, dbEntity[this.orm.getPrimaryKey().name]);
			if(dbEntity[this.orm.getPrimaryKey().name]){
				try{
					this.remove(dbEntity[this.orm.getPrimaryKey().name]);
				} catch(err) {
					this.$log.error('Could not rollback changes after failed {}[{}}] insert. ', this.orm.table, dbEntity[this.orm.getPrimaryKey().name]);
				}
			}
			throw e;
	    }
    }
    
    if(_entity.constructor!== Array)
    	return ids[0];
	else
		return ids;
};

// update entity from a JSON object. Returns the id of the updated entity.
DAO.prototype.update = function(entity) {

	this.$log.info('Updating {}[{}] entity', this.orm.table, entity!==undefined?entity[this.orm.getPrimaryKey().name]:entity);

	if(entity === undefined || entity === null){
		throw new Error('Illegal argument: entity is ' + entity);
	}
	
	var ignoredProperties = this.orm.getMandatoryProperties()
							.filter(function(property){
								return property.allowedOps && property.allowedOps.indexOf('update')<0;
							})
							.map(function(property){
								return property.name;
							});
	this.validateEntity(entity, ignoredProperties);
    
	var dbEntity = this.createNoSQLEntity(entity);
	dbEntity[this.orm.getPrimaryKey().name] = entity["_id"];
	dbEntity["_id"] = entity["_id"];

    try {
      	this.notify('beforeUpdateEntity', dbEntity);

		var collection = db.getCollection(this.orm.table);
		collection.update({"_id": entity["_id"]}, dbEntity);

       	this.$log.info('{}[{}] entity updated', this.orm.table, dbEntity[this.orm.getPrimaryKey().name]);
    
	    return this;    
    } catch(e) {
     	this.$log.error('Updating {}[{}] failed', this.orm.table, entity!==undefined?entity[this.orm.getPrimaryKey().name]:entity);
	 	throw e;
    }
};

// delete entity by id, or array of ids, or delete all (if not argument is provided).
DAO.prototype.remove = function(id) {

	var ids = [];
	if(arguments.length===0){
		ids = this.list({
			"$select": [this.orm.getPrimaryKey().name]
		}).map(function(ent){
			return ent[this.orm.getPrimaryKey().name];
		}.bind(this));
	} else {
		if(arguments[0].constructor !== Array){
			ids = [arguments[0]];
		} else {
			ids = arguments[0];
		}
	}

	this.$log.info('Deleting '+this.orm.table+((ids!==undefined && ids.length===1)?'['+ids[0]+'] entity': ids.length+' entities'));


	for(var i=0; i1)
			this.$log.info('Deleting {}[{}] entity', this.orm.table, id);
	
		if(id === undefined || id === null){
			throw new Error('Illegal argument for id parameter:' + id);
		}
	
	    try {
	    
	    	this.notify('beforeRemoveEntity', id);

			var collection = db.getCollection(this.orm.table);
			collection.remove({"_id": id});

	    } catch(e) {
		 	this.$log.error('Deleting {}[{}] entity failed', this.orm.table, id);
		 	throw e;
	    }
	    
    }
    
};

DAO.prototype.expand = function(expansionPath, context){
	this.$log.info('Expanding for association path {} and context entity {}', expansionPath, (typeof arguments[1] !== 'object' ? 'id ': '') + JSON.stringify(arguments[1]));
	throw Error("Not implemented.");
};

/* 
	Reads a single entity by id, parsed into JSON object. 
	If requested as expanded the returned entity will comprise associated (dependent) entities too. Expand can be a string tha tis a valid association name defined in this dao orm or
	an array of such names.
*/
DAO.prototype.find = function(id, expand, select) {

	if(typeof arguments[0] === 'object'){
		id = arguments[0].id;
		expand = arguments[0].$expand || arguments[0].expand;
		select = arguments[0].$select || arguments[0].select;
	}

	this.$log.info('Finding {}[{}] entity with list parameters expand[{}], select[{}]', this.orm.table, id, expand, select);

	if(id === undefined || id === null){
		throw new Error('Illegal argument for id parameter:' + id);
	}

    try {
        var entity;
        if(select!==undefined){
			if(select.constructor !== Array){
				if(select.constructor === String){
					select= select.split(',').map(function(sel){
						if(sel.constructor !== String)
							throw Error('Illegal argument: select array components are expected ot be strings but found ' + (typeof sel));
						return sel.trim();
					});
				} else {
					throw Error('Illegal argument: select is expected to be string or array of strings but was ' + (typeof select));
				}
			}
		}
		//ensure that joinkeys for required expands are available and not filtered by select
		if(select!==undefined && expand!==undefined){
			select.push(this.orm.getPrimaryKey().name);
		}

       	var params = {};
		params["_id"] = id;

		var collection = db.getCollection(this.orm.table);
		var entity = collection.findOneById(params, select);

		if(entity) {
			this.$log.info('{}[{}] entity found', this.orm.table, id);
			this.notify('afterFound', entity);
		} else {
			this.$log.info('{}[{}] entity not found', this.orm.table, id);
		}
        return entity;
    } catch(e) {
        this.$log.error("Finding {}[{}] entitiy failed.", this.orm.table, id);
		throw e;
    }
};

DAO.prototype.count = function() {

	this.$log.info('Counting '+this.orm.table+' entities');

	var count = 0;
    try {
    	var collection = db.getCollection(this.orm.table);
		count = collection.count();
    } catch(e) {
    	this.$log.error('Counting {} entities failed', e, this.orm.table); 
		e.errContext = parametericStatement.toString();
		throw e;
    }
    
    this.$log.info('{} {} entities counted', String(count), this.orm.table);

    return count;
};

/*
 * list parameters:
 * - $expand
 * - $filter
 * - $select
 * - $sort
 * - $order 
 * - $limit
 * - $offset
 */
DAO.prototype.list = function(settings) {
	
	settings = settings || {};
	
	var expand = settings.$expand || settings.expand;
	if(expand!==undefined){
		if(expand.constructor !== Array){
			if(expand.constructor === String){
				if(expand.indexOf(',')>-1){
					settings.$expand =  expand.split(',').map(function(exp){
						if(exp.constructor !== String)
							throw Error('Illegal argument: expand array components are expected ot be strings but found ' + (typeof exp));
						return exp.trim();
					});	
				} else {
					settings.$expand = [expand];
				}
			} else {
				throw Error('Illegal argument: expand is expected to be string or array of strings but was ' + (typeof expand));
			}
		}
	}
	
	var select = settings.$select || settings.select; 
	if(select!==undefined){
		if(select.constructor !== Array){
			if(select.constructor === String){
				if(select.indexOf(',')>-1){
					settings.$select =  select.split(',').map(function(exp){
						if(exp.constructor !== String)
							throw Error('Illegal argument: select array components are expected ot be strings but found ' + (typeof exp));
						return exp.trim();
					});	
				} else {
					settings.$select = [select];
				}
			} else {
				throw Error('Illegal argument: select is expected to be string or array of strings but was ' + (typeof expand));
			}
		}
	}
	
	var listArgs = [];
	for(var key in settings){
		listArgs.push(' ' + key + '[' + settings[key] + ']');
	}
	
	this.$log.info('Listing {} entity collection with list operators: {}', this.orm.table, listArgs.join(','));
	
	if(settings.$select!==undefined && expand!==undefined){
		settings.$select.push(this.orm.getPrimaryKey().name);
	}

    //simplistic filtering of (only) string properties with like
	if(settings.$filter){
		if(settings.$filter.indexOf(',')>-1){
			settings.$filter = settings.$filter.split(',');			
		} else {
			settings.$filter = [settings.$filter];
		}
		settings.$filter = settings.$filter.filter(function(filterField){
			var prop = this.ormstatements.orm.getProperty(filterField);
			if(prop===undefined || prop.type.toUpperCase()!=='VARCHAR' || settings[prop.name]===undefined)
				return false;
			settings[prop.name] = '%' + settings[prop.name] + '%';
			return true;
		}.bind(this));
	}
  
   try {
    	var entities = [];
		var collection = db.getCollection(this.orm.table);
		var cursor = collection.find();
		while (cursor.hasNext()) {
			entities.push(cursor.next());
		}
	
    	this.$log.info('{} {} entities found', entities.length, this.orm.table);
        
		return entities;
  } catch(e) {
  	this.$log.error("Listing {} entities failed.", this.orm.table);
	throw e;
  } 
};

DAO.prototype.existsTable = function() {
	return true;
};

DAO.prototype.createTable = function() {
};

DAO.prototype.dropTable = function(dropIdSequence) {
    return this;
};

/**
 * oDefinition can be table definition or standard orm definition object. Or it can be a valid path to
 * a .table file, or any other text file contianing a standard dao orm definition.
 */
exports.create = exports.dao = function(oDefinition, logCtxName, dataSourceName, databaseType){
	var orm;

	orm = oDefinition;
	
	var productName = globals.get(databaseType + "_" + dataSourceName);
	if (!productName) {
		productName = "MongoDB";
		globals.set(databaseType + "_" + dataSourceName, productName);
	}

	return new DAO(orm, logCtxName, dataSourceName, databaseType);
};




© 2015 - 2025 Weber Informatics LLC | Privacy Policy