UNPKG

pgobject

Version:

pgObject - simple ORM for PostgreSQL and MySql

584 lines (520 loc) 16.2 kB
# pgObject - simple ORM for PostgreSQL and MySql ## For PostgreSQL orm is used with [PG][pg] ## For MySQL orm is used with [mysql][mysql] or [mysql2][mysql2] ### [Exaple][example] ### Quick Example (PostgreSQL). For MySql it works the same. #### 1. Create a table in the database: ```SQL CREATE TABLE userExample ( id SERIAL, name VARCHAR(60), surname VARCHAR(60), email VARCHAR(60), token VARCHAR(64), createdDate timestamp(6) with time zone, PRIMARY KEY (id) ); ``` #### 2. Create a class: ```js const PgObject = require('pgobject'); class UserExample extends PgObject { static get schema() { return { id: { pk: true, }, name: {}, surname: {}, email: { required: true, }, token: {}, createdDate: { default: new Date(), } } } static get table() { return 'userExample'; } } ``` #### 3. pgObject configuration: ##### PostgreSQL: ```js const { Client } = require('pg'); const PgObject = require('pgobject'); const client = new Client({ user: process.env.DB_USER, host: process.env.DB_HOST, database: process.env.DB_NAME, password: process.env.DB_PASS, port: process.env.DB_PORT, }); await client.connect(); PgObject.setClient(client); ``` ##### MySQl: ```js const mysql = require('mysql2'); const PgObject = require('pgobject'); const client = mysql.createConnection({ user: process.env.DB_USER, host: process.env.DB_HOST, database: process.env.DB_NAME, password: process.env.DB_PASS, port: process.env.DB_PORT, }); PgObject.setClient(client, 'mysql'); ``` #### 4. Use this class: ```js const userExample = new UserExample({ name: "nameExample", surname: "surnameExample", }); console.log(userExample.f.name); // "nameExample" console.log(userExample.f.surname); // "surnameExample" await userExample.save(); // OR await userExample.insert(); const users1 = await UserExample.select("WHERE name = $1 LIMIT 1", ['nameExample']); // OR await PgObject // .query("SELECT * FROM userExample WHERE name = $1 LIMIT 1", ['nameExample'], UserExample); console.log(users1[0].f.name); // "nameExample" console.log(users1[0].f.surname); // "surnameExample" users1[0].f.surname = "newSurname"; await users1[0].save(); // OR await users1[0].update(); const users2 = await UserExample.select("WHERE name = $1 LIMIT 1", ['nameExample']); console.log(users1[0].f.name); // "nameExample" console.log(users1[0].f.surname); // "newSurname" await users2[0].delete(); ``` ## Query to DB #### 1. Static method `select`: ```js const users = await UserExample.select("WHERE name = $1 LIMIT 1", ['nameExample']); ``` - `static select(String where, Array values)` - return array of UserExample objects; #### 2. Static method `query`: ```js const users = await PgObject.query("SELECT * FROM userExample WHERE name = $1 LIMIT 1", ['nameExample'], UserExample); // OR const users = await UserExample.query("SELECT * FROM userExample WHERE name = $1 LIMIT 1", ['nameExample'], UserExample); ``` - `static query(String query, Array values, class PgObjecExtension)` - return array of UserExample objects; ```js const users = await PgObject.query("SELECT * FROM userExample WHERE name = $1 LIMIT 1", ['nameExample']); // OR const users = await UserExample.query("SELECT * FROM userExample WHERE name = $1 LIMIT 1", ['nameExample']); ``` - `static query(String query, Array values)` - see [pg query documentation][pgQuery] #### 3. Method `save` ```js const user = new UserExample({ name: "nameExample", surname: "surnameExample", }); // in this case there will be an insert await user.save(); user.f.name = "newName"; // in this case there will be an update await user.save(); ``` -`save()` - depending on we saved this object in the database will be an `insert` or an `update` #### 4. Method `insert` ```js const user = new UserExample({ name: "nameExample", surname: "surnameExample", }); await user.insert(); ``` -`insert()` - save this object to the database #### 5. Method `update` ```js const users = await UserExample.select("WHERE name = $1 LIMIT 1", ["nameExample"]); users[0].f.name = "newName"; await users[0].update(); ``` -`update()` - update this object in the database #### 5. Method `delete` ```js const users = await UserExample.select("WHERE name = $1 LIMIT 1", ["nameExample"]); await users[0].delete(); ``` -`delete()` - delete this object from the database ## PgObject class extension For the PgObject class extension we must define `static get schema()` and `static get table()` ```js const PgObject = require('pgobject'); class UserExample extends PgObject { static get schema() { return { id: { pk: true, }, name: {}, surname: {}, email: { set (val, target, name) { if (target[name]) { return target[name]; } return val; }, required: true, }, token: { get (val, target, name) { if (!val) { Math.random().toString(36).substr(2); } return val; }, }, createdDate: { default: new Date(), }, fullName: { computed: true, get (val, target, name) { return `${target['name']} ${target['surname']}`; }, } } } static get table() { return 'userExample'; } static get notValidateSchema() { // default return false return true; } } ``` #### 1. `static get schema()` - return object: - `pk: true` - PRIMARY KEY - `computed: true` - This is a calculated field - it does not exist in the database - `required: true` - This fied is required - `default: new Date()` - Default value - `get (val, target, name)` - val: current value, target: all fields, name: name of this field - `set (val, target, name)` - val: new value, target: all fields, name: name of this field `pk: true`: You should define at least one field as the primary key. If your schema doesn't have a primary key you will see an error. ```console Error, please set the PRIMARY KEY in the UserExample class ``` `computed: true`: If you want to have a field that does not exist in the database table and will not participate in an insert or update, you must set a computed property. Example: fullName is computed field ```js class UserExample extends PgObject { static get schema() { return { ... fullName: { computed: true } } } ... } const user = new UserExample({ fullName: 'Test Tets', ... }); console.log(user.f.fullName); // 'Test Tets'; // fullName will not save in the database await user.save(); ``` `required: true`: If you try to save your UserExample object to the database without values of the required fields - you will see an error. Example: email is required field ```js class UserExample extends PgObject { static get schema() { return { ... email: { required: true, } } } ... } const user = new UserExample({ name: "nameExample", surname: "surnameExample", }); await user.save(); // console: // Error: email field in UserExample object is required; ``` `default: someDefaultValue` You can set default values for fields ```js class UserExample extends PgObject { static get schema() { return { ... name: { default: 'Test', } } } ... } const user = new UserExample(); console.log(user.f.name); // 'Test'; // the name field will save with the default value ('Test'); await user.save(); user.f.name = 'newValue'; // the name field will save with the new value ('newValue'); await user.save(); ``` `get (val, target, name)` - is like standart getter `val` - the current value of this field `target` - all fields of this object (this.f) `name` - string, name of this field Example: ```js class UserExample extends PgObject { static get schema() { return { id: { pk: true, }, name: { default: 'TEST NAME', }, surname: { get(val, target, name) { console.log('val:', val); console.log('target:', target); console.log('field name:', name); console.log('full name:', target.name, val); return `Surname - ${val}`; } }, ... } ... } const user = new UserExample(); user.f.surname = 'SURNAME' const surname = user.f.surname; console.log(surname); // console: // val: SURNAME // target: { // id: { pk: true }, // name: { default: 'TEST NAME' }, // surname: { get: [Function: get], value: 'SURNAME' }, // ... // } // field name: surname // full name: TEST NAME SURNAME // Surname - SURNAME ``` `set (val, target, name)` - is like standart setter `val` - new value of this field `target` - all fields of this object (this.f) `name` - string, name of this field Example: ```js class UserExample extends PgObject { static get schema() { return { id: { pk: true, }, name: { default: 'TEST NAME', }, surname: { set(val, target, name) { console.log('val:', val); console.log('target:', target); console.log('field name:', name); console.log('full name:', target.name, val); return `Surname - ${val}`; } }, ... } ... } const user = new UserExample(); user.f.surname = 'NEW SURNAME'; // console: // val: NEW SURNAME // target: { // id: { pk: true }, // name: { default: 'TEST NAME' }, // surname: { set: [Function: set] }, // ... // } // name: surname // full name: TEST NAME NEW SURNAME // the surname field will save with the 'Surname - NEW SURNAME' value ('newValue'); await user.save(); // console: // QueryLog: INSERT INTO userExample ( name, surname ) VALUES ( $1, $2 ) RETURNING * // Values: [ 'TEST NAME', 'Surname - NEW SURNAME' ] // Execution time: 1 ms ``` #### 2. `static get table()` - return string with table name #### 3. `static get notValidateSchema()` - if return true - schema will be not validated By default you can't dynamically add fields. But be careful, if you add a field outside of your schema, you may have problems saving the object in the database. Example: ```js const userExample = new UserExample(); userExample.f.newfield = 'test'; // console: if static get notValidateSchema() { return false } (by default) // Error, newfield is not in the schema, check your schema getter, or notValidateSchema should return true ``` ## Display logs #### 1. `PgObject.setLog(true)` - enable the log If you want to see your queries to the database enable the log. ```js PgObject.setLog(true); ``` And after that, you will see log in your console. Example: ```js PgObject.setLog(true); const users = await UserExample.select("WHERE name = $1 LIMIT 1", ['newName']); // console: // QueryLog: SELECT * FROM admin WHERE name = $1 LIMIT 1 // Values: [ 'newName' ] // Execution time: 1 ms const user = new UserExample({ name: "nameExample", surname: "surnameExample", }); await user.save(); // console: // QueryLog: INSERT INTO admin ( name, surname, ctime ) VALUES ( $1, $2, $3 ) RETURNING * // Values: [ 'nameExample', 'surnameExample', 2022-09-29T13:04:34.257Z ] // Execution time: 1 ms ``` #### 2. `PgObject.setLogger(console)` - enable the log If you want use your own logger you can set yor logger. By default we use console. Example: ```js const logger = { log() { console.log("MyLogger", arguments) } }; PgObject.setLog(true); PgObject.setLogger(logger); const users = await UserExample.select("WHERE name = $1 LIMIT 1", ['newName']); // console: // MyLogger [Arguments] { // '0': '\x1B[32m', // '1': 'Query: ', // '2': 'DELETE FROM exapmleAdmin WHERE id = $1', // '3': '\x1B[0m', // '4': '\nValues: ', // '5': [ 6 ], // '6': '\nExecution time:', // '7': 3, // '8': 'ms' // } ``` ## TO JSON If you want to serialize your object to JSON you can override `toJSON()` method; By default we serialize all fields in schema. Example: ```js const users = await UserExample.select("WHERE name = $1 LIMIT 1", ['newName']); console.log(JSON.stringify(users)); // console: // ["{\"id\":437,\"name\":\"TEST NAME\",\"createdDate\":\"2022-09-29T22:20:59.740Z\" ...] ``` ## Transaction #### Quick Example ```js PgObject.setLog(true); await PgObject.createTransaction(async () => { const user1 = new UserExample(); user1.f.name = 'user1'; const user2 = new UserExample(); user2.f.name = 'user2'; await user1.save(); await user2.save(); }); // console: // QueryLog: START TRANSACTION ISOLATION LEVEL READ UNCOMMITTED // Values: undefined // Execution time: 1 ms // QueryLog: INSERT INTO admin ( name, ctime ) VALUES ( $1, $2 ) RETURNING * // Values: [ 'user1', 2022-09-29T13:45:20.620Z ] // Execution time: 1 ms // QueryLog: INSERT INTO admin ( name, ctime ) VALUES ( $1, $2 ) RETURNING * // Values: [ 'user2', 2022-09-29T13:45:20.620Z ] // Execution time: 1 ms // QueryLog: COMMIT // Values: undefined // Execution time: 1 ms ``` #### Transaction Isolation - `READ UNCOMMITTED` - PgObject.mode.readUncommitted (by default) - `READ COMMITTED` - PgObject.mode.readCommitted - `REPEATABLE READ` - PgObject.mode.repeatableRead - `SERIALIZABLE` - PgObject.mode.serializable example: ```js PgObject.setLog(true); await PgObject.create(async () => { const user1 = new UserExample(); user1.f.name = 'user1'; const user2 = new UserExample(); user2.f.name = 'user2'; await user1.save(); await user2.save(); }, PgObject.mode.serializable); // console: // QueryLog: START TRANSACTION ISOLATION LEVEL SERIALIZABLE // Values: undefined // Execution time: 1 ms // QueryLog: INSERT INTO admin ( name, ctime ) VALUES ( $1, $2 ) RETURNING * // Values: [ 'user1', 2022-09-29T13:45:20.620Z ] // Execution time: 1 ms // QueryLog: INSERT INTO admin ( name, ctime ) VALUES ( $1, $2 ) RETURNING * // Values: [ 'user2', 2022-09-29T13:45:20.620Z ] // Execution time: 1 ms // QueryLog: COMMIT // Values: undefined // Execution time: 1 ms ``` #### PgObject public methods: - `.insert()` - insert data. - `.update()` - update data. - `.delete()` - delete data. - `.save()` - insert or update data. #### PgObject static methods: - `PgObject.setClient(Object client, String type)` - set db client. client - db client, type - 'mysql' or 'postgresql', by default 'postgresql'. - `PgObject.setLog(Boolean log)` - if true, write a log to the console. - `PgObject.setLogger(Object logger)` - install your own logger. - `PgObject.query(String query, Array values, Class classObj)` - create a db query - `PgObject.select(String whereString, Array values)` - select data from db - `PgObject.createTransaction(Function cb, PgObject.mode mode)` - create a transaction. cb - function, mode - isolation level - `PgObject.startTransaction(PgObject.mode mode)` - start transaction. mode - isolation level - `PgObject.commit()` - commit transaction. - `PgObject.rollback()` - rollback transaction. #### PgObject override methods: - `static get schema() {}` - `static get table() {}` - `static get notValidateSchema() { }` - `toJSON() {}` ## License MIT [pg]: https://node-postgres.com/ [mysql]: https://www.npmjs.com/package/mysql [mysql2]: https://www.npmjs.com/package/mysql2 [pgQuery]: https://node-postgres.com/features/queries [example]: https://github.com/gyk088/pgObject/blob/main/example.js