@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 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 new Postgres database service for [SAP Cloud Application Programming Model](https://cap.cloud.sap) Node.js, based on new, streamlined database architecture and [*pg* driver](https://www.npmjs.com/package/pg) .
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 one of the database packages, as follows:
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 _**BREAKING CHANGE**_)
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 `dateime` comes in being in [an ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) compatible format
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': '^7', '@cap-js/postgres': '^1' },
30
+ dependencies: { '@sap/cds': '^8', '@cap-js/postgres': '^1' },
31
31
  scripts: { start: 'cds-deploy' },
32
32
  }).to('package.json'),
33
33
  )
@@ -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
- return super.onPlainSQL(req, next)
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 ? expr => `cast(${expr} as varchar)` : undefined,
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
- await this.dbc.end()
573
- delete this.dbc
574
-
575
- // Update credentials to new Database owner
576
- await this.disconnect()
577
- this.options.credentials = Object.assign({}, system, creds)
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 this.tx(async tx => {
593
- // await tx.run(`DROP USER IF EXISTS "${creds.user}"`)
594
- await tx
595
- .run(`CREATE USER "${creds.user}" IN GROUP "${creds.usergroup}" PASSWORD '${creds.password}'`)
596
- .catch(e => {
597
- if (e.code === '42710') return
598
- throw e
599
- })
600
- })
601
- await this.tx(async tx => {
602
- await tx.run(`GRANT CREATE, CONNECT ON DATABASE "${creds.database}" TO "${creds.user}";`)
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}"`).catch(() => { })
636
+ if (!clean) await tx.run(`CREATE SCHEMA "${creds.schema}" AUTHORIZATION "${creds.user}"`)
614
637
  })
615
638
  } finally {
616
639
  await this.disconnect()
@@ -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.9.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 && jest --silent",
27
- "start": "docker-compose -f pg-stack.yml up -d"
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"