Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: generate GraphQL descriptions from CDS doc comments #30

Merged
merged 25 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f55dfef
Support generating descriptions from doc comments
schwma Jan 5, 2023
31cc86a
Add changelog entry
schwma Jan 5, 2023
a37a05f
Enable docs compiler option for test schemas
schwma Jan 5, 2023
35a649a
Remove managed from localized test schema
schwma Jan 5, 2023
7ec3c92
Move comment
schwma Jan 5, 2023
c4005cb
Merge branch 'main' into doc-comments
schwma Jan 19, 2023
bd32388
Merge branch 'main' into doc-comments
schwma Jan 23, 2023
92c3e0f
Merge branch 'main' into doc-comments
schwma Feb 27, 2023
8dfca1f
Merge branch 'main' into doc-comments
schwma Feb 27, 2023
7738791
Move changelog entry to newest release
schwma Feb 27, 2023
53bd780
Merge branch 'main' into doc-comments
schwma Mar 2, 2023
ffdaa88
Merge branch 'main' into doc-comments
schwma Apr 18, 2023
4d9902e
Merge branch 'main' into doc-comments
schwma Sep 13, 2023
b4a3d88
Regenerate schema
schwma Sep 13, 2023
ba59bec
Merge branch 'main' into doc-comments
schwma Sep 29, 2023
44c88d2
Merge branch 'main' into doc-comments
schwma Oct 10, 2023
4df91c1
Generate descriptions only for service and entity types and element f…
schwma Oct 10, 2023
b4e4647
Merge branch 'main' into doc-comments
schwma Oct 11, 2023
322e54a
Merge branch 'main' into doc-comments
schwma Oct 13, 2023
bf92446
Extract type and args consts again
schwma Oct 25, 2023
5e855ea
Merge branch 'main' into doc-comments
schwma Nov 21, 2023
ddf09a1
Improve wording of doc comment
schwma Nov 21, 2023
c233af8
Fix capitalization in doc comment
schwma Nov 21, 2023
67e42ae
Improve changelog entry
schwma Nov 21, 2023
cea3781
Merge branch 'main' into doc-comments
schwma Nov 23, 2023
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Support for generating GraphQL descriptions from CDS doc comments of services, entities, and elements

### Changed

### Fixed
Expand Down
13 changes: 10 additions & 3 deletions lib/schema/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ module.exports = cache => {
for (const key in services) {
const service = services[key]
const serviceName = gqlName(service.name)
const resolve = resolvers[serviceName]
fields[serviceName] = { type: _serviceToObjectType(service), resolve }
fields[serviceName] = {
type: _serviceToObjectType(service),
resolve: resolvers[serviceName]
}
}

return new GraphQLObjectType({ name: 'Query', fields })
Expand All @@ -33,7 +35,12 @@ module.exports = cache => {
fields[gqlName(key)] = { type, args }
}

return new GraphQLObjectType({ name: gqlName(service.name), fields })
return new GraphQLObjectType({
name: gqlName(service.name),
// REVISIT: Passed services currently don't directly contain doc property
description: service.model.definitions[service.name].doc,
fields
})
}

return { generateQueryObjectType }
Expand Down
8 changes: 6 additions & 2 deletions lib/schema/types/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ module.exports = cache => {
if (cachedEntityObjectType) return cachedEntityObjectType

const fields = {}
const newEntityObjectType = new GraphQLObjectType({ name: entityName, fields: () => fields })
const newEntityObjectType = new GraphQLObjectType({
name: entityName,
description: entity.doc,
fields: () => fields
})
cache.set(entityName, newEntityObjectType)

for (const name in entity.elements) {
Expand All @@ -38,7 +42,7 @@ module.exports = cache => {
// REVISIT: requires differentiation for support of configurable schema flavors
const type = element.is2many ? _elementToObjectConnectionType(element) : _elementToObjectType(element)
if (type) {
const field = { type }
const field = { type, description: element.doc }
if (element.is2many) field.args = argsGenerator(cache).generateArgumentsForType(element)
fields[gqlName(name)] = field
}
Expand Down
1 change: 1 addition & 0 deletions test/resources/bookshop-graphql/db/schema.cds
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extend bookshop.Books with {
on chapters.book = $self;
}

/** A Chapter of a Book */
entity Chapters : managed {
key book : Association to bookshop.Books;
key number : Integer;
Expand Down
3 changes: 3 additions & 0 deletions test/resources/bookshop-graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
"auth": {
"kind": "mocked"
}
},
"cdsc": {
"docs": true
}
}
}
1 change: 1 addition & 0 deletions test/resources/bookshop-graphql/srv/admin-service.cds
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ using {sap.capire.graphql} from '../db/schema';
using {AdminService} from '../../bookshop/srv/admin-service';

@graphql
/** Service used by administrators to manage Books and Authors */
extend service AdminService with {
entity Chapters as projection on graphql.Chapters;
}
2 changes: 0 additions & 2 deletions test/resources/edge-cases/srv/field-named-localized.cds
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using {managed} from '@sap/cds/common';

service FieldNamedLocalizedService {
entity localized {
key ID : Integer;
Expand Down
73 changes: 73 additions & 0 deletions test/schemas/bookshop-graphql.gql
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Service used by administrators to manage Books and Authors"""
type AdminService {
Authors(filter: [AdminService_Authors_filter], orderBy: [AdminService_Authors_orderBy], skip: Int, top: Int): AdminService_Authors_connection
Books(filter: [AdminService_Books_filter], orderBy: [AdminService_Books_orderBy], skip: Int, top: Int): AdminService_Books_connection
Expand All @@ -9,14 +10,23 @@ type AdminService {
Genres_texts(filter: [AdminService_Genres_texts_filter], orderBy: [AdminService_Genres_texts_orderBy], skip: Int, top: Int): AdminService_Genres_texts_connection
}

"""
Aspect to capture changes by user and name

See https://cap.cloud.sap/docs/cds/common#aspect-managed
"""
type AdminService_Authors {
ID: Int
books(filter: [AdminService_Books_filter], orderBy: [AdminService_Books_orderBy], skip: Int, top: Int): AdminService_Books_connection
createdAt: Timestamp

"""Canonical user ID"""
createdBy: String
dateOfBirth: Date
dateOfDeath: Date
modifiedAt: Timestamp

"""Canonical user ID"""
modifiedBy: String
name: String
placeOfBirth: String
Expand Down Expand Up @@ -87,20 +97,35 @@ input AdminService_Authors_orderBy {
placeOfDeath: SortDirection
}

"""
Aspect to capture changes by user and name

See https://cap.cloud.sap/docs/cds/common#aspect-managed
"""
type AdminService_Books {
ID: Int
author: AdminService_Authors
author_ID: Int
chapters(filter: [AdminService_Chapters_filter], orderBy: [AdminService_Chapters_orderBy], skip: Int, top: Int): AdminService_Chapters_connection
createdAt: Timestamp

"""Canonical user ID"""
createdBy: String

"""
Type for an association to Currencies

See https://cap.cloud.sap/docs/cds/common#type-currency
"""
currency: AdminService_Currencies
currency_code: String
descr: String
genre: AdminService_Genres
genre_ID: Int
image: Binary
modifiedAt: Timestamp

"""Canonical user ID"""
modifiedBy: String
price: Decimal
stock: Int
Expand Down Expand Up @@ -195,6 +220,8 @@ input AdminService_Books_orderBy {
type AdminService_Books_texts {
ID: Int
descr: String

"""Type for a language code"""
locale: String
title: String
}
Expand Down Expand Up @@ -236,12 +263,17 @@ input AdminService_Books_texts_orderBy {
title: SortDirection
}

"""A Chapter of a Book"""
type AdminService_Chapters {
book: AdminService_Books
book_ID: Int
createdAt: Timestamp

"""Canonical user ID"""
createdBy: String
modifiedAt: Timestamp

"""Canonical user ID"""
modifiedBy: String
number: Int
title: String
Expand Down Expand Up @@ -297,6 +329,11 @@ input AdminService_Chapters_orderBy {
title: SortDirection
}

"""
Code list for currencies

See https://cap.cloud.sap/docs/cds/common#entity-currencies
"""
type AdminService_Currencies {
code: String
descr: String
Expand Down Expand Up @@ -353,6 +390,8 @@ input AdminService_Currencies_orderBy {
type AdminService_Currencies_texts {
code: String
descr: String

"""Type for a language code"""
locale: String
name: String
}
Expand Down Expand Up @@ -394,6 +433,7 @@ input AdminService_Currencies_texts_orderBy {
name: SortDirection
}

"""Hierarchically organized Code List for Genres"""
type AdminService_Genres {
ID: Int
children(filter: [AdminService_Genres_filter], orderBy: [AdminService_Genres_orderBy], skip: Int, top: Int): AdminService_Genres_connection
Expand Down Expand Up @@ -451,6 +491,8 @@ input AdminService_Genres_orderBy {
type AdminService_Genres_texts {
ID: Int
descr: String

"""Type for a language code"""
locale: String
name: String
}
Expand Down Expand Up @@ -524,11 +566,18 @@ type CatalogService {
ListOfBooks(filter: [CatalogService_ListOfBooks_filter], orderBy: [CatalogService_ListOfBooks_orderBy], skip: Int, top: Int): CatalogService_ListOfBooks_connection
}

"""For display in details pages"""
type CatalogService_Books {
ID: Int
author: String
chapters(filter: [CatalogService_Chapters_filter], orderBy: [CatalogService_Chapters_orderBy], skip: Int, top: Int): CatalogService_Chapters_connection
createdAt: Timestamp

"""
Type for an association to Currencies

See https://cap.cloud.sap/docs/cds/common#type-currency
"""
currency: CatalogService_Currencies
currency_code: String
descr: String
Expand Down Expand Up @@ -619,6 +668,8 @@ input CatalogService_Books_orderBy {
type CatalogService_Books_texts {
ID: Int
descr: String

"""Type for a language code"""
locale: String
title: String
}
Expand Down Expand Up @@ -660,12 +711,17 @@ input CatalogService_Books_texts_orderBy {
title: SortDirection
}

"""A Chapter of a Book"""
type CatalogService_Chapters {
book: CatalogService_Books
book_ID: Int
createdAt: Timestamp

"""Canonical user ID"""
createdBy: String
modifiedAt: Timestamp

"""Canonical user ID"""
modifiedBy: String
number: Int
title: String
Expand Down Expand Up @@ -721,6 +777,11 @@ input CatalogService_Chapters_orderBy {
title: SortDirection
}

"""
Code list for currencies

See https://cap.cloud.sap/docs/cds/common#entity-currencies
"""
type CatalogService_Currencies {
code: String
descr: String
Expand Down Expand Up @@ -777,6 +838,8 @@ input CatalogService_Currencies_orderBy {
type CatalogService_Currencies_texts {
code: String
descr: String

"""Type for a language code"""
locale: String
name: String
}
Expand Down Expand Up @@ -818,6 +881,7 @@ input CatalogService_Currencies_texts_orderBy {
name: SortDirection
}

"""Hierarchically organized Code List for Genres"""
type CatalogService_Genres {
ID: Int
children(filter: [CatalogService_Genres_filter], orderBy: [CatalogService_Genres_orderBy], skip: Int, top: Int): CatalogService_Genres_connection
Expand Down Expand Up @@ -875,6 +939,8 @@ input CatalogService_Genres_orderBy {
type CatalogService_Genres_texts {
ID: Int
descr: String

"""Type for a language code"""
locale: String
name: String
}
Expand Down Expand Up @@ -916,11 +982,18 @@ input CatalogService_Genres_texts_orderBy {
name: SortDirection
}

"""For displaying lists of Books"""
type CatalogService_ListOfBooks {
ID: Int
author: String
chapters(filter: [CatalogService_Chapters_filter], orderBy: [CatalogService_Chapters_orderBy], skip: Int, top: Int): CatalogService_Chapters_connection
createdAt: Timestamp

"""
Type for an association to Currencies

See https://cap.cloud.sap/docs/cds/common#type-currency
"""
currency: CatalogService_Currencies
currency_code: String
genre: CatalogService_Genres
Expand Down
2 changes: 1 addition & 1 deletion test/scripts/generate-schemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const { models } = require('../resources')
fs.mkdirSync(SCHEMAS_DIR)
for (const model of models) {
console.log(`Generating GraphQL schema "${model.name}.gql"`)
const csn = await cds.load(model.files)
const csn = await cds.load(model.files, { docs: true })
const graphQLSchema = cds.compile(csn).to.gql({ sort: true })
const schemaPath = path.join(SCHEMAS_DIR, `${model.name}.gql`)
const schemaPathDir = path.parse(schemaPath).dir
Expand Down
2 changes: 1 addition & 1 deletion test/tests/schema.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('graphql - schema generation', () => {
describe('generated schema should match saved schema', () => {
models.forEach(model => {
it('should process model ' + model.name, async () => {
const csn = await cds.load(model.files)
const csn = await cds.load(model.files, { docs: true })
const generatedSchemaObject = cds.compile(csn).to.graphql({ as: 'obj', sort: true })
const schemaValidationErrors = validateSchema(generatedSchemaObject)
expect(schemaValidationErrors.length).toEqual(0)
Expand Down