Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d434f67
fix(ts): type model handler parameters (#397)
MrSwitch Feb 4, 2025
7d8eb1b
chore(release): 0.93.1 [skip ci]
5app-Machine Feb 4, 2025
877c3e7
fix(ts): type model handler parameters (#398)
MrSwitch Feb 5, 2025
6e6fdbb
chore(release): 0.93.2 [skip ci]
5app-Machine Feb 5, 2025
a47d137
chore(deps): update dependency mysql2 to 3.13 (#400)
renovate[bot] Mar 18, 2025
111576c
chore(deps): update dependency mysql2 to 3.14 (#401)
renovate[bot] Mar 21, 2025
2de8d82
chore(deps): update dependency node to v7.1.0
renovate[bot] Apr 9, 2025
7795924
Merge pull request #402 from 5app/renovate/node-7.x
MrSwitch Apr 25, 2025
dc92f17
feat(type): field attributes (#403)
MrSwitch Apr 25, 2025
0d31355
chore(release): 0.94.0 [skip ci]
5app-Machine Apr 25, 2025
3eb962f
fix(null-safe): add null-safe negate equality conditions (#404)
MrSwitch Apr 29, 2025
98bb59c
chore(release): 0.94.1 [skip ci]
5app-Machine Apr 29, 2025
64b0fd9
feat(jsdoc): use @import (#405)
MrSwitch May 15, 2025
81faa31
chore(release): 0.95.0 [skip ci]
5app-Machine May 15, 2025
08457e8
chore(prettier): update styles, noissue
May 21, 2025
4256631
feat(type): format date types (#406)
MrSwitch May 21, 2025
9c13f3e
chore(release): 0.96.0 [skip ci]
5app-Machine May 21, 2025
6a12832
feat(type): format date filters, noissue (#407)
MrSwitch May 21, 2025
6990851
chore(release): 0.97.0 [skip ci]
5app-Machine May 21, 2025
c3ff946
fix: add type RequestOptions ignore boolean (#410)
MrSwitch Jul 3, 2025
e5aeca7
chore(release): 0.97.1 [skip ci]
5app-Machine Jul 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ executors:
# Orbs

orbs:
node: circleci/node@7.0.0
node: circleci/node@7.1.0

################################
# Jobs
Expand Down
6 changes: 6 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
"max-params": [2, {"max": 4}],
"multiline-comment-style": [2, "starred-block"],
"linebreak-style": 0,
"jsdoc/check-tag-names": [
2,
{
"definedTags": ["import"]
}
],
"n/no-unsupported-features/es-syntax": [2, {"ignores": ["modules"]}],
"n/no-missing-import": [
"error",
Expand Down
56 changes: 56 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,59 @@
## [0.97.1](https://github.com/5app/dare/compare/v0.97.0...v0.97.1) (2025-07-03)


### Bug Fixes

* add type RequestOptions ignore boolean ([#410](https://github.com/5app/dare/issues/410)) ([c3ff946](https://github.com/5app/dare/commit/c3ff946ef27c9143acf28f923559e8ee11aed837))

# [0.97.0](https://github.com/5app/dare/compare/v0.96.0...v0.97.0) (2025-05-21)


### Features

* **type:** format date filters, noissue ([#407](https://github.com/5app/dare/issues/407)) ([6a12832](https://github.com/5app/dare/commit/6a12832e5e0fb75493e45c99e743dd5bba5b5e18))

# [0.96.0](https://github.com/5app/dare/compare/v0.95.0...v0.96.0) (2025-05-21)


### Features

* **type:** format date types ([#406](https://github.com/5app/dare/issues/406)) ([4256631](https://github.com/5app/dare/commit/4256631f0234d4c9ed2098382ae5b6169bf3862f))

# [0.95.0](https://github.com/5app/dare/compare/v0.94.1...v0.95.0) (2025-05-15)


### Features

* **jsdoc:** use [@import](https://github.com/import) ([#405](https://github.com/5app/dare/issues/405)) ([64b0fd9](https://github.com/5app/dare/commit/64b0fd93f600fdebf700f0bd0dc052e1e799a217))

## [0.94.1](https://github.com/5app/dare/compare/v0.94.0...v0.94.1) (2025-04-29)


### Bug Fixes

* **null-safe:** add null-safe negate equality conditions ([#404](https://github.com/5app/dare/issues/404)) ([3eb962f](https://github.com/5app/dare/commit/3eb962f7bcb93a7f0099bfa5053c3aca41969a59))

# [0.94.0](https://github.com/5app/dare/compare/v0.93.2...v0.94.0) (2025-04-25)


### Features

* **type:** field attributes ([#403](https://github.com/5app/dare/issues/403)) ([dc92f17](https://github.com/5app/dare/commit/dc92f17cef0ab697b41c86a6dd3c9cc0aaa9b37e))

## [0.93.2](https://github.com/5app/dare/compare/v0.93.1...v0.93.2) (2025-02-05)


### Bug Fixes

* **ts:** type model handler parameters ([#398](https://github.com/5app/dare/issues/398)) ([877c3e7](https://github.com/5app/dare/commit/877c3e7a7e14fa4f245ce28c54222e1ab50b966c))

## [0.93.1](https://github.com/5app/dare/compare/v0.93.0...v0.93.1) (2025-02-04)


### Bug Fixes

* **ts:** type model handler parameters ([#397](https://github.com/5app/dare/issues/397)) ([d434f67](https://github.com/5app/dare/commit/d434f67fcfa6de3cfa2bd1e5490fd6b9c7def4dc))

# [0.93.0](https://github.com/5app/dare/compare/v0.92.1...v0.93.0) (2025-01-23)


Expand Down
66 changes: 43 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ The setup needs to define a execution handler `dare.execute(SqlRequest) : Promis

The integration tests illustrates how a [setup of a dare instance](`./test/integration/helpers/api.js`) connects to different clients...

- **MySQL** (5.6, 5.7, 8.0,...) and **MariaDB** (11) See [connection with `mysql2`](./test/integration/helpers/MySQL.js)
- **Postgres** (16+) See [connection with `pg`](./test/integration/helpers/Postgres.js)
- **MySQL** (5.6, 5.7, 8.0,...) and **MariaDB** (11) See [connection with `mysql2`](./test/integration/helpers/MySQL.js)
- **Postgres** (16+) See [connection with `pg`](./test/integration/helpers/Postgres.js)

# Methods

Expand Down Expand Up @@ -146,11 +146,11 @@ _note_: It is currently limited to defining just one table field, we hope this w

`FUNCTION_NAME([FIELD_PREFIX]? field_name [MATH_OPERATOR MATH_VALUE]?[, ADDITIONAL_PARAMETERS]*)`

- _FUNCTION_NAME_: uppercase, no spaces
- _FIELD_PREFIX_: optional, uppercase
- _field_name_: db field reference
- _MATH_OPERATOR_ _MATH_VALUE_: optional
- _ADDITIONAL_PARAMETERS_: optional, prefixed with `,`, (uppercase, digit or quoted string)
- _FUNCTION_NAME_: uppercase, no spaces
- _FIELD_PREFIX_: optional, uppercase
- _field_name_: db field reference
- _MATH_OPERATOR_ _MATH_VALUE_: optional
- _ADDITIONAL_PARAMETERS_: optional, prefixed with `,`, (uppercase, digit or quoted string)

_e.g._

Expand Down Expand Up @@ -193,8 +193,8 @@ The SQL this creates renames the fields and then recreates the structured format
}
```

- At the moment this only supports _n:1_ mapping.
- The relationship between the tables must be defined in a model field reference.
- At the moment this only supports _n:1_ mapping.
- The relationship between the tables must be defined in a model field reference.

### Filter `filter`

Expand Down Expand Up @@ -245,9 +245,9 @@ The type of value affects the choice of SQL Condition syntax to use. For example

Prefixing the prop with:

- `%`: creates a `LIKE` comparison (or `ILIKE` in _postgres_)
- `-`: hyhen negates the value
- `~`: creates a range
- `%`: creates a `LIKE` comparison (or `ILIKE` in _postgres_)
- `-`: hyhen negates the value
- `~`: creates a range

| Key | Value | Type | = SQL Condition |
| ---------- | ------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
Expand Down Expand Up @@ -589,7 +589,7 @@ await dare.get({
| `models` | `Object<ModelName, Model>` | An object where the keys are the model names to which models can be referred. |
| `validateInput` | `Function(fieldAttributes, field, value)` | Validate input on _patch_ and _post_ operations |
| `getFieldKey` | `Function(field, schema)` | Override the default function for retrieving schema fields, this is useful if you want to support altenative case (camelCase and/or snakeCase) |
| `state` | `any` | Arbitary data which can be used within the Method handlers to set additional filters or formatting |
| `state` | `any` | Arbitary data which can be used within the Method handlers to set additional filters or formatting |

# Model

Expand Down Expand Up @@ -708,6 +708,27 @@ const dare = new Dare({
});
```

**`date`**

With `type=date`; Instance of the `Date` objects are converted to `YYYY-MM-DD` format for insertion

```js
const dare = new Dare({
models: {
members: {
schema: {
start_date: {
type: 'date',
},
},
},
},
});

// Example POSt => SQL
dare.post('members', {start_date: new Date()}); // 'INSERT INTO members (`start_date`) VALUES ('2025-01-02');`
```

**`json`**

Serializes Objects and Deserializes JSON strings in `get`, `post` and `patch` operations. Setting this value also enables the ability to filter results by querying within the JSON values
Expand Down Expand Up @@ -1027,7 +1048,6 @@ Here's an example of setting a model to be invoked whenever we access `users` mo

```js
function get(options) {

// In this example we're filtering access to the `users` model by the properties of the `state` data.
options.filter.id = options.state.userId;
}
Expand All @@ -1048,7 +1068,7 @@ await dare.get({
limit: 100,
state: {
userId: 123,
}
},
});

// SELECT name FROM users WHERE id = 123 LIMIT 100;
Expand Down Expand Up @@ -1248,8 +1268,8 @@ Typically databases will buffer the resultset into memory and send over one larg

Dare, has some functions to take advantage of Streaming

- `this.addRow(record)`: process an individual record
- `options.rowHandler`: See above
- `this.addRow(record)`: process an individual record
- `options.rowHandler`: See above

When combined we can efficiently redirect the results immediatly without building up an internal memory.

Expand Down Expand Up @@ -1474,9 +1494,9 @@ await dare.get({

By default `conditional_operators_in_value = '!%'`. Which is a selection of special characters within the value to be compared.

- `%`: A string containing `%` within the value to be compared will indicate a wild character and the SQL `LIKE` conditional operator will be used.
- `!`: A string starting with `!` will negate the value using a SQL `LIKE` comparison operator.
- `..`: A string containing `..` will use a range `BETWEEN`, `<` or `>` comparison operator where a string value contains `..` or the value is an array with two values (dependending if the first or second value is empty it will use `<` or `>` respecfively). This denotes a range and is enabled using the `~` operator (because `.` within prop name has another meaning)
- `%`: A string containing `%` within the value to be compared will indicate a wild character and the SQL `LIKE` conditional operator will be used.
- `!`: A string starting with `!` will negate the value using a SQL `LIKE` comparison operator.
- `..`: A string containing `..` will use a range `BETWEEN`, `<` or `>` comparison operator where a string value contains `..` or the value is an array with two values (dependending if the first or second value is empty it will use `<` or `>` respecfively). This denotes a range and is enabled using the `~` operator (because `.` within prop name has another meaning)

```js
// Enabling support for one or more of the above special characters...
Expand Down Expand Up @@ -1553,9 +1573,9 @@ await dare.patch({

This version of Dare is designed to work with:

- MySQL (5.6, 5.7 and 8)
- Postgres (16.3)
- MariaDB (11)
- MySQL (5.6, 5.7 and 8)
- Postgres (16.3)
- MariaDB (11)

Set the property `engine` on the Dare instance
e.g.
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dare",
"version": "0.93.0",
"version": "0.97.1",
"description": "Database to REST, REST to Database",
"type": "module",
"main": "./src/index.js",
Expand All @@ -21,13 +21,13 @@
"scripts": {
"prepare": "is-ci || husky install",
"pretest": "npm run lint",
"types": "tsc -p ./tsconfig.json",
"prepublish": "npm run types",
"check-types": "tsc -p ./tsconfig.json",
"prepublish": "npm run check-types",
"test": "npm run spec && ((c8 report --reporter=text-lcov | coveralls) || exit 0)",
"test:ci": "eslint ./ && c8 mocha test/specs/**/*.spec.js --reporter mocha-circleci-reporter && (c8 report --reporter=text-lcov | coveralls)",
"test:integration": "bash ./test/integration/run.sh",
"spec": "c8 mocha test/specs/**/*.spec.js",
"lint": "eslint ./ && npx prettier --check . && npx tsc -p ./tsconfig.json",
"lint": "eslint ./ && npx prettier --check . && npm run check-types",
"prettier": "prettier --write --ignore-unknown .",
"lint-fix": "eslint --fix ./",
"lint-diff": "LIST=`git diff-index --cached --name-only --diff-filter=d HEAD | grep '.*\\.js$';`; if [ \"$LIST\" ]; then eslint $LIST; fi",
Expand Down Expand Up @@ -73,7 +73,7 @@
"is-ci": "^4.1.0",
"mocha": "^11.1.0",
"mocha-circleci-reporter": "0.0.3",
"mysql2": "3.12",
"mysql2": "3.14",
"pg": "^8.13.1",
"pg-query-stream": "^4.7.1",
"prettier": "^3.4.2",
Expand Down
4 changes: 2 additions & 2 deletions src/format/limit_clause.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import DareError from '../utils/error.js';
* Limit Clause
* Set/Check limit and start positions
* @param {object} opts - Options object
* @param {number} opts.limit - Limit defintion
* @param {number} opts.start - Start defintion
* @param {number} [opts.limit] - Limit defintion
* @param {number} [opts.start] - Start defintion
* @param {number} MAX_LIMIT - Max limit on instance
* @returns {LimitClause} - Limit Clause
*/
Expand Down
39 changes: 28 additions & 11 deletions src/format/reducer_conditions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,11 @@ import formatDateTime from '../utils/format_datetime.js';
import getFieldAttributes from '../utils/field_attributes.js';
import unwrap_field from '../utils/unwrap_field.js';

/* eslint-disable jsdoc/valid-types */
/**
* @typedef {import('sql-template-tag').Sql} Sql
* @typedef {import('../index.js').default} Dare
* @typedef {import('../index.js').Engine} Engine
*/
/* eslint-enable jsdoc/valid-types */

/**
* Reduce conditions, call extract
* @import {Sql} from 'sql-template-tag'
* @import Dare, {Engine} from '../index.js'
*
* Reduce conditions, call extract
* @param {object} filter - Filter conditions
* @param {object} options - Options object
* @param {Function} options.extract - Extract (key, value) related to nested model
Expand Down Expand Up @@ -57,6 +51,7 @@ export default function reduceConditions(
if (
value &&
typeof value === 'object' &&
!(value instanceof Date) &&
!Array.isArray(value) &&
key_definition?.type !== 'json' &&
!Buffer.isBuffer(value)
Expand Down Expand Up @@ -196,6 +191,10 @@ function prepCondition({
if (type === 'datetime') {
value = formatDateTime(value);
}
// @ts-ignore
else if (type === 'date' && value instanceof Date) {
value = value.toISOString().split('T').at(0);
}

// JSON
if (
Expand Down Expand Up @@ -383,7 +382,15 @@ function sqlCondition({
const items = engine.startsWith('mysql:5.7')
? filteredValue.map(quote)
: filteredValue;
conds.push(SQL`${sql_field} ${NOT}IN (${join(items)})`);

let condition = SQL`${sql_field} ${NOT}IN (${join(items)})`;

if (negate && !value.includes(null)) {
// If negated, and the value is not null, then add the null check
condition = SQL`(${condition} OR ${sql_field} IS NULL)`;
}

conds.push(condition);
}

// Other Values which can't be grouped ...
Expand Down Expand Up @@ -413,7 +420,17 @@ function sqlCondition({
value = String(value);
}

return SQL`${sql_field} ${raw(negate ? '!' : '')}= ${value}`;
let condition = SQL`${sql_field} ${raw(negate ? '!' : '')}= ${value}`;

if (negate) {
/*
* NULL-safe equality operator
* @see {@link https://vettabase.com/null-comparisons-in-mariadb-postgresql-and-sqlite/}
* If negated, then add the null check
*/
condition = SQL`(${condition} OR ${sql_field} IS NULL)`;
}
return condition;
}
}

Expand Down
Loading