Error-Handling

This commit is contained in:
Sam 2024-12-07 02:42:25 +01:00
parent fc19ac2672
commit a5aacf2f14
8 changed files with 267 additions and 31 deletions

View File

@ -1,9 +1,12 @@
"use strict"
const mysql = require("mysql"); const mysql = require("mysql");
const Select = require("./lib/Select"); const Select = require("./lib/Select");
const Insert = require("./lib/Insert"); const Insert = require("./lib/Insert");
const Delete = require("./lib/Delete"); const Delete = require("./lib/Delete");
const Update = require("./lib/Update"); const Update = require("./lib/Update");
const { CreateTable, Structure, AlterTable } = require("./lib/Tables"); const { CreateTable, Structure, AlterTable } = require("./lib/Tables");
const { throwTypeError } = require("./lib/Errors");
/** /**
* @typedef {Object} InstanceOptions * @typedef {Object} InstanceOptions
@ -38,6 +41,8 @@ class awSQL {
customIdentifier: false, customIdentifier: false,
isDefault: false, isDefault: false,
}){ }){
if (!password) throw new Error(`Can't create instance: No password given`);
if (!username) throw new Error(`Can't create instance: No username given`);
const identifier = options.customIdentifier||`${username}@${hostname}`; // Set identifier to given identifier or [username]@[hostname] const identifier = options.customIdentifier||`${username}@${hostname}`; // Set identifier to given identifier or [username]@[hostname]
// If an instance with that identifier exists, throw error // If an instance with that identifier exists, throw error
if (this.#instances[identifier]) throw new Error(`Can't create new instance with identifier "${identifier}": An instance with the same name already exists`); if (this.#instances[identifier]) throw new Error(`Can't create new instance with identifier "${identifier}": An instance with the same name already exists`);
@ -57,11 +62,12 @@ class awSQL {
getInstance(identifier) { getInstance(identifier) {
if (Object.keys(this.#instances).length===0) return undefined; // If no instance is found at all return -> Safety return if (Object.keys(this.#instances).length===0) return undefined; // If no instance is found at all return -> Safety return
// If no identifier is set return default or first instance // If no identifier is set return default or first instance
if (!identifier) return if (!identifier) {
this.#default? return this.#default?
this.#instances[this.#default] // If default exists get that this.#instances[this.#default] // If default exists get that
: :
this.#instances[Object.keys(this.#instances)[0]]; // Otherwise get instance with that identifier this.#instances[Object.keys(this.#instances)[0]]; // Otherwise return first instance
}
return this.#instances[identifier]; // If identifier given return that instance return this.#instances[identifier]; // If identifier given return that instance
} }
@ -80,6 +86,7 @@ class awSQL {
*/ */
deleteInstance(identifier){ deleteInstance(identifier){
if (!identifier) throw new Error("Can't delete Instance: No identifier set"); if (!identifier) throw new Error("Can't delete Instance: No identifier set");
if (typeof identifier !== "string") throwTypeError("string", identifier);
if (!this.#instances[identifier]) throw new Error(`Can't delete Instance '${identifier}': No Instance`); if (!this.#instances[identifier]) throw new Error(`Can't delete Instance '${identifier}': No Instance`);
this.#instances[identifier].destroy(); // Memory: Close connection this.#instances[identifier].destroy(); // Memory: Close connection
if (this.#default === identifier) this.#default = undefined; // If this instance was default, clear it from default if (this.#default === identifier) this.#default = undefined; // If this instance was default, clear it from default
@ -156,8 +163,11 @@ class Instance {
* @param {Array<Any>} values - An array holding all replacable ?-values from left to right. * @param {Array<Any>} values - An array holding all replacable ?-values from left to right.
* @returns {Any} - The individual result of your query * @returns {Any} - The individual result of your query
*/ */
queryRaw(queryString, values){ queryRaw(queryString, values=[]){
return new Promise((resolve, reject) => { if (!queryString) throw new Error(`queryString must not be empty`);
if (typeof queryString !== "string") throwTypeError("string", queryString);
if (!Array.isArray(values)) throwTypeError("array", values);
return new Promise((resolve) => {
if (!this.#connection) throw new Error("Querying failed: No connection"); if (!this.#connection) throw new Error("Querying failed: No connection");
this.#connection.query(queryString, values, (err, result) => { this.#connection.query(queryString, values, (err, result) => {
if (err) throw err; if (err) throw err;
@ -172,6 +182,7 @@ class Instance {
* @returns {Array<String>} * @returns {Array<String>}
*/ */
async getDatabases (excludeSchema=false){ async getDatabases (excludeSchema=false){
if (typeof excludeSchema !== "boolean") throwTypeError("boolean", excludeSchema);
let dbs = await this.queryRaw("SHOW DATABASES;"); let dbs = await this.queryRaw("SHOW DATABASES;");
if (excludeSchema) dbs = dbs.filter((db)=>db.Database!=="information_schema") if (excludeSchema) dbs = dbs.filter((db)=>db.Database!=="information_schema")
return dbs.map(db => db.Database); return dbs.map(db => db.Database);
@ -183,6 +194,8 @@ class Instance {
* @returns {this} * @returns {this}
*/ */
selectDatabase(name){ selectDatabase(name){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
this.#selectedDatabase = name; this.#selectedDatabase = name;
return this; return this;
} }
@ -207,6 +220,8 @@ class Instance {
* @returns {Select} * @returns {Select}
*/ */
select(from, ...columns){ select(from, ...columns){
if (!from) throw new Error("Can't prepare select: No 'from' given");
if (typeof from !== "string") throwTypeError("string", from);
return new Select(this, this.#selectedDatabase, from, columns); return new Select(this, this.#selectedDatabase, from, columns);
} }
@ -217,6 +232,8 @@ class Instance {
* @returns {Insert} * @returns {Insert}
*/ */
insert(into){ insert(into){
if (!into) throw new Error("Can't prepare insert: No 'into' given");
if (typeof into !== "string") throwTypeError("string", into);
return new Insert(this, this.#selectedDatabase, into); return new Insert(this, this.#selectedDatabase, into);
} }
@ -226,6 +243,8 @@ class Instance {
* @returns {Delete} * @returns {Delete}
*/ */
delete(from){ delete(from){
if (!from) throw new Error("Can't prepare delete: No 'from' given");
if (typeof from !== "string") throwTypeError("string", from);
return new Delete(this, this.#selectedDatabase, from); return new Delete(this, this.#selectedDatabase, from);
} }
@ -235,6 +254,8 @@ class Instance {
* @returns {Update} * @returns {Update}
*/ */
update(table){ update(table){
if (!table) throw new Error("Can't prepare update: No 'table' given");
if (typeof table !== "string") throwTypeError("string", table);
return new Update(this, this.#selectedDatabase, table); return new Update(this, this.#selectedDatabase, table);
} }
@ -245,6 +266,8 @@ class Instance {
* @returns {Any} * @returns {Any}
*/ */
async dropDatabase (database){ async dropDatabase (database){
if (!database) throw new Error(`Can't drop database: No database given`);
if (typeof database !== "string") throwTypeError("string", database);
return await this.queryRaw(`DROP DATABASE ${database};`); return await this.queryRaw(`DROP DATABASE ${database};`);
} }
@ -254,6 +277,8 @@ class Instance {
* @returns {Any} * @returns {Any}
*/ */
async dropTable(table){ async dropTable(table){
if (!table) throw new Error("Can't drop table: No table set");
if (typeof table !== "string") throwTypeError("string", table);
if (!this.#selectedDatabase) throw new Error(`Can't drop table '${table}': Database not set`); if (!this.#selectedDatabase) throw new Error(`Can't drop table '${table}': Database not set`);
return await this.queryRaw(`DROP TABLE ${this.#selectedDatabase}.${table}`); return await this.queryRaw(`DROP TABLE ${this.#selectedDatabase}.${table}`);
} }
@ -265,6 +290,8 @@ class Instance {
* @returns {Any} * @returns {Any}
*/ */
async createDatabase(name){ async createDatabase(name){
if (!name) throw new Error(`Can't create database: No name given`);
if (typeof name !== "string") throwTypeError("string", name);
return await this.queryRaw(`CREATE DATABASE ${name};`); return await this.queryRaw(`CREATE DATABASE ${name};`);
} }
@ -274,6 +301,8 @@ class Instance {
* @returns {CreateTable} * @returns {CreateTable}
*/ */
createTable(name){ createTable(name){
if (!name) throw new Error("Can't create table: No name given");
if (typeof name !== "string") throwTypeError("string", name);
return new CreateTable(this, this.#selectedDatabase, name); return new CreateTable(this, this.#selectedDatabase, name);
} }
@ -284,6 +313,8 @@ class Instance {
* @returns {AlterTable} * @returns {AlterTable}
*/ */
alterTable(name){ alterTable(name){
if (!name) throw new Error("Can't alter table: No name given");
if (typeof name !== "string") throwTypeError("string", name);
return new AlterTable(this, this.#selectedDatabase, name); return new AlterTable(this, this.#selectedDatabase, name);
} }
@ -302,6 +333,8 @@ class Instance {
* @returns {Structure} * @returns {Structure}
*/ */
async getStructure(table, database){ async getStructure(table, database){
if (!table) throw new Error("Can't get structure: table not given");
if (typeof table !== "string") throwTypeError("string", table);
if (!this.#selectedDatabase && !database) throw new Error(`Can't get structure of table ${table}: Database not selected`); if (!this.#selectedDatabase && !database) throw new Error(`Can't get structure of table ${table}: Database not selected`);
return new Structure(await this.queryRaw(`DESCRIBE ${database||this.#selectedDatabase}.${table};`)); return new Structure(await this.queryRaw(`DESCRIBE ${database||this.#selectedDatabase}.${table};`));
} }
@ -314,6 +347,9 @@ class Instance {
* @returns {CheckResult} * @returns {CheckResult}
*/ */
async checkStructure(table, desiredStructure, database){ async checkStructure(table, desiredStructure, database){
if (!table) throw new Error("Can't check structure: table not given");
if (typeof table !== "string") throwTypeError("string", table);
if (typeof desiredStructure !== "function") throwTypeError("function", desiredStructure);
if (!this.#selectedDatabase && !database) throw new Error(`Can't get structure of table ${table}: Database not selected`); if (!this.#selectedDatabase && !database) throw new Error(`Can't get structure of table ${table}: Database not selected`);
const dbStruc = (await this.getStructure(table, database||this.#selectedDatabase)).get(); // Get current structure -> Array<Objects> const dbStruc = (await this.getStructure(table, database||this.#selectedDatabase)).get(); // Get current structure -> Array<Objects>
const result = { const result = {
@ -351,6 +387,9 @@ class Instance {
* @returns {Any} * @returns {Any}
*/ */
async total(table){ async total(table){
if (!table) throw new Error("Can't get structure: table not given");
if (typeof table !== "string") throwTypeError("string", table);
if (!this.#selectedDatabase) throw new Error("Can't get total: No default table set");
return await new Select(this, this.#selectedDatabase, table).count(true).execute(); return await new Select(this, this.#selectedDatabase, table).count(true).execute();
} }
@ -371,7 +410,7 @@ class Instance {
*/ */
const awSQLInstance = new awSQL(); const awSQLInstance = new awSQL();
module.exports = {awSQLInstance, Structure}; module.exports = {awSQL: awSQLInstance, Structure};
/** /**
* @exports awSQLInstance * @exports awSQLInstance

View File

@ -1,3 +1,5 @@
const { throwTypeError } = require("./Errors");
/** /**
* Prepares a new Deletion * Prepares a new Deletion
*/ */
@ -23,6 +25,8 @@ class Delete {
* @returns {this} * @returns {this}
*/ */
selectDatabase(database){ selectDatabase(database){
if (!database) throw new Error("database must not be empty");
if (typeof database !== "string") throwTypeError("string", database);
this.#database = database; this.#database = database;
return this; return this;
} }
@ -35,6 +39,9 @@ class Delete {
* @returns {this} * @returns {this}
*/ */
where(string, values=[]){ where(string, values=[]){
if (!string) throw new Error("string must not be empty");
if (typeof string !== "string") throwTypeError("string", string);
if (!Array.isArray(values)) throwTypeError("array", values);
this.#where = string; this.#where = string;
this.#whereValues = values; this.#whereValues = values;
return this; return this;

15
lib/Errors.js Normal file
View File

@ -0,0 +1,15 @@
function throwTypeError(e, r){
throw new TypeError(`Expected '${e}'. Received ${r}`);
}
function throwRangeError(min,max,r){
throw new RangeError(`The argument must be between ${min} and ${max}. Received ${r}`);
}
function throwEnumError(e=[],r){
throw new RangeError(`The argument must be one of [${e.join(",")}]. Received '${r}'`);
}
module.exports = {throwTypeError, throwRangeError, throwEnumError};

View File

@ -1,3 +1,5 @@
const { throwTypeError } = require("./Errors");
/** /**
* Prepares a new insertion * Prepares a new insertion
*/ */
@ -20,6 +22,8 @@ class Insert {
* @returns {this} * @returns {this}
*/ */
selectDatabase(database){ selectDatabase(database){
if (!database) throw new Error("database must not be empty");
if (typeof database !== "string") throwTypeError("string", database);
this.#database = database; this.#database = database;
return this; return this;
} }
@ -29,7 +33,9 @@ class Insert {
* @param {Array<Object>} objects - Array containing objects to insert, where the key represents the column-name. All objects must have the same structure! * @param {Array<Object>} objects - Array containing objects to insert, where the key represents the column-name. All objects must have the same structure!
* @returns {this} * @returns {this}
*/ */
data(objects){ data(objects=[]){
if (!Array.isArray(objects)) throwTypeError("array", objects);
if (objects.length===0) throw new Error("data objects must not be empty");
this.#data = objects; this.#data = objects;
return this; return this;
} }

View File

@ -1,3 +1,4 @@
const { throwTypeError, throwEnumError } = require("./Errors");
/** /**
* Prepares a new Selection * Prepares a new Selection
@ -37,6 +38,8 @@ class Select {
* @returns {this} * @returns {this}
*/ */
selectDatabase(database){ selectDatabase(database){
if (!database) throw new Error("database must not be empty");
if (typeof database !== "string") throwTypeError("string", database);
this.#database = database; this.#database = database;
return this; return this;
} }
@ -61,6 +64,9 @@ class Select {
* @returns {this} * @returns {this}
*/ */
where(string, values=[]){ where(string, values=[]){
if (!string) throw new Error("string must not be empty");
if (typeof string !== "string") throwTypeError("string", string);
if (!Array.isArray(values)) throwTypeError("array", values);
this.#where = string; this.#where = string;
this.#whereValues = values; this.#whereValues = values;
return this; return this;
@ -75,6 +81,9 @@ class Select {
* @returns {this} * @returns {this}
*/ */
having(string, values = []){ having(string, values = []){
if (!string) throw new Error("string must not be empty");
if (typeof string !== "string") throwTypeError("string", string);
if (!Array.isArray(values)) throwTypeError("array", values);
this.#having = string; this.#having = string;
this.#havingValues = values; this.#havingValues = values;
return this; return this;
@ -89,7 +98,14 @@ class Select {
* @returns {this} * @returns {this}
*/ */
order(column, desc=false, aggregation){ order(column, desc=false, aggregation){
if (["MIN", "MAX", "COUNT", "SUM", "AVG"].includes(aggregation)){ if (!column) throw new Error("column must not be empty");
if (typeof column !== "string") throwTypeError("string", column);
if (typeof desc !== "boolean") throwTypeError("boolean", desc);
const POSSIBLE_AGGREGATION = ["MIN", "MAX", "COUNT", "SUM", "AVG"];
if (aggregation && POSSIBLE_AGGREGATION.includes(aggregation)){
throwEnumError(POSSIBLE_AGGREGATION, aggregation);
}
if (POSSIBLE_AGGREGATION.includes(aggregation)){
switch(aggregation){ switch(aggregation){
case "MIN": case "MIN":
column = `MIN(${column})`; column = `MIN(${column})`;
@ -122,6 +138,7 @@ class Select {
* @returns {this} * @returns {this}
*/ */
count(doParse=false){ count(doParse=false){
if (typeof doParse !== "boolean") throwTypeError("boolean", doParse);
this.#aggregator = "COUNT"; this.#aggregator = "COUNT";
this.#aggregatorParse = doParse; this.#aggregatorParse = doParse;
return this; return this;
@ -133,6 +150,7 @@ class Select {
* @returns {this} * @returns {this}
*/ */
sum(doParse=false){ sum(doParse=false){
if (typeof doParse !== "boolean") throwTypeError("boolean", doParse);
this.#aggregator ="SUM"; this.#aggregator ="SUM";
this.#aggregatorParse = doParse; this.#aggregatorParse = doParse;
return this; return this;
@ -144,6 +162,7 @@ class Select {
* @returns {this} * @returns {this}
*/ */
avg(doParse=false){ avg(doParse=false){
if (typeof doParse !== "boolean") throwTypeError("boolean", doParse);
this.#aggregator = "AVG"; this.#aggregator = "AVG";
this.#aggregatorParse = doParse; this.#aggregatorParse = doParse;
return this; return this;
@ -155,6 +174,7 @@ class Select {
* @returns {this} * @returns {this}
*/ */
group(...columns){ group(...columns){
if (columns.length===0) throw new Error("Arguments must not be empty");
this.#group = columns; this.#group = columns;
return this; return this;
} }
@ -169,6 +189,15 @@ class Select {
* @returns {this} * @returns {this}
*/ */
join(type, table, onOriginalColumn, onJoinedColumn, ...columns){ join(type, table, onOriginalColumn, onJoinedColumn, ...columns){
const POSSIBLE_TYPES = ["LEFT", "INNER", "RIGHT", "FULL OUTER"];
if (!POSSIBLE_TYPES.includes(type)) throwEnumError(POSSIBLE_TYPES, type);
if (!table) throw new Error("table must not be empty");
if (typeof table !== "string") throwTypeError("string", table);
if (!onOriginalColumn) throw new Error("onOriginalColumn must not be empty");
if (typeof onOriginalColumn !== "string") throwTypeError("string", onOriginalColumn);
if (!onJoinedColumn) throw new Error("onOriginalColumn must not be empty");
if (typeof onJoinedColumn !== "string") throwTypeError("string", onJoinedColumn);
if (columns.length===0) throw new Error("columns must not be empty");
this.#joins.push({ this.#joins.push({
type, type,
on: `%%FROM%%.${onOriginalColumn}=${table}.${onJoinedColumn}`, on: `%%FROM%%.${onOriginalColumn}=${table}.${onJoinedColumn}`,
@ -185,6 +214,10 @@ class Select {
* @returns {this} * @returns {this}
*/ */
limit(number, offset){ limit(number, offset){
if (!number) throw new Error("number must not be empty");
if (typeof number !== "number") throwTypeError("number", number);
if (!offset) throw new Error("offset must not be empty");
if (typeof offset !== "number") throwTypeError("number", offset);
this.#limit = { this.#limit = {
number, number,
offset offset
@ -199,6 +232,10 @@ class Select {
* @returns {this} * @returns {this}
*/ */
pagination(page, itemsPerPage){ pagination(page, itemsPerPage){
if (!page) throw new Error("page must not be empty");
if (typeof page !== "number") throwTypeError("number", page);
if (!itemsPerPage) throw new Error("itemsPerPage must not be empty");
if (typeof itemsPerPage !== "number") throwTypeError("number", itemsPerPage);
if (page<1) page=1; if (page<1) page=1;
this.#limit = { this.#limit = {
number: itemsPerPage, number: itemsPerPage,

View File

@ -1,3 +1,4 @@
const { throwTypeError, throwRangeError } = require("./Errors");
/** /**
@ -20,6 +21,8 @@ class AlterTable {
* @returns {this} * @returns {this}
*/ */
selectDatabase(database){ selectDatabase(database){
if (!database) throw new Error("database must not be empty");
if (typeof database !== "string") throwTypeError("string", database);
this.#database = database; this.#database = database;
return this; return this;
} }
@ -33,6 +36,8 @@ class AlterTable {
* @returns {this} * @returns {this}
*/ */
structure(struc){ structure(struc){
if (!struc) throw new Error("struc must not be empty");
if (typeof struc !== "function") throwTypeError("function", struc);
this.#structure = struc; this.#structure = struc;
return this; return this;
} }
@ -135,6 +140,8 @@ class CreateTable {
* @returns {this} * @returns {this}
*/ */
selectDatabase(database){ selectDatabase(database){
if (!database) throw new Error("database must not be empty");
if (typeof database !== "string") throwTypeError("string", database);
this.#database = database; this.#database = database;
return this; return this;
} }
@ -145,6 +152,8 @@ class CreateTable {
* @returns {this} * @returns {this}
*/ */
name(name){ name(name){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
this.#name = name; this.#name = name;
return this; return this;
} }
@ -155,6 +164,8 @@ class CreateTable {
* @returns {this} * @returns {this}
*/ */
structure(struc){ structure(struc){
if (!struc) throw new Error("struc must not be empty");
if (typeof struc !== "function") throwTypeError("function", struc);
this.#structure = struc; this.#structure = struc;
return this; return this;
} }
@ -207,6 +218,8 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
drop(name){ drop(name){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
let index; let index;
for (let i = 0; i < this.#columns.length; i++){ for (let i = 0; i < this.#columns.length; i++){
if (this.#columns[i].Field === name) { if (this.#columns[i].Field === name) {
@ -233,9 +246,13 @@ class Structure {
* @param {ConstraintOptions} [options] - Extra constraint options * @param {ConstraintOptions} [options] - Extra constraint options
* @returns {this} * @returns {this}
*/ */
char(name, size=1, options){ char(name, size=1, options={}){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 0 || size > 255){ if (size < 0 || size > 255){
throw new Error(`Column datatype 'char' size must be a number between 0 and 255. Received: ${size}`); throwRangeError(0, 255, size);
} }
this.#columns.push(parseColumnData(name, `char(${size})`, options)); this.#columns.push(parseColumnData(name, `char(${size})`, options));
return this; return this;
@ -249,8 +266,12 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
varchar(name, size=8, options){ varchar(name, size=8, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 0 || size > 255){ if (size < 0 || size > 255){
throw new Error(`Column datatype 'varchar' size must be a number between 0 and 65535. Received: ${size}`); throwRangeError(0, 255, size);
} }
this.#columns.push(parseColumnData(name, `varchar(${size})`, options)); this.#columns.push(parseColumnData(name, `varchar(${size})`, options));
return this; return this;
@ -264,8 +285,12 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
binary(name, size=1, options){ binary(name, size=1, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1){ if (size < 1){
throw new Error(`Column datatype 'binary' size must be a number above 0. Received: ${size}`); throwRangeError(1, "*", size);
} }
this.#columns.push(parseColumnData(name, `binary(${size})`, options)); this.#columns.push(parseColumnData(name, `binary(${size})`, options));
return this; return this;
@ -279,8 +304,12 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
varbinary(name, size=1, options){ varbinary(name, size=1, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1){ if (size < 1){
throw new Error(`Column datatype 'varbinary' size must be a number above 0. Received: ${size}`); throwRangeError(1, "*", size);
} }
this.#columns.push(parseColumnData(name, `varbinary(${size})`, options)); this.#columns.push(parseColumnData(name, `varbinary(${size})`, options));
@ -294,6 +323,9 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
tinyblob(name, options){ tinyblob(name, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof options !== "object") throwTypeError("object", options);
this.#columns.push(parseColumnData(name, `tinyblob`, options)); this.#columns.push(parseColumnData(name, `tinyblob`, options));
return this; return this;
} }
@ -305,6 +337,9 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
tinytext(name, options){ tinytext(name, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof options !== "object") throwTypeError("object", options);
this.#columns.push(parseColumnData(name, `tinytext`, options)); this.#columns.push(parseColumnData(name, `tinytext`, options));
return this; return this;
} }
@ -316,6 +351,9 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
text(name, options){ text(name, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof options !== "object") throwTypeError("object", options);
this.#columns.push(parseColumnData(name, `text`, options)); this.#columns.push(parseColumnData(name, `text`, options));
return this; return this;
} }
@ -328,7 +366,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
blob(name, size=65535, options){ blob(name, size=65535, options){
if (size < 1 || size > 65535) throw new Error(`Column datatype 'blob' size must be a number between 1 and 65535. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1 || size > 65535) throwRangeError(1, 65535, size);
this.#columns.push(parseColumnData(name, `blob(${size})`, options)); this.#columns.push(parseColumnData(name, `blob(${size})`, options));
return this; return this;
} }
@ -340,6 +382,9 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
mediumtext(name, options){ mediumtext(name, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof options !== "object") throwTypeError("object", options);
this.#columns.push(parseColumnData(name, `mediumtext`, options)); this.#columns.push(parseColumnData(name, `mediumtext`, options));
return this; return this;
} }
@ -351,6 +396,9 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
longtext(name, options){ longtext(name, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof options !== "object") throwTypeError("object", options);
this.#columns.push(parseColumnData(name, `longtext`, options)); this.#columns.push(parseColumnData(name, `longtext`, options));
return this; return this;
} }
@ -362,6 +410,9 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
longblob(name, options){ longblob(name, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof options !== "object") throwTypeError("object", options);
this.#columns.push(parseColumnData(name, `longblob`, options)); this.#columns.push(parseColumnData(name, `longblob`, options));
return this; return this;
} }
@ -374,6 +425,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
enum(name, vals=[], options){ enum(name, vals=[], options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (!Array.isArray(vals)) throwTypeError("array", vals);
if (vals.length===0) throw new Error("vals must not be empty");
if (typeof options !== "object") throwTypeError("object", options);
if (!Array.isArray(vals)) throw new Error(`Column datatype 'enum': 'vals' must be of type Array`); if (!Array.isArray(vals)) throw new Error(`Column datatype 'enum': 'vals' must be of type Array`);
if (vals.length<=0) throw new Error(`Column datatype 'enum' must contain a list of possible values. Received undefined`); if (vals.length<=0) throw new Error(`Column datatype 'enum' must contain a list of possible values. Received undefined`);
this.#columns.push(parseColumnData(name, `enum(${vals.map(val=>`'${val}'`)})`, options)); this.#columns.push(parseColumnData(name, `enum(${vals.map(val=>`'${val}'`)})`, options));
@ -388,6 +444,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
set(name, vals=[], options){ set(name, vals=[], options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (!Array.isArray(vals)) throwTypeError("array", vals);
if (vals.length===0) throw new Error("vals must not be empty");
if (typeof options !== "object") throwTypeError("object", options);
if (!Array.isArray(vals)) throw new Error(`Column datatype 'set': 'vals' must be of type Array`); if (!Array.isArray(vals)) throw new Error(`Column datatype 'set': 'vals' must be of type Array`);
if (vals.length<=0) throw new Error(`Column datatype 'set' must contain a list of possible values. Received undefined`); if (vals.length<=0) throw new Error(`Column datatype 'set' must contain a list of possible values. Received undefined`);
this.#columns.push(parseColumnData(name, `set(${vals.map(val=>`'${val}'`)})`, options)); this.#columns.push(parseColumnData(name, `set(${vals.map(val=>`'${val}'`)})`, options));
@ -402,7 +463,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
bit(name, size=1, options){ bit(name, size=1, options){
if (size < 1 || size > 64) throw new Error(`Column datatype 'bit' size must be a number between 1 and 64. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1 || size > 64) throwRangeError(1, 64, size);
this.#columns.push(parseColumnData(name, `bit(${size})`, options)); this.#columns.push(parseColumnData(name, `bit(${size})`, options));
return this; return this;
} }
@ -415,7 +480,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
tinyint(name, size=255, options){ tinyint(name, size=255, options){
if (size < 1 || size > 255) throw new Error(`Column datatype 'tinyint' size must be a number between 1 and 255. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1 || size > 255) throwRangeError(1, 255, size);
this.#columns.push(parseColumnData(name, `tinyint(${size})`, options)); this.#columns.push(parseColumnData(name, `tinyint(${size})`, options));
return this; return this;
@ -428,6 +497,9 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
bool(name, options){ bool(name, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof options !== "object") throwTypeError("object", options);
this.#columns.push(parseColumnData(name, `bool`, options)); this.#columns.push(parseColumnData(name, `bool`, options));
return this; return this;
} }
@ -440,7 +512,10 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
smallint(name, size=255, options){ smallint(name, size=255, options){
if (size < 1 || size > 255) throw new Error(`Column datatype 'smallint' size must be a number between 1 and 255. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1 || size > 255) throwRangeError(1, 255, size);
this.#columns.push(parseColumnData(name, `smallint(${size})`, options)); this.#columns.push(parseColumnData(name, `smallint(${size})`, options));
return this; return this;
} }
@ -453,7 +528,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
mediumint(name, size=255, options){ mediumint(name, size=255, options){
if (size < 1 || size > 255) throw new Error(`Column datatype 'mediumint' size must be a number between 1 and 255. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1 || size > 255) throwRangeError(1, 255, size);
this.#columns.push(parseColumnData(name, `mediumint(${size})`, options)); this.#columns.push(parseColumnData(name, `mediumint(${size})`, options));
return this; return this;
} }
@ -466,7 +545,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
int(name, size=255, options){ int(name, size=255, options){
if (size < 1 || size > 255) throw new Error(`Column datatype 'int' size must be a number between 1 and 255. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1 || size > 255) throwRangeError(1, 255, size);
this.#columns.push(parseColumnData(name, `int(${size})`, options)); this.#columns.push(parseColumnData(name, `int(${size})`, options));
return this; return this;
} }
@ -479,7 +562,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
bigint(name, size=255, options){ bigint(name, size=255, options){
if (size < 1 || size > 255) throw new Error(`Column datatype 'bigint' size must be a number between 1 and 255. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1 || size > 255) throwRangeError(1, 255, size);
this.#columns.push(parseColumnData(name, `bigint(${size})`, options)); this.#columns.push(parseColumnData(name, `bigint(${size})`, options));
return this; return this;
} }
@ -492,7 +579,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
float(name, p=25, options){ float(name, p=25, options){
if (p < 1 || p > 53) throw new Error(`Column datatype 'float' size must be a number between 1 and 53. Received: ${p}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof p !== "number") throwTypeError("number", p);
if (typeof options !== "object") throwTypeError("object", options);
if (p < 1 || p > 53) throwRangeError(1, 53, p);
this.#columns.push(parseColumnData(name, `float(${p})`, options)); this.#columns.push(parseColumnData(name, `float(${p})`, options));
return this; return this;
@ -507,8 +598,13 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
double(name, size=16, d=8, options){ double(name, size=16, d=8, options){
if (size < 1) throw new Error(`Column datatype 'double' size must be greater than 0. Received: ${p}`); if (!name) throw new Error("name must not be empty");
if (d < 1) throw new Error(`Column datatype 'double' d must be greater than 0. Received: ${p}`); if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof d !== "number") throwTypeError("number", d);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1) throwRangeError(1, "*", size);
if (d < 1) throwRangeError(1, "*", d);
this.#columns.push(parseColumnData(name, `double(${size},${d})`, options)); this.#columns.push(parseColumnData(name, `double(${size},${d})`, options));
return this; return this;
} }
@ -522,8 +618,13 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
decimal(name, size=10, d=0, options){ decimal(name, size=10, d=0, options){
if (size < 1 || size > 65) throw new Error(`Column datatype 'decimal' size must be a number between 1 and 65. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (d < 0) throw new Error(`Column datatype 'decimal' d must be positive. Received: ${d}`); if (typeof name !== "string") throwTypeError("string", name);
if (typeof size !== "number") throwTypeError("number", size);
if (typeof d !== "number") throwTypeError("number", d);
if (typeof options !== "object") throwTypeError("object", options);
if (size < 1 || size > 65) throwRangeError(1, 65, size);
if (d < 0) throwRangeError(0, "*", d);
this.#columns.push(parseColumnData(name, `decimal(${size},${d})`, options)); this.#columns.push(parseColumnData(name, `decimal(${size},${d})`, options));
return this; return this;
@ -536,6 +637,9 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
date(name, options){ date(name, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof options !== "object") throwTypeError("object", options);
this.#columns.push(parseColumnData(name, `date`, options)); this.#columns.push(parseColumnData(name, `date`, options));
return this; return this;
} }
@ -548,7 +652,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
datetime(name, fsp=0, options){ datetime(name, fsp=0, options){
if (fsp < 0 || fsp > 6) throw new Error(`Column datatype 'fsp' size must be a number between 0 and 6. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof fsp !== "number") throwTypeError("number", fsp);
if (typeof options !== "object") throwTypeError("object", options);
if (fsp < 0 || fsp > 6) throwRangeError(0, 6, fsp);
this.#columns.push(parseColumnData(name, `datetime(${fsp})`, options)); this.#columns.push(parseColumnData(name, `datetime(${fsp})`, options));
return this; return this;
@ -562,7 +670,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
timestamp(name, fsp=0, options){ timestamp(name, fsp=0, options){
if (fsp < 0 || fsp > 6) throw new Error(`Column datatype 'fsp' size must be a number between 0 and 6. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof fsp !== "number") throwTypeError("number", fsp);
if (typeof options !== "object") throwTypeError("object", options);
if (fsp < 0 || fsp > 6) throwRangeError(0, 6, fsp);
this.#columns.push(parseColumnData(name, `timestamp(${fsp})`, options)); this.#columns.push(parseColumnData(name, `timestamp(${fsp})`, options));
return this; return this;
@ -576,7 +688,11 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
time(name, fsp=0, options){ time(name, fsp=0, options){
if (fsp < 0 || fsp > 6) throw new Error(`Column datatype 'fsp' size must be a number between 0 and 6. Received: ${size}`); if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof fsp !== "number") throwTypeError("number", fsp);
if (typeof options !== "object") throwTypeError("object", options);
if (fsp < 0 || fsp > 6) throwRangeError(0, 6, fsp);
this.#columns.push(parseColumnData(name, `time(${fsp})`, options)); this.#columns.push(parseColumnData(name, `time(${fsp})`, options));
return this; return this;
@ -589,6 +705,9 @@ class Structure {
* @returns {this} * @returns {this}
*/ */
year(name, options){ year(name, options){
if (!name) throw new Error("name must not be empty");
if (typeof name !== "string") throwTypeError("string", name);
if (typeof options !== "object") throwTypeError("object", options);
this.#columns.push(parseColumnData(name, `time`, options)); this.#columns.push(parseColumnData(name, `time`, options));
return this; return this;
} }

View File

@ -1,3 +1,4 @@
const { throwTypeError } = require("./Errors");
/** /**
* Prepares a new Update * Prepares a new Update
@ -23,6 +24,8 @@ class Update{
* @returns {this} * @returns {this}
*/ */
data(object){ data(object){
if (!object) throw new Error("data object must not be empty");
if (typeof object !== "object") throwTypeError("object", object);
this.#data = object; this.#data = object;
return this; return this;
} }
@ -33,6 +36,8 @@ class Update{
* @returns {this} * @returns {this}
*/ */
selectDatabase(database){ selectDatabase(database){
if (!database) throw new Error("database must not be empty");
if (typeof database !== "string") throwTypeError("string", database);
this.#database = database; this.#database = database;
return this; return this;
} }
@ -54,6 +59,9 @@ class Update{
* @returns {this} * @returns {this}
*/ */
where(string, values=[]){ where(string, values=[]){
if (!string) throw new Error("string must not be empty");
if (typeof string !== "string") throwTypeError("string", string);
if (!Array.isArray(values)) throwTypeError("array", values);
this.#where = string; this.#where = string;
this.#whereValues = values; this.#whereValues = values;
return this; return this;
@ -70,7 +78,6 @@ class Update{
const values = []; const values = [];
const queryString = `UPDATE ${this.#database}.${this.#table} SET ${Object.keys(this.#data).map(col=>{values.push(this.#data[col]);return `${col}=?`})}${this.#where&&` WHERE ${this.#where}`}`; const queryString = `UPDATE ${this.#database}.${this.#table} SET ${Object.keys(this.#data).map(col=>{values.push(this.#data[col]);return `${col}=?`})}${this.#where&&` WHERE ${this.#where}`}`;
this.#where&&values.push(...this.#whereValues); this.#where&&values.push(...this.#whereValues);
console.log(queryString);
return await this.#instance.queryRaw(queryString, values); return await this.#instance.queryRaw(queryString, values);
} }
} }

6
tests/test.js Normal file
View File

@ -0,0 +1,6 @@
const {awSQL, Structure} = require("..");
function test(){
new Structure().drop(1234);
}
test();