Skip to content

Commit

Permalink
release 3.0.0-alpha.3 (#28)
Browse files Browse the repository at this point in the history
- routes/permission: added GET, POST, DELETE
- permission.get: default search with deleted=0
- session.put: added
- session: store user/group info in cookie (saves DB trips)
- mysql(insert, select, update, delete): return just the query
- lib/group.get: convert booleans
- lib/user.get: convert booleans
  • Loading branch information
msimerson committed Mar 5, 2024
1 parent a3734f9 commit 28f979e
Show file tree
Hide file tree
Showing 29 changed files with 558 additions and 244 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule ".release"]
path = .release
url = [email protected]:msimerson/.release.git
1 change: 1 addition & 0 deletions .release
Submodule .release added at 8959a9
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# CHANGES

### Unreleased

### 3.0.0-alpha.3

- routes/permission: added GET, POST, DELETE
- permission.get: default search with deleted=0
- session.put: added
- session: store user/group info in cookie (saves DB trips)
- mysql(insert, select, update, delete): return just the query
- lib/group.get: convert booleans
- lib/user.get: convert booleans


[3.0.0-alpha.3]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.3
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ or

`npm run develop (development)`

will start up the HTTP service on the port specified in `conf.d/http.yml`. The default URL for the service is [http://localhost:3000](http://localhost:3000) and the API methods have documentation at [http://localhost:3000/documentation](http://localhost:3000/documentation).
will start up the HTTP service on the port specified in `conf.d/http.yml`. The default URL for the service is [http://localhost:3000](http://localhost:3000) and the API methods have documentation at [http://localhost:3000/documentation#/](http://localhost:3000/documentation#/).


## Using the API service
Expand Down
3 changes: 1 addition & 2 deletions conf.d/http.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@

default:
host: localhost
port: 3000
cookie:
# https://hapi.dev/module/cookie/api/?v=12.0.1
name: sid-nictool
password: af1b926a5e21f535c4f5b6c42941c4cf
ttl: 3600000 # 1 hour
ttl: 3600000 # 1 hour
# domain:
path: /
clearInvalid: true
Expand Down
2 changes: 1 addition & 1 deletion conf.d/mysql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ default:
# settings below this line override default settings
production:
host: mysql
password: "********"
password: '********'

# used for CI testing (GitHub Actions workflows)
test:
Expand Down
61 changes: 29 additions & 32 deletions lib/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Mysql from './mysql.js'
import { mapToDbColumn } from './util.js'

const groupDbMap = { id: 'nt_group_id', parent_gid: 'parent_group_id' }
const boolFields = ['deleted']

class Group {
constructor() {
Expand All @@ -11,65 +12,61 @@ class Group {
async create(args) {
if (args.id) {
const g = await this.get({ id: args.id })
if (g.length) return g[0].id
if (g.length === 1) return g[0].id
}

return await Mysql.insert(
`INSERT INTO nt_group`,
mapToDbColumn(args, groupDbMap),
return await Mysql.execute(
...Mysql.insert(`nt_group`, mapToDbColumn(args, groupDbMap)),
)
}

async get(args) {
return await Mysql.select(
`SELECT nt_group_id AS id
const rows = await Mysql.execute(
...Mysql.select(
`SELECT nt_group_id AS id
, parent_group_id AS parent_gid
, name
FROM nt_group WHERE`,
mapToDbColumn(args, groupDbMap),
)
}

async getAdmin(args) {
return await Mysql.select(
`SELECT nt_group_id AS id
, name
, parent_group_id AS parent_gid
, deleted
FROM nt_group WHERE`,
mapToDbColumn(args, groupDbMap),
, deleted
FROM nt_group`,
mapToDbColumn(args, groupDbMap),
),
)
for (const r of rows) {
for (const b of boolFields) {
r[b] = r[b] === 1
}
}
return rows
}

async put(args) {
if (!args.id) return false
const id = args.id
delete args.id
// Mysql.debug(1)
const r = await Mysql.update(
`UPDATE nt_group SET`,
`WHERE nt_group_id=${id}`,
mapToDbColumn(args, groupDbMap),
const r = await Mysql.execute(
...Mysql.update(
`nt_group`,
`nt_group_id=${id}`,
mapToDbColumn(args, groupDbMap),
),
)
// console.log(r)
return r.changedRows === 1
}

async delete(args, val) {
const g = await this.getAdmin(args)
if (g.length !== 1) return false
async delete(args) {
await Mysql.execute(`UPDATE nt_group SET deleted=? WHERE nt_group_id=?`, [
val ?? 1,
g[0].id,
args.deleted ?? 1,
args.id,
])
return true
}

async destroy(args) {
const g = await this.getAdmin(args)
if (g.length === 1) {
await Mysql.execute(`DELETE FROM nt_group WHERE nt_group_id=?`, [g[0].id])
}
return await Mysql.execute(
...Mysql.delete(`nt_group`, { nt_group_id: args.id }),
)
}
}

Expand Down
13 changes: 8 additions & 5 deletions lib/group.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ describe('group', function () {
id: testCase.id,
name: testCase.name,
parent_gid: 0,
deleted: false,
})
})

Expand All @@ -29,6 +30,7 @@ describe('group', function () {
id: testCase.id,
name: testCase.name,
parent_gid: 0,
deleted: false,
})
})

Expand All @@ -39,17 +41,18 @@ describe('group', function () {
id: testCase.id,
name: 'example.net',
parent_gid: 0,
deleted: false,
},
])
assert.ok(await Group.put({ id: testCase.id, name: testCase.name }))
})

it('deletes a group', async () => {
assert.ok(await Group.delete({ id: testCase.id }))
let g = await Group.getAdmin({ id: testCase.id })
assert.equal(g[0].deleted, 1)
await Group.delete({ id: testCase.id }, 0) // restore
g = await Group.getAdmin({ id: testCase.id })
assert.equal(g[0].deleted, 0)
let g = await Group.get({ id: testCase.id, deleted: 1 })
assert.equal(g[0]?.deleted, true)
await Group.delete({ id: testCase.id, deleted: 0 }) // restore
g = await Group.get({ id: testCase.id })
assert.equal(g[0].deleted, false)
})
})
44 changes: 16 additions & 28 deletions lib/mysql.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,34 +42,26 @@ class Mysql {
return rows
}

async insert(query, params = {}) {
const skipExecute = params.skipExecute ?? false
delete params.skipExecute

query += `(${Object.keys(params).join(',')}) VALUES(${Object.keys(params).map(() => '?')})`

if (skipExecute) return query
return await this.execute(query, Object.values(params))
insert(table, params = {}) {
return [
`INSERT INTO ${table} (${Object.keys(params).join(',')}) VALUES(${Object.keys(params).map(() => '?')})`,
Object.values(params),
]
}

async select(query, params = {}) {
const skipExecute = params.skipExecute ?? false
delete params.skipExecute

const [queryWhere, paramsArray] = this.whereConditions(query, params)

if (skipExecute) return queryWhere
return await this.execute(queryWhere, paramsArray)
select(query, params = {}) {
return this.whereConditions(query, params)
}

async update(query, where, params = {}) {
const skipExecute = params.skipExecute ?? false
delete params.skipExecute

query += ` ${Object.keys(params).join('=?,')}=? ${where}`
update(table, where, params = {}) {
return [
`UPDATE ${table} SET ${Object.keys(params).join('=?,')}=? WHERE ${where}`,
Object.values(params),
]
}

if (skipExecute) return { q: query, p: Object.values(params) }
return await this.execute(query, Object.values(params))
delete(table, params) {
return this.whereConditions(`DELETE FROM ${table}`, params)
}

whereConditions(query, params) {
Expand All @@ -82,6 +74,7 @@ class Mysql {
// Object to WHERE conditions
let first = true
for (const p in params) {
if (first) newQuery += ' WHERE'
if (!first) newQuery += ' AND'
newQuery += ` ${p}=?`
paramsArray.push(params[p])
Expand All @@ -91,11 +84,6 @@ class Mysql {
return [newQuery, paramsArray]
}

async delete(query, params) {
const [queryWhere, paramsArray] = this.whereConditions(query, params)
return await this.execute(queryWhere, paramsArray)
}

async disconnect(dbh) {
const d = dbh || this.dbh
if (_debug) console.log(`MySQL connection id ${d.connection.connectionId}`)
Expand Down
103 changes: 63 additions & 40 deletions lib/mysql.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,57 +20,80 @@ describe('mysql', () => {
})
}

it('SQL: formats SELECT queries', async () => {
const r = await Mysql.select(`SELECT * FROM nt_user WHERE`, {
last_name: 'Test',
skipExecute: true,
})
assert.equal(r, `SELECT * FROM nt_user WHERE last_name=?`)
it('formats SELECT queries', () => {
assert.deepEqual(
Mysql.select(`SELECT * FROM nt_user`, {
last_name: 'Test',
}),
[`SELECT * FROM nt_user WHERE last_name=?`, ['Test']],
)
})

it('SQL: formats INSERT queries', async () => {
const r = await Mysql.select(`INSERT INTO nt_user SET`, {
it('formats INSERT query', () => {
const r = Mysql.insert(`nt_user`, {
first_name: 'uNite',
last_name: 'Test',
skipExecute: true,
})
assert.equal(r, `INSERT INTO nt_user SET first_name=? AND last_name=?`)
assert.deepEqual(r, [
`INSERT INTO nt_user (first_name,last_name) VALUES(?,?)`,
['uNite', 'Test'],
])
})

it('SQL: formats UPDATE queries, 1', async () => {
const { q, p } = await Mysql.update(
`UPDATE nt_user SET`,
`WHERE nt_user_id=4096`,
{ first_name: 'uNite', skipExecute: true },
)
assert.equal(q, `UPDATE nt_user SET first_name=? WHERE nt_user_id=4096`)
assert.deepEqual(p, ['uNite'])
describe('update', () => {
it('formats with one value', () => {
const r = Mysql.update(`nt_user`, `nt_user_id=4096`, {
first_name: 'uNite',
})
assert.deepEqual(r, [
`UPDATE nt_user SET first_name=? WHERE nt_user_id=4096`,
['uNite'],
])
})

it('formats with two values', () => {
const r = Mysql.update(`nt_user`, `nt_user_id=4096`, {
last_name: 'Teste',
is_admin: 1,
})
assert.deepEqual(r, [
`UPDATE nt_user SET last_name=?,is_admin=? WHERE nt_user_id=4096`,
['Teste', 1],
])
})

it('formats with three values', () => {
const r = Mysql.update(`nt_user`, `nt_user_id=4096`, {
first_name: 'Unit',
last_name: 'Test',
is_admin: 0,
})
assert.deepEqual(r, [
`UPDATE nt_user SET first_name=?,last_name=?,is_admin=? WHERE nt_user_id=4096`,
['Unit', 'Test', 0],
])
})
})

it('SQL: formats UPDATE queries, 2', async () => {
const { q, p } = await Mysql.update(
`UPDATE nt_user SET`,
`WHERE nt_user_id=4096`,
{ last_name: 'Teste', is_admin: 1, skipExecute: true },
)
assert.equal(
q,
`UPDATE nt_user SET last_name=?,is_admin=? WHERE nt_user_id=4096`,
)
assert.deepEqual(p, ['Teste', 1])
describe('delete', () => {
it('no params', () => {
assert.deepEqual(Mysql.delete(`nt_user`, {}), [`DELETE FROM nt_user`, []])
})

it('with params', () => {
assert.deepEqual(Mysql.delete(`nt_user`, { last_name: 'Test' }), [
`DELETE FROM nt_user WHERE last_name=?`,
['Test'],
])
})
})

it('SQL: formats UPDATE queries, 3', async () => {
const { q, p } = await Mysql.update(
`UPDATE nt_user SET`,
`WHERE nt_user_id=4096`,
{ first_name: 'Unit', last_name: 'Test', is_admin: 0, skipExecute: true },
)
assert.equal(
q,
`UPDATE nt_user SET first_name=?,last_name=?,is_admin=? WHERE nt_user_id=4096`,
)
assert.deepEqual(p, ['Unit', 'Test', 0])
it('executes formatted queries', async () => {
const [query, argsArray] = Mysql.select(`SELECT * FROM nt_options`)
const r = await Mysql.execute(query, argsArray)
assert.deepEqual(r[0].option_id, 1)

// await Mysql.execute(...Mysql.select(`SELECT * FROM nt_options`))
})

it('disconnects', async () => {
Expand Down
Loading

0 comments on commit 28f979e

Please sign in to comment.