@cap-js/postgres 1.11.1 → 1.12.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 CHANGED
@@ -4,6 +4,18 @@
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.12.0](https://github.com/cap-js/cds-dbs/compare/postgres-v1.11.1...postgres-v1.12.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
+
15
+ ### Fixed
16
+
17
+ * `expand@odata.count` queries ([#966](https://github.com/cap-js/cds-dbs/issues/966)) ([6607a84](https://github.com/cap-js/cds-dbs/commit/6607a8404aa70f2f3f7c6c65c7e9b1c324a5230b))
18
+
7
19
  ## [1.11.1](https://github.com/cap-js/cds-dbs/compare/postgres-v1.11.0...postgres-v1.11.1) (2025-02-09)
8
20
 
9
21
 
@@ -28,7 +28,7 @@ class PostgresService extends SQLService {
28
28
  ...this.options.pool,
29
29
  },
30
30
  create: async () => {
31
- const cr = this.options.credentials || {}
31
+ const { credentials: cr = {}, client: clientOptions = {} } = this.options
32
32
  const credentials = {
33
33
  // Cloud Foundry provides the user in the field username the pg npm module expects user
34
34
  user: cr.username || cr.user,
@@ -49,7 +49,7 @@ class PostgresService extends SQLService {
49
49
  ca: cr.sslrootcert,
50
50
  }),
51
51
  }
52
- const dbc = new Client(credentials)
52
+ const dbc = new Client({...credentials, ...clientOptions})
53
53
  await dbc.connect()
54
54
  return dbc
55
55
  },
@@ -389,14 +389,7 @@ GROUP BY k
389
389
  const cols = SELECT.columns.map(x => {
390
390
  const name = this.column_name(x)
391
391
  const outputConverter = this.output_converter4(x.element, `${queryAlias}.${this.quote(name)}`)
392
- let col = `${outputConverter} as ${this.doubleQuote(name)}`
393
-
394
- if (x.SELECT?.count) {
395
- // Return both the sub select and the count for @odata.count
396
- const qc = cds.ql.clone(x, { columns: [{ func: 'count' }], one: 1, limit: 0, orderBy: 0 })
397
- col += `,${this.expr(qc)} as ${this.doubleQuote(`${name}@odata.count`)}`
398
- }
399
- return col
392
+ return `${outputConverter} as ${this.doubleQuote(name)}`
400
393
  })
401
394
  const isRoot = SELECT.expand === 'root'
402
395
  const isSimple = cds.env.features.sql_simple_queries &&
@@ -1,66 +1,175 @@
1
+ 'use strict'
2
+
1
3
  const session = require('./session.json')
2
4
 
3
5
  const StandardFunctions = {
6
+ // ==============================
7
+ // Session Context Functions
8
+ // ==============================
9
+
10
+ /**
11
+ * Generates SQL statement to retrieve session context
12
+ * @param {Object} x - Object containing the session variable
13
+ * @returns {string} - SQL statement
14
+ */
4
15
  session_context: x => {
5
16
  let sql = `current_setting('${session[x.val] || x.val}')`
6
17
  if (x.val === '$now') sql += '::timestamp'
7
18
  return sql
8
19
  },
9
- count: x => `count(${x?.val || x || '*'})`,
10
- countdistinct: x => `count(distinct ${x.val || x || '*'})`,
20
+
21
+ // ==============================
22
+ // String Functions
23
+ // ==============================
24
+
25
+ /**
26
+ * Generates SQL statement that checks if one string contains another
27
+ * @param {...string} args - The strings to evaluate
28
+ * @returns {string} - SQL statement
29
+ */
11
30
  contains: (...args) => `(coalesce(strpos(${args}),0) > 0)`,
31
+
32
+ /**
33
+ * Generates SQL statement for the index of the first occurrence of one string in another
34
+ * @param {string} x - The string to search
35
+ * @param {string} y - The substring to find
36
+ * @returns {string} - SQL statement
37
+ */
12
38
  indexof: (x, y) => `strpos(${x},${y}) - 1`, // strpos is 1 indexed
13
- startswith: (x, y) => `coalesce(strpos(${x},${y}) = 1,false)`, // strpos is 1 indexed
39
+
40
+ /**
41
+ * Generates SQL statement that checks if a string starts with another string
42
+ * @param {string} x - The string to evaluate
43
+ * @param {string} y - The prefix to check
44
+ * @returns {string} - SQL statement
45
+ */
46
+ startswith: (x, y) => `coalesce(strpos(${x},${y}) = 1,false)`,
47
+
48
+ /**
49
+ * Generates SQL statement that checks if a string ends with another string
50
+ * @param {string} x - The string to evaluate
51
+ * @param {string} y - The suffix to check
52
+ * @returns {string} - SQL statement
53
+ */
14
54
  endswith: (x, y) => `coalesce(substr(${x},length(${x}) + 1 - length(${y})) = ${y},false)`,
55
+
56
+ /**
57
+ * Generates SQL statement to match a string against a regular expression
58
+ * @param {string} x - The string to match
59
+ * @param {string} y - The regular expression
60
+ * @returns {string} - SQL statement
61
+ */
15
62
  matchesPattern: (x, y) => `regexp_like(${x}, ${y})`,
63
+
64
+ /**
65
+ * Alias for matchesPattern
66
+ * @param {string} x - The string to match
67
+ * @param {string} y - The regular expression
68
+ * @returns {string} - SQL statement
69
+ */
16
70
  matchespattern: (x, y) => `regexp_like(${x}, ${y})`,
17
71
 
72
+ // ==============================
18
73
  // Date and Time Functions
74
+ // ==============================
75
+
76
+ /**
77
+ * Generates SQL statement for the year part of a date
78
+ * @param {string} x - The date input
79
+ * @returns {string} - SQL statement
80
+ */
19
81
  year: x => `date_part('year', ${castVal(x)})`,
82
+
83
+ /**
84
+ * Generates SQL statement for the month part of a date
85
+ * @param {string} x - The date input
86
+ * @returns {string} - SQL statement
87
+ */
20
88
  month: x => `date_part('month', ${castVal(x)})`,
89
+
90
+ /**
91
+ * Generates SQL statement for the day part of a date
92
+ * @param {string} x - The date input
93
+ * @returns {string} - SQL statement
94
+ */
21
95
  day: x => `date_part('day', ${castVal(x)})`,
96
+
97
+ /**
98
+ * Generates SQL statement to extract time from a date
99
+ * @param {string} x - The date input
100
+ * @returns {string} - SQL statement
101
+ */
22
102
  time: x => `to_char(${castVal(x)}, 'HH24:MI:SS')`,
103
+
104
+ /**
105
+ * Generates SQL statement for the hour part of a date
106
+ * @param {string} x - The date input
107
+ * @returns {string} - SQL statement
108
+ */
23
109
  hour: x => `date_part('hour', ${castVal(x)})`,
110
+
111
+ /**
112
+ * Generates SQL statement for the minute part of a date
113
+ * @param {string} x - The date input
114
+ * @returns {string} - SQL statement
115
+ */
24
116
  minute: x => `date_part('minute', ${castVal(x)})`,
117
+
118
+ /**
119
+ * Generates SQL statement for the second part of a date
120
+ * @param {string} x - The date input
121
+ * @returns {string} - SQL statement
122
+ */
25
123
  second: x => `floor(date_part('second', ${castVal(x)}))`,
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
- )`,
47
- now: function() {
48
- return this.session_context({val: '$now'})
49
- }
124
+
125
+ /**
126
+ * Generates SQL statement for fractional seconds
127
+ * @param {string} x - The date input
128
+ * @returns {string} - SQL statement
129
+ */
130
+ fractionalseconds: x =>
131
+ `CAST(date_part('second', ${castVal(x)}) - floor(date_part('second', ${castVal(x)})) AS DECIMAL)`,
50
132
  }
51
133
 
52
134
  const isTime = /^\d{1,2}:\d{1,2}:\d{1,2}$/
53
135
  const isVal = x => x && 'val' in x
54
- const castVal = (x) => `${x}${isVal(x) ? isTime.test(x.val) ? '::TIME' : '::TIMESTAMP' : ''}`
136
+ const castVal = x => `${x}${isVal(x) ? (isTime.test(x.val) ? '::TIME' : '::TIMESTAMP') : ''}`
55
137
 
56
138
  const HANAFunctions = {
57
- // https://help.sap.com/docs/SAP_HANA_PLATFORM/4fe29514fd584807ac9f2a04f6754767/f12b86a6284c4aeeb449e57eb5dd3ebd.html
139
+ // ==============================
140
+ // Time Difference Functions
141
+ // ==============================
58
142
 
59
- // Time functions
143
+ /**
144
+ * Generates SQL statement for the difference in 100-nanoseconds between two timestamps
145
+ * @param {string} x - Start timestamp
146
+ * @param {string} y - End timestamp
147
+ * @returns {string} - SQL statement
148
+ */
60
149
  nano100_between: (x, y) => `EXTRACT(EPOCH FROM ${y} - ${x}) * 10000000`,
150
+
151
+ /**
152
+ * Generates SQL statement for the difference in seconds between two timestamps
153
+ * @param {string} x - Start timestamp
154
+ * @param {string} y - End timestamp
155
+ * @returns {string} - SQL statement
156
+ */
61
157
  seconds_between: (x, y) => `EXTRACT(EPOCH FROM ${y} - ${x})`,
62
- days_between: (x, y) => `EXTRACT(DAY FROM ${y} - ${x})`,
63
158
 
159
+ /**
160
+ * Generates SQL statement for the difference in days between two timestamps
161
+ * @param {string} x - Start timestamp
162
+ * @param {string} y - End timestamp
163
+ * @returns {string} - SQL statement
164
+ */
165
+ days_between: (x, y) => `EXTRACT(DAY FROM ${y}::timestamp - ${x}::timestamp)::integer`,
166
+
167
+ /**
168
+ * Generates SQL statement for the difference in months between two timestamps
169
+ * @param {string} x - Start timestamp
170
+ * @param {string} y - End timestamp
171
+ * @returns {string} - SQL statement
172
+ */
64
173
  months_between: (x, y) => `((
65
174
  (EXTRACT(YEAR FROM ${y}) - EXTRACT(YEAR FROM ${x})) * 12
66
175
  )+(
@@ -72,6 +181,13 @@ const HANAFunctions = {
72
181
  cast((cast( to_char(${y},'DDHH24MISSFF3') as bigint ) < cast( to_char(${x},'DDHH24MISSFF3') as bigint )) as Integer) * -1
73
182
  end
74
183
  ))`,
184
+
185
+ /**
186
+ * Generates SQL statement for the difference in years between two timestamps
187
+ * @param {string} x - Start timestamp
188
+ * @param {string} y - End timestamp
189
+ * @returns {string} - SQL statement
190
+ */
75
191
  years_between(x, y) {
76
192
  return `TRUNC(${this.months_between(x, y)} / 12,0)`
77
193
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cap-js/postgres",
3
- "version": "1.11.1",
3
+ "version": "1.12.0",
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": {
@@ -27,7 +27,7 @@
27
27
  "start": "docker compose -f pg-stack.yml up -d"
28
28
  },
29
29
  "dependencies": {
30
- "@cap-js/db-service": "^1.17.0",
30
+ "@cap-js/db-service": "^1.18.0",
31
31
  "pg": "^8"
32
32
  },
33
33
  "peerDependencies": {