@cap-js/postgres 1.10.0 → 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,15 @@
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
+
7
16
  ## [1.10.0](https://github.com/cap-js/cds-dbs/compare/postgres-v1.9.1...postgres-v1.10.0) (2024-07-25)
8
17
 
9
18
 
@@ -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.10.0",
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"