breadfruit 2.2.1 → 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 CHANGED
@@ -1,49 +1,107 @@
1
1
  # breadfruit
2
2
 
3
- [![NPM](https://nodei.co/npm/breadfruit.png?compact=true)](https://nodei.co/npm/breadfruit/)
3
+ [![npm version](https://img.shields.io/npm/v/breadfruit.svg)](https://www.npmjs.com/package/breadfruit)
4
+ [![CI](https://github.com/iceddev/breadfruit/actions/workflows/ci.yml/badge.svg)](https://github.com/iceddev/breadfruit/actions/workflows/ci.yml)
5
+ [![codecov](https://codecov.io/gh/iceddev/breadfruit/branch/main/graph/badge.svg)](https://codecov.io/gh/iceddev/breadfruit)
6
+ [![node](https://img.shields.io/node/v/breadfruit.svg)](https://nodejs.org)
7
+ [![npm downloads](https://img.shields.io/npm/dm/breadfruit.svg)](https://www.npmjs.com/package/breadfruit)
8
+ [![license](https://img.shields.io/npm/l/breadfruit.svg)](https://github.com/iceddev/breadfruit/blob/main/LICENSE)
4
9
 
5
- Not really bread. Not really fruit. Just like this package. Some simple helpers on top of knex.
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
  ![breadfruit](happy_breadfruit.png)
8
13
 
9
- ## create an instance of breadfruit
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: 'postgresql',
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 bread = require('breadfruit')(config);
35
+ const { browse, read, edit, add, del, raw } = breadfruit(config);
19
36
  ```
20
37
 
21
- ## Browse, Read, Edit, Add, Delete, Raw
38
+ ## API
22
39
 
23
- ```javascript
24
- const {browse, read, edit, add, del, raw} = require('breadfruit')(config);
40
+ ### `browse(table, fields, filter, options?)`
25
41
 
26
- //get an array of users, by table, columns, and a filter
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
- //get a single user by table, columns, and a filter
31
- const user = await read('users', ['username', 'first_name'], {user_id: 1337});
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
- //edit a user by table, returned columns, updated values, and a filter
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
- //add a new user by table, returned columns, and user data
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
- //delete a user by table and a filter
43
- const deleteCount = await del('users', {user_id: 1337});
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
- //perform a raw query
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
- const knexConstructor = require('knex');
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 defaultOptions = {
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
- return {
14
- browse(table, fields, filter, options = {}) {
15
- const dbApi = options.dbApi || defaultOptions.dbApi || knex;
16
- const limit = options.limit || defaultOptions.limit;
17
- const offset = options.offset || defaultOptions.offset;
18
- const dateField = options.dateField || defaultOptions.dateField;
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
- let query = dbApi(table)
22
- .where(filter)
23
- .select(fields)
24
- .limit(limit)
25
- .offset(offset);
19
+ let query = dbApi(table)
20
+ .where(filter)
21
+ .select(fields)
22
+ .limit(limit)
23
+ .offset(offset);
26
24
 
27
- if (options.search_start_date && options.search_end_date) {
28
- query = query
29
- .whereBetween(dateField, [options.search_start_date, options.search_end_date]);
30
- }
31
-
32
- if (options.orderBy) {
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
- return query;
46
- },
47
- read(table, fields, filter, options = {}) {
48
- const dbApi = options.dbApi || knex;
49
- return dbApi(table)
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
- add(table, fields, data, options = {}) {
57
- const dbApi = options.dbApi || knex;
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 || res);
38
+ } else {
39
+ query = query.orderBy(options.orderBy, sortOrder);
40
+ }
85
41
  }
86
- };
87
- }
88
42
 
89
- module.exports = connect;
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,10 +1,28 @@
1
1
  {
2
2
  "name": "breadfruit",
3
- "version": "2.2.1",
4
- "description": "Boilerplate sql query system for Node.js using Knex",
5
- "main": "index.js",
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
- "test": "nyc --reporter=lcov --reporter=text-summary mocha"
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"
8
26
  },
9
27
  "author": "Alyson Zepeda",
10
28
  "license": "ISC",
@@ -14,14 +32,26 @@
14
32
  "homepage": "https://github.com/iceddev/breadfruit#readme",
15
33
  "repository": {
16
34
  "type": "git",
17
- "url": "git+ssh://git@github.com/iceddev/breadfruit.git"
35
+ "url": "git+https://github.com/iceddev/breadfruit.git"
18
36
  },
37
+ "keywords": [
38
+ "knex",
39
+ "sql",
40
+ "crud",
41
+ "postgres",
42
+ "mysql",
43
+ "database"
44
+ ],
19
45
  "dependencies": {
20
- "knex": "^0.21.5"
46
+ "knex": "^3.2.0"
21
47
  },
22
48
  "devDependencies": {
23
- "chai": "^4.2.0",
24
- "mocha": "^8.1.3",
25
- "nyc": "^15.1.0"
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"
26
56
  }
27
57
  }
package/.coveralls.yml DELETED
@@ -1,2 +0,0 @@
1
- service_name: travis-pro
2
- repo_token:
package/.travis.yml DELETED
@@ -1,4 +0,0 @@
1
- language: node_js
2
- node_js:
3
- - '6'
4
- after_success: 'npm run coveralls'
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
- });