Skip to content

Commit 88403b5

Browse files
authored
Merge pull request #18 from iceddev/es6
update to es6
2 parents e7b9030 + bd33923 commit 88403b5

11 files changed

Lines changed: 2001 additions & 215 deletions

File tree

.coveralls.yml

Lines changed: 0 additions & 2 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, master]
6+
pull_request:
7+
branches: [main, master]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
node-version: [20, 22, 24]
16+
steps:
17+
- uses: actions/checkout@v4
18+
- name: Use Node.js ${{ matrix.node-version }}
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: ${{ matrix.node-version }}
22+
cache: npm
23+
- run: npm ci
24+
- run: npm run lint
25+
- run: npm run test:coverage
26+
- name: Upload coverage
27+
if: matrix.node-version == 22
28+
uses: codecov/codecov-action@v5
29+
with:
30+
files: ./coverage/lcov.info
31+
fail_ci_if_error: false

.gitignore

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
# Dependency directory
2-
# Deployed apps should consider commenting this line out:
3-
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
41
node_modules
5-
6-
# Other
7-
.DS_Store
82
coverage
93
.nyc_output
10-
package-lock.json
11-
4+
.DS_Store
5+
*.log

.travis.yml

Lines changed: 0 additions & 4 deletions
This file was deleted.

README.md

Lines changed: 80 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,107 @@
11
# breadfruit
22

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)
49

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/).
611

712
![breadfruit](happy_breadfruit.png)
813

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';
1028

11-
```javascript
1229
const config = {
13-
client: 'postgresql',
30+
client: 'pg',
1431
connection: 'postgres://postgres@localhost:5432/someDatabase',
15-
pool: { min: 1, max: 7 }
32+
pool: { min: 1, max: 7 },
1633
};
1734

18-
const bread = require('breadfruit')(config);
35+
const { browse, read, edit, add, del, raw } = breadfruit(config);
1936
```
2037

21-
## Browse, Read, Edit, Add, Delete, Raw
38+
## API
2239

23-
```javascript
24-
const {browse, read, edit, add, del, raw} = require('breadfruit')(config);
40+
### `browse(table, fields, filter, options?)`
2541

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.
2843

44+
```js
45+
const users = await browse('users', ['username', 'user_id'], { active: true });
46+
```
2947

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)
3256

57+
### `read(table, fields, filter, options?)`
3358

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.
3660

61+
```js
62+
const user = await read('users', ['username', 'first_name'], { user_id: 1337 });
63+
```
3764

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?)`
4066

67+
Inserts and returns the new row.
4168

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+
```
4475

76+
### `edit(table, returnFields, data, filter, options?)`
4577

46-
//perform a raw query
47-
const rows = await raw('select * from users');
78+
Updates matching rows and returns the first updated row.
4879

80+
```js
81+
const updated = await edit(
82+
'users',
83+
['username', 'first_name'],
84+
{ first_name: 'Howard' },
85+
{ user_id: 1337 },
86+
);
4987
```
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

eslint.config.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import js from '@eslint/js';
2+
import globals from 'globals';
3+
4+
export default [
5+
js.configs.recommended,
6+
{
7+
languageOptions: {
8+
ecmaVersion: 2024,
9+
sourceType: 'module',
10+
globals: { ...globals.node },
11+
},
12+
rules: {
13+
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
14+
'prefer-const': 'error',
15+
'no-var': 'error',
16+
eqeqeq: ['error', 'always', { null: 'ignore' }],
17+
},
18+
},
19+
];

index.js

Lines changed: 65 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,79 @@
1-
const knexConstructor = require('knex');
1+
import knexConstructor from 'knex';
22

3-
function connect(settings) {
3+
export default function connect(settings) {
44
const knex = knexConstructor(settings);
5-
const defaultOptions = {
5+
const defaults = {
66
dateField: 'created_at',
7-
dbApi: knex,
87
limit: 1000,
98
offset: 0,
109
sortOrder: 'ASC',
1110
};
1211

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;
2018

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);
2624

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+
}
4431

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);
5437
});
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+
}
8541
}
86-
};
87-
}
8842

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+
}

0 commit comments

Comments
 (0)