breadfruit 2.1.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -22
- package/index.js +65 -75
- package/package.json +39 -12
- package/.coveralls.yml +0 -2
- package/.npmignore +0 -8
- package/.travis.yml +0 -4
- package/happy_breadfruit.png +0 -0
- package/test/index.js +0 -95
package/README.md
CHANGED
|
@@ -1,49 +1,107 @@
|
|
|
1
1
|
# breadfruit
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/breadfruit)
|
|
4
|
+
[](https://github.com/iceddev/breadfruit/actions/workflows/ci.yml)
|
|
5
|
+
[](https://codecov.io/gh/iceddev/breadfruit)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
[](https://www.npmjs.com/package/breadfruit)
|
|
8
|
+
[](https://github.com/iceddev/breadfruit/blob/main/LICENSE)
|
|
4
9
|
|
|
5
|
-
Not really bread. Not really fruit. Just like this package.
|
|
10
|
+
Not really bread. Not really fruit. Just like this package. Simple CRUD helpers on top of [knex](https://knexjs.org/).
|
|
6
11
|
|
|
7
12
|

|
|
8
13
|
|
|
9
|
-
##
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install breadfruit
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Requires Node.js `>=20`.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
Breadfruit is an ES module with a default export.
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
import breadfruit from 'breadfruit';
|
|
10
28
|
|
|
11
|
-
```javascript
|
|
12
29
|
const config = {
|
|
13
|
-
client: '
|
|
30
|
+
client: 'pg',
|
|
14
31
|
connection: 'postgres://postgres@localhost:5432/someDatabase',
|
|
15
|
-
pool: { min: 1, max: 7 }
|
|
32
|
+
pool: { min: 1, max: 7 },
|
|
16
33
|
};
|
|
17
34
|
|
|
18
|
-
const
|
|
35
|
+
const { browse, read, edit, add, del, raw } = breadfruit(config);
|
|
19
36
|
```
|
|
20
37
|
|
|
21
|
-
##
|
|
38
|
+
## API
|
|
22
39
|
|
|
23
|
-
|
|
24
|
-
const {browse, read, edit, add, del, raw} = require('breadfruit')(config);
|
|
40
|
+
### `browse(table, fields, filter, options?)`
|
|
25
41
|
|
|
26
|
-
|
|
27
|
-
const users = await browse('users', ['username', 'user_id'], {active: true});
|
|
42
|
+
Returns an array of rows.
|
|
28
43
|
|
|
44
|
+
```js
|
|
45
|
+
const users = await browse('users', ['username', 'user_id'], { active: true });
|
|
46
|
+
```
|
|
29
47
|
|
|
30
|
-
|
|
31
|
-
|
|
48
|
+
Supported `options`:
|
|
49
|
+
- `limit` (default `1000`)
|
|
50
|
+
- `offset` (default `0`)
|
|
51
|
+
- `orderBy` — column name or array of column names
|
|
52
|
+
- `sortOrder` — `'ASC'` / `'DESC'` (default `'ASC'`), or an array matching `orderBy`
|
|
53
|
+
- `dateField` (default `'created_at'`)
|
|
54
|
+
- `search_start_date` / `search_end_date` — adds a `whereBetween` on `dateField`
|
|
55
|
+
- `dbApi` — override the internal knex instance (useful for transactions)
|
|
32
56
|
|
|
57
|
+
### `read(table, fields, filter, options?)`
|
|
33
58
|
|
|
34
|
-
|
|
35
|
-
const updatedUser = await edit('users', ['username', 'first_name'], {first_name: 'Howard'}, {user_id: 1337});
|
|
59
|
+
Returns a single row.
|
|
36
60
|
|
|
61
|
+
```js
|
|
62
|
+
const user = await read('users', ['username', 'first_name'], { user_id: 1337 });
|
|
63
|
+
```
|
|
37
64
|
|
|
38
|
-
|
|
39
|
-
const newUser = await add('users', ['user_id'], {first_name: 'Howard', username: 'howitzer'});
|
|
65
|
+
### `add(table, returnFields, data, options?)`
|
|
40
66
|
|
|
67
|
+
Inserts and returns the new row.
|
|
41
68
|
|
|
42
|
-
|
|
43
|
-
const
|
|
69
|
+
```js
|
|
70
|
+
const newUser = await add('users', ['user_id'], {
|
|
71
|
+
first_name: 'Howard',
|
|
72
|
+
username: 'howitzer',
|
|
73
|
+
});
|
|
74
|
+
```
|
|
44
75
|
|
|
76
|
+
### `edit(table, returnFields, data, filter, options?)`
|
|
45
77
|
|
|
46
|
-
|
|
47
|
-
const rows = await raw('select * from users');
|
|
78
|
+
Updates matching rows and returns the first updated row.
|
|
48
79
|
|
|
80
|
+
```js
|
|
81
|
+
const updated = await edit(
|
|
82
|
+
'users',
|
|
83
|
+
['username', 'first_name'],
|
|
84
|
+
{ first_name: 'Howard' },
|
|
85
|
+
{ user_id: 1337 },
|
|
86
|
+
);
|
|
49
87
|
```
|
|
88
|
+
|
|
89
|
+
### `del(table, filter, options?)`
|
|
90
|
+
|
|
91
|
+
Deletes matching rows and returns the count.
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
const count = await del('users', { user_id: 1337 });
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### `raw(sql, options?)`
|
|
98
|
+
|
|
99
|
+
Runs a raw SQL statement and returns rows.
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
const rows = await raw('select * from users');
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
ISC
|
package/index.js
CHANGED
|
@@ -1,89 +1,79 @@
|
|
|
1
|
-
|
|
1
|
+
import knexConstructor from 'knex';
|
|
2
2
|
|
|
3
|
-
function connect(settings) {
|
|
3
|
+
export default function connect(settings) {
|
|
4
4
|
const knex = knexConstructor(settings);
|
|
5
|
-
const
|
|
5
|
+
const defaults = {
|
|
6
6
|
dateField: 'created_at',
|
|
7
|
-
dbApi: knex,
|
|
8
7
|
limit: 1000,
|
|
9
8
|
offset: 0,
|
|
10
9
|
sortOrder: 'ASC',
|
|
11
10
|
};
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const sortOrder = options.sortOrder || defaultOptions.sortOrder;
|
|
12
|
+
function browse(table, fields, filter, options = {}) {
|
|
13
|
+
const dbApi = options.dbApi || knex;
|
|
14
|
+
const limit = options.limit ?? defaults.limit;
|
|
15
|
+
const offset = options.offset ?? defaults.offset;
|
|
16
|
+
const dateField = options.dateField || defaults.dateField;
|
|
17
|
+
const sortOrder = options.sortOrder || defaults.sortOrder;
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
let query = dbApi(table)
|
|
20
|
+
.where(filter)
|
|
21
|
+
.select(fields)
|
|
22
|
+
.limit(limit)
|
|
23
|
+
.offset(offset);
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if(Array.isArray(options.orderBy)) {
|
|
34
|
-
options.orderBy.forEach((orderBy, index) => {
|
|
35
|
-
if(Array.isArray(sortOrder)) {
|
|
36
|
-
return query = query.orderBy(orderBy, sortOrder[index]);
|
|
37
|
-
}
|
|
38
|
-
query = query.orderBy(orderBy, sortOrder);
|
|
39
|
-
});
|
|
40
|
-
} else {
|
|
41
|
-
query = query.orderBy(options.orderBy, sortOrder);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
25
|
+
if (options.search_start_date && options.search_end_date) {
|
|
26
|
+
query = query.whereBetween(dateField, [
|
|
27
|
+
options.search_start_date,
|
|
28
|
+
options.search_end_date,
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
44
31
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
.where(filter)
|
|
51
|
-
.select(fields)
|
|
52
|
-
.then(([row]) => {
|
|
53
|
-
return row;
|
|
32
|
+
if (options.orderBy) {
|
|
33
|
+
if (Array.isArray(options.orderBy)) {
|
|
34
|
+
options.orderBy.forEach((orderBy, index) => {
|
|
35
|
+
const order = Array.isArray(sortOrder) ? sortOrder[index] : sortOrder;
|
|
36
|
+
query = query.orderBy(orderBy, order);
|
|
54
37
|
});
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return dbApi(table)
|
|
59
|
-
.returning(fields)
|
|
60
|
-
.insert(data)
|
|
61
|
-
.then(([row]) => {
|
|
62
|
-
return row;
|
|
63
|
-
});
|
|
64
|
-
},
|
|
65
|
-
edit(table, fields, data, filter, options = {}) {
|
|
66
|
-
const dbApi = options.dbApi || knex;
|
|
67
|
-
return dbApi(table)
|
|
68
|
-
.where(filter)
|
|
69
|
-
.returning(fields)
|
|
70
|
-
.update(data)
|
|
71
|
-
.then(([row]) => {
|
|
72
|
-
return row;
|
|
73
|
-
});
|
|
74
|
-
},
|
|
75
|
-
del(table, filter, options = {}) {
|
|
76
|
-
const dbApi = options.dbApi || knex;
|
|
77
|
-
return dbApi(table)
|
|
78
|
-
.where(filter)
|
|
79
|
-
.del();
|
|
80
|
-
},
|
|
81
|
-
raw(sql, options = {}) {
|
|
82
|
-
const dbApi = options.dbApi || knex;
|
|
83
|
-
return dbApi.raw(sql, options)
|
|
84
|
-
.then(res => res.rows);
|
|
38
|
+
} else {
|
|
39
|
+
query = query.orderBy(options.orderBy, sortOrder);
|
|
40
|
+
}
|
|
85
41
|
}
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
42
|
|
|
89
|
-
|
|
43
|
+
return query;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function read(table, fields, filter, options = {}) {
|
|
47
|
+
const dbApi = options.dbApi || knex;
|
|
48
|
+
const [row] = await dbApi(table).where(filter).select(fields);
|
|
49
|
+
return row;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function add(table, fields, data, options = {}) {
|
|
53
|
+
const dbApi = options.dbApi || knex;
|
|
54
|
+
const [row] = await dbApi(table).returning(fields).insert(data);
|
|
55
|
+
return row;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function edit(table, fields, data, filter, options = {}) {
|
|
59
|
+
const dbApi = options.dbApi || knex;
|
|
60
|
+
const [row] = await dbApi(table)
|
|
61
|
+
.where(filter)
|
|
62
|
+
.returning(fields)
|
|
63
|
+
.update(data);
|
|
64
|
+
return row;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function del(table, filter, options = {}) {
|
|
68
|
+
const dbApi = options.dbApi || knex;
|
|
69
|
+
return dbApi(table).where(filter).del();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function raw(sql, options = {}) {
|
|
73
|
+
const dbApi = options.dbApi || knex;
|
|
74
|
+
const res = await dbApi.raw(sql, options);
|
|
75
|
+
return res.rows || res;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { browse, read, add, edit, del, raw, knex };
|
|
79
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "breadfruit",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Boilerplate
|
|
5
|
-
"
|
|
3
|
+
"version": "3.0.1",
|
|
4
|
+
"description": "Boilerplate SQL query helpers for Node.js using Knex",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./index.js",
|
|
10
|
+
"default": "./index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"index.js",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=20"
|
|
19
|
+
},
|
|
6
20
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
21
|
+
"lint": "eslint .",
|
|
22
|
+
"lint:fix": "eslint . --fix",
|
|
23
|
+
"test": "node --test",
|
|
24
|
+
"test:coverage": "c8 --reporter=text --reporter=lcov node --test",
|
|
25
|
+
"prepublishOnly": "npm run lint && npm test"
|
|
10
26
|
},
|
|
11
27
|
"author": "Alyson Zepeda",
|
|
12
28
|
"license": "ISC",
|
|
@@ -16,15 +32,26 @@
|
|
|
16
32
|
"homepage": "https://github.com/iceddev/breadfruit#readme",
|
|
17
33
|
"repository": {
|
|
18
34
|
"type": "git",
|
|
19
|
-
"url": "git+
|
|
35
|
+
"url": "git+https://github.com/iceddev/breadfruit.git"
|
|
20
36
|
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"knex",
|
|
39
|
+
"sql",
|
|
40
|
+
"crud",
|
|
41
|
+
"postgres",
|
|
42
|
+
"mysql",
|
|
43
|
+
"database"
|
|
44
|
+
],
|
|
21
45
|
"dependencies": {
|
|
22
|
-
"knex": "^
|
|
46
|
+
"knex": "^3.2.0"
|
|
23
47
|
},
|
|
24
48
|
"devDependencies": {
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
49
|
+
"@eslint/js": "^10.0.1",
|
|
50
|
+
"c8": "^11.0.0",
|
|
51
|
+
"eslint": "^10.2.0",
|
|
52
|
+
"globals": "^17.5.0"
|
|
53
|
+
},
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"access": "public"
|
|
29
56
|
}
|
|
30
57
|
}
|
package/.coveralls.yml
DELETED
package/.npmignore
DELETED
package/.travis.yml
DELETED
package/happy_breadfruit.png
DELETED
|
Binary file
|
package/test/index.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chai = require('chai');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var expect = chai.expect;
|
|
7
|
-
chai.should();
|
|
8
|
-
|
|
9
|
-
var breadfruit = require('../');
|
|
10
|
-
|
|
11
|
-
describe('breadfruit', function(){
|
|
12
|
-
|
|
13
|
-
it('be awesome', function(done){
|
|
14
|
-
done();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should create an instance of the api', function(done) {
|
|
18
|
-
const api = breadfruit({client: 'pg'});
|
|
19
|
-
api.should.be.an('object');
|
|
20
|
-
done();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should fail to browse without a real connection', function(done) {
|
|
24
|
-
const api = breadfruit({client: 'pg'});
|
|
25
|
-
api.browse('tableName', [], {})
|
|
26
|
-
.catch((error) => {
|
|
27
|
-
done();
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('should fail to browse without a real connection', function(done) {
|
|
32
|
-
const api = breadfruit({client: 'pg'});
|
|
33
|
-
api.browse('tableName', [], {}, {orderBy: 'someColumn'})
|
|
34
|
-
.catch((error) => {
|
|
35
|
-
done();
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should fail to browse without a real connection', function(done) {
|
|
40
|
-
const api = breadfruit({client: 'pg'});
|
|
41
|
-
api.browse('tableName', [], {}, {orderBy: ['someColumn', 'otherColumn']})
|
|
42
|
-
.catch((error) => {
|
|
43
|
-
done();
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should fail to browse without a real connection', function(done) {
|
|
48
|
-
const api = breadfruit({client: 'pg'});
|
|
49
|
-
api.browse('tableName', [], {}, {orderBy: ['someColumn', 'otherColumn'], sortOrder: ['asc', 'desc']})
|
|
50
|
-
.catch((error) => {
|
|
51
|
-
done();
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should fail to read without a real connection', function(done) {
|
|
56
|
-
const api = breadfruit({client: 'pg'});
|
|
57
|
-
api.read('tableName', [], {})
|
|
58
|
-
.catch((error) => {
|
|
59
|
-
done();
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should fail to add without a real connection', function(done) {
|
|
64
|
-
const api = breadfruit({client: 'pg'});
|
|
65
|
-
api.add('tableName', [], {})
|
|
66
|
-
.catch((error) => {
|
|
67
|
-
done();
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should fail to edit without a real connection', function(done) {
|
|
72
|
-
const api = breadfruit({client: 'pg'});
|
|
73
|
-
api.edit('tableName', [], {})
|
|
74
|
-
.catch((error) => {
|
|
75
|
-
done();
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should fail to delete without a real connection', function(done) {
|
|
80
|
-
const api = breadfruit({client: 'pg'});
|
|
81
|
-
api.del('tableName', [], {})
|
|
82
|
-
.catch((error) => {
|
|
83
|
-
done();
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should fail to do raw query without a real connection', function(done) {
|
|
88
|
-
const api = breadfruit({client: 'pg'});
|
|
89
|
-
api.raw('select NOW()', {})
|
|
90
|
-
.catch((error) => {
|
|
91
|
-
done();
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
});
|