Skip to content

Commit

Permalink
[main] release hotfix 0.10.1 (#159)
Browse files Browse the repository at this point in the history
  • Loading branch information
schwma authored Mar 7, 2024
1 parent e35ae67 commit 132afcd
Show file tree
Hide file tree
Showing 23 changed files with 174 additions and 45 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package-lock.json
.idea
.DS_Store
.vscode
**/_out

# cds-typer
@cds-models/
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Version 0.10.0 - 2023-01-30
## Version 0.10.1 - 2024-03-07

### Fixed

- Type parsing error for literal values passed within arguments on fields of scalar type differing from the literal type. This case occurred for delete mutations when the filter operands had a type other than `Int`.

## Version 0.10.0 - 2024-01-30

### Added

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
A GraphQL protocol adapter for [SAP Cloud Application Programming Model](https://cap.cloud.sap) Node.js.
This adapter generically generates a GraphQL schema for the models of an application and serves an endpoint that allows you to query your services using the GraphQL query language.

_**WARNING:** This package is in an early general availability state. This means that it is general available, with stable APIs unless otherwise indicated, and you can use it for production. However, please note the [current limitations](#limitations) listed below._
_**WARNING:** This package is in an early general availability state. This means that it is generally available, with stable APIs unless otherwise indicated, and you can use it for production. However, please note the [current limitations](#limitations) listed below._

## Requirements and Setup

Expand All @@ -16,7 +16,7 @@ _**WARNING:** This package is in an early general availability state. This means
npm add @cap-js/graphql
```

> This will automatically plugin to `@sap/cds` runtime, enabling the new [middlewares architecture](https://cap.cloud.sap/docs/node.js/middlewares) in Node.js, and register a GraphQL endpoint at `/graphql` serving all CRUD requests for the application services found in your model.
> This command will set up the GraphQL plug-in with the `@sap/cds` runtime. It enables the new [middlewares architecture](https://cap.cloud.sap/docs/node.js/middlewares) in Node.js and registers a GraphQL endpoint at `/graphql` serving all CRUD requests for the application services found in your model.

2. Annotate the services you want to serve, e.g. using `@graphql` or `@protocol: 'graphql'`.

Expand Down
3 changes: 2 additions & 1 deletion lib/resolvers/crud/read.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ module.exports = async ({ req, res }, service, entity, selection) => {
const args = selection.arguments

let query = SELECT.from(entity)
query.columns(astToColumns(entity, selection.selectionSet.selections, true))
const columns = astToColumns(entity, selection.selectionSet.selections, true)
if (columns.length) query.columns(columns)

const filter = getArgumentByName(args, ARGS.filter)
if (filter) {
Expand Down
4 changes: 2 additions & 2 deletions lib/resolvers/parse/ast/literal.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const _getTypeFrom_fields = (_fields, path, index = 0) => {
const _field = _fields[name]
const type = _getTypeFrom_fieldOr_arg(_field)

// If type has the parseLiteral function it is a scalar type -> leaf -> end of path
if (type.parseLiteral) return type
// If we are at the end of the path, this field is a leaf and therefore is of scalar type with a parseLiteral function
if (index === path.length) return type

const next = path[index]
// Is the next path element an argument? If yes, follow the argument
Expand Down
3 changes: 2 additions & 1 deletion lib/resolvers/parse/ast2cqn/where.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const _objectFieldTo_xpr = (objectField, columnName) => {
const operand = objectField.value

if (gqlOperator === LOGICAL_OPERATORS.in) {
const list = operand.kind === Kind.LIST ? operand.values.map(value => ({ val: value.value })) : [{ val: operand.value }]
const list =
operand.kind === Kind.LIST ? operand.values.map(value => ({ val: value.value })) : [{ val: operand.value }]
return [ref, _gqlOperatorToCdsOperator(gqlOperator), { list }]
}

Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cap-js/graphql",
"version": "0.10.0",
"version": "0.10.1",
"description": "CDS protocol adapter for GraphQL",
"keywords": [
"CAP",
Expand Down Expand Up @@ -44,8 +44,7 @@
"eslint": "^8",
"express": "^4.17.1",
"jest": "^29.3.1",
"prettier": "3.2.4",
"semver": "^7.4.0",
"sqlite3": "^5.0.2"
"@cap-js/sqlite": "^1"
}
}
3 changes: 3 additions & 0 deletions test/resources/annotations/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"dependencies": {
"@cap-js/graphql": "*"
},
"devDependencies": {
"@cap-js/sqlite": "*"
},
"cds": {
"protocols": {
"graphql": {
Expand Down
4 changes: 4 additions & 0 deletions test/resources/bookshop-graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
"dependencies": {
"@cap-js/graphql": "*"
},
"devDependencies": {
"@cap-js/sqlite": "*"
},
"cds": {
"requires": {
"db": {
"kind": "sqlite",
"impl": "@cap-js/sqlite",
"credentials": {
"database": ":memory:"
}
Expand Down
3 changes: 3 additions & 0 deletions test/resources/bookshop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
"@sap/cds": ">=5.9",
"express": "^4.17.1"
},
"devDependencies": {
"@cap-js/sqlite": "*"
},
"scripts": {
"genres": "cds serve test/genres.cds",
"start": "cds run",
Expand Down
3 changes: 3 additions & 0 deletions test/resources/cds.Request/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"dependencies": {
"@cap-js/graphql": "*"
},
"devDependencies": {
"@cap-js/sqlite": "*"
}
}
3 changes: 3 additions & 0 deletions test/resources/concurrency/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"dependencies": {
"@cap-js/graphql": "*"
},
"devDependencies": {
"@cap-js/sqlite": "*"
}
}
3 changes: 3 additions & 0 deletions test/resources/custom-error-formatter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"dependencies": {
"@cap-js/graphql": "*"
},
"devDependencies": {
"@cap-js/sqlite": "*"
},
"cds": {
"protocols": {
"graphql": {
Expand Down
5 changes: 5 additions & 0 deletions test/resources/custom-handlers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"devDependencies": {
"@cap-js/sqlite": "*"
}
}
3 changes: 3 additions & 0 deletions test/resources/edge-cases/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"dependencies": {
"@cap-js/graphql": "*"
},
"devDependencies": {
"@cap-js/sqlite": "*"
}
}
3 changes: 3 additions & 0 deletions test/resources/error-handling/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"dependencies": {
"@cap-js/graphql": "*"
},
"devDependencies": {
"@cap-js/sqlite": "*"
},
"cds": {
"requires": {
"db": {
Expand Down
5 changes: 5 additions & 0 deletions test/resources/types/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"@cap-js/sqlite": "*"
}
}
4 changes: 3 additions & 1 deletion test/tests/annotations.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ describe('graphql - annotations', () => {
}
`
const response = await POST(path, { query })
expect(response.data.errors[0].message).toMatch(/^Cannot query field "AnnotatedWithAtProtocolNone" on type "Query"\./)
expect(response.data.errors[0].message).toMatch(
/^Cannot query field "AnnotatedWithAtProtocolNone" on type "Query"\./
)
})

test('service annotated with non-GraphQL protocol is not served', async () => {
Expand Down
21 changes: 20 additions & 1 deletion test/tests/enrich.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ describe('graphql - enrich AST ', () => {
expect(value).toEqual(2)
})

test('parsing of literal value in nested input value', async () => {
test('parsing of literal value in nested input value passed as arg on field with sub-selection of fields', async () => {
const query = gql`
{
AdminService {
Expand All @@ -198,6 +198,25 @@ describe('graphql - enrich AST ', () => {
const value = enrichedAST[0].selectionSet.selections[0].arguments[0].value.fields[0].value.fields[0].value.value
expect(value).toEqual(201)
})

test('parsing of literal value in nested input value passed as arg on field of scalar type', async () => {
const query = gql`
mutation {
AdminService {
Authors {
delete(filter: { dateOfBirth: { eq: "1818-07-30T00:00:00.000Z" } })
}
}
}
`
const document = parse(query)
const fakeInfo = fakeInfoObject(document, bookshopSchema, 'Mutation')
const enrichedAST = enrich(fakeInfo)
const value =
enrichedAST[0].selectionSet.selections[0].selectionSet.selections[0].arguments[0].value.fields[0].value
.fields[0].value.value
expect(value).toEqual('1818-07-30')
})
})

describe('variable values are substituted into the AST', () => {
Expand Down
29 changes: 29 additions & 0 deletions test/tests/mutations/delete.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,35 @@ describe('graphql - delete mutations', () => {
])
})

test('delete single entry by filtering for non-key field', async () => {
const query = gql`
mutation {
AdminService {
Books {
delete(filter: { title: { eq: "Jane Eyre" } })
}
}
}
`
const data = {
AdminService: {
Books: {
delete: 1
}
}
}
const response = await POST('/graphql', { query })
expect(response.data).toEqual({ data })

const result = await SELECT.from('sap.capire.bookshop.Books').columns('ID', 'title')
expect(result).toEqual([
{ ID: 201, title: 'Wuthering Heights' },
{ ID: 251, title: 'The Raven' },
{ ID: 252, title: 'Eleonora' },
{ ID: 271, title: 'Catweazle' }
])
})

test('delete multiple entries', async () => {
const query = gql`
mutation ($filter: AdminService_Books_filter) {
Expand Down
6 changes: 3 additions & 3 deletions test/tests/queries/filter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ describe('graphql - filter', () => {
const query = gql`
{
AdminService {
Books(filter: [{ ID: { in: [201, 251] } }, { title: { contains: "cat" } }]) {
Books(filter: [{ ID: { in: [201, 251] } }, { title: { contains: "Cat" } }]) {
nodes {
ID
title
Expand Down Expand Up @@ -468,10 +468,10 @@ describe('graphql - filter', () => {
Books(
filter: [
{
title: [{ startswith: "the", endswith: "raven" }, { contains: "height" }]
title: [{ startswith: "The", endswith: "Raven" }, { contains: "Height" }]
ID: [{ eq: 201 }, { eq: 251 }]
}
{ title: { contains: "cat" } }
{ title: { contains: "Cat" } }
]
) {
nodes {
Expand Down
61 changes: 41 additions & 20 deletions test/tests/queries/paging-offset.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,27 @@ describe('graphql - offset-based paging', () => {
}
`
const data = {
AdminServiceBasic: {
Authors: null
AdminService: {
Authors: [
{
name: 'Edgar Allen Poe',
books: [
// Edgar Allen Poe has 2 books, but only 1 requested.
{
title: 'Eleonora'
}
]
},
{
name: 'Richard Carpenter',
books: []
}
]
}
}
const errors = [
{
locations: [{ column: 13, line: 4 }],
message: 'Pagination is not supported in expand',
path: ['AdminServiceBasic', 'Authors']
}
]

const response = await POST('/graphql', { query })
expect(response.data).toEqual({ data, errors })
expect(response.data).toEqual({ data })
})
})

Expand Down Expand Up @@ -139,19 +147,32 @@ describe('graphql - offset-based paging', () => {
`
const data = {
AdminService: {
Authors: null
Authors: {
nodes: [
{
name: 'Edgar Allen Poe',
books: {
// Edgar Allen Poe has 2 books, but only 1 requested.
nodes: [
{
title: 'Eleonora'
}
]
}
},
{
name: 'Richard Carpenter',
books: {
nodes: []
}
}
]
}
}
}
const errors = [
{
locations: [{ column: 13, line: 4 }],
message: 'Pagination is not supported in expand',
path: ['AdminService', 'Authors'],
extensions: expect.any(Object)
}
]

const response = await POST('/graphql', { query })
expect(response.data).toEqual({ data, errors })
expect(response.data).toEqual({ data })
})
})
})
Loading

0 comments on commit 132afcd

Please sign in to comment.