HEX
Server: nginx/1.24.0
System: Linux nowruzgan 6.8.0-57-generic #59-Ubuntu SMP PREEMPT_DYNAMIC Sat Mar 15 17:40:59 UTC 2025 x86_64
User: babak (1000)
PHP: 8.3.6
Disabled: NONE
Upload Files
File: /var/dev/farhangmoaser/web/models/dictionary.js
/**
 * Dictionary Model
 * Version: 0.1
 * Author: Babak Vandad
 *
 * Abstraction layer for Dictionary table in MySQL db
 */

"use strict";
var md5 = require('md5');
var uuid = require('uuid');
var consts = require('../consts')

class DictionaryModel {

	/**
	 * Constructor
	 * @param  {object} conn db connection from db pool.
	 * @param  {Object} data values for table fields.
	 *                       At least on of `title` or `id` must be set.
	 */
	constructor(conn, data) {
		this.data = data;
		this.conn = conn;
	}

	/**
	 * fetch/set fields of the table
	 * if `value` argument is passed the field is set, otherwise fetched
	 * @param  {string} key   field name
	 * @param  {mixed} value value of the field
	 * @return {mixed}       returns the value
	 */
	field(key, value) {
		if(arguments.length==0) return;
		if(arguments.length==1)
			return this.data[key];
		
		if(value===undefined)
			delete this.data[key];
		else
			this.data[key] = value;
	}

	/**
	 * fetch all fields
	 * @return {object} row data
	 */
	fields(){

		return this.data;
	}

	/**
	 * if id is set updated row otherwise creates a new record
	 * @return {Promise} promise object
	 */
	save() {
		if(this.data.hasOwnProperty('id')) return this.update();
		else return this.add();
	}

	/**
	 * updates the row data
	 * @return {promise} promise object
	 */
	update() {
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.hasOwnProperty('id'))
				return reject('id is required.');

			self.conn.query("UPDATE source SET ? where ?", [self.data, {id: self.data.id}], function(err, result){
				if(err) return reject('db error.');
				resolve(self);
			});
		});
	}

	/**
	 * creates a new record
	 * @return {promise} promise object
	 */
	add() {
		var self = this;
		return new Promise(function(resolve, reject){
			var record = {};
			if(self.data.hasOwnProperty('title')) record.title = self.data.title;
			if(self.data.hasOwnProperty('author')) record.author = self.data.author;
			if(self.data.hasOwnProperty('pubYear')) record.pubYear = self.data.pubYear;
			if(self.data.hasOwnProperty('cover')) record.cover = self.data.cover;
			if(self.data.hasOwnProperty('state')) record.state = self.data.state;
			if(self.data.hasOwnProperty('desc')) record.desc = self.data.desc;
			record.uuid = uuid();

			self.conn.query(`INSERT INTO source SET ?`, record, function(err, result){
				if(err) return reject('db error.');
				self.data.id = result.insertId;
				self.data.uuid = record.uuid;
				resolve(self);
			})
		});
	}

	/**
	 * loads row data corresponding to id or uuid
	 * @return {Promise} promise object
	 */
	load() {
		var self = this;
		return new Promise(function(resolve, reject){
			if(self.data.hasOwnProperty('id')) {
				self.conn.query(`SELECT * FROM source WHERE ?`, {id: self.data.id}, function(err, rows, fields){
					if (err) return reject(err.message);
					if(rows.length) {
						self.data = rows[0];
						resolve(self);
					}else
						resolve(false);
				});
			}else
			if(self.data.hasOwnProperty('uuid')) {
				self.conn.query(`SELECT * FROM source WHERE ?`, {uuid: self.data.uuid}, function(err, rows, fields){
					if (err) return reject(err.message);
					if(rows.length) {
						self.data = rows[0];
						resolve(self);
					}else
						resolve(false);
				});
			}else
				return reject('At least on of the id and title fields must be provided.');
		});
	}

	/**
	 * deletes a record
	 * @return {promise} promise object
	 */
	remove() {
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.hasOwnProperty('id')) return reject('id is required.');
			self.conn.query('DELETE FROM `source` WHERE ?', {id: self.data.id}, function(err, rows, fields){
				if(err) return reject(err.message);
				resolve(self);
			});
		});
	}

	/**
	 * list all records
	 * @param  {object} conn  connection object to mysql
	 * @return {promise}      promise object
	 */
	static list(conn) {
		return new Promise(function(resolve, reject){
			conn.query(`SELECT
							source.uuid, source.title, source.author, source.pubYear, source.cover, source.state, source.entryCount,
							GROUP_CONCAT(CONCAT(source_cat.id, '|', source_cat.title)) AS categories
						FROM source
						LEFT JOIN source_cat_rel on source_cat_rel.source = source.id
						LEFT JOIN source_cat on source_cat_rel.cat=source_cat.id
						GROUP BY source.id`, function(err, rows, fields){
				if (err) return reject(err.message);
				resolve(rows);
			});
		});
	}

	/**
	 * list all active records (with state set to STATE_ACTIVE const)
	 * @param  {object} conn  connection object to mysql
	 * @return {promise}      promise object
	 */
	static listActives(conn) {
		return new Promise(function(resolve, reject){
			conn.query(`SELECT
							\`source\`.uuid, \`source\`.title, \`source\`.author, \`source\`.pubYear, \`source\`.cover, \`source\`.state, \`source\`.entryCount,
							GROUP_CONCAT(CONCAT(source_cat.id, '|', source_cat.title)) AS categories,
							GROUP_CONCAT(CONCAT(source_lang.lang_from, ':', source_lang.lang_to)) AS langs
						FROM source
						LEFT JOIN source_cat_rel on source_cat_rel.source = \`source\`.id
						LEFT JOIN source_cat on source_cat_rel.cat=source_cat.id
						LEFT JOIN source_lang on source_lang.\`source\`=\`source\`.id
						WHERE \`source\`.state=${consts.v.STATE_ACTIVE}
						GROUP BY \`source\`.id`, function(err, rows, fields){
				if (err) return reject(err.message);
				resolve(rows);
			});
		});
	}

	/**
	 * add a record to source_lang table.
	 * @param  {array} langs  array of lang objects like: {from: 1, to: 2}
	 * @return {promise}      promise object
	 */
	addLangs(langs) {
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.id) reject('id is required.');
			self.removeLangs().then(
				function(self){
					if(!langs.length) resolve(langs);
					var data = [];
					for(let i in langs)
						data.push([self.data.id, langs[i].from, langs[i].to]);
					self.conn.query('INSERT INTO source_lang (source, lang_from, lang_to) VALUES ?', [data], function(err, result){
						if(err) return reject('db error.');
						resolve(langs);
					});
				}, function(err) {
					reject(err);
				}
			);
		});
	}

	removeLangs() {
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.id) reject('id is required.');
			self.conn.query(`DELETE FROM source_lang WHERE ?`, {source: self.data.id}, function(err, result){
				if(err) return reject('db error.');
				resolve(self);
			});
		});
	}

	getLangs() {
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.id) reject('id is required.');
			self.conn.query(
				`SELECT * FROM source_lang
				 WHERE ?`,
				{source: self.data.id}, function(err, rows, fields){
					if(err) return reject('db error.');
					resolve(rows);
			});
		});
	}

	relateCategories(categories) {
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.id) reject('id is required.');
			self.unrelateAllCategories().then(
				function(self){
					if(!categories.length) resolve(categories);
					var data = [];
					for(let i in categories)
						data.push([self.data.id, categories[i]]);
					self.conn.query('INSERT INTO source_cat_rel (source, cat) VALUES ?', [data], function(err, result){
						if(err) return reject('db error.');
						resolve(categories);
					});
				}, function(err) {
					reject(err);
				}
			);
		});
	}

	unrelateAllCategories() {
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.id) reject('id is required.');
			self.conn.query(`DELETE FROM source_cat_rel WHERE ?`, {source: self.data.id}, function(err, result){
				if(err) return reject('db error.');
				resolve(self);
			});
		});
	}

	getRelatedCategories() {
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.id) reject('id is required.');
			self.conn.query(
				`SELECT source_cat.* FROM source_cat_rel
				 join source_cat on source_cat_rel.cat=source_cat.id
				 where ?`,
				{source: self.data.id}, function(err, rows, fields){
					if(err) return reject('db error.');
					resolve(rows);
			});

		});
	}

	updateEntryCount(){
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.id) reject('id is required.');
			self.conn.query('SELECT COUNT(`source`) AS sum FROM entry WHERE ?', {source: self.data.id}, function(err, rows, fields){
				if(err) return reject('db error.');
				var sum = rows[0].sum;
				self.conn.query('UPDATE source SET ? WHERE ?', [{entryCount: sum}, {id: self.data.id}], function(err){
					if(err) return reject('db error.');
					self.data.entryCount = sum;
					resolve(self);
				});
			});
		});
	}
}

module.exports = DictionaryModel;