@cap-js/postgres 1.9.1 → 1.10.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/CHANGELOG.md +16 -0
- package/README.md +5 -5
- package/cds-plugin.js +1 -1
- package/lib/PostgresService.js +47 -24
- package/lib/cql-functions.js +20 -0
- package/package.json +9 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@
|
|
|
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.10.1](https://github.com/cap-js/cds-dbs/compare/postgres-v1.10.0...postgres-v1.10.1) (2024-10-15)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
* add cds schema for postgres build plugin ([#843](https://github.com/cap-js/cds-dbs/issues/843)) ([6306d5c](https://github.com/cap-js/cds-dbs/commit/6306d5ce50c071b38a3d9f61b0820ea713a782d8))
|
|
13
|
+
* Improved behavioral consistency between the database services ([#837](https://github.com/cap-js/cds-dbs/issues/837)) ([b6f7187](https://github.com/cap-js/cds-dbs/commit/b6f718701e48dfb1c4c3d98ee016ec45930f8e7b))
|
|
14
|
+
* null as default value ([#845](https://github.com/cap-js/cds-dbs/issues/845)) ([0041ec0](https://github.com/cap-js/cds-dbs/commit/0041ec0a26c29b30f91470d93611b29acd837216))
|
|
15
|
+
|
|
16
|
+
## [1.10.0](https://github.com/cap-js/cds-dbs/compare/postgres-v1.9.1...postgres-v1.10.0) (2024-07-25)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
* build script generates cds8 dependency in deployer app ([#758](https://github.com/cap-js/cds-dbs/issues/758)) ([5c21a67](https://github.com/cap-js/cds-dbs/commit/5c21a6758ccc927cde857e98145c3f4393deb739))
|
|
22
|
+
|
|
7
23
|
## [1.9.1](https://github.com/cap-js/cds-dbs/compare/postgres-v1.9.0...postgres-v1.9.1) (2024-07-09)
|
|
8
24
|
|
|
9
25
|
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# CDS database service for Postgres
|
|
2
2
|
|
|
3
|
-
Welcome to the
|
|
3
|
+
Welcome to the PostgreSQL database service for [SAP Cloud Application Programming Model](https://cap.cloud.sap) Node.js, based on streamlined database architecture and [*pg* driver](https://www.npmjs.com/package/pg) .
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
7
|
-
In general, all you need to do is to install
|
|
7
|
+
In general, all you need to do is to install the database package, as follows:
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
10
|
npm add @cap-js/postgres
|
|
@@ -38,7 +38,7 @@ Copyright 2023 SAP SE or an SAP affiliate company and cds-dbs contributors. Plea
|
|
|
38
38
|
`@cap-js/postgres` works as a drop-in replacement for `cds-pg`.
|
|
39
39
|
However, some preliminary checks and cleanups help:
|
|
40
40
|
|
|
41
|
-
- for using the BTP Postgres Hyperscaler as database,
|
|
41
|
+
- for using the BTP Postgres Hyperscaler as database,
|
|
42
42
|
- know that the credentials are picked up automatically by from the enviornment (`VCAP_SERVICES.postgres`)
|
|
43
43
|
- the service binding label is `postgresql-db`
|
|
44
44
|
- `cds-dbm` is replaced by a hand-crafted "db-deployer" app → see below
|
|
@@ -134,11 +134,11 @@ now, re-use the CDS definitions: `SELECT.from(Beers).columns('brewery_ID').group
|
|
|
134
134
|
|
|
135
135
|
So please adjust your `CQL` statements accordingly.
|
|
136
136
|
|
|
137
|
-
### timezones (potential
|
|
137
|
+
### timezones (potential **BREAKING CHANGE**)
|
|
138
138
|
|
|
139
139
|
any date- + time-type will get stored in [`UTC`](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) **without any timezone identifier in the actual data field**.
|
|
140
140
|
CAP's inbound- and outbound adapters take care of converting incoming and outgoing data from/to the desired time zones.
|
|
141
|
-
So when a `
|
|
141
|
+
So when a `datetime` comes in being in [an ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) compatible format
|
|
142
142
|
`2009-01-01T15:00:00+01:00` (15:00:00 on January 1 2009 in Vienna (CEST))
|
|
143
143
|
will get stored as
|
|
144
144
|
`2009-01-01T13:00:00` (13:00:00 on January 1 2009 in UTC).
|
package/cds-plugin.js
CHANGED
|
@@ -27,7 +27,7 @@ cds.build?.register?.('postgres', class PostgresBuildPlugin extends cds.build.Pl
|
|
|
27
27
|
} else {
|
|
28
28
|
promises.push(
|
|
29
29
|
this.write({
|
|
30
|
-
dependencies: { '@sap/cds': '^
|
|
30
|
+
dependencies: { '@sap/cds': '^8', '@cap-js/postgres': '^1' },
|
|
31
31
|
scripts: { start: 'cds-deploy' },
|
|
32
32
|
}).to('package.json'),
|
|
33
33
|
)
|
package/lib/PostgresService.js
CHANGED
|
@@ -253,7 +253,7 @@ GROUP BY k
|
|
|
253
253
|
return this.dbc.query(sql)
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
onPlainSQL(req, next) {
|
|
256
|
+
async onPlainSQL(req, next) {
|
|
257
257
|
const query = req.query
|
|
258
258
|
if (this.options.independentDeploy) {
|
|
259
259
|
// REVISIT: Should not be needed when deployment supports all types or sends CQNs
|
|
@@ -289,8 +289,19 @@ GROUP BY k
|
|
|
289
289
|
// eslint-disable-next-line no-unused-vars
|
|
290
290
|
req.query = query.replace(/('|")(\1|[^\1]*?\1)|(\?)/g, (a, _b, _c, d, _e, _f, _g) => (d ? '$' + i++ : a))
|
|
291
291
|
}
|
|
292
|
-
|
|
293
|
-
|
|
292
|
+
try {
|
|
293
|
+
return await super.onPlainSQL(req, next)
|
|
294
|
+
}
|
|
295
|
+
catch (err) {
|
|
296
|
+
if (err.code === '3F000') {
|
|
297
|
+
if (this.options?.credentials?.schema) {
|
|
298
|
+
cds.error`Failed to configure schema ("${this.options?.credentials?.schema}") before plainSQL call: ${req.query}`
|
|
299
|
+
} else {
|
|
300
|
+
cds.error`No schema was configure / detected before plainSQL call: ${req.query}`
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
throw err
|
|
304
|
+
}
|
|
294
305
|
}
|
|
295
306
|
|
|
296
307
|
async onSELECT({ query, data }) {
|
|
@@ -459,7 +470,7 @@ GROUP BY k
|
|
|
459
470
|
}
|
|
460
471
|
|
|
461
472
|
defaultValue(defaultValue = this.context.timestamp.toISOString()) {
|
|
462
|
-
return this.string(`${defaultValue}`)
|
|
473
|
+
return typeof defaultValue === 'string' ? this.string(`${defaultValue}`) : defaultValue
|
|
463
474
|
}
|
|
464
475
|
|
|
465
476
|
static Functions = { ...super.Functions, ...require('./cql-functions') }
|
|
@@ -532,7 +543,10 @@ GROUP BY k
|
|
|
532
543
|
Int64: cds.env.features.ieee754compatible ? expr => `cast(${expr} as varchar)` : undefined,
|
|
533
544
|
// REVISIT: always cast to string in next major
|
|
534
545
|
// Reading decimal as string to not loose precision
|
|
535
|
-
Decimal: cds.env.features.ieee754compatible ?
|
|
546
|
+
Decimal: cds.env.features.ieee754compatible ? (expr, elem) => elem?.scale
|
|
547
|
+
? `to_char(${expr},'FM${'0'.padStart(elem.precision, '9')}${'D'.padEnd(elem.scale + 1, '0')}')`
|
|
548
|
+
: `cast(${expr} as varchar)`
|
|
549
|
+
: undefined,
|
|
536
550
|
|
|
537
551
|
// Convert point back to json format
|
|
538
552
|
'cds.hana.ST_POINT': expr => `CASE WHEN (${expr}) IS NOT NULL THEN json_object('x':(${expr})[0],'y':(${expr})[1])::varchar END`,
|
|
@@ -567,14 +581,21 @@ GROUP BY k
|
|
|
567
581
|
`)
|
|
568
582
|
await this.exec(`CREATE DATABASE "${creds.database}" OWNER="${creds.user}" TEMPLATE=template0`)
|
|
569
583
|
} catch {
|
|
584
|
+
// Failed to connect to database
|
|
585
|
+
if (!this.dbc) {
|
|
586
|
+
return this.database({ database })
|
|
587
|
+
}
|
|
570
588
|
// Failed to reset database
|
|
571
589
|
} finally {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
590
|
+
// Only clean when successfully connected
|
|
591
|
+
if (this.dbc) {
|
|
592
|
+
await this.dbc.end()
|
|
593
|
+
delete this.dbc
|
|
594
|
+
|
|
595
|
+
// Update credentials to new Database owner
|
|
596
|
+
await this.disconnect()
|
|
597
|
+
this.options.credentials = Object.assign({}, system, creds)
|
|
598
|
+
}
|
|
578
599
|
}
|
|
579
600
|
}
|
|
580
601
|
|
|
@@ -589,18 +610,20 @@ GROUP BY k
|
|
|
589
610
|
|
|
590
611
|
try {
|
|
591
612
|
if (!clean) {
|
|
592
|
-
await
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
})
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
613
|
+
await cds
|
|
614
|
+
.run(`CREATE USER "${creds.user}" IN GROUP "${creds.usergroup}" PASSWORD '${creds.password}'`)
|
|
615
|
+
.catch(e => {
|
|
616
|
+
if (e.code === '42710') return
|
|
617
|
+
throw e
|
|
618
|
+
})
|
|
619
|
+
// Retry granting priviledges as this is being done by multiple instances
|
|
620
|
+
// Postgres just rejects when other connections are granting the same user
|
|
621
|
+
const grant = (i = 0) => cds.run(`GRANT CREATE, CONNECT ON DATABASE "${creds.database}" TO "${creds.user}";`)
|
|
622
|
+
.catch((err) => {
|
|
623
|
+
if (i > 100) throw err
|
|
624
|
+
return grant(i + 1)
|
|
625
|
+
})
|
|
626
|
+
await grant()
|
|
604
627
|
}
|
|
605
628
|
|
|
606
629
|
// Update credentials to new Schema owner
|
|
@@ -610,7 +633,7 @@ GROUP BY k
|
|
|
610
633
|
// Create new schema using schema owner
|
|
611
634
|
await this.tx(async tx => {
|
|
612
635
|
await tx.run(`DROP SCHEMA IF EXISTS "${creds.schema}" CASCADE`)
|
|
613
|
-
if (!clean) await tx.run(`CREATE SCHEMA "${creds.schema}" AUTHORIZATION "${creds.user}"`)
|
|
636
|
+
if (!clean) await tx.run(`CREATE SCHEMA "${creds.schema}" AUTHORIZATION "${creds.user}"`)
|
|
614
637
|
})
|
|
615
638
|
} finally {
|
|
616
639
|
await this.disconnect()
|
package/lib/cql-functions.js
CHANGED
|
@@ -24,6 +24,26 @@ const StandardFunctions = {
|
|
|
24
24
|
minute: x => `date_part('minute', ${castVal(x)})`,
|
|
25
25
|
second: x => `floor(date_part('second', ${castVal(x)}))`,
|
|
26
26
|
fractionalseconds: x => `CAST(date_part('second', ${castVal(x)}) - floor(date_part('second', ${castVal(x)})) AS DECIMAL)`,
|
|
27
|
+
totalseconds: x => `(
|
|
28
|
+
(
|
|
29
|
+
(
|
|
30
|
+
CAST(substring(${x},2,strpos(${x},'DT') - 2) AS INTEGER)
|
|
31
|
+
) + (
|
|
32
|
+
EXTRACT (EPOCH FROM
|
|
33
|
+
CAST(
|
|
34
|
+
replace(
|
|
35
|
+
replace(
|
|
36
|
+
replace(
|
|
37
|
+
substring(${x},strpos(${x},'DT') + 2),
|
|
38
|
+
'H',':'
|
|
39
|
+
),'M',':'
|
|
40
|
+
),'S','Z'
|
|
41
|
+
)
|
|
42
|
+
as TIME)
|
|
43
|
+
) - 0.5
|
|
44
|
+
)
|
|
45
|
+
) * 86400
|
|
46
|
+
)`,
|
|
27
47
|
now: function() {
|
|
28
48
|
return this.session_context({val: '$now'})
|
|
29
49
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cap-js/postgres",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"description": "CDS database service for Postgres",
|
|
5
5
|
"homepage": "https://github.com/cap-js/cds-dbs/tree/main/postgres#cds-database-service-for-postgres",
|
|
6
6
|
"repository": {
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"CHANGELOG.md"
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
|
-
"test": "npm start &&
|
|
27
|
-
"start": "docker
|
|
26
|
+
"test": "npm start && cds-test $(../test/find)",
|
|
27
|
+
"start": "docker compose -f pg-stack.yml up -d"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@cap-js/db-service": "^1.9.0",
|
|
@@ -67,6 +67,12 @@
|
|
|
67
67
|
}
|
|
68
68
|
},
|
|
69
69
|
"db": "sql"
|
|
70
|
+
},
|
|
71
|
+
"schema": {
|
|
72
|
+
"buildTaskType": {
|
|
73
|
+
"name": "postgres",
|
|
74
|
+
"description": "Postgres database build plugin"
|
|
75
|
+
}
|
|
70
76
|
}
|
|
71
77
|
},
|
|
72
78
|
"license": "SEE LICENSE"
|