EZ Objects (MySQL Edition) is a Node.js module (that can also be usefully browserify'd) that aims to save you lots of time writing class objects that are strictly typed in JavaScript, and can be tied directly to MySQL database tables by way of a mix of automatically generated insert/update/load/delete class method signatures. All you have to do is create simple class configurations for each of your objects and then create them using the exported ezobjects.createClass() function.
- Installation
- Required Property
- Basic Example
- EZ Object Types
- Exported Functions
- Basic EZ Object Method Signatures
- MySQL EZ Object Method Signatures
- Configuration Specifications
- Defining Additional Class Methods
- Client Side Usage
- Wasted Space
- Advanced Example With Each EZ Object Type
- Contributing
- License
EZ Object's capabilities has been split into multiple packages to target the needs of specific users. This
is a branch of the original ezobjects
module that preserves the original MySQL table-linked capability,
while the original ezobjects
has had it removed so those who don't need the database storage can remove
the dependency. It also worked out better that way so that ezobjects
types can be different than MySQL
types, which might be different from another database's types, etc. If you don't need MySQL capability,
you can find the original ezobjects
package on npm or GitHub.
npm i ezobjects-mysql
IMPORTANT: Each of your MySQL EZ Objects must include a property of EZ Object type int
named id
that will be automatically
configured to serve as an auto-incrementing primary index in the MySQL table that you are linking your object to. The load
method
will generally be based off the id
field, unless you specify a otherSearchProperty to load
by as an alternative. Also note that you must also use the mysql-await
module for your database connection for compatability purposes and to allow async/await functionality. It is simply
a wrapper for the popular mysql module and takes no time to scan and see that nothing
fishy is going on.
It might be best to start off with a basic example where we do the following:
- Configure an EZ Object called
DatabaseRecord
- Configure another EZ Object called
UserAccount
that extends fromDatabaseRecord
- Create the classes for both using the ezobjects.createClass() function
- Create my user_accounts MySQL table using the ezobjects.createTable() function (if it doesn't already exist)
- Demonstrate the instatiation of an EZ Object and use of the getters, setters, and insert/update/load/delete class methods that EZ Objects automatically provides.
See below:
const ezobjects = require(`ezobjects-mysql;`);
const fs = require(`fs`);
const mysql = require(`mysql-await`);
/**
* Load external MySQL configuration which uses the following JSON
* format:
* {
* "host" : "localhost",
* "user" : "ezobjects",
* "password" : "myPassword",
* "database" : "ezobjects"
* }
*/
const configMySQL = JSON.parse(fs.readFileSync(`mysql-config.json`));
/**
* Create a connection object for the MySQL database using our MySQL
* module async/await wrapper.
*/
const db = mysql.createConnection(configMySQL);
/**
* Configure a new EZ Object called DatabaseRecord with the required
* `id` property that will serve as the auto-incrementing primary index.
*/
const configDatabaseRecord = {
className: `DatabaseRecord`,
properties: [
{ name: `id`, type: `int` }
]
};
/**
* Create the DatabaseRecord class -- Note: This object is not linked
* to a MySQL table directly, as it has no `tableName` property, but
* it can be extended by EZ Objects that are linked to tables.
*/
const DatabaseRecord = ezobjects.createClass(configDatabaseRecord);
/**
* Configure a new EZ Object called UserAccount that extends from the
* DatabaseRecord object and adds several additional properties,
* including an array of `int` property and a MySQL index.
*/
const configUserAccount = {
tableName: `user_accounts`,
className: `UserAccount`,
extends: DatabaseRecord,
extendsConfig: configDatabaseRecord,
properties: [
{ name: `username`, type: `varchar`, length: 20 },
{ name: `firstName`, type: `varchar`, length: 20 },
{ name: `lastName`, type: `varchar`, length: 20 },
{ name: `checkingBalance`, type: `decimal`, length: 17, decimals: 2 },
{ name: `permissions`, type: `Array`, arrayOf: { type: `int` } },
{ name: `favoriteDay`, type: `date` }
],
indexes: [
{ name: `username`, type: `BTREE`, columns: [ `username` ] }
]
};
/** Create the UserAccount class */
const UserAccount = ezobjects.createClass(configUserAccount);
/** Let's use a self-executing async wrapper so we can await results */
(async () => {
try {
/**
* Create a new UserAccount called `userAccount`, initializing with
* plain object passed to constructor.
*/
const userAccount = new UserAccount({
username: `richlowe`,
firstName: `Rich`,
lastName: `Lowe`,
checkingBalance: 4.32,
permissions: [1, 3, 5],
favoriteDay: new Date(`01-01-2018`)
});
/**
* Test if `userAccount` is an instance of DatabaseRecord using
* the included `instanceOf` helper function.
*/
console.log(ezobjects.instanceOf(userAccount, `DatabaseRecord`));
/** Create `user_accounts` table if it doesn`t already exist */
await ezobjects.createTable(configUserAccount, db);
/** Insert `userAccount` into the database */
await userAccount.insert(db);
/** Log `userAccount` (should have automatically incremented ID now) */
console.log(userAccount);
/** Capture ID of new record */
const id = userAccount.id();
/** Change the property values a bit */
userAccount.checkingBalance(50.27);
userAccount.firstName(`Richard`);
userAccount.favoriteDay(new Date(`09-01-2019`));
/** Update `userAccount` in the database */
await userAccount.update(db);
/** Log `userAccount` (should have `checkingBalance` of 50.27) */
console.log(userAccount);
/** Create another new UserAccount called `anotherUserAccount` */
const anotherUserAccount = new UserAccount();
/**
* Using the ID captured from the previous insert operation, load
* the record from database.
*/
await anotherUserAccount.load(id, db, [`username`, `firstName`, `lastName`]);
/** Log `anotherUserAccount` (should match last `userAccount`) */
console.log(anotherUserAccount);
/** Delete `anotherUserAccount` from the database */
await anotherUserAccount.delete(db);
} catch ( err ) {
/** Cleanly log any errors */
console.log(err.message);
} finally {
/** Close database connection */
await db.awaitEnd();
}
})();
true
UserAccount {
_id: 1,
_username: `richlowe`,
_firstName: `Rich`,
_lastName: `Lowe`,
_checkingBalance: 4.32,
_permissions: [ 1, 3, 5 ],
_favoriteDay: 2018-01-01T06:00:00.000Z }
UserAccount {
_id: 1,
_username: `richlowe`,
_firstName: `Richard`,
_lastName: `Lowe`,
_checkingBalance: 50.27,
_permissions: [ 1, 3, 5 ],
_favoriteDay: 2019-09-01T05:00:00.000Z }
UserAccount {
_id: 0,
_username: `richlowe`,
_firstName: `Richard`,
_lastName: `Lowe`,
_checkingBalance: 0,
_permissions: [],
_favoriteDay: null }
See the table below for a list of EZ Object types along with their JavaScript type and default value, as well as the default MySQL type.
EZ Object Type | JavaScript Type | Default JavaScript Value | Default MySQL Type |
---|---|---|---|
bit | Buffer |
Buffer.from([]) |
BIT |
tinyint | Number |
0 | TINYINT |
smallint | Number |
0 | SMALLINT |
mediumint | Number |
0 | MEDIUMINT |
int | Number |
0 | INT |
bigint | Number |
0 | BIGINT |
real | Number |
0 | REAL |
double | Number |
0 | DOUBLE |
float | Number |
0 | FLOAT |
decimal | Number |
0 | DECIMAL |
numeric | Number |
0 | NUMERIC |
time | String |
'00:00:00' | TIME |
char | String |
'' | CHAR |
varchar | String |
'' | VARCHAR |
binary | Buffer |
Buffer.from([]) |
BINARY |
varbinary | Buffer |
Buffer.from([]) |
VARBINARY |
tinyblob | Buffer |
Buffer.from([]) |
TINYBLOB |
blob | Buffer |
Buffer.from([]) |
BLOB |
mediumblob | Buffer |
Buffer.from([]) |
MEDIUMBLOB |
longblob | Buffer |
Buffer.from([]) |
LONGBLOB |
tinytext | String |
'' | TINYTEXT |
text | String |
'' | TEXT |
mediumtext | String |
'' | MEDIUMTEXT |
longtext | String |
'' | LONGTEXT |
set | Set |
new Set() |
SET |
boolean | Boolean |
false |
TINYINT |
function | function |
function () { } |
TEXT |
object | Object |
{} |
TEXT |
MyEZObject | MyEZObject | null |
TINYTEXT |
Array[bit] | Array |
[] |
TEXT |
Array[tinyint] | Array |
[] |
TEXT |
Array[smallint] | Array |
[] |
TEXT |
Array[mediumint] | Array |
[] |
TEXT |
Array[int] | Array |
[] |
TEXT |
Array[bigint] | Array |
[] |
TEXT |
Array[real] | Array |
[] |
TEXT |
Array[double] | Array |
[] |
TEXT |
Array[float] | Array |
[] |
TEXT |
Array[decimal] | Array |
[] |
TEXT |
Array[numeric] | Array |
[] |
TEXT |
Array[time] | Array |
[] |
TEXT |
Array[char] | Array |
[] |
TEXT |
Array[varchar] | Array |
[] |
TEXT |
Array[binary] | Array |
[] |
TEXT |
Array[varbinary] | Array |
[] |
TEXT |
Array[tinyblob] | Array |
[] |
TEXT |
Array[blob] | Array |
[] |
MEDIUMTEXT |
Array[mediumblob] | Array |
[] |
LONGTEXT |
Array[longblob] | Array |
[] |
LONGTEXT |
Array[tinytext] | Array |
[] |
TEXT |
Array[text] | Array |
[] |
MEDIUMTEXT |
Array[mediumtext] | Array |
[] |
LONGTEXT |
Array[longtext] | Array |
[] |
LONGTEXT |
Array[set] | Array |
[] |
TEXT |
Array[boolean] | Array |
[] |
TEXT |
Array[function] | Array |
[] |
MEDIUMTEXT |
Array[object] | Array |
[] |
MEDIUMTEXT |
Array[MyEZObject] | Array |
[] |
TEXT |
The EZ Objects module exports three functions:
-
Parameter: objectConfig -
Object
- See Configuration Specifications -
Parameter: db -
MySQLConnection
- Created usingmysql-await
module -
Description: A function that creates a MySQL table corresponding to the configuration outlined in
objectConfig
, if it doesn't already exist.
-
Parameter: objectConfig -
Object
- See Configuration Specifications -
Returns:
mixed
- Your custom created EZ Object in all of its glory -
Description: A function that creates an ES6 class corresponding to the configuration outlined in
objectConfig
, with constructor, initializer, getters, setters, and also delete, insert, load, and update iftableName
is configured. The resulting class is both returned from the function and exported from theezobjects-mysql
module.
-
Parameter: obj -
mixed
- Any object created using an EZ Object class -
Parameter: constructorName -
string
-
Returns:
boolean
-
Description: A function that tests whether a given object
obj
is an instance of classconstructorName
, meaningconstructorName
is the name of the object's constructor, or the name of any constructor in the object's prototype chain.
These are the object method signatures even the most basic of EZ Objects will have:
-
Parameter: data -
Object
- (optional) -
Description: Create a new MyObject object and initialize it using either defaults or any provided key/value pairs in the plain object
data
. Keys can either be equal to the name of a property, or they can have an underscore before the name of a property, as would be the case if you were to JSON.stringify() and then JSON.parse() an EZ Object. This allows for easy transferability in cases where JSON is used as the transfer medium.
-
Parameter: data -
string
- (optional) -
Description: Create a new MyObject object and initialize it using either defaults or any provided key/value pairs in the JSON encoded string
data
. Keys can either be equal to the name of a property, or they can have an underscore before the name of a property, as would be the case if you were to JSON.stringify() an EZ Object. This allows for easy transferability in cases where JSON is used as the transfer medium.
-
Parameter: data -
MyObject
- (optional) -
Description: Create a new MyObject object and initialize it using either defaults or any getter functions in the EZ Object
data
.
-
Parameter: data -
Object
-
Description: Initialize this object using either defaults or any provided key/value pairs in the plain object
data
. Keys can either be equal to the name of a property, or they can have an underscore before the name of a property, as would be the case if you were to JSON.stringify() and then JSON.parse() an EZ Object. This allows for easy transferability in cases where JSON is used as the transfer medium. This is also the method used by the constructor.
-
Parameter: data -
Object
-
Description: Initialize this object using either defaults or any provided key/value pairs in the JSON0-encoded string
data
. Keys can either be equal to the name of a property, or they can have an underscore before the name of a property, as would be the case if you were to JSON.stringify() and then JSON.parse() an EZ Object. This allows for easy transferability in cases where JSON is used as the transfer medium. This is also the method used by the constructor.
-
Parameter: data -
MyObject
-
Description: Initialize this object using either defaults or any provided getter functions in the EZ Object
data
. This is also the method used by the constructor.
In addition, each property you define will have a single method that is a getter and setter, and it will have the following signatures:
-
Returns:
mixed
- Description: Get the value of the property.
-
Parameter: value -
mixed
-
Throws:
TypeError
ifvalue
is not of the correct javascript data type for myProperty -
Returns:
this
-
Description: Set the value of the property, throwing an error if the javascript data type does not match the configuration, this is how the strict typing is implemented. This signature returns
this
to allow for set call chaining.
These are the object method signatures that will additionally be provided if your configuration contains a tableName
,
meaning it's intended to be linked to a MySQL table:
-
Parameter: db -
Object
-
Description: Delete the record in database
db
, tabletableName
, that has itsid
field equal to theid
property of this object.
-
Parameter: db -
Object
-
Description: Insert this object's property values into the database
db
, tabletableName
, and store the resulting insertId in theid
property of this object.
-
Parameter: mysqlRow
RowDataPacket
- A MySQLRowDataPacket
returned as part of a MySQL result set -
Parameter: db -
Object
- (optional) -
Parameter: propertiesToInclude -
Array
- (optional) Properties to load (or not load if inverse option is used) -
Parameter: options -
Object
- (optional) Desired options (currently just inverse = true/false) -
Description: Load any configured properties from key/value pairs in
mysqlRow
. You can optionally pass the databasedb
if you need it to be provided as a third argument to any loadTransform handlers defined for configured properties.
- Parameter: obj Object
-
Parameter: db -
Object
- (optional) -
Parameter: propertiesToInclude -
Array
- (optional) Properties to load (or not load if inverse option is used) -
Parameter: options -
Object
- (optional) Desired options (currently just inverse = true/false) -
Description: Load any configured properties from key/value pairs in
obj
. You can optionally pass the databasedb
if you need it to be provided as a third argument to any loadTransform handlers defined for configured properties.
-
Parameter: id number The value of the
id
property of the record you wish to load -
Parameter: db -
Object
-
Parameter: propertiesToInclude -
Array
- (optional) Properties to load (or not load if inverse option is used) -
Parameter: options -
Object
- (optional) Desired options (currently just inverse = true/false) -
Description: Load the record in database
db
, tabletableName
, that has itsid
field equal to providedid
parameter.
-
Parameter: propertyValue -
mixed
- The value of theotherSearchProperty
property of the record you wish to load -
Parameter: db -
Object
-
Parameter: propertiesToInclude -
Array
- (optional) Properties to load (or not load if inverse option is used) -
Parameter: options -
Object
- (optional) Desired options (currently just inverse = true/false) -
Description: Load the record in database
db
, tabletableName
, that has itsotherSearchProperty
field equal to providedpropertyValue
parameter. Here, the actual field name ofotherSearchProperty
is provided in the object configuration, see the configuration section below.
-
Parameter: url -
string
- The URL of a back-end that provides JSON data compatible with this object's initializer -
Parameter: db -
Object
-
Description: Load any configured properties from the JSON-encoded key/value pairs obtained from
url
. You can optionally pass the databasedb
if you need it to be provided as a third argument to any loadTransform handlers defined for configured properties. -
Note: This signature is useful only when your classes are standalone browserify'd and requires you to implement a backend at
url
that will output the JSON. (This signature no longer requires jQuery to use)
-
Parameter: db -
Object
-
Description: Update the record in database
db
, tabletableName
, with itsid
field equal to theid
property of this object, using this object's property values.
See the following for how to configure your EZ Objects:
-
className -
string
- (required) Name of the class -
properties -
Array
- (optional) An array of property configurations that the object (and MySQL table, if applicable) should have corresponding properties for -
extends -
mixed
- (optional) The class that the new EZ Object should be extended from [required to extend EZ Object] -
extendsConfig -
object
- (optional) The EZ Object configuration for the EZ Object that is being extended from [required to extend EZ Object] -
indexes -
Array
- (optional) An array of MySQL index configurations that should be created in the MySQL table
-
tableName -
string
- (optional) Provide if object should be linked with MySQL database table -
otherSearchProperty -
string
- (optional) The name of a unique property that you want to be able to load with as an alternative to the mandatoryid
property. Note theid
property is still required. -
url -
string
- (optional) The URL of a back-end that will provide a JSON.stringify output of the EZ Object for browserify'd loading of the object using an AJAX background request. For now, the URL must take the ID # of the record at the very end, i.e. http://go.to/myObject/load/{ID#}
-
name -
string
- (required) Name of the property, must conform to both JavaScript and MySQL rules -
type -
string
- (optional) EZ Object type that the property must be equal to -- types can bebit
,tinyint
,smallint
,mediumint
,int
,bigint
,real
,double
,float
,decimal
,numeric
,date
,time
,timestamp
,datetime
,char
,varchar
,binary
,varbinary
,tinyblob
,blob
,mediumblob
,longblob
,tinytext
,text
,mediumtext
,longtext
,set
,boolean
,function
,object
, any other valid object constructor name, orarray
wherearrayOf
is provided with information about the array element types. [either type or instanceOf is required] -
instanceOf -
string
- (optional) JavaScript class constructor name that the property must be an instance of [either type or instanceOf is required] -
default -
mixed
- (optional) Sets the default value for the property in the class object -
allowNull -
boolean
- (optional) Indicates the property can be null, default is that onlydate
,datetime
,timestamp
, and custom object types are nullable -
arrayOf -
object
- (required for typearray
) A plain object containing the EZ Objecttype
orinstanceOf
of the elements of the array -- types can bebit
,tinyint
,smallint
,mediumint
,int
,bigint
,real
,double
,float
,decimal
,numeric
,date
,time
,timestamp
,datetime
,char
,varchar
,binary
,varbinary
,tinyblob
,blob
,mediumblob
,longblob
,tinytext
,text
,mediumtext
,longtext
,set
,boolean
,function
,object
, or any other valid object constructor name (which can alternatively be used withinstanceOf
instead). Should also include any other relevant MySQL attributes for the stored properties, such as allowNull, length, unsigned, etc, though not all specifics will be used as the current practice is to store arrays using the family of MySQLtext
-type andblob
-type fields. That may change in future versions though where they may be stored in transparent sub-tables, so it's best practice to include the MySQL specifics if you desire future compatability. Important Note: Arrays also therefore don't yet have unlimited size capability, and if the MySQL type used by default isn't big enough, it will be up to you to manually override themysqlType
of thearray
property configuration. [either type or instanceOf is required] -
setTransform(x, propertyConfig) -
function
- (optional) Function that transforms and returns the property value prior to setting. The handler for this transform will also be passed the EZ ObjectspropertyConfig
, if needed.
-
length -
number
- (optional) MySQL data length for the property [required for some data types like VARCHAR, optional for others where it's used to determine displayed precision on SELECT'ed data types like FLOAT] -
decimals -
number
- (optional) Number of decimals that should be displayed for certain data types when SELECT'ed from the MySQL table -
unique -
boolean
- (optional) Indicates the property is a UNIQUE KEY in the MySQL table -
unsigned -
boolean
- (optional) Indicates the property should be unsigned in the MySQL table -
zerofill -
boolean
- (optional) Indicates the property should be zero-filled in the MySQL table -
comment -
string
- (optional) Indicates the property should note the provided comment in the MySQL table -
characterSet -
string
- (optional) Indicates the property should use the provided charset in the MySQL table -
collate -
string
- (optional) Indicates the property should use the provided collation in the MySQL table -
autoIncrement -
boolean
- (optional) Indicates the property should be auto-incremented in the MySQL table -
mysqlType -
string
- (optional) Provide the name of a valid MySQL data type in order to override the default, this can be especially useful for saving database space when you know you will be well under the default MySQL type sizes. -
saveTransform(x, propertyConfig) -
function
- (optional) Provide a function that transforms and returns the property value prior to saving in the database in order to override the default. The handler for this transform will also be passed the EZ ObjectspropertyConfig
, if needed. -
loadTransform(x, propertyConfig, db) -
function
- (optional) Provide a function that transforms and returns the property value after loading from the database in order to override the default. The handler for this transform will also be passed the EZ ObjectspropertyConfig
, if needed, along with the MySQL connectiondb
iff it was provided as the third argument of the object'sload
method.
-
name -
string
- (required) Name of the index, can be arbitrary, but must be unique and not PRIMARY -
columns -
Array
- (required) An array of strings containing property names to be indexed -
type -
string
- (optional) Index type, can be BTREE or HASH, defaults to BTREE -
keyBlockSize -
number
- (optional) Indicates the index should use the provided key block size -
withParser -
string
- (optional) Indicates the index should use the provided parser -
visible -
boolean
- (optional) Indicates the index should be visible -
invisible -
boolean
- (optional) Indicates the index should be invisible
There are appropriate setTransform, saveTransform, and loadTransform methods for each EZ Object type. It is generally recommended that you don't override transforms unless you know what you are doing. For those who insist on doing so, first reference the default transforms in use in the ezobjectTypes
array here
Defining additional class methods is really just a matter of adding the functions to the class prototype.
const ezobjects = require(`ezobjects-mysql`);
/** Configure material */
const materialConfig = {
className: `Material`,
tableName: `materials`,
properties: [
{ name: `name`, type: `varchar`, length: 32 },
{ name: `density`, type: `double` },
{ name: `volume`, type: `double` }
]
};
/** Create material class */
const Material = ezobjects.createClass(materialConfig);
/** Simply add weight function to the class prototype after creating it with createClass() */
Material.prototype.weight = function () {
return this.density() * this.volume();
};
There is another example available that demonstrates the browserify'd capabilities of EZ Objects by loading objects client-side over an Ajax back-end:
It should be noted that it's possible for there to be considerable space wasted through too liberal use of large data types or arrays of large data types. In many cases this is not an issue, space is cheap right? However, in database tables with massive amounts of records, you may want to do a little due diligence and see if you need to override some of the default MySQL types.
For example, let's say that you have the following property config:
{ name: 'permissions', type: 'array', arrayOf: { type: 'int' } }
Well, each record will store that field as MySQL type TEXT which takes 65538 bytes of space per entry. If there are only, say, 25 permissions in your system numbered 1-25 or 0-24, then someone having all 25 permissions, stored using comma separated values in the database by EZ Objects, would not exceed the 255 bytes provided by a TINYTEXT field. You may therefore wish to override the default MySQL type in this case if you have thousands of users in your database, like so:
{ name: 'permissions', type: 'array', mysqlType: 'tinytext', arrayOf: { type: 'int' } }
/** Require external modules */
const ezobjects = require(`ezobjects-mysql`);
const fs = require(`fs`);
const util = require(`util`);
const mysql = require(`mysql-await`);
/** Connect to the MySQL database using login info stored externally */
const db = mysql.createConnection(JSON.parse(fs.readFileSync(`mysql-config.json`)));
/**
* Configure a new EZ Object class called Example that tests out the
* various data types supported.
*
* VERY IMPORTANT:
*
* All MySQL EZ Objects MUST have an integer `id` field that will serve
* as an auto-incrementing primary index.
*/
const configExample = {
tableName: `examples`,
className: `Example`,
properties: [
{ name: `id`, type: `int` },
{ name: `bitExample`, type: `bit`, length: 2 },
{ name: `tinyintExample`, type: `tinyint` },
{ name: `tinyintExample2`, type: `tinyint`, unsigned: true, zerofill: true },
{ name: `smallintExample`, type: `smallint` },
{ name: `mediumintExample`, type: `mediumint` },
{ name: `intExample`, type: `int` },
{ name: `bigintExample`, type: `bigint` },
{ name: `doubleExample`, type: `double` },
{ name: `floatExample`, type: `float` },
{ name: `decimalExample`, type: `decimal`, length: 5, decimals: 3 },
{ name: `numericExample`, type: `numeric`, length: 8, decimals: 5 },
{ name: `dateExample`, type: `date` },
{ name: `timeExample`, type: `time` },
{ name: `timestampExample`, type: `timestamp` },
{ name: `datetimeExample`, type: `datetime` },
{ name: `charExample`, type: `char`, length: 2 },
{ name: `charExample2`, type: `char`, length: 2, characterSet: `latin1`, collate: `latin1_german1_ci` },
{ name: `varcharExample`, type: `varchar`, length: 40 },
{ name: `varcharExample2`, type: `varchar`, length: 40, allowNull: true },
{ name: `binaryExample`, type: `binary`, length: 4 },
{ name: `varbinaryExample`, type: `varbinary`, length: 4 },
{ name: `tinyblobExample`, type: `tinyblob` },
{ name: `blobExample`, type: `blob` },
{ name: `mediumblobExample`, type: `mediumblob` },
{ name: `longblobExample`, type: `longblob` },
{ name: `tinytextExample`, type: `tinytext` },
{ name: `textExample`, type: `text` },
{ name: `mediumtextExample`, type: `mediumtext` },
{ name: `longtextExample`, type: `longtext` },
{ name: `setExample`, type: `set`, values: [`a`, `b`, `c`, `d`] },
{ name: `booleanExample`, type: `boolean` },
{ name: `functionExample`, type: `function` },
{ name: `plainObjectExample`, type: `object` },
{ name: `ezobjectTypeExample`, type: `OtherObj` },
{ name: `ezobjectInstanceExample`, instanceOf: `OtherObj` },
{ name: `ezobjectInstanceExample2`, instanceOf: `OtherObj`, store: false },
{ name: `bitArrayExample`, type: `Array`, arrayOf: { type: `bit`, length: 2 } },
{ name: `tinyintArrayExample`, type: `Array`, arrayOf: { type: `tinyint` } },
{ name: `tinyintArrayExample2`, type: `Array`, arrayOf: { type: `tinyint`, unsigned: true, zerofill: true } },
{ name: `smallintArrayExample`, type: `Array`, arrayOf: { type: `smallint` } },
{ name: `mediumintArrayExample`, type: `Array`, arrayOf: { type: `mediumint` } },
{ name: `intArrayExample`, type: `Array`, arrayOf: { type: `int` } },
{ name: `bigintArrayExample`, type: `Array`, arrayOf: { type: `bigint` } },
{ name: `doubleArrayExample`, type: `Array`, arrayOf: { type: `double` } },
{ name: `floatArrayExample`, type: `Array`, arrayOf: { type: `float` } },
{ name: `decimalArrayExample`, type: `Array`, arrayOf: { type: `decimal`, length: 5, decimals: 3 } },
{ name: `numericArrayExample`, type: `Array`, arrayOf: { type: `numeric`, length: 8, decimals: 5 } },
{ name: `dateArrayExample`, type: `Array`, arrayOf: { type: `date` } },
{ name: `timeArrayExample`, type: `Array`, arrayOf: { type: `time` } },
{ name: `timestampArrayExample`, type: `Array`, arrayOf: { type: `timestamp` } },
{ name: `datetimeArrayExample`, type: `Array`, arrayOf: { type: `datetime` } },
{ name: `charArrayExample`, type: `Array`, arrayOf: { type: `char`, length: 2 } },
{ name: `charArrayExample2`, type: `Array`, arrayOf: { type: `char`, length: 2, characterSet: `latin1`, collate: `latin1_german1_ci` } },
{ name: `varcharArrayExample`, type: `Array`, arrayOf: { type: `varchar`, length: 40 } },
{ name: `varcharArrayExample2`, type: `Array`, arrayOf: { type: `varchar`, length: 40, allowNull: true } },
{ name: `binaryArrayExample`, type: `Array`, arrayOf: { type: `binary`, length: 4 } },
{ name: `varbinaryArrayExample`, type: `Array`, arrayOf: { type: `varbinary`, length: 4 } },
{ name: `tinyblobArrayExample`, type: `Array`, arrayOf: { type: `tinyblob` } },
{ name: `blobArrayExample`, type: `Array`, arrayOf: { type: `blob` } },
{ name: `mediumblobArrayExample`, type: `Array`, arrayOf: { type: `mediumblob` } },
{ name: `longblobArrayExample`, type: `Array`, arrayOf: { type: `longblob` } },
{ name: `tinytextArrayExample`, type: `Array`, arrayOf: { type: `tinytext` } },
{ name: `textArrayExample`, type: `Array`, arrayOf: { type: `text` } },
{ name: `mediumtextArrayExample`, type: `Array`, arrayOf: { type: `mediumtext` } },
{ name: `longtextArrayExample`, type: `Array`, arrayOf: { type: `longtext` } },
{ name: `setArrayExample`, type: `Array`, arrayOf: { type: `set`, values: [`a`, `b`, `c`, `d`] } },
{ name: `booleanArrayExample`, type: `Array`, arrayOf: { type: `boolean` } },
{ name: `functionArrayExample`, type: `Array`, arrayOf: { type: `function` } },
{ name: `plainObjectArrayExample`, type: `Array`, arrayOf: { type: `object` } },
{ name: `ezobjectTypeArrayExample`, type: `Array`, arrayOf: { type: `OtherObj` } },
{ name: `ezobjectInstanceArrayExample`, type: `Array`, arrayOf: { instanceOf: `OtherObj` } },
{ name: `ezobjectInstanceArrayExample2`, type: `Array`, arrayOf: { instanceOf: `OtherObj` }, store: false },
],
indexes: [
{ name: `varcharExample`, type: `BTREE`, columns: [ `varcharExample` ] },
{ name: `charExample`, type: `HASH`, columns: [ `charExample` ] }
]
};
/** Create the Example class */
const Example = ezobjects.createClass(configExample);
/** Configure a simple `other` object for use in the example */
const configOtherObj = {
className: `OtherObj`,
tableName: `other_objects`,
properties: [
{ name: `id`, type: `int` },
{ name: `name`, type: `varchar`, length: 40 }
]
};
/** Create the OtherObj class */
const OtherObj = ezobjects.createClass(configOtherObj);
/** Configure an extended object for use in the example */
const configExtendedObj = {
className: `ExtendedObj`,
tableName: `extended_objects`,
extends: OtherObj,
extendsConfig: configOtherObj,
};
/** Create the ExtendedObj class */
const ExtendedObj = ezobjects.createClass(configExtendedObj);
/** Self-executing async wrapper so we can await results */
(async () => {
try {
/** Create example table if it doesn`t already exist */
await ezobjects.createTable(configExample, db);
/** Create other object table if it doesn`t already exist */
await ezobjects.createTable(configOtherObj, db);
/** Create extended object table if it doesn`t already exist */
await ezobjects.createTable(configExtendedObj, db);
const otherObj1 = new OtherObj({ name: `Type Example 1` });
const otherObj2 = new OtherObj({ name: `Type Example 2` });
const extendedObj1 = new ExtendedObj({ name: `Instance Example Stored 1` });
const extendedObj2 = new ExtendedObj({ name: `Instance Example Stored 2` });
const extendedObj3 = new ExtendedObj({ name: `Instance Example Not Stored 1` });
const extendedObj4 = new ExtendedObj({ name: `Instance Example Not Stored 2` });
/**
* Insert other objects and extended objects into the database.
*
* Note: This must be done before inserting the example so that
* the other objects and extended objects have ID's to store!
**/
await otherObj1.insert(db);
await otherObj2.insert(db);
await extendedObj1.insert(db);
await extendedObj2.insert(db);
/** Create new example object, initializing with object passed to constructor */
const example = new Example({
bitExample: Buffer.from([0b1, 0b0]),
tinyintExample: -128,
tinyintExample2: 255,
smallintExample: -32767,
mediumintExample: -8388608,
intExample: -2147483648,
// bigintExample: -9223372036854775808, Gives ER_WARN_DATA_OUT_OF_RANGE error due to bug?
doubleExample: 193448295822329038402340234.23840923804823094809234245,
floatExample: 1927492498374.2348927395,
decimalExample: 23.452,
numericExample: 942.28734,
dateExample: new Date(`1986-06-20`),
timeExample: `-838:59:59`,
timestampExample: new Date(`2011-07-16T04:52:23-06:00`),
datetimeExample: new Date(`2011-07-16T04:52:23-06:00`),
charExample: `AU`,
charExample2: `ÄÜ`,
varcharExample: `Varchar Example`,
varcharExample2: null,
binaryExample: Buffer.from([0x04, 0x7F, 0x13, 0x38]),
varbinaryExample: Buffer.from([0x04, 0x7F]),
tinyblobExample: Buffer.from(`I am a tiny blob up to 256 bytes`),
blobExample: Buffer.from(`I am a bigger blob up to 65 kB`),
mediumblobExample: Buffer.from(`I am a bigger blob up to 16 MB`),
longblobExample: Buffer.from(`I am a bigger blob up to 4 GB`),
tinytextExample: `I am a tiny text up to 256 bytes`,
textExample: `I am a bigger text up to 65 kB`,
mediumtextExample: `I am a bigger text up to 16 MB`,
longtextExample: `I am a bigger text up to 4 GB`,
setExample: new Set([`a`, `d`, `d`]),
booleanExample: true,
functionExample: (arg) => { return `I am ${arg}`; },
plainObjectExample: { a: `I am A`, 14: `Plain Object` },
ezobjectTypeExample: otherObj1,
ezobjectInstanceExample: extendedObj1,
ezobjectInstanceExample2: extendedObj3,
bitArrayExample: [Buffer.from([0b1, 0b0]), Buffer.from([0b0, 0b1])],
tinyintArrayExample: [-128, 128],
tinyintArrayExample2: [0, 255],
smallintArrayExample: [-32767, 32767],
mediumintArrayExample: [-8388608, 8388608],
intArrayExample: [-2147483648, 2147483648],
bigintArrayExample: [-9223372036854775808, 9223372036854775808],
doubleArrayExample: [-193448295822329038402340234.23840923804823094809234245, 193448295822329038402340234.23840923804823094809234245],
floatArrayExample: [-1927492498374.2348927395, 1927492498374.2348927395],
decimalArrayExample: [-23.452, 23.452],
numericArrayExample: [-942.28734, 942.28734],
dateArrayExample: [new Date(`06-20-1986`), new Date(`11-02-1909`)],
timeArrayExample: [`-838:59:59`, `838:59:59`],
timestampArrayExample: [new Date(`2011-07-16T04:52:23-06:00`), new Date(`2013-04-26T17:04:13-06:00`)],
datetimeArrayExample: [new Date(`2011-07-16T04:52:23-06:00`), new Date(`2013-04-26T17:04:13-06:00`)],
charArrayExample: [`AU`, `CD`],
charArrayExample2: [`ÄÜ`, `CD`],
varcharArrayExample: [`Varchar Example`, `Another Varchar Example`],
varcharArrayExample2: [null, `Varchar Example 2`],
binaryArrayExample: [Buffer.from([0x04, 0x7F, 0x13, 0x38]), Buffer.from([0xA3, 0x09])],
varbinaryArrayExample: [Buffer.from([0x04, 0x7F]), Buffer.from([0xA3, 0x09, 0xDC])],
tinyblobArrayExample: [Buffer.from(`I am a tiny blob up to 256 bytes`), Buffer.from(`I am another tiny blob up to 256 bytes`)],
blobArrayExample: [Buffer.from(`I am a bigger blob up to 65 kB`), Buffer.from(`I am another bigger blob up to 65 kB`)],
mediumblobArrayExample: [Buffer.from(`I am a bigger blob up to 16 MB`), Buffer.from(`I am another bigger blob up to 16 MB`)],
longblobArrayExample: [Buffer.from(`I am a bigger blob up to 4 GB`), Buffer.from(`I am another bigger blob up to 4 GB`)],
tinytextArrayExample: [`I am a tiny text up to 256 bytes`, `I am another tiny text up to 256 bytes`],
textArrayExample: [`I am a bigger text up to 65 kB`, `I am another bigger text up to 65 kB`],
mediumtextArrayExample: [`I am a bigger text up to 16 MB`, `I am another bigger text up to 16 MB`],
longtextArrayExample: [`I am a bigger text up to 4 GB`, `I am another bigger text up to 4 GB`],
setArrayExample: [new Set([`a`, `d`]), new Set([`a`, `c`, `d`, `d`])],
booleanArrayExample: [false, true],
functionArrayExample: [(arg) => { return `I am ${arg} 1`; }, (arg) => { return `I am ${arg} 2`; }],
plainObjectArrayExample: [{ a: `I am A`, 14: `Plain Object` }, { and: `So am I too a`, 930: `Plain Object` }],
ezobjectTypeArrayExample: [otherObj1, otherObj2],
ezobjectInstanceArrayExample: [extendedObj1, extendedObj2],
ezobjectInstanceArrayExample2: [extendedObj3, extendedObj4]
});
/** Log the initialized example object */
console.log(`Initialized example object:`);
console.log(`${util.inspect(example, { depth: null })}\n`);
/** Insert example into the database */
await example.insert(db);
/** Get the inserted ID */
const id = example.id();
/** Create a second example object */
const example2 = new Example();
console.log(`Loading previous example by ID# ${id}...`);
/** Attempt to load the original example from the database into example2 */
await example2.load(id, db);
/** Test stored anonymous function */
console.log(`${example2.functionExample()(`Rich`)}\n`);
/** Log the database loaded example object */
console.log(`Database loaded example object:`);
console.log(util.inspect(example2, { depth: null }));
/** To demonstrate the ability to override the MySQL type, create config for example override */
const exampleOverrideConfig = {
tableName: `example_overrides`,
className: `ExampleOverride`,
properties: [
{ name: `id`, type: `int` },
{
name: `examples`,
type: `array`,
mysqlType: `tinytext`,
arrayOf: { type: `Example` },
saveTransform: x => x.map(y => y.id()).join(`,`),
loadTransform: async (x, property, db) => {
const arr = [];
for ( let i = 0, list = x === `` ? [] : x.split(`,`), i_max = list.length; i < i_max; i++ )
arr.push(await (new Example()).load(parseInt(list[i]), db)); /** You can also use ezobjects.Example from anywhere */
return arr;
}
}
]
};
/** Create example override class */
const ExampleOverride = ezobjects.createClass(exampleOverrideConfig);
/** Create example overrides table if it doesn`t already exist */
await ezobjects.createTable(exampleOverrideConfig, db);
/** Create new example override */
const exampleOverride = new ExampleOverride();
/** Let's just push on the two previous example objects we created, which are both the same record */
exampleOverride.examples().push(example);
exampleOverride.examples().push(example2);
/** Insert our example override into the database */
await exampleOverride.insert(db);
console.log(exampleOverride);
/** Create another example override */
const exampleOverride2 = new ExampleOverride();
/** Load it using the ID of the previous override */
await exampleOverride2.load(exampleOverride.id(), db);
/** As you can see, the two log outputs are the same, demonstrating the success of the MySQL override and change of transforms */
console.log(exampleOverride2);
} catch ( err ) {
/** Cleanly log any errors */
console.log(err.message);
} finally {
/** Close database connection */
await db.awaitEnd();
}
})();
Please open an issue on the GitHub repository if you find any broken functionality or other bugs/errors. Feature requests will also be accepted, but are not guaranteed to be implemented.
MIT Licensed