<?php
 namespace TCMS\Migration;
 use TCMS\TException;
 if(!function_exists("showLogInfo")) {
 function showLogInfo($text) {
 echo "\e[1;34m$text\e[0m\n";
 }
 function showLogError($text) {
 echo "\e[1;31m$text\e[0m\n";
 }
 function showLogSuccess($text) {
 echo "\e[1;32m$text\e[0m\n";
 }
 }
 class MigrationDb {
 private $__mdb = null;
 public $__cur_version = 0;
 public $__file_name = "";
 public $__isOK = true;
 public $_isMongodb = false;
 public $_pathToMigration = false;
 public function create(string $tableName, Callable $setColumnFunction) {
 if(empty($tableName) || empty($setColumnFunction)) {
 throw new TException("Vui lòng truyền đầy đủ tham số cho hàm table");
 }
 $tableColumn = new TableColumn();
 if($setColumnFunction != null && is_callable($setColumnFunction)) call_user_func($setColumnFunction, $tableColumn);
 if($this->__mdb == null) {
 $this->__mdb = \Db::table("asd");
 }
 if($this->isTableExist($tableName) === false) {
 $this->createTable($tableName, $tableColumn);
 }
 }
 private function getCreateQueryMySql(string $tableName, TableColumn $tableColumn) {
 $dbConfig = \Config::$dbConfig;
 $query = "CREATE TABLE `$tableName` (";
 $primaryColumn = null;
 $uniques = [];
 $foreigns = [];
 foreach ($tableColumn->columns as $k => $v) {
 if ($v->_isUnique) {
 $uniques[] = $v;
 }
 if ($v->_isPrimaryKey) {
 $primaryColumn = $v->_name;
 }
 if ($v->_foreignKey != null && $v->_foreignTable != null) {
 $foreigns[] = [ 'table_foreign' => $v->_foreignTable, 'column_foreign' => $v->_foreignKey, 'column' => $v->_name, 'deleteOnCase' => $v->_deleteOnCase ];
 }
 $query .= $this->createColumnType($v, $dbConfig);
 }
 if(empty($primaryColumn) === false) {
 $query .= "PRIMARY KEY (`$primaryColumn`),\n";
 }
 if(empty($uniques) === false) {
 $uniqueStr = "";
 foreach($uniques as $unique) {
 $uniqueStr .= "`$unique->_name`,";
 }
 if($uniqueStr != "") {
 $uniqueStr = substr($uniqueStr, 0, strlen($uniqueStr) - 1);
 $query .= "UNIQUE KEY($uniqueStr),\n";
 }
 }
 if(empty($foreigns) === false) {
 foreach($foreigns as $foreign) {
 $column = $foreign['column'];
 $table = $foreign['table_foreign'];
 $c = $foreign['column_foreign'];
 $deleteOncase = $foreign['deleteOnCase'] ? " ON DELETE CASCADE" : "";
 $query .= "FOREIGN KEY(`$column`) REFERENCES `$table`(`$c`)$deleteOncase,\n";
 }
 }
 $query = substr($query, 0, strlen($query) - 2);
 $query .= ')';
 return $query;
 }
 private function getCreateQueryPostgres(string $tableName, TableColumn $tableColumn) {
 $query = "CREATE TABLE $tableName (";
 $primaryColumn = null;
 $uniques = [];
 $foreigns = [];
 foreach ($tableColumn->columns as $k => $v) {
 if ($v->_isUnique) {
 $uniques[] = $v;
 }
 if ($v->_isPrimaryKey) {
 $primaryColumn = $v->_name;
 }
 if ($v->_foreignKey != null && $v->_foreignTable != null) {
 $foreigns[] = [ 'table_foreign' => $v->_foreignTable, 'column_foreign' => $v->_foreignKey, 'column' => $v->_name, 'deleteOnCase' => $v->_deleteOnCase ];
 }
 $query .= $this->createColumnTypePostgres($v, null);
 }
 if(empty($foreigns) === false) {
 foreach($foreigns as $foreign) {
 $column = $foreign['column'];
 $table = $foreign['table_foreign'];
 $c = $foreign['column_foreign'];
 $deleteOncase = $foreign['deleteOnCase'] ? " ON DELETE CASCADE" : "";
 $query .= "FOREIGN KEY($column) REFERENCES $table($c)$deleteOncase,\n";
 }
 }
 $query = substr($query, 0, strlen($query) - 2);
 $query .= ')';
 return $query;
 }
 private function createTable(string $tableName, TableColumn $tableColumn) {
 $dbConfig = \Config::$dbConfig;
 switch($dbConfig['driver']) {
 case 'postgres': $query = $this->getCreateQueryPostgres($tableName, $tableColumn);
 break;
 case 'mongodb': showLogError("Mongodb không hỗ trợ tạo table");
 break;
 default: $query = $this->getCreateQueryMySql($tableName, $tableColumn);
 break;
 }
 try {
 $this->__mdb->query($query)->exec();
 $this->showLogFileName();
 showLogSuccess("Tạo table $tableName thành công!");
 }
 catch (TException $ex) {
 $this->__isOK = false;
 $this->showLogFileName();
 showLogError("Tạo table $tableName thất bại: $ex");
 }
 }
 private function createColumnType(TableColumnInfo $v, $dbConfig) {
 $query = '';
 switch ($v->_type) {
 case MIG_FIELD_DATA_TYPE::INTEGER: $query .= "`$v->_name` INT";
 break;
 case MIG_FIELD_DATA_TYPE::STRING: $query .= "`$v->_name` VARCHAR($v->_length)";
 $charset = $v->_charset;
 $collation = $v->_collate;
 if(empty($collation)) {
 $collation = $dbConfig['collation'];
 }
 if(empty($charset)) {
 $charset = $dbConfig['charset'];
 }
 $query .= " CHARACTER SET $charset COLLATE $collation";
 break;
 case MIG_FIELD_DATA_TYPE::TEXT: $query .= "`$v->_name` TEXT";
 $charset = $v->_charset;
 $collation = $v->_collate;
 if(empty($collation)) {
 $collation = $dbConfig['collation'];
 }
 if(empty($charset)) {
 $charset = $dbConfig['charset'];
 }
 $query .= " CHARACTER SET $charset COLLATE $collation";
 break;
 case MIG_FIELD_DATA_TYPE::BIG_INTEGER: $query .= "`$v->_name` BIGINT";
 break;
 case MIG_FIELD_DATA_TYPE::BOOLEAN: $query .= "`$v->_name` TINYINT(1)";
 break;
 case MIG_FIELD_DATA_TYPE::CHAR: $query .= "`$v->_name` CHAR($v->_length)";
 $charset = $v->_charset;
 $collation = $v->_collate;
 if(empty($collation)) {
 $collation = $dbConfig['collation'];
 }
 if(empty($charset)) {
 $charset = $dbConfig['charset'];
 }
 $query .= " CHARACTER SET $charset COLLATE $collation";
 break;
 case MIG_FIELD_DATA_TYPE::DATE: $query .= "`$v->_name` DATE";
 break;
 case MIG_FIELD_DATA_TYPE::DATETIME: $query .= "`$v->_name` DATETIME";
 break;
 case MIG_FIELD_DATA_TYPE::DECIMAL: $query .= "`$v->_name` DECIMAL($v->_length,$v->_residual)";
 break;
 case MIG_FIELD_DATA_TYPE::DOUBLE: $query .= "`$v->_name` DOUBLE";
 break;
 case MIG_FIELD_DATA_TYPE::SMALL_INTEGER: $query .= "`$v->_name` SMALLINT";
 break;
 case MIG_FIELD_DATA_TYPE::TIME: $query .= "`$v->_name` TIME";
 break;
 case MIG_FIELD_DATA_TYPE::TINY_INTEGER: $query .= "`$v->_name` TINYINT($v->_length)";
 break;
 }
 if ($v->_isNull === false) {
 $query .= " NOT NULL";
 }
 else {
 $query .= " NULL";
 }
 if ($v->_autoIncrement) {
 $query .= " AUTO_INCREMENT";
 }
 if ($v->_defaultValue != null) {
 $defaultValue = $v->_defaultValue;
 $query .= " DEFAULT '$defaultValue'";
 }
 $query .= ",\n";
 return $query;
 }
 private function createColumnTypePostgres(TableColumnInfo $v, $dbConfig) {
 $query = '';
 switch ($v->_type) {
 case MIG_FIELD_DATA_TYPE::INTEGER: if ($v->_autoIncrement) {
 $query .= "$v->_name serial";
 }
 else {
 $query .= "$v->_name int";
 }
 break;
 case MIG_FIELD_DATA_TYPE::STRING: $query .= "$v->_name VARCHAR($v->_length)";
 break;
 case MIG_FIELD_DATA_TYPE::TEXT: $query .= "$v->_name TEXT";
 break;
 case MIG_FIELD_DATA_TYPE::BIG_INTEGER: if ($v->_autoIncrement) {
 $query .= "$v->_name bigserial";
 }
 else {
 $query .= "$v->_name BIGINT";
 }
 break;
 case MIG_FIELD_DATA_TYPE::BOOLEAN: $query .= "$v->_name smallint";
 break;
 case MIG_FIELD_DATA_TYPE::CHAR: $query .= "$v->_name CHAR($v->_length)";
 break;
 case MIG_FIELD_DATA_TYPE::DATE: $query .= "$v->_name DATE";
 break;
 case MIG_FIELD_DATA_TYPE::DATETIME: $query .= "$v->_name timestamp";
 break;
 case MIG_FIELD_DATA_TYPE::DECIMAL: $query .= "$v->_name DECIMAL($v->_length,$v->_residual)";
 break;
 case MIG_FIELD_DATA_TYPE::DOUBLE: $query .= "$v->_name real";
 break;
 case MIG_FIELD_DATA_TYPE::SMALL_INTEGER: if ($v->_autoIncrement) {
 $query .= "$v->_name serial";
 }
 else {
 $query .= "$v->_name SMALLINT";
 }
 break;
 case MIG_FIELD_DATA_TYPE::TIME: $query .= "$v->_name TIME";
 break;
 case MIG_FIELD_DATA_TYPE::TINY_INTEGER: $query .= "$v->_name smallint";
 break;
 }
 if ($v->_isNull === false) {
 $query .= " NOT NULL";
 }
 else {
 $query .= " NULL";
 }
 if($v->_isPrimaryKey) {
 $query .= " PRIMARY KEY";
 }
 if ($v->_isUnique) {
 $query .= " UNIQUE";
 }
 if ($v->_defaultValue != null) {
 $defaultValue = $v->_defaultValue;
 $query .= " DEFAULT '$defaultValue'";
 }
 $query .= ",\n";
 return $query;
 }
 public function update(string $tableName, Callable $setColumnFunction) {
 if(empty($tableName) || empty($setColumnFunction)) {
 throw new TException("Vui lòng truyền đầy đủ tham số cho hàm update");
 }
 $tableColumn = new TableColumn();
 if($setColumnFunction != null && is_callable($setColumnFunction)) call_user_func($setColumnFunction, $tableColumn);
 if($this->__mdb == null) {
 $this->__mdb = \Db::table("asd");
 }
 if($this->isTableExist($tableName)) {
 $this->updateTable($tableName, $tableColumn);
 }
 }
 public function updateOrCreate(string $tableName, Callable $setColumnFunction) {
 if(empty($tableName) || empty($setColumnFunction)) {
 throw new TException("Vui lòng truyền đầy đủ tham số cho hàm update");
 }
 $tableColumn = new TableColumn();
 if($setColumnFunction != null && is_callable($setColumnFunction)) call_user_func($setColumnFunction, $tableColumn);
 if($this->__mdb == null) {
 $this->__mdb = \Db::table("asd");
 }
 if($this->isTableExist($tableName)) {
 $this->updateTable($tableName, $tableColumn);
 }
 else {
 $this->createTable($tableName, $tableColumn);
 }
 }
 private function updateTable(string $tableName, TableColumn $tableColumn) {
 if($this->__mdb == null) {
 $this->__mdb = \Db::table("asd");
 }
 $dbConfig = \Config::$dbConfig;
 switch($dbConfig['driver']) {
 case 'postgres': $this->updateTablePostgres($tableName, $tableColumn);
 break;
 case 'mongodb': $this->updateTableMongodb($tableName, $tableColumn);
 break;
 default: $this->updateTableMySql($tableName, $tableColumn);
 break;
 }
 }
 private function updateTableMySql(string $tableName, TableColumn $tableColumn) {
 $dbConfig = \Config::$dbConfig;
 foreach($tableColumn->columns as $column) {
 try {
 $columnName = $column->_name;
 if($this->isColumnExist($tableName, $column->_name)) {
 $query = "ALTER TABLE `$tableName` DROP `$columnName`";
 $this->__mdb->query($query)->exec();
 }
 $query = "ALTER TABLE `$tableName` ADD ";
 $query .= $this->createColumnType($column, $dbConfig);
 $query = substr($query, 0, strlen($query) - 2);
 $this->__mdb->query($query)->exec();
 $this->showLogFileName();
 showLogSuccess("Tạo column $columnName trong table $tableName thành công!");
 }
 catch(TException $ex) {
 $this->__isOK = false;
 $this->showLogFileName();
 showLogError("Tạo column $columnName trong table $tableName Thất bại: $ex");
 }
 }
 }
 private function updateTableMongodb(string $tableName, TableColumn $tableColumn) {
 $dbm = \Db::table($tableName);
 $data = $dbm->toList();
 foreach($data as $k => $value) {
 $isChanged = false;
 foreach($tableColumn->columns as $column) {
 $clName = $column->_name;
 if(!isset($value->$clName)) {
 $isChanged = true;
 if(!empty($column->_defaultValue)) {
 $value->$clName = $column->_defaultValue;
 }
 else {
 switch($column->_type) {
 case MIG_FIELD_DATA_TYPE::INTEGER: case MIG_FIELD_DATA_TYPE::BOOLEAN: case MIG_FIELD_DATA_TYPE::DOUBLE: case MIG_FIELD_DATA_TYPE::BIG_INTEGER: case MIG_FIELD_DATA_TYPE::SMALL_INTEGER: case MIG_FIELD_DATA_TYPE::TINY_INTEGER: case MIG_FIELD_DATA_TYPE::DECIMAL: $value->$clName = 0;
 break;
 case MIG_FIELD_DATA_TYPE::TIME: $curDateTime = new \DateTime();
 $value->$clName = $curDateTime->format('H:i:m');
 break;
 case MIG_FIELD_DATA_TYPE::DATE: $curDateTime = new \DateTime();
 $value->$clName = $curDateTime->format('Y-m-d');
 break;
 case MIG_FIELD_DATA_TYPE::DATETIME: $curDateTime = new \DateTime();
 $value->$clName = $curDateTime->format('Y-m-d H:i:m');
 break;
 case MIG_FIELD_DATA_TYPE::OBJECT_ID: $value->$clName = '54759eb3c090d83494e2d804';
 break;
 default: $value->$clName = '';
 }
 }
 }
 }
 if($isChanged) {
 if($dbm->update($value)) {
 }
 }
 }
 showLogSuccess("Update table $tableName thành công!");
 try {
 $dateTime = substr($this->__file_name, 0, 17);
 $ymd = \DateTime::createFromFormat('d-m-Y-His', $dateTime);
 $fp = fopen($this->_pathToMigration . 'last-update.txt', 'w');
 fwrite($fp, $ymd->format('Y-m-d H:i:s'));
 fclose($fp);
 }
 catch(\Exception $ex) {
 }
 }
 private function updateTablePostgres(string $tableName, TableColumn $tableColumn) {
 $dbConfig = \Config::$dbConfig;
 foreach($tableColumn->columns as $column) {
 try {
 $columnName = $column->_name;
 if($this->isColumnExist($tableName, $column->_name)) {
 $query = "ALTER TABLE $tableName DROP $columnName";
 $this->__mdb->query($query)->exec();
 }
 $query = "ALTER TABLE $tableName ADD ";
 $query .= $this->createColumnTypePostgres($column, $dbConfig);
 $query = substr($query, 0, strlen($query) - 2);
 $this->__mdb->query($query)->exec();
 $this->showLogFileName();
 showLogSuccess("Tạo column $columnName trong table $tableName thành công!");
 }
 catch(TException $ex) {
 $this->__isOK = false;
 $this->showLogFileName();
 showLogError("Tạo column $columnName trong table $tableName Thất bại: $ex");
 }
 }
 }
 private function showLogFileName() {
 if($this->__file_name == "") echo "";
 else echo $this->__file_name . ": ";
 }
 public function isColumnExist(string $tableName, string $columnName) {
 if($this->__mdb == null) {
 $this->__mdb = \Db::table("asd");
 }
 $dbConfig = \Config::$dbConfig;
 switch($dbConfig['driver']) {
 case 'postgres': $query = "SELECT $columnName FROM $tableName LIMIT 1;";
 break;
 default: $query = "SELECT `$columnName` FROM `$tableName` LIMIT 1;";
 break;
 }
 try {
 $this->__mdb->query($query)->exec();
 return true;
 }
 catch(TException $ex) {
 return false;
 }
 }
 public function isTableExist(string $tableName) {
 if($this->__mdb == null) {
 $this->__mdb = \Db::table("asd");
 }
 $dbConfig = \Config::$dbConfig;
 switch($dbConfig['driver']) {
 case 'postgres': $query = "SELECT 1 FROM $tableName LIMIT 1;";
 break;
 case 'mongodb': $ddq = \Db::table($tableName)->limit(1)->toList();
 if($ddq) return true;
 return false;
 break;
 default: $query = "SELECT 1 FROM `$tableName` LIMIT 1;";
 break;
 }
 try {
 $this->__mdb->query($query)->exec();
 return true;
 }
 catch(TException $ex) {
 return false;
 }
 }
 public function ___insertToMigration() {
 try {
 if($this->__mdb == null) {
 $this->__mdb = \Db::table("asd");
 }
 $dbConfig = \Config::$dbConfig;
 switch($dbConfig['driver']) {
 case 'postgres': $this->__mdb->query("INSERT INTO migrations(file_name,version_index) VALUES(?,?)", [$this->__file_name, $this->__cur_version])->exec();
 break;
 default: $this->__mdb->query("INSERT INTO migrations(`file_name`,`version_index`) VALUES(?,?)", [$this->__file_name, $this->__cur_version])->exec();
 break;
 }
 }
 catch (TException $ex) {
 }
 }
 public function drop(string $tableName) {
 if(empty($tableName)) {
 throw new TException("Vui lòng truyền tên table cho hàm delete");
 }
 if($this->__mdb == null) {
 $this->__mdb = \Db::table("asd");
 }
 try {
 $dbConfig = \Config::$dbConfig;
 switch($dbConfig['driver']) {
 case 'postgres': $this->__mdb->query("DROP TABLE $tableName")->exec();
 break;
 default: $this->__mdb->query("DROP TABLE `$tableName`")->exec();
 break;
 }
 }
 catch (TException $ex) {
 showLogError("drop table $tableName error: " . $ex->getMessage());
 }
 }
 public function dropColumn(string $tableName, string $columnName) {
 if(empty($tableName) || empty($columnName)) {
 throw new TException("Vui lòng truyền dữ liệu cho hàm dropColumn");
 }
 if($this->__mdb == null) {
 $this->__mdb = \Db::table("asd");
 }
 try {
 $dbConfig = \Config::$dbConfig;
 switch($dbConfig['driver']) {
 case 'postgres': $this->__mdb->query("ALTER TABLE $tableName DROP $columnName")->exec();
 break;
 default: $this->__mdb->query("ALTER TABLE `$tableName` DROP `$columnName`")->exec();
 break;
 }
 }
 catch (TException $ex) {
 showLogError("drop column $columnName error: " . $ex->getMessage());
 }
 }
 public function query(string $queryString, array $prepareData = null) {
 if(empty($queryString)) {
 throw new TException("Vui lòng truyền query cho hàm query");
 }
 if($this->__mdb == null) {
 $this->__mdb = \Db::table("sdsa");
 }
 return $this->__mdb->query($queryString, $prepareData)->exec();
 }
 }
 class TableColumn {
 public $columns = [];
 public function string(string $name, int $length = 256) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::STRING);
 $column->length($length);
 $this->columns[$name] = $column;
 return $column;
 }
 public function char(string $name, int $length) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::CHAR);
 $column->length($length);
 $this->columns[$name] = $column;
 return $column;
 }
 public function text(string $name) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::TEXT);
 $this->columns[$name] = $column;
 return $column;
 }
 public function int(string $name, bool $autoIncrement = false) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::INTEGER);
 $column->autoIncrement($autoIncrement);
 $this->columns[$name] = $column;
 return $column;
 }
 public function bigInt(string $name, bool $autoIncrement = false) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::BIG_INTEGER);
 $column->autoIncrement($autoIncrement);
 $this->columns[$name] = $column;
 return $column;
 }
 public function smallInt(string $name, bool $autoIncrement = false) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::SMALL_INTEGER);
 $column->autoIncrement($autoIncrement);
 $this->columns[$name] = $column;
 return $column;
 }
 public function tinyInt(string $name) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::TINY_INTEGER);
 $this->columns[$name] = $column;
 return $column;
 }
 public function double(string $name) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::DOUBLE);
 $this->columns[$name] = $column;
 return $column;
 }
 public function decimal(string $name, int $length, int $residual = 0) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::DECIMAL);
 $column->length($length);
 $column->residual($residual);
 $this->columns[$name] = $column;
 return $column;
 }
 public function boolean(string $name) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::BOOLEAN);
 $this->columns[$name] = $column;
 return $column;
 }
 public function dateTime(string $name) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::DATETIME);
 $this->columns[$name] = $column;
 return $column;
 }
 public function date(string $name) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::DATE);
 $this->columns[$name] = $column;
 return $column;
 }
 public function time(string $name) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::TIME);
 $this->columns[$name] = $column;
 return $column;
 }
 public function objectId(string $name) {
 $column = new TableColumnInfo($name, MIG_FIELD_DATA_TYPE::OBJECT_ID);
 $this->columns[$name] = $column;
 return $column;
 }
 }
 class TableColumnInfo {
 public $_name = null;
 public $_type = -1;
 public $_length = 0;
 public $_isNull = true;
 public $_isPrimaryKey = false;
 public $_autoIncrement = false;
 public $_defaultValue = null;
 public $_foreignTable = null;
 public $_foreignKey = null;
 public $_deleteOnCase = false;
 public $_isUnique = false;
 public $_collate = null;
 public $_charset = null;
 private $_residual = 0;
 public function __construct(string $name, int $type) {
 $this->_name = $name;
 $this->_type = $type;
 }
 public function autoIncrement($autoIncrement = true) {
 $this->_autoIncrement = $autoIncrement;
 return $this;
 }
 public function nullable($isNull = true) {
 $this->_isNull = $isNull;
 return $this;
 }
 public function primaryKey($isPrimary = true) {
 $this->_isPrimaryKey = $isPrimary;
 $this->_isNull = false;
 return $this;
 }
 public function unique($isUnique = true) {
 $this->_isUnique = $isUnique;
 return $this;
 }
 public function default($value) {
 $this->_defaultValue = $value;
 return $this;
 }
 public function collation(string $collation, string $charset) {
 $this->_collate = $collation;
 $this->_charset = $charset;
 return $this;
 }
 public function length(int $length) {
 $this->_length = $length;
 return $this;
 }
 public function residual(int $residual) {
 $this->_residual = $residual;
 return $this;
 }
 public function foreign(string $tableForeign, string $columnForeign = 'id', $deleteOncase = false) {
 $this->_foreignTable = $tableForeign;
 $this->_foreignKey = $columnForeign;
 $this->_deleteOnCase = $deleteOncase;
 $this->_isNull = false;
 return $this;
 }
 }
 class MIG_FIELD_DATA_TYPE {
 const STRING = 0;
 const TEXT = 1;
 const BOOLEAN = 2;
 const INTEGER = 3;
 const DOUBLE = 4;
 const CHAR = 5;
 const BIG_INTEGER = 6;
 const SMALL_INTEGER = 7;
 const TINY_INTEGER = 8;
 const DATETIME = 9;
 const DATE = 10;
 const TIME = 11;
 const DECIMAL = 12;
 const OBJECT_ID = 13;
 const UUID = 14;
 }
 