Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/actions/hce/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: 'Start HANA'
description: 'Starts a pre-initialized HANA container for isolated testing'
inputs:
GITHUB_TOKEN:
description: 'Token used to pull from ghcr.io'
required: true
image:
description: 'Image reference to pull and run'
required: false
default: 'ghcr.io/cap-js/hana:latest'
runs:
using: "composite"
steps:
- name: Start HANA
shell: bash
env:
IMAGE: ${{ inputs.image }}
GH_TOKEN: ${{ inputs.GITHUB_TOKEN }}
run: |
echo "$GH_TOKEN" | docker login ghcr.io -u $ --password-stdin
docker run -d --name hana --hostname buildkitsandbox -p 30041:30041 "$IMAGE"
docker logs -f hana &
LOGS_PID=$!
trap 'kill "$LOGS_PID" 2>/dev/null || true' EXIT

# Poll readiness; bail out early if the container has died.
until docker exec hana ./check_hana_health >/dev/null 2>&1; do
if ! docker ps --format '{{.Names}}' | grep -q '^hana$'; then
echo "::error::HANA container exited before becoming healthy"
docker ps -a --filter name=hana
docker logs --tail 200 hana || true
exit 1
fi
sleep 10
done

echo "HANA is ready."
55 changes: 0 additions & 55 deletions .github/actions/hxe/action.yml

This file was deleted.

7 changes: 3 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,14 @@ jobs:
- run: npm ci
- run: npm install -g @sap/cds-dk
- run: npm run lint
- id: hxe
uses: ./.github/actions/hxe
- id: hce
uses: ./.github/actions/hce
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# testing
- run: npm test -ws
env:
TAG: ${{ steps.hxe.outputs.TAG }}
IMAGE_ID: ${{ steps.hxe.outputs.IMAGE_ID }}
HANA_HOST: 'localhost'
- name: sqlite driver (better-sqlite3))
run: npm test -w sqlite
env:
Expand Down
35 changes: 8 additions & 27 deletions db-service/lib/cqn2sql.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ const cds_infer = require('./infer')
const cqn4sql = require('./cqn4sql')
const { resolveTable } = require('./utils')

const _simple_queries = cds.env.features.sql_simple_queries
const _strict_booleans = _simple_queries < 2
// REVISIT: make string the default in next major
const _count_as_string = cds.env.features.count_as_string
const _count = _count_as_string ? { func: 'count', cast: { type: 'cds.String' } } : { func: 'count' }
Expand Down Expand Up @@ -270,10 +268,10 @@ class CQN2SQLRenderer {
if (!_empty(from)) sql += ` FROM ${this.from(from, q)}`
else sql += this.from_dummy()
}
if (!recurse && !_empty(where)) sql += ` WHERE ${this.where(where)}`
if (!recurse && !_empty(groupBy)) sql += ` GROUP BY ${this.groupBy(groupBy)}`
if (!recurse && !_empty(having)) sql += ` HAVING ${this.having(having)}`
if (!recurse && !_empty(orderBy)) sql += ` ORDER BY ${this.orderBy(orderBy, localized)}`
if (!recurse && !_empty(where)) sql += ` WHERE ${this.where(where, q)}`
if (!recurse && !_empty(groupBy)) sql += ` GROUP BY ${this.groupBy(groupBy, q)}`
if (!recurse && !_empty(having)) sql += ` HAVING ${this.having(having, q)}`
if (!recurse && !_empty(orderBy)) sql += ` ORDER BY ${this.orderBy(orderBy, localized, q)}`
if (one) limit = Object.assign({}, limit, { rows: { val: 1 } })
if (limit) sql += ` LIMIT ${this.limit(limit)}`
if (forUpdate) sql += ` ${this.forUpdate(forUpdate)}`
Expand Down Expand Up @@ -626,27 +624,10 @@ class CQN2SQLRenderer {
if (!SELECT.columns) return sql

const isRoot = SELECT.expand === 'root'
const isSimple = _simple_queries &&
isRoot && // Simple queries are only allowed to have a root
!ObjectKeys(q.elements).some(e =>
_strict_booleans && q.elements[e].type === 'cds.Boolean' || // REVISIT: Booleans require json for sqlite
q.elements[e].isAssociation || // Indicates columns contains an expand
q.elements[e].$assocExpand || // REVISIT: sometimes associations are structs
q.elements[e].items // Array types require to be inlined with a json result
)

let cols = SELECT.columns.map(isSimple
? x => {
const name = this.column_name(x)
const escaped = `${name.replace(/"/g, '""')}`
return `${this.output_converter4(x.element, this.quote(name))} AS "${escaped}"`
}
: x => {
const name = this.column_name(x)
return `${this.string(`$.${JSON.stringify(name)}`)},${this.output_converter4(x.element, this.quote(name))}`
}).flat()

if (isSimple) return `SELECT ${cols} FROM (${sql})`
let cols = SELECT.columns.map(x => {
const name = this.column_name(x)
return `${this.string(`$.${JSON.stringify(name)}`)},${this.output_converter4(x.element, this.quote(name))}`
}).flat()

// Prevent SQLite from hitting function argument limit of 100
let obj = "'{}'"
Expand Down
Loading
Loading