@cap-js/sqlite 1.7.8 → 1.9.0
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/CHANGELOG.md +14 -0
- package/lib/SQLiteService.js +7 -4
- package/lib/cql-functions.js +146 -3
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
- The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
5
5
|
- This project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [1.9.0](https://github.com/cap-js/cds-dbs/compare/sqlite-v1.8.0...sqlite-v1.9.0) (2025-03-04)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
* pass through of arbitrary client options ([#1024](https://github.com/cap-js/cds-dbs/issues/1024)) ([b090ccd](https://github.com/cap-js/cds-dbs/commit/b090ccda2dfd4fa535aa0fd5be9d2fc27531db05))
|
|
13
|
+
|
|
14
|
+
## [1.8.0](https://github.com/cap-js/cds-dbs/compare/sqlite-v1.7.8...sqlite-v1.8.0) (2025-01-28)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
* support for cds.Map ([#889](https://github.com/cap-js/cds-dbs/issues/889)) ([cde7514](https://github.com/cap-js/cds-dbs/commit/cde7514df20396383e0179ffce838596e3706bb2))
|
|
20
|
+
|
|
7
21
|
## [1.7.8](https://github.com/cap-js/cds-dbs/compare/sqlite-v1.7.7...sqlite-v1.7.8) (2024-12-16)
|
|
8
22
|
|
|
9
23
|
|
package/lib/SQLiteService.js
CHANGED
|
@@ -5,6 +5,7 @@ const $session = Symbol('dbc.session')
|
|
|
5
5
|
const convStrm = require('stream/consumers')
|
|
6
6
|
const { Readable } = require('stream')
|
|
7
7
|
|
|
8
|
+
const SANITIZE_VALUES = process.env.NODE_ENV === 'production' && cds.env.log.sanitize_values !== false
|
|
8
9
|
const keywords = cds.compiler.to.sql.sqlite.keywords
|
|
9
10
|
// keywords come as array
|
|
10
11
|
const sqliteKeywords = keywords.reduce((prev, curr) => {
|
|
@@ -29,7 +30,7 @@ class SQLiteService extends SQLService {
|
|
|
29
30
|
options: { max: 1, ...this.options.pool },
|
|
30
31
|
create: tenant => {
|
|
31
32
|
const database = this.url4(tenant)
|
|
32
|
-
const dbc = new sqlite(database)
|
|
33
|
+
const dbc = new sqlite(database, this.options.client)
|
|
33
34
|
const deterministic = { deterministic: true }
|
|
34
35
|
dbc.function('session_context', key => dbc[$session][key])
|
|
35
36
|
dbc.function('regexp', deterministic, (re, x) => (RegExp(re).test(x) ? 1 : 0))
|
|
@@ -247,6 +248,7 @@ class SQLiteService extends SQLService {
|
|
|
247
248
|
Time: () => 'TIME_TEXT',
|
|
248
249
|
DateTime: () => 'DATETIME_TEXT',
|
|
249
250
|
Timestamp: () => 'TIMESTAMP_TEXT',
|
|
251
|
+
Map: () => 'JSON_TEXT'
|
|
250
252
|
}
|
|
251
253
|
|
|
252
254
|
get is_distinct_from_() {
|
|
@@ -267,7 +269,7 @@ class SQLiteService extends SQLService {
|
|
|
267
269
|
try {
|
|
268
270
|
return await super.onINSERT(req)
|
|
269
271
|
} catch (err) {
|
|
270
|
-
throw _not_unique(err, 'ENTITY_ALREADY_EXISTS')
|
|
272
|
+
throw _not_unique(err, 'ENTITY_ALREADY_EXISTS', req.data)
|
|
271
273
|
}
|
|
272
274
|
}
|
|
273
275
|
|
|
@@ -275,7 +277,7 @@ class SQLiteService extends SQLService {
|
|
|
275
277
|
try {
|
|
276
278
|
return await super.onUPDATE(req)
|
|
277
279
|
} catch (err) {
|
|
278
|
-
throw _not_unique(err, 'UNIQUE_CONSTRAINT_VIOLATION')
|
|
280
|
+
throw _not_unique(err, 'UNIQUE_CONSTRAINT_VIOLATION', req.data)
|
|
279
281
|
}
|
|
280
282
|
}
|
|
281
283
|
}
|
|
@@ -288,13 +290,14 @@ class SQLiteService extends SQLService {
|
|
|
288
290
|
// })
|
|
289
291
|
// }
|
|
290
292
|
|
|
291
|
-
function _not_unique(err, code) {
|
|
293
|
+
function _not_unique(err, code, data) {
|
|
292
294
|
if (err.message.match(/unique constraint/i))
|
|
293
295
|
return Object.assign(err, {
|
|
294
296
|
originalMessage: err.message, // FIXME: required because of next line
|
|
295
297
|
message: code, // FIXME: misusing message as code
|
|
296
298
|
code: 400, // FIXME: misusing code as (http) status
|
|
297
299
|
})
|
|
300
|
+
if (data) err.values = SANITIZE_VALUES ? ['***'] : data
|
|
298
301
|
return err
|
|
299
302
|
}
|
|
300
303
|
|
package/lib/cql-functions.js
CHANGED
|
@@ -1,15 +1,158 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const StandardFunctions = {
|
|
4
|
-
//
|
|
4
|
+
// ==============================
|
|
5
|
+
// Date and Time Functions
|
|
6
|
+
// ==============================
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Ensures ISO strings are returned for current timestamp
|
|
10
|
+
* @returns {string} - SQL statement
|
|
11
|
+
*/
|
|
5
12
|
current_timestamp: () => 'ISO(current_timestamp)',
|
|
6
|
-
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* SQLite doesn't support arguments for current_date
|
|
16
|
+
* @returns {string} - SQL statement
|
|
17
|
+
*/
|
|
7
18
|
current_date: () => 'current_date',
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* SQLite doesn't support arguments for current_time
|
|
22
|
+
* @returns {string} - SQL statement
|
|
23
|
+
*/
|
|
8
24
|
current_time: () => 'current_time',
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Generates SQL statement that produces the fractional seconds of a given timestamp
|
|
28
|
+
* @param {string} x - The timestamp input
|
|
29
|
+
* @returns {string} - SQL statement
|
|
30
|
+
*/
|
|
31
|
+
fractionalseconds: x => `cast(substr(strftime('%f', ${x}), length(strftime('%f', ${x})) - 3) as REAL)`,
|
|
32
|
+
|
|
33
|
+
// ==============================
|
|
34
|
+
// String Functions
|
|
35
|
+
// ==============================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Generates SQL statement that produces a boolean value indicating whether the first string contains the second string
|
|
39
|
+
* @param {...string} args - The strings to evaluate
|
|
40
|
+
* @returns {string} - SQL statement
|
|
41
|
+
*/
|
|
42
|
+
contains: (...args) => `(ifnull(instr(${args}),0) > 0)`,
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generates SQL statement that produces the index of the first occurrence of the second string in the first string
|
|
46
|
+
* @param {string} x - The string to search
|
|
47
|
+
* @param {string} y - The substring to find
|
|
48
|
+
* @returns {string} - SQL statement
|
|
49
|
+
*/
|
|
50
|
+
indexof: (x, y) => `instr(${x},${y}) - 1`,
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Generates SQL statement that produces a boolean value indicating whether the first string starts with the second string
|
|
54
|
+
* @param {string} x - The string to evaluate
|
|
55
|
+
* @param {string} y - The prefix to check
|
|
56
|
+
* @returns {string} - SQL statement
|
|
57
|
+
*/
|
|
58
|
+
startswith: (x, y) => `coalesce(instr(${x},${y}) = 1,false)`,
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Generates SQL statement that produces a boolean value indicating whether the first string ends with the second string
|
|
62
|
+
* @param {string} x - The string to evaluate
|
|
63
|
+
* @param {string} y - The suffix to check
|
|
64
|
+
* @returns {string} - SQL statement
|
|
65
|
+
*/
|
|
66
|
+
endswith: (x, y) => `coalesce(substr(${x}, length(${x}) + 1 - length(${y})) = ${y},false)`,
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Generates SQL statement that matches the given string against a regular expression
|
|
70
|
+
* @param {string} x - The string to match
|
|
71
|
+
* @param {string} y - The regular expression
|
|
72
|
+
* @returns {string} - SQL statement
|
|
73
|
+
*/
|
|
74
|
+
matchesPattern: (x, y) => `(${x} regexp ${y})`,
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Alias for matchesPattern
|
|
78
|
+
* @param {string} x - The string to match
|
|
79
|
+
* @param {string} y - The regular expression
|
|
80
|
+
* @returns {string} - SQL statement
|
|
81
|
+
*/
|
|
82
|
+
matchespattern: (x, y) => `(${x} regexp ${y})`,
|
|
9
83
|
}
|
|
10
84
|
|
|
11
85
|
const HANAFunctions = {
|
|
12
|
-
|
|
86
|
+
// ==============================
|
|
87
|
+
// Timestamp Difference Functions
|
|
88
|
+
// ==============================
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Generates SQL statement that calculates the difference in 100-nanoseconds between two timestamps
|
|
92
|
+
* @param {string} x - Left timestamp
|
|
93
|
+
* @param {string} y - Right timestamp
|
|
94
|
+
* @returns {string} - SQL statement
|
|
95
|
+
*/
|
|
96
|
+
nano100_between: (x, y) => `(julianday(${y}) - julianday(${x})) * 864000000000`,
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Generates SQL statement that calculates the difference in seconds between two timestamps
|
|
100
|
+
* @param {string} x - Left timestamp
|
|
101
|
+
* @param {string} y - Right timestamp
|
|
102
|
+
* @returns {string} - SQL statement
|
|
103
|
+
*/
|
|
104
|
+
seconds_between: (x, y) => `(julianday(${y}) - julianday(${x})) * 86400`,
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Generates SQL statement that calculates the difference in days between two timestamps
|
|
108
|
+
* @param {string} x - Left timestamp
|
|
109
|
+
* @param {string} y - Right timestamp
|
|
110
|
+
* @returns {string} - SQL statement
|
|
111
|
+
*/
|
|
112
|
+
days_between: (x, y) => `(
|
|
113
|
+
cast(julianday(${y}) as Integer) - cast(julianday(${x}) as Integer)
|
|
114
|
+
) + (
|
|
115
|
+
case
|
|
116
|
+
when (julianday(${y}) < julianday(${x})) then
|
|
117
|
+
(cast(strftime('%H%M%S%f0000', ${y}) as Integer) < cast(strftime('%H%M%S%f0000', ${x}) as Integer))
|
|
118
|
+
else
|
|
119
|
+
(cast(strftime('%H%M%S%f0000', ${y}) as Integer) > cast(strftime('%H%M%S%f0000', ${x}) as Integer)) * -1
|
|
120
|
+
end
|
|
121
|
+
)`,
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Generates SQL statement that calculates the difference in months between two timestamps
|
|
125
|
+
* @param {string} x - Left timestamp
|
|
126
|
+
* @param {string} y - Right timestamp
|
|
127
|
+
* @returns {string} - SQL statement
|
|
128
|
+
*/
|
|
129
|
+
months_between: (x, y) => `
|
|
130
|
+
(
|
|
131
|
+
(
|
|
132
|
+
(cast(strftime('%Y', ${y}) as Integer) - cast(strftime('%Y', ${x}) as Integer)) * 12
|
|
133
|
+
) + (
|
|
134
|
+
cast(strftime('%m', ${y}) as Integer) - cast(strftime('%m', ${x}) as Integer)
|
|
135
|
+
) + (
|
|
136
|
+
(
|
|
137
|
+
case
|
|
138
|
+
when (cast(strftime('%Y%m', ${y}) as Integer) < cast(strftime('%Y%m', ${x}) as Integer)) then
|
|
139
|
+
(cast(strftime('%d%H%M%S%f0000', ${y}) as Integer) > cast(strftime('%d%H%M%S%f0000', ${x}) as Integer))
|
|
140
|
+
else
|
|
141
|
+
(cast(strftime('%d%H%M%S%f0000', ${y}) as Integer) < cast(strftime('%d%H%M%S%f0000', ${x}) as Integer)) * -1
|
|
142
|
+
end
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
)`,
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Generates SQL statement that calculates the difference in years between two timestamps
|
|
149
|
+
* @param {string} x - Left timestamp
|
|
150
|
+
* @param {string} y - Right timestamp
|
|
151
|
+
* @returns {string} - SQL statement
|
|
152
|
+
*/
|
|
153
|
+
years_between(x, y) {
|
|
154
|
+
return `floor(${this.months_between(x, y)} / 12)`
|
|
155
|
+
},
|
|
13
156
|
}
|
|
14
157
|
|
|
15
158
|
for (let each in HANAFunctions) HANAFunctions[each.toUpperCase()] = HANAFunctions[each]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cap-js/sqlite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "CDS database service for SQLite",
|
|
5
5
|
"homepage": "https://github.com/cap-js/cds-dbs/tree/main/sqlite#cds-database-service-for-sqlite",
|
|
6
6
|
"repository": {
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"CHANGELOG.md"
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
|
-
"test": "cds-test
|
|
26
|
+
"test": "cds-test"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@cap-js/db-service": "^1.
|
|
29
|
+
"@cap-js/db-service": "^1.18.0",
|
|
30
30
|
"better-sqlite3": "^11.0.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|