ReadME
![Codacy Badge](https://api.codacy.com/project/badge/Grade/928cce8dd2ba4fcaa4d857552209fd16)
![](./test/resource/UiYBH9U.png)
This is depend on mysql
which made for migrating to features
-
multiple connection pool
-
connection writer/reader
-
async/await
-
model.query
-
log print
-
events
See the test Examples
Installation
npm i pool-mysql --save
Usage
Settings
- pool-mysql loads settings from process.env
There is a helpful package dotenv
SQL_HOST={{writer}}
SQL_HOST_READER={{reader}}
SQL_USER={{user}}
SQL_PASSWORD={{passwd}}
SQL_TABLE={{table name}}
Normal Query
const pool = require('pool-mysql')
pool.query(sql, value, (err, data) => {
})
Multiple Pool
const options = {
writer: {
host: process.env.HOST2,
database: process.env.DB2
},
reader: {
host: process.env.HOST2,
database: process.env.DB2
},
forceWriter: true
}
const pool2 = pool.createPool({ options })
Create connection
const connection = pool.connection()
connection.query(sql, values, (err,data) => {
})
try {
const result = await connection.q(sql,value)
} catch(err) {
console.log(err)
}
Connection tag
const connection = pool.connection({ limit: 5 })
const connection = pool.connection({ priority: 1 })
Model setting
const Schema = require('pool-mysql').Schema
const Posts = class posts extends Schema {
get columns() {
return {
id: Schema.Types.PK,
user: require('./user')
user2: {
ref: require('./user'),
column: 'user'
},
user3: {
type: Schema.Types.FK(require('./User.js'), 'id'),
required: true,
length: { min: 1, max: 20 },
},
user_type: {
type: Schema.Types.ENUM('A','B','C')
},
available_area: {
type: Schema.Types.Polygon
},
created_at: {
type: Schema.Types.DateTime
}
}
}
const User = class user extends Schema {
get columns() {
return {
id: Schema.Types.PK,
user: [require('./posts')]
}
}
Query
await Posts
.SELECT()
.FROM()
.WHERE({id: 3})
.POPULATE('user')
.PRINT()
.WRITER
.exec()
Populate
const result = await Drivers
.SELECT()
.FROM()
.WHERE({ driver_id: 3925 })
.POPULATE({ trip_id: { driver_loc_FK_multiple: {} }})
.FIRST()
.exec()
Nested Query
const results = Trips.SELECT(Trips.KEYS, Users.KEYS)
.FROM()
.LEFTJOIN('user_info ON uid = trips.user_id')
.WHERE('trip_id = ?', 23890)
.AND('trip_id > 0')
.LIMIT()
.NESTTABLES()
.MAP(result => {
const trip = result.trips
trip.user = result.user_info
return trip
})
.FIRST()
.exec()
results.should.have.property('trip_id')
results.trip_id.should.equal(23890)
results.should.have.property('user_id')
results.should.have.property('user')
results.user.should.have.property('uid')
assert(results instanceof Trips)
Stream Query
for massive rows query
TableA
.SELECT()
.FROM()
.LEFTJOIN('tableB on tableB.id = tableA.id')
.LIMIT(25)
.NESTTABLES()
.MAP(data => {
const tableA = data.tableA
return { ...tableA, user: data.tableB }
})
.stream({
connection,
highWaterMark: 5,
onValue: (rows, done) => {
assert.equal(rows.length, 5)
expect(rows[0]).haveOwnProperty('id')
expect(rows[0]).haveOwnProperty('user')
done()
},
onEnd: (error) => {
ok()
}
})
async / await
done
will be a empty function
.stream({
connection,
highWaterMark: 1,
onValue: async (row,done) => {
await doSomething()
},
onEnd: async (error) => {
ok()
}
})
Insert
await FOO.INSERT()
.INTO()
.SET(obj)
.exec(connection)
await FOO.INSERT()
.INTO('table (`id`, `some_one_field`)')
.VALUES(array)
.exec(connection)
Updated
- return value after updated
const results = await Block
.UPDATE()
.SET('id = id')
.WHERE({ blocked: 3925 })
.UPDATED('id', 'blocker')
.AFFECTED_ROWS(1)
.CHANGED_ROWS(1)
.ON_ERR('error message')
.exec()
for (const result of results) {
result.should.have.property('id')
result.should.have.property('blocker')
}
cache
const redis = require('redis')
const bluebird = require('bluebird')
bluebird.promisifyAll(redis.RedisClient.prototype)
bluebird.promisifyAll(redis.Multi.prototype)
const client = redis.createClient({
host: ...,
port: ...,
db: ...
})
pool.redisClient = Redis
const connection = pool.connection
await connection.q('SELECT id FROM user WHERE uid = ?', userID, {
key: `api:user:id:${userID}`,
EX: process.env.NODE_ENV == 'production' ? 240 : 12,
isJSON: true,
})
await connection.q('SELECT id FROM user WHERE uid = ?', userID, { EX: 60})
User.SELECT().FROM().WHERE('uid = ?',id).EX(60, { forceUpdate: true }).exec()
custom error message
await Trips.UPDATE('user_info')
.SET({ user_id: 31 })
.WHERE({ uid: 31 })
.CHANGED_ROWS(1)
.ON_ERR(errMessage)
.exec()
await Trips.UPDATE('user_info')
.SET({ user_id: 31 })
.WHERE({ uid: 31 })
.CHANGED_ROWS(1)
.ON_ERR(err => {
return 'error value'
})
.exec()
Combine queries
- mass queries in the same time, combined queries will query once only (scope in instance)
Trips.SELECT().FROM().WHERE({ trip_id:1 }).COMBINE().exec().then().catch()
Trips.SELECT().FROM().WHERE({ trip_id:1 }).COMBINE().exec().then().catch()
Trips.SELECT().FROM().WHERE({ trip_id:1 }).COMBINE().exec().then().catch()
Trips.SELECT().FROM().WHERE({ trip_id:1 }).COMBINE().exec().then().catch()
Auto Free Connections
Events
-
log
logs not suggested to subscribe
-
get
called when connection got from pool
-
create
called when connection created
-
release
called when connection released
-
will_query
-
query
called when connection query
-
did_query
-
amount
called when connection pool changes amount
-
end
called when connection end
-
request
request a connection but capped on connection limit
-
recycle
free connection is back
-
warn
warning
-
err
error
pool.event.on('get', connection => {
console.log(connection.id)
})
Validation
default types
Variables
class PlateNumber extends Scheme.Types.Base {
static validate(string) {
return string.match(/[0-9]+-[A-Z]+/)
}
}
module.exports = class driver_review_status extends Scheme {
get columns() {
return {
'uid': {
type: Scheme.Types.PK,
required: true
},
'first_name': {
type: Scheme.Types.String,
required: true,
},
'last_name': String,
'car_brand': {
type: Scheme.Types.JSONString
},
'model': {
type: String
},
'phone_number': {
type: Scheme.Types.String,
required: true,
length: 10
},
'plate_number': {
type: PlateNumber,
length: { min: 6 , max: 9 }
},
'email': {
type: Scheme.Types.Email,
required: true
}
}
}
}
Mock response
Dry Run
await Table.INSERT().INTO().rollback()
Log level
default to error
pool.logger = 'error'
Custom Logger
pool._logger = (err, toPrint) => { }