Skip to content

Commit 72f0246

Browse files
schwmajohannes-vogeldanjoahm23smahati
authored
release 0.11.0 (#182)
Co-authored-by: Johannes Vogel <[email protected]> Co-authored-by: Daniel Hutzel <[email protected]> Co-authored-by: d049904 <[email protected]> Co-authored-by: Heiko Witteborg <[email protected]> Co-authored-by: Mahati Shankar <[email protected]> Co-authored-by: Samuel Brucksch <[email protected]> Co-authored-by: Samuel Brucksch <[email protected]> Co-authored-by: D050513 <[email protected]> Co-authored-by: sjvans <[email protected]> Co-authored-by: Mariya Yordanova <[email protected]>
1 parent 132afcd commit 72f0246

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+717
-679
lines changed

.github/workflows/label-issues.yml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: Label issues
2+
on:
3+
issues:
4+
types:
5+
- reopened
6+
- opened
7+
jobs:
8+
label_issues:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
issues: write
12+
steps:
13+
- run: gh issue edit "$NUMBER" --add-label "$LABELS"
14+
env:
15+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
16+
GH_REPO: ${{ github.repository }}
17+
NUMBER: ${{ github.event.issue.number }}
18+
LABELS: new

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## Version 0.11.0 - 2024-07-30
9+
10+
### Added
11+
12+
- Support for configuring request payload limit using global flag `cds.server.body_parser.limit`
13+
14+
### Changed
15+
16+
- Bump required `@sap/cds` version to `>=7.8`
17+
- To improve performance, binary payloads are no longer validated to check if they are properly base64 or base64url encoded
18+
- Bump required `node` version to `^16` due to usage of `Buffer.toString('base64url')`
19+
- Use `cds.compile.to.serviceinfo` to determine if a service should be compiled to GraphQL schema
20+
821
## Version 0.10.1 - 2024-03-07
922

1023
### Fixed

lib/GraphQLAdapter.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function GraphQLAdapter(options) {
2020
: defaultErrorFormatter
2121

2222
router
23-
.use(express.json()) //> required by logger below
23+
.use(express.json({ ...cds.env.server.body_parser })) //> required by logger below
2424
.use(queryLogger)
2525

2626
if (options.graphiql) router.use(graphiql)

lib/compile.js

+7-20
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,16 @@ const cds = require('@sap/cds')
22
const { generateSchema4 } = require('./schema')
33
const { lexicographicSortSchema, printSchema } = require('graphql')
44

5-
const _isServiceAnnotatedWithGraphQL = service => {
6-
const { definition } = service
7-
8-
if (definition['@graphql']) return true
9-
10-
const protocol = definition['@protocol']
11-
if (protocol) {
12-
// @protocol: 'graphql' or @protocol: ['graphql', 'odata']
13-
const protocols = Array.isArray(protocol) ? protocol : [protocol]
14-
// Normalize objects such as { kind: 'graphql' } to strings
15-
return protocols.map(p => (typeof p === 'object' ? p.kind : p)).some(p => p.match(/graphql/i))
16-
}
17-
18-
return false
19-
}
20-
215
function cds_compile_to_gql(csn, options = {}) {
22-
const m = cds.linked(csn)
6+
const model = cds.linked(csn)
7+
const serviceinfo = cds.compile.to.serviceinfo(csn, options)
238
const services = Object.fromEntries(
24-
m.services
25-
.map(s => [s.name, new cds.ApplicationService(s.name, m)])
9+
model.services
10+
.map(s => [s.name, new cds.ApplicationService(s.name, model)])
2611
// Only compile services with GraphQL endpoints
27-
.filter(([_, service]) => _isServiceAnnotatedWithGraphQL(service))
12+
.filter(([_, service]) =>
13+
serviceinfo.find(s => s.name === service.name)?.endpoints.some(e => e.kind === 'graphql')
14+
)
2815
)
2916

3017
let schema = generateSchema4(services)

lib/resolvers/GraphQLRequest.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const cds = require('@sap/cds/lib')
1+
const cds = require('@sap/cds')
22

33
class GraphQLRequest extends cds.Request {
44
constructor(args) {

lib/resolvers/crud/create.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const cds = require('@sap/cds/lib')
1+
const cds = require('@sap/cds')
22
const { INSERT } = cds.ql
33
const { ARGS } = require('../../constants')
44
const { getArgumentByName, astToEntries } = require('../parse/ast2cqn')

lib/resolvers/crud/delete.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const cds = require('@sap/cds/lib')
1+
const cds = require('@sap/cds')
22
const { DELETE } = cds.ql
33
const { ARGS } = require('../../constants')
44
const { getArgumentByName, astToWhere } = require('../parse/ast2cqn')

lib/resolvers/crud/read.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const cds = require('@sap/cds/lib')
1+
const cds = require('@sap/cds')
22
const { SELECT } = cds.ql
33
const { ARGS, CONNECTION_FIELDS } = require('../../constants')
44
const { getArgumentByName, astToColumns, astToWhere, astToOrderBy, astToLimit } = require('../parse/ast2cqn')

lib/resolvers/crud/update.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const cds = require('@sap/cds/lib')
1+
const cds = require('@sap/cds')
22
const { SELECT, UPDATE } = cds.ql
33
const { ARGS } = require('../../constants')
44
const { getArgumentByName, astToColumns, astToWhere, astToEntries } = require('../parse/ast2cqn')

lib/resolvers/parse/ast2cqn/where.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const _arrayInsertBetweenFlat = (array, element) =>
6565

6666
const _joinedXprFrom_xprs = (_xprs, operator) => ({ xpr: _arrayInsertBetweenFlat(_xprs, operator) })
6767

68-
const _true_xpr = [{ val: 1 }, '=', { val: 1 }]
68+
const _true_xpr = [{ val: '1' }, '=', { val: '1' }]
6969

7070
const _parseObjectValue = (objectValue, columnName) => {
7171
const _xprs = objectValue.fields
@@ -76,7 +76,7 @@ const _parseObjectValue = (objectValue, columnName) => {
7676
return _joinedXprFrom_xprs(_xprs, 'and')
7777
}
7878

79-
const _false_xpr = [{ val: 0 }, '=', { val: 1 }]
79+
const _false_xpr = [{ val: '0' }, '=', { val: '1' }]
8080

8181
const _parseListValue = (listValue, columnName) => {
8282
const _xprs = listValue.values.map(value => _parseObjectValue(value, columnName)).filter(value => value !== undefined)

lib/schema/index.js

+1-18
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,6 @@ const queryGenerator = require('./query')
22
const mutationGenerator = require('./mutation')
33
const { GraphQLSchema } = require('graphql')
44
const { createRootResolvers, registerAliasFieldResolvers } = require('../resolvers')
5-
const { printSchema } = require('graphql')
6-
7-
// REVISIT: remove class with cds^8
8-
class SchemaGenerator {
9-
generate(services) {
10-
this._schema = generateSchema4(services)
11-
return this
12-
}
13-
14-
getSchema() {
15-
return this._schema
16-
}
17-
18-
printSchema() {
19-
return printSchema(this._schema)
20-
}
21-
}
225

236
function generateSchema4(services) {
247
const resolvers = createRootResolvers(services)
@@ -30,4 +13,4 @@ function generateSchema4(services) {
3013
return schema
3114
}
3215

33-
module.exports = { SchemaGenerator, generateSchema4 }
16+
module.exports = { generateSchema4 }

lib/schema/types/custom/GraphQLBinary.js

+9-23
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,20 @@
1-
const { GraphQLScalarType, Kind, GraphQLError } = require('graphql')
1+
const { GraphQLScalarType, Kind } = require('graphql')
22
const { getGraphQLValueError } = require('./util')
33

44
const ERROR_NON_STRING_VALUE = 'Binary cannot represent non string value'
5-
const ERROR_NON_BASE64_OR_BASE64URL = 'Binary values must be base64 or base64url encoded and normalized strings'
65

7-
const _normalizeBase64 = value => (Buffer.isBuffer(value) ? value : Buffer.from(value, 'base64')).toString('base64')
8-
9-
const _validateBase64String = (value, buffer, valueNode) => {
10-
const base64Value = _toBase64(value)
11-
const normalized = _normalizeBase64(buffer)
12-
if (_stripPadding(base64Value) !== _stripPadding(normalized) || base64Value.length > normalized.length)
13-
throw new GraphQLError(ERROR_NON_BASE64_OR_BASE64URL, valueNode)
6+
const serialize = value => {
7+
// Normalize to base64url string
8+
const buffer = Buffer.isBuffer(value) ? value : Buffer.from(value, 'base64')
9+
const base64url = buffer.toString('base64url')
10+
// Buffer base64url encoding does not have padding by default -> add it
11+
return base64url.padEnd(Math.ceil(base64url.length / 4) * 4, '=')
1412
}
1513

16-
const _toBase64 = value => value.replace(/_/g, '/').replace(/-/g, '+')
17-
const _toBase64Url = value => value.replace(/\//g, '_').replace(/\+/g, '-')
18-
const _stripPadding = value => value.replace(/=/g, '')
19-
20-
const serialize = outputValue => _toBase64Url(_normalizeBase64(outputValue))
21-
2214
const parseValue = inputValue => {
2315
if (typeof inputValue !== 'string') throw getGraphQLValueError(ERROR_NON_STRING_VALUE, inputValue)
2416

25-
const buffer = Buffer.from(inputValue, 'base64')
26-
_validateBase64String(inputValue, buffer)
27-
28-
return buffer
17+
return Buffer.from(inputValue, 'base64')
2918
}
3019

3120
const parseLiteral = valueNode => {
@@ -36,10 +25,7 @@ const parseLiteral = valueNode => {
3625
// WORKAROUND: value could have already been parsed to a Buffer, necessary because of manual parsing in enrich AST
3726
if (Buffer.isBuffer(value)) return value
3827

39-
const buffer = Buffer.from(value, 'base64')
40-
_validateBase64String(value, buffer, valueNode)
41-
42-
return buffer
28+
return Buffer.from(value, 'base64')
4329
}
4430

4531
module.exports = new GraphQLScalarType({

lib/schema/types/custom/GraphQLDate.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const ERROR_NON_DATE_VALUE = 'Date values must be strings in the ISO 8601 format
77
const _parseDate = inputValueOrValueNode => {
88
const date = parseDate(inputValueOrValueNode, ERROR_NON_DATE_VALUE)
99
// Only return YYYY-MM-DD
10-
return date.substring(0, date.indexOf('T'))
10+
return date.slice(0, 10)
1111
}
1212

1313
const parseValue = inputValue => {

package.json

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@cap-js/graphql",
3-
"version": "0.10.1",
3+
"version": "0.11.0",
44
"description": "CDS protocol adapter for GraphQL",
55
"keywords": [
66
"CAP",
@@ -22,12 +22,12 @@
2222
"LICENSE"
2323
],
2424
"engines": {
25-
"node": ">=14"
25+
"node": ">=16"
2626
},
2727
"scripts": {
28-
"prettier": "npx prettier --write app lib test",
29-
"prettier:check": "npx prettier --check app lib test",
30-
"lint": "npx eslint .",
28+
"prettier": "npm_config_yes=true npx prettier@latest --write app lib test",
29+
"prettier:check": "npm_config_yes=true npx prettier@latest --check app lib test",
30+
"lint": "npm_config_yes=true npx eslint@latest .",
3131
"test": "jest --silent",
3232
"test:generate-schemas": "node ./test/scripts/generate-schemas.js"
3333
},
@@ -36,15 +36,14 @@
3636
"graphql-http": "^1.18.0"
3737
},
3838
"peerDependencies": {
39-
"@sap/cds": ">=7.3"
39+
"@sap/cds": ">=7.8"
4040
},
4141
"devDependencies": {
4242
"@cap-js/graphql": "file:.",
43+
"@cap-js/sqlite": "^1",
4344
"axios": "^1",
44-
"eslint": "^8",
4545
"express": "^4.17.1",
4646
"jest": "^29.3.1",
47-
"semver": "^7.4.0",
48-
"@cap-js/sqlite": "^1"
47+
"semver": "^7.4.0"
4948
}
5049
}
+21-19
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,49 @@
1-
service NotAnnotated {
1+
context protocols {
22
entity A {
33
key id : UUID;
44
}
55
}
66

7+
service NotAnnotated {
8+
entity A as projection on protocols.A;
9+
}
10+
711
@protocol: 'none'
812
service AnnotatedWithAtProtocolNone {
9-
entity A {
10-
key id : UUID;
11-
}
13+
entity A as projection on protocols.A;
1214
}
1315

1416
@protocol: 'odata'
1517
service AnnotatedWithNonGraphQL {
16-
entity A {
17-
key id : UUID;
18-
}
18+
entity A as projection on protocols.A;
1919
}
2020

2121
@graphql
2222
service AnnotatedWithAtGraphQL {
23-
entity A {
24-
key id : UUID;
25-
}
23+
entity A as projection on protocols.A;
2624
}
2725

2826
@protocol: 'graphql'
2927
service AnnotatedWithAtProtocolString {
30-
entity A {
31-
key id : UUID;
32-
}
28+
entity A as projection on protocols.A;
3329
}
3430

3531
@protocol: ['graphql']
3632
service AnnotatedWithAtProtocolStringList {
37-
entity A {
38-
key id : UUID;
39-
}
33+
entity A as projection on protocols.A;
4034
}
4135

4236
@protocol: [{kind: 'graphql'}]
4337
service AnnotatedWithAtProtocolObjectList {
44-
entity A {
45-
key id : UUID;
46-
}
38+
entity A as projection on protocols.A;
39+
}
40+
41+
@protocol: { graphql }
42+
service AnnotatedWithAtProtocolObjectWithKey {
43+
entity A as projection on protocols.A;
44+
}
45+
46+
@protocol: { graphql: 'dummy' }
47+
service AnnotatedWithAtProtocolObjectWithKeyAndValue {
48+
entity A as projection on protocols.A;
4749
}

test/resources/bookshop-graphql/srv/test-service.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const cds = require('@sap/cds/lib')
1+
const cds = require('@sap/cds')
22

33
module.exports = cds.service.impl(srv => {
44
const { Foo } = srv.entities

test/resources/bookshop/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"index.js"
1111
],
1212
"dependencies": {
13+
"@cap-js/graphql": "*",
1314
"@sap/cds": ">=5.9",
1415
"express": "^4.17.1"
1516
},

test/resources/custom-handlers/package.json

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
2+
"Note: Programmatic configuration of GraphQL protocol adapter in server.js": "",
3+
"__dependencies": {
4+
"@cap-js/graphql": "*"
5+
},
26
"devDependencies": {
37
"@cap-js/sqlite": "*"
48
}

test/resources/types/package.json

+13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
{
22
"dependencies": {
3+
"@cap-js/graphql": "*"
4+
},
5+
"devDependencies": {
36
"@cap-js/sqlite": "*"
7+
},
8+
"cds": {
9+
"server": {
10+
"body_parser": {
11+
"limit": "110KB"
12+
}
13+
},
14+
"features": {
15+
"ieee754compatible": true
16+
}
417
}
518
}

test/resources/types/server.js

-6
This file was deleted.

0 commit comments

Comments
 (0)