Compare commits

..

5 Commits

Author SHA1 Message Date
Daniel
9ce3bb9ef6 typo 2021-03-03 23:25:45 +01:00
Daniel
5135276952 copy error 2021-03-03 23:22:43 +01:00
Daniel
eb98444afb one more 2021-03-03 23:11:41 +01:00
Daniel
83537482b8 Adding cucumber tests 2021-03-03 22:47:23 +01:00
Daniel
cf10129b68 Prepare for compiler v2 2021-03-02 17:14:38 +01:00
39 changed files with 591 additions and 491 deletions

37
.vscode/launch.json vendored
View File

@@ -4,31 +4,28 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Attach by Process ID",
"processId": "${command:PickProcess}",
"request": "attach",
"skipFiles": [
"<node_internals>/**"
],
"type": "pwa-node"
},
{
"name": "bookshop",
"command": "npx cds watch bookshop",
"type": "node-terminal",
"command": "cds watch bookshop",
"request": "launch",
"skipFiles": [
"<node_internals>/**",
"**/node_modules/**",
"**/cds/lib/lazy.js",
"**/cds/lib/req/cls.js",
"**/odata-v4/okra/**"
]
"type": "node-terminal",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Fiori App",
"command": "npx cds watch fiori",
"type": "node-terminal",
"name": "Fiori app",
"command": "cds watch fiori",
"request": "launch",
"skipFiles": [
"<node_internals>/**",
"**/node_modules/**",
"**/cds/lib/lazy.js",
"**/cds/lib/req/cls.js",
"**/odata-v4/okra/**"
]
"type": "node-terminal",
"skipFiles": ["<node_internals>/**"]
}
],
"inputs": [
@@ -36,7 +33,7 @@
"type": "pickString",
"id": "sample",
"description": "Which sample do you want to start?",
"options": [ "bookshop", "fiori", "reviews", "reviews" ],
"options": ["bookshop", "fiori", "reviews", "reviews/test/bookshop"],
"default": "bookshop"
}
]

15
.vscode/settings.json vendored
View File

@@ -1,17 +1,6 @@
{
"files.exclude": {
".reuse/**": true,
"**/.gitignore": true,
"**/.vscode": true,
"LICENSES/**": true
},
"debug.javascript.terminalOptions": {
"skipFiles": [
"<node_internals>/**",
"**/node_modules/**",
"**/cds/lib/lazy.js",
"**/cds/lib/req/cls.js",
"**/odata-v4/okra/**"
]
},
"**/.vscode": true
}
}

208
LICENSE Normal file
View File

@@ -0,0 +1,208 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION,
AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution
as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct
or indirect, to cause the direction or management of such entity, whether
by contract or otherwise, or (ii) ownership of fifty percent (50%) or more
of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions
granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation
or translation of a Source form, including but not limited to compiled object
code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form,
made available under the License, as indicated by a copyright notice that
is included in or attached to the work (an example is provided in the Appendix
below).
"Derivative Works" shall mean any work, whether in Source or Object form,
that is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative
Works shall not include works that remain separable from, or merely link (or
bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative
Works thereof, that is intentionally submitted to Licensor for inclusion in
the Work by the copyright owner or by an individual or Legal Entity authorized
to submit on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication
sent to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor
for the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently incorporated
within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this
License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
Derivative Works of, publicly display, publicly perform, sublicense, and distribute
the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License,
each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section) patent
license to make, have made, use, offer to sell, sell, import, and otherwise
transfer the Work, where such license applies only to those patent claims
licensable by such Contributor that are necessarily infringed by their Contribution(s)
alone or by combination of their Contribution(s) with the Work to which such
Contribution(s) was submitted. If You institute patent litigation against
any entity (including a cross-claim or counterclaim in a lawsuit) alleging
that the Work or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses granted to You
under this License for that Work shall terminate as of the date such litigation
is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or
Derivative Works thereof in any medium, with or without modifications, and
in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy
of this License; and
(b) You must cause any modified files to carry prominent notices stating that
You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source
form of the Work, excluding those notices that do not pertain to any part
of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution,
then any Derivative Works that You distribute must include a readable copy
of the attribution notices contained within such NOTICE file, excluding those
notices that do not pertain to any part of the Derivative Works, in at least
one of the following places: within a NOTICE text file distributed as part
of the Derivative Works; within the Source form or documentation, if provided
along with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works
that You distribute, alongside or as an addendum to the NOTICE text from the
Work, provided that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction,
or distribution of Your modifications, or for any such Derivative Works as
a whole, provided Your use, reproduction, and distribution of the Work otherwise
complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any
Contribution intentionally submitted for inclusion in the Work by You to the
Licensor shall be under the terms and conditions of this License, without
any additional terms or conditions. Notwithstanding the above, nothing herein
shall supersede or modify the terms of any separate license agreement you
may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names,
trademarks, service marks, or product names of the Licensor, except as required
for reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to
in writing, Licensor provides the Work (and each Contributor provides its
Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied, including, without limitation, any warranties
or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR
A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness
of using or redistributing the Work and assume any risks associated with Your
exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether
in tort (including negligence), contract, or otherwise, unless required by
applicable law (such as deliberate and grossly negligent acts) or agreed to
in writing, shall any Contributor be liable to You for damages, including
any direct, indirect, special, incidental, or consequential damages of any
character arising as a result of this License or out of the use or inability
to use the Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all other commercial
damages or losses), even if such Contributor has been advised of the possibility
of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work
or Derivative Works thereof, You may choose to offer, and charge a fee for,
acceptance of support, warranty, indemnity, or other liability obligations
and/or rights consistent with this License. However, in accepting such obligations,
You may act only on Your own behalf and on Your sole responsibility, not on
behalf of any other Contributor, and only if You agree to indemnify, defend,
and hold each Contributor harmless for any liability incurred by, or claims
asserted against, such Contributor by reason of your accepting any such warranty
or additional liability. END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "[]" replaced with your own identifying
information. (Don't include the brackets!) The text should be enclosed in
the appropriate comment syntax for the file format. We also recommend that
a file or class name and description of purpose be included on the same "printed
page" as the copyright notice for easier identification within third-party
archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -3,7 +3,8 @@
Find here a collection of samples for the [SAP Cloud Application Programming Model](https://cap.cloud.sap) organized in a simplistic [monorepo setup](samples.md#all-in-one-monorepo). &rarr; See [**Overview** of contained samples](samples.md)
![](https://github.com/SAP-samples/cloud-cap-samples/workflows/CI/badge.svg)
[![REUSE status](https://api.reuse.software/badge/github.com/SAP-samples/cloud-cap-samples)](https://api.reuse.software/info/github.com/SAP-samples/cloud-cap-samples)
<!--[![REUSE status](https://api.reuse.software/badge/github.com/SAP-samples/cloud-cap-samples)](https://api.reuse.software/info/github.com/SAP-samples/cloud-cap-samples)-->
### Preliminaries
@@ -83,4 +84,4 @@ In case you've a question, find a bug, or otherwise need support, use our [commu
## License
Copyright (c) 2021 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSE.txt) file.
Copyright (c) 2021 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSES/Apache-2.0.txt) file.

View File

@@ -44,11 +44,11 @@
<img v-bind:src="book.image" alt=""/>
<label style="text-align:right">
<span class="succeeded"> {{ order.succeeded }} </span>
<span class="failed"> {{ order.failed }} </span>
&nbsp;&nbsp; {{ book.stock }} in stock
<span class="failed"> {{ order.failed }} </span> &nbsp;&nbsp;
<span id="stock"> {{ book.stock }} in stock </span>
</label>
<form @submit.prevent="submitOrder" style="float:right; display:flex; flex-direction:row-reverse">
<input type="number" v-model="order.amount" v-bind:class="{ failed: order.failed }" style="width:5em">
<input id="amount" type="number" v-model="order.amount" v-bind:class="{ failed: order.failed }" style="width:5em">
<input type="submit" value="Order:" class="muted-button">
</form>
<h4> {{ book.title }} </h4>

View File

@@ -1,5 +1,5 @@
ID;name
101;Emily Brontë
107;Charlotte Brontë
150;Edgar Allen Poe
170;Richard Carpenter
ID;name;dateOfBirth;placeOfBirth;dateOfDeath;placeOfDeath
101;Emily Brontë;1818-07-30;Thornton, Yorkshire;1848-12-19;Haworth, Yorkshire
107;Charlotte Brontë;1818-04-21;Thornton, Yorkshire;1855-03-31;Haworth, Yorkshire
150;Edgar Allen Poe;1809-01-19;Boston, Massachusetts;1849-10-07;Baltimore, Maryland
170;Richard Carpenter;1929-08-14;Kings Lynn, Norfolk;2012-02-26;Hertfordshire, England
1 ID name dateOfBirth placeOfBirth dateOfDeath placeOfDeath
2 101 Emily Brontë 1818-07-30 Thornton, Yorkshire 1848-12-19 Haworth, Yorkshire
3 107 Charlotte Brontë 1818-04-21 Thornton, Yorkshire 1855-03-31 Haworth, Yorkshire
4 150 Edgar Allen Poe 1809-01-19 Boston, Massachusetts 1849-10-07 Baltimore, Maryland
5 170 Richard Carpenter 1929-08-14 King’s Lynn, Norfolk 2012-02-26 Hertfordshire, England

View File

@@ -1,6 +1,6 @@
ID;title;author_ID;genre_ID
201;Wuthering Heights;101;11
207;Jane Eyre;107;11
251;The Raven;150;16
252;Eleonora;150;16
271;Catweazle;170;13
ID;title;descr;author_ID;stock;price;currency_code;genre_ID
201;Wuthering Heights;"Wuthering Heights, Emily Brontë's only novel, was published in 1847 under the pseudonym ""Ellis Bell"". It was written between October 1845 and June 1846. Wuthering Heights and Anne Brontë's Agnes Grey were accepted by publisher Thomas Newby before the success of their sister Charlotte's novel Jane Eyre. After Emily's death, Charlotte edited the manuscript of Wuthering Heights and arranged for the edited version to be published as a posthumous second edition in 1850.";101;12;11.11;GBP;11
207;Jane Eyre;"Jane Eyre /ɛər/ (originally published as Jane Eyre: An Autobiography) is a novel by English writer Charlotte Brontë, published under the pen name ""Currer Bell"", on 16 October 1847, by Smith, Elder & Co. of London. The first American edition was published the following year by Harper & Brothers of New York. Primarily a bildungsroman, Jane Eyre follows the experiences of its eponymous heroine, including her growth to adulthood and her love for Mr. Rochester, the brooding master of Thornfield Hall. The novel revolutionised prose fiction in that the focus on Jane's moral and spiritual development is told through an intimate, first-person narrative, where actions and events are coloured by a psychological intensity. The book contains elements of social criticism, with a strong sense of Christian morality at its core and is considered by many to be ahead of its time because of Jane's individualistic character and how the novel approaches the topics of class, sexuality, religion and feminism.";107;11;12.34;GBP;11
251;The Raven;"""The Raven"" is a narrative poem by American writer Edgar Allan Poe. First published in January 1845, the poem is often noted for its musicality, stylized language, and supernatural atmosphere. It tells of a talking raven's mysterious visit to a distraught lover, tracing the man's slow fall into madness. The lover, often identified as being a student, is lamenting the loss of his love, Lenore. Sitting on a bust of Pallas, the raven seems to further distress the protagonist with its constant repetition of the word ""Nevermore"". The poem makes use of folk, mythological, religious, and classical references.";150;333;13.13;USD;16
252;Eleonora;"""Eleonora"" is a short story by Edgar Allan Poe, first published in 1842 in Philadelphia in the literary annual The Gift. It is often regarded as somewhat autobiographical and has a relatively ""happy"" ending.";150;555;14;USD;16
271;Catweazle;Catweazle is a British fantasy television series, starring Geoffrey Bayldon in the title role, and created by Richard Carpenter for London Weekend Television. The first series, produced and directed by Quentin Lawrence, was screened in the UK on ITV in 1970. The second series, directed by David Reid and David Lane, was shown in 1971. Each series had thirteen episodes, most but not all written by Carpenter, who also published two books based on the scripts.;170;22;15;EUR;13
1 ID title descr author_ID stock price currency_code genre_ID
2 201 Wuthering Heights Wuthering Heights, Emily Brontë's only novel, was published in 1847 under the pseudonym "Ellis Bell". It was written between October 1845 and June 1846. Wuthering Heights and Anne Brontë's Agnes Grey were accepted by publisher Thomas Newby before the success of their sister Charlotte's novel Jane Eyre. After Emily's death, Charlotte edited the manuscript of Wuthering Heights and arranged for the edited version to be published as a posthumous second edition in 1850. 101 12 11.11 GBP 11
3 207 Jane Eyre Jane Eyre /ɛər/ (originally published as Jane Eyre: An Autobiography) is a novel by English writer Charlotte Brontë, published under the pen name "Currer Bell", on 16 October 1847, by Smith, Elder & Co. of London. The first American edition was published the following year by Harper & Brothers of New York. Primarily a bildungsroman, Jane Eyre follows the experiences of its eponymous heroine, including her growth to adulthood and her love for Mr. Rochester, the brooding master of Thornfield Hall. The novel revolutionised prose fiction in that the focus on Jane's moral and spiritual development is told through an intimate, first-person narrative, where actions and events are coloured by a psychological intensity. The book contains elements of social criticism, with a strong sense of Christian morality at its core and is considered by many to be ahead of its time because of Jane's individualistic character and how the novel approaches the topics of class, sexuality, religion and feminism. 107 11 12.34 GBP 11
4 251 The Raven "The Raven" is a narrative poem by American writer Edgar Allan Poe. First published in January 1845, the poem is often noted for its musicality, stylized language, and supernatural atmosphere. It tells of a talking raven's mysterious visit to a distraught lover, tracing the man's slow fall into madness. The lover, often identified as being a student, is lamenting the loss of his love, Lenore. Sitting on a bust of Pallas, the raven seems to further distress the protagonist with its constant repetition of the word "Nevermore". The poem makes use of folk, mythological, religious, and classical references. 150 333 13.13 USD 16
5 252 Eleonora "Eleonora" is a short story by Edgar Allan Poe, first published in 1842 in Philadelphia in the literary annual The Gift. It is often regarded as somewhat autobiographical and has a relatively "happy" ending. 150 555 14 USD 16
6 271 Catweazle Catweazle is a British fantasy television series, starring Geoffrey Bayldon in the title role, and created by Richard Carpenter for London Weekend Television. The first series, produced and directed by Quentin Lawrence, was screened in the UK on ITV in 1970. The second series, directed by David Reid and David Lane, was shown in 1971. Each series had thirteen episodes, most but not all written by Carpenter, who also published two books based on the scripts. 170 22 15 EUR 13

View File

@@ -1,5 +1,5 @@
ID;locale;title
201;de;Sturmhöhe
201;fr;Les Hauts de Hurlevent
207;de;Jane Eyre
252;de;Eleonora
ID;locale;title;descr
201;de;Sturmhöhe;Sturmhöhe (Originaltitel: Wuthering Heights) ist der einzige Roman der englischen Schriftstellerin Emily Brontë (18181848). Der 1847 unter dem Pseudonym Ellis Bell veröffentlichte Roman wurde vom viktorianischen Publikum weitgehend abgelehnt, heute gilt er als ein Klassiker der britischen Romanliteratur des 19. Jahrhunderts.
201;fr;Les Hauts de Hurlevent;Les Hauts de Hurlevent (titre original : Wuthering Heights), parfois orthographié Les Hauts de Hurle-Vent, est l'unique roman d'Emily Brontë, publié pour la première fois en 1847 sous le pseudonyme dEllis Bell. Loin d'être un récit moralisateur, Emily Brontë achève néanmoins le roman dans une atmosphère sereine, suggérant le triomphe de la paix et du Bien sur la vengeance et le Mal.
207;de;Jane Eyre;Jane Eyre. Eine Autobiographie (Originaltitel: Jane Eyre. An Autobiography), erstmals erschienen im Jahr 1847 unter dem Pseudonym Currer Bell, ist der erste veröffentlichte Roman der britischen Autorin Charlotte Brontë und ein Klassiker der viktorianischen Romanliteratur des 19. Jahrhunderts. Der Roman erzählt in Form einer Ich-Erzählung die Lebensgeschichte von Jane Eyre (ausgesprochen /ˌdʒeɪn ˈɛə/), die nach einer schweren Kindheit eine Stelle als Gouvernante annimmt und sich in ihren Arbeitgeber verliebt, jedoch immer wieder um ihre Freiheit und Selbstbestimmung kämpfen muss. Als klein, dünn, blass, stets schlicht dunkel gekleidet und mit strengem Mittelscheitel beschrieben, gilt die Heldin des Romans Jane Eyre nicht zuletzt aufgrund der Kino- und Fernsehversionen der melodramatischen Romanvorlage als die bekannteste englische Gouvernante der Literaturgeschichte
252;de;Eleonora;“Eleonora” ist eine Erzählung von Edgar Allan Poe. Sie wurde 1841 erstveröffentlicht. In ihr geht es um das Paradox der Treue in der Treulosigkeit.
1 ID locale title descr
2 201 de Sturmhöhe Sturmhöhe (Originaltitel: Wuthering Heights) ist der einzige Roman der englischen Schriftstellerin Emily Brontë (1818–1848). Der 1847 unter dem Pseudonym Ellis Bell veröffentlichte Roman wurde vom viktorianischen Publikum weitgehend abgelehnt, heute gilt er als ein Klassiker der britischen Romanliteratur des 19. Jahrhunderts.
3 201 fr Les Hauts de Hurlevent Les Hauts de Hurlevent (titre original : Wuthering Heights), parfois orthographié Les Hauts de Hurle-Vent, est l'unique roman d'Emily Brontë, publié pour la première fois en 1847 sous le pseudonyme d’Ellis Bell. Loin d'être un récit moralisateur, Emily Brontë achève néanmoins le roman dans une atmosphère sereine, suggérant le triomphe de la paix et du Bien sur la vengeance et le Mal.
4 207 de Jane Eyre Jane Eyre. Eine Autobiographie (Originaltitel: Jane Eyre. An Autobiography), erstmals erschienen im Jahr 1847 unter dem Pseudonym Currer Bell, ist der erste veröffentlichte Roman der britischen Autorin Charlotte Brontë und ein Klassiker der viktorianischen Romanliteratur des 19. Jahrhunderts. Der Roman erzählt in Form einer Ich-Erzählung die Lebensgeschichte von Jane Eyre (ausgesprochen /ˌdʒeɪn ˈɛə/), die nach einer schweren Kindheit eine Stelle als Gouvernante annimmt und sich in ihren Arbeitgeber verliebt, jedoch immer wieder um ihre Freiheit und Selbstbestimmung kämpfen muss. Als klein, dünn, blass, stets schlicht dunkel gekleidet und mit strengem Mittelscheitel beschrieben, gilt die Heldin des Romans Jane Eyre nicht zuletzt aufgrund der Kino- und Fernsehversionen der melodramatischen Romanvorlage als die bekannteste englische Gouvernante der Literaturgeschichte
5 252 de Eleonora “Eleonora” ist eine Erzählung von Edgar Allan Poe. Sie wurde 1841 erstveröffentlicht. In ihr geht es um das Paradox der Treue in der Treulosigkeit.

View File

@@ -14,8 +14,3 @@ ID;parent_ID;name
22;21;Autobiography
23;20;Essay
24;20;Speech
30;;Others
31;30;Other-A
32;30;Other-A
33;30;Other-A
34;30;Other-A
1 ID parent_ID name
14 22 21 Autobiography
15 23 20 Essay
16 24 20 Speech
30 Others
31 30 Other-A
32 30 Other-A
33 30 Other-A
34 30 Other-A

View File

@@ -1,19 +1,29 @@
using { Currency, managed, sap } from '@sap/cds/common';
namespace sap.capire.bookshop;
entity Books {
entity Books : managed {
key ID : Integer;
title : localized String(111);
descr : localized String(1111);
author : Association to Authors;
genre : Association to Genres;
stock : Integer;
price : Decimal;
currency : Currency;
image : LargeBinary @Core.MediaType : 'image/png';
}
entity Authors {
entity Authors : managed {
key ID : Integer;
name : String(111);
dateOfBirth : Date;
dateOfDeath : Date;
placeOfBirth : String;
placeOfDeath : String;
books : Association to many Books on books.author = $self;
}
/** Hierarchically organized Code List for Genres */
entity Genres : sap.common.CodeList {
key ID : Integer;
parent : Association to Genres;

View File

@@ -1,3 +1,4 @@
namespace sap.capire.bookshop; //> important for reflection
using from './db/schema';
using from './srv/cat-service';
using from './srv/admin-service';

1
bookshop/index.js Normal file
View File

@@ -0,0 +1 @@
exports.CatalogService = require('./srv/cat-service')

View File

@@ -3,42 +3,20 @@
"version": "1.0.0",
"description": "A simple self-contained bookshop service.",
"dependencies": {
"@sap/cds": "^5.0.4",
"@capire/common": "*",
"@sap/cds": "^4",
"express": "^4.17.1",
"passport": "0.4.1",
"@sap/hana-client": "^2.7.21"
"passport": "0.4.1"
},
"scripts": {
"genres": "cds serve test/genres.cds",
"start": "cds run",
"watch": "cds watch"
},
"cds": {
"requires": {
"db": {
"kind": "sql",
"xxx-model": "*",
"xxx-credentials": {
"database": "localSqlite.db"
}
},
"[production]": {
"db": {
"kind": "hana",
"model": [
"db",
"srv"
]
}
}
},
"features": {
"assert_integrity": false
},
"hana": {
"deploy-format": "hdbtable"
},
"cdsc": {
"beta": {
"foreignKeyConstraints": true
"kind": "sql"
}
}
}

View File

@@ -1,126 +1,31 @@
# Foreign key constraints on DB
# Bookshop Getting Started Sample
As model we use a simplified version of the bookshop scenario, we work with nodejs runtime.
This stand-alone sample introduces the essential tasks in the development of CAP-based services as also covered in the [Getting Started guide in capire](https://cap.cloud.sap/docs/get-started/in-a-nutshell).
## Hypothetical Use Cases
## Preparation
1. Build a service that allows to browse _Books_ and _Authors_.
2. Books have assigned _Genres_, which are organized hierarchically.
3. All users may browse books without login.
4. All entries are maintained by Administrators.
5. End users may order books (the actual order mgmt being out of scope).
As we want to see the effects of the database constaints, we first need to switch off the integrity checks done by the node runtime. In the `package.json`:
```json
"cds": {
...,
"features": {
"assert_integrity": false
}
}
## Running the Sample
```sh
npm run watch
```
Then switch on constraint generation. In the `package.json`:
```json
"cds": {
...,
"cdsc": {
"beta": {
"foreignKeyConstraints": true
}
}
}
```
## Content & Best Practices
## SQLite
In SQLite, FK constraints can only be specified during the creation of a table. They cannot be altered for an existing table. So here we at least don't have issues with existing data.
For SQLite, constraint checks need to be enabled by application at runtime for each db connection with the command
```sql
PRAGMA foreign_keys = ON;
```
We do this via a custom handler in `admin-service.js`.
Now run the requests in `requests.http` (use `http://localhost:4004` as server URL). They behave as expected.
But the error messages are not providing any details. They say "constraint violation", but they don't say which table/constraint is violated:
```
HTTP/1.1 500 Internal Server Error
...
{
"error": {
"code": "SQLITE_CONSTRAINT",
"message": "SQLITE_CONSTRAINT: FOREIGN KEY constraint failed in: \nCOMMIT"
}
}
```
The runtime constraint checks do provide the name of the restricting association (but not the name of the entity where the association lives).
## HANA
Preparation:
* logon to cf account (e.g. trial)
* create HANA service instance: `cf create-service hanatrial hdi-shared bookshop-db`
First make the deplyoment without constraints (switch off constraint generation in `package.json`).
* Run `cds build --production`. No constraints are generated.
* Deploy db model: `cf push -f gen/db`
* Deploy nodejs app: `cf push -f gen/srv --random-route`. Take note of the app URL.
Run the requests in `request.http` (use the URL from the previous step as server URL, prepend with `https://`).
Make sure to introduce some data that violates the constraints. No errors are reported - as expected.
Now switch on constraint generation in `package.json`.
* Run `cds build --production`. The constraints are placed in separate `hdbconstraint` files in `gen\db\src\gen`. They are generated with `VALIDATED ON`.
* Re-deploy db model: `cf push -f gen/db`. It fails, as the existing data violates the constraints.
* Check logs: `cf logs bookshop-db-deployer --recent`.
```
Error: com.sap.hana.di.constraint: Could not create the database object [8250005]
at "src/gen/sap.capire.bookshop.Books_author.hdbconstraint" (1:1)
Error: com.sap.hana.di.constraint: Database error 7: : feature not supported: referential constraint violated by existing value [8201003]
at "src/gen/sap.capire.bookshop.Books_author.hdbconstraint" (1:1)
```
You can see which constraint is violated, but there is no info about the offensive entries.
Now use the requests from `request.http` to fix the entries that have been broken above.
* Re-deploy db model: `cf push -f gen/db`. It should succeed.
Again run the requests from `request.http`. This time all changes that would lead to a
constraint violation fail.
Inserting a book with non-existing author ID or changing a book's author ID to an invalid value yields
the message
```
HTTP/1.1 500 Internal Server Error
...
{
"error": {
"code": "500",
"message": "Internal Server Error"
}
}
```
When trying to delete a genre that is still referenced in a book we get
```
HTTP/1.1 462 status code 462
...
{
"error": {
"code": "462",
"message": "failed on update or delete by foreign key constraint violation: TrexColumnUpdate failed on table '21F87859727E470E94917B690908A09D:SAP_CAPIRE_BOOKSHOP_GENRES' with error: DELETE on 21F87859727E470E94917B690908A09D:SAP_CAPIRE_BOOKSHOP_GENRES(ID) failed, because 1 rows with corresponding foreign keys still exist in 21F87859727E470E94917B690908A09D:SAP_CAPIRE_BOOKSHOP_BOOKS(GENRE_ID), rc=1536"
}
}
```
Note: when using `cdsc` to generate the constraints
```
cdsc Q --beta foreignKeyConstraints -d hana -s hdi -o dbstuff db\schema.cds srv\admin-service.cds
```
there will be constraints for e.g. `sap_common_Currencies_texts`. This cannot be deplyoed, as the corresponding table is removed from `cds` via the tree-shaking mechanism. These constraints need to be removed manually before deployment.
## Todo
* Provide a way to control parameters `VALIDATED` and `ENFORCED` of the constraints (only interesting for HANA, as in SQLite changing constraints after table generation is not possible).
* Provide some tool to identify existing entries that violate constraints. We can generate a list of `SELECT` statements that find these entries, but how do we run it and show the results to the user?
* Can runtimes improve the error messages?
| Links to capire | Sample files / folders |
| --------------------------------------------------------------------------------------------------------- | ------------------------------------ |
| [Project Setup & Layouts](https://cap.cloud.sap/docs/get-started/projects#sharing-and-reusing-content) | [`./`](./) |
| [Domain Modeling with CDS](https://cap.cloud.sap/docs/guides/domain-models) | [`./db/schema.cds`](./db/schema.cds) |
| [Defining Services](https://cap.cloud.sap/docs/guides/services#defining-services) | [`./srv/*.cds`](./srv) |
| [Single-purposed Services](https://cap.cloud.sap/docs/guides/services#single-purposed-services) | [`./srv/*.cds`](./srv) |
| [Providing & Consuming Providers](https://cap.cloud.sap/docs/guides/providing-services) | http://localhost:4004 |
| [Using Databases](https://cap.cloud.sap/docs/guides/databases) | [`./db/data/*.csv`](./db/data) |
| [Adding Custom Logic](https://cap.cloud.sap/docs/guides/service-impl) | [`./srv/*.js`](./srv) |
| Adding Tests | [`./test`](./test) |
| [Sharing for Reuse](https://cap.cloud.sap/docs/guides/reuse-and-compose) | [`./index.cds`](./index.cds) |

View File

@@ -1,6 +1,5 @@
using { sap.capire.bookshop as my } from '../db/schema';
service AdminService {
service AdminService @(requires:'admin') {
entity Books as projection on my.Books;
entity Authors as projection on my.Authors;
entity Genres as projection on my.Genres;
}

View File

@@ -1,15 +1,12 @@
// sqlite: FK constraint checks need to be enabled by application at runtime
// for each db connection
const cds = require('@sap/cds')
module.exports = cds.service.impl (async function(){
const db = await cds.connect.to('db')
if (db.kind === 'sqlite')
{
db.before('BEGIN', function (req) {
//console.log('--- PRAGMA foreign_keys = ON ---')
return this.dbc.run('PRAGMA foreign_keys = ON;')
})
}
module.exports = cds.service.impl (function(){
this.before ('NEW','Authors', genid)
this.before ('NEW','Books', genid)
})
/** Generate primary keys for target entity in request */
async function genid (req) {
const {ID} = await cds.tx(req).run (SELECT.one.from(req.target).columns('max(ID) as ID'))
req.data.ID = ID - ID % 100 + 100 + 1
}

View File

@@ -0,0 +1,14 @@
using { sap.capire.bookshop as my } from '../db/schema';
service CatalogService @(path:'/browse') {
@readonly entity Books as SELECT from my.Books { *,
author.name as author
} excluding { createdBy, modifiedBy };
@readonly entity ListOfBooks as SELECT from Books
excluding { descr };
@requires: 'authenticated-user'
action submitOrder ( book: Books:ID, amount: Integer ) returns { stock: Integer };
event OrderedBook : { book: Books:ID; amount: Integer; buyer: String };
}

View File

@@ -0,0 +1,28 @@
const cds = require('@sap/cds')
const { Books } = cds.entities ('sap.capire.bookshop')
class CatalogService extends cds.ApplicationService { init(){
// Reduce stock of ordered books if available stock suffices
this.on ('submitOrder', async req => {
const {book,amount} = req.data, tx = cds.tx(req)
let {stock} = await tx.read('stock').from(Books,book)
if (stock >= amount) {
await tx.update (Books,book).with ({ stock: stock -= amount })
await this.emit ('OrderedBook', { book, amount, buyer:req.user.id })
return { stock }
}
else return req.error (409,`${amount} exceeds stock for book #${book}`)
})
// Add some discount for overstocked books
this.after ('READ','Books', each => {
if (each.stock > 111) {
each.title += ` -- 11% discount!`
}
})
return super.init()
}}
module.exports = { CatalogService }

4
bookshop/test/genres.cds Normal file
View File

@@ -0,0 +1,4 @@
using { sap.capire.bookshop as my } from '../db/schema';
service TestService {
entity Genres as projection on my.Genres;
}

38
bookshop/test/genres.http Normal file
View File

@@ -0,0 +1,38 @@
#################################################
#
# Genres
#
GET http://localhost:4004/test/Genres?
###
GET http://localhost:4004/test/Genres?
&$filter=parent_ID eq null&$select=name
&$expand=children($select=name)
###
POST http://localhost:4004/test/Genres?
Content-Type: application/json
{ "ID":100, "name":"Some Sample Genres...", "children":[
{ "ID":101, "name":"Cat", "children":[
{ "ID":102, "name":"Kitty", "children":[
{ "ID":103, "name":"Kitty Cat", "children":[
{ "ID":104, "name":"Aristocat" } ]},
{ "ID":105, "name":"Kitty Bat" } ]},
{ "ID":106, "name":"Catwoman", "children":[
{ "ID":107, "name":"Catalina" } ]} ]},
{ "ID":108, "name":"Catweazle" }
]}
###
GET http://localhost:4004/test/Genres(100)?
# &$expand=children
# &$expand=children($expand=children($expand=children($expand=children)))
###
DELETE http://localhost:4004/test/Genres(103)
###
DELETE http://localhost:4004/test/Genres(100)
###

View File

@@ -1,68 +1,82 @@
# running locally
@server = http://localhost:4004
# running on cf
#@server = https://bookshop-srv-....hana.ondemand.com
### get all books
GET {{server}}/admin/Books
### get all authors
GET {{server}}/admin/Authors
### get all genres
GET {{server}}/admin/Genres
@me = Authorization: Basic {{$processEnv USER}}:
### create book with wrong author ID -> should fail
POST {{server}}/admin/Books
Content-Type: application/json
### ------------------------------------------------------------------------
# Get service info
GET {{server}}/browse
{{me}}
{
"ID": 701,
"title": "XXX",
"author": { "ID": 9999 }
}
### create book with correct author ID -> should work
### ------------------------------------------------------------------------
# Get $metadata document
GET {{server}}/browse/$metadata
{{me}}
### ------------------------------------------------------------------------
# Browse Books as any user
GET {{server}}/browse/Books?
# &$select=title,stock
# &$expand=currency
# &sap-language=de
{{me}}
### ------------------------------------------------------------------------
# Fetch Authors as admin
GET {{server}}/admin/Authors?
# &$select=name,dateOfBirth,placeOfBirth
# &$expand=books($select=title;$expand=currency)
# &$filter=ID eq 101
# &sap-language=de
Authorization: Basic alice:
### ------------------------------------------------------------------------
# Create book
POST {{server}}/admin/Books
Content-Type: application/json;IEEE754Compatible=true
Authorization: Basic alice:
{
"ID": 702,
"ID": 2,
"title": "Poems : Pocket Poets",
"author": { "ID": 101 }
"descr": "The Everyman's Library Pocket Poets hardcover series is popular for its compact size and reasonable price which does not compromise content. Poems: Bronte contains poems that demonstrate a sensibility elemental in its force with an imaginative discipline and flexibility of the highest order. Also included are an Editor's Note and an index of first lines.",
"author": { "ID": 101 },
"genre": { "ID": 12 },
"stock": 5,
"price": "12.05",
"currency": { "code": "USD" }
}
### delete book
DELETE {{server}}/admin/Books(ID=701)
### change book to wrong author ID -> should fail
### ------------------------------------------------------------------------
# Put image to books
PUT {{server}}/admin/Books(2)/image
Content-Type: image/png
Authorization: Basic alice:
PATCH {{server}}/admin/Books(ID=207)
Content-Type:application/json
{"author_ID": 9999}
### change book to correct author ID -> should work
PATCH {{server}}/admin/Books(ID=207)
Content-Type:application/json
{"author_ID": 170}
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAADcCAYAAAAbWs+BAAAGwElEQVR4Ae3cwZFbNxBFUY5rkrDTmKAUk5QT03Aa44U22KC7NHptw+DRikVAXf8fzC3u8Hj4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgZzAW26USQT+e4HPx+Mz+RRvj0e0kT+SD2cWAQK1gOBqH6sEogKCi3IaRqAWEFztY5VAVEBwUU7DCNQCgqt9rBKICgguymkYgVpAcLWPVQJRAcFFOQ0jUAsIrvaxSiAqILgop2EEagHB1T5WCUQFBBflNIxALSC42scqgaiA4KKchhGoBQRX+1glEBUQXJTTMAK1gOBqH6sEogKCi3IaRqAWeK+Xb1z9iN558fHxcSPS9p2ezx/ROz4e4TtIHt+3j/61hW9f+2+7/+UXbifjewIDAoIbQDWSwE5AcDsZ3xMYEBDcAKqRBHYCgtvJ+J7AgIDgBlCNJLATENxOxvcEBgQEN4BqJIGdgOB2Mr4nMCAguAFUIwnsBAS3k/E9gQEBwQ2gGklgJyC4nYzvCQwICG4A1UgCOwHB7WR8T2BAQHADqEYS2AkIbifjewIDAoIbQDWSwE5AcDsZ3xMYEEjfTzHwiK91B8npd6Q8n8/oGQ/ckRJ9vvQwv3BpUfMIFAKCK3AsEUgLCC4tah6BQkBwBY4lAmkBwaVFzSNQCAiuwLFEIC0guLSoeQQKAcEVOJYIpAUElxY1j0AhILgCxxKBtIDg0qLmESgEBFfgWCKQFhBcWtQ8AoWA4AocSwTSAoJLi5pHoBAQXIFjiUBaQHBpUfMIFAKCK3AsEUgLCC4tah6BQmDgTpPsHSTFs39p6fQ7Q770UsV/Ov19X+2OFL9wxR+rJQJpAcGlRc0jUAgIrsCxRCAtILi0qHkECgHBFTiWCKQFBJcWNY9AISC4AscSgbSA4NKi5hEoBARX4FgikBYQXFrUPAKFgOAKHEsE0gKCS4uaR6AQEFyBY4lAWkBwaVHzCBQCgitwLBFICwguLWoegUJAcAWOJQJpAcGlRc0jUAgIrsCxRCAt8J4eePq89B0ar3ZnyOnve/rfn1+400/I810lILirjtPLnC4guNNPyPNdJSC4q47Ty5wuILjTT8jzXSUguKuO08ucLiC400/I810lILirjtPLnC4guNNPyPNdJSC4q47Ty5wuILjTT8jzXSUguKuO08ucLiC400/I810lILirjtPLnC4guNNPyPNdJSC4q47Ty5wuILjTT8jzXSUguKuO08ucLiC400/I810l8JZ/m78+szP/zI47fJo7Q37vgJ7PHwN/07/3TOv/9gu3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhg4P6H9J0maYHXuiMlrXf+vOfA33Turf3C5SxNItAKCK4lsoFATkBwOUuTCLQCgmuJbCCQExBcztIkAq2A4FoiGwjkBASXszSJQCsguJbIBgI5AcHlLE0i0AoIriWygUBOQHA5S5MItAKCa4lsIJATEFzO0iQCrYDgWiIbCOQEBJezNIlAKyC4lsgGAjkBweUsTSLQCgiuJbKBQE5AcDlLkwi0Akff//Dz6U+/I6U1/sUNr3bnytl3kPzi4bXb/cK1RDYQyAkILmdpEoFWQHAtkQ0EcgKCy1maRKAVEFxLZAOBnIDgcpYmEWgFBNcS2UAgJyC4nKVJBFoBwbVENhDICQguZ2kSgVZAcC2RDQRyAoLLWZpEoBUQXEtkA4GcgOByliYRaAUE1xLZQCAnILicpUkEWgHBtUQ2EMgJCC5naRKBVkBwLZENBHIC/4M7TXIv+3PS22d24qvdQfL3C/7N5P5i/MLlLE0i0AoIriWygUBOQHA5S5MItAKCa4lsIJATEFzO0iQCrYDgWiIbCOQEBJezNIlAKyC4lsgGAjkBweUsTSLQCgiuJbKBQE5AcDlLkwi0AoJriWwgkBMQXM7SJAKtgOBaIhsI5AQEl7M0iUArILiWyAYCOQHB5SxNItAKCK4lsoFATkBwOUuTCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAvyrwDySEJ2VQgUSoAAAAAElFTkSuQmCC
### delete "leaf" genre that is used in a book -> should not work
DELETE {{server}}/admin/Genres(ID=13)
### delete "leaf" genre that is not used in a book -> should work
DELETE {{server}}/admin/Genres(ID=14)
### ------------------------------------------------------------------------
# Reading image from from the server directly
GET {{server}}/browse/Books(2)/image
### delete "header" genre where leaves are used in a book -> should not work
DELETE {{server}}/admin/Genres(ID=10)
### ------------------------------------------------------------------------
# Submit Order as authenticated user
# (send that three times to get out-of-stock message)
POST {{server}}/browse/submitOrder
Content-Type: application/json
{{me}}
{ "book":201, "amount":5 }
### delete "header" genre where leaves are not used in a book -> should work and delete all leaves
DELETE {{server}}/admin/Genres(ID=30)
### ------------------------------------------------------------------------
# Browse Genres
GET {{server}}/browse/Genres?
# &$filter=parent_ID eq null&$select=name
# &$expand=children($select=name)
{{me}}

View File

@@ -1,4 +1,4 @@
using { AdminService } from '../../db/schema';
using { AdminService } from '../../db';
////////////////////////////////////////////////////////////////////////////
//

View File

@@ -2,7 +2,7 @@
// Add Author.age and .lifetime with a DB-specific function
//
using { AdminService } from '../schema';
using { AdminService } from '..';
extend projection AdminService.Authors with {
YEARS_BETWEEN(dateOfBirth, dateOfDeath) as age: Integer,

View File

@@ -2,7 +2,7 @@
// Add Author.age and .lifetime with a DB-specific function
//
using { AdminService } from '../schema';
using { AdminService } from '..';
extend projection AdminService.Authors with {
strftime('%Y',dateOfDeath)-strftime('%Y',dateOfBirth) as age: Integer,

View File

@@ -6,7 +6,7 @@
"@capire/reviews": "*",
"@capire/orders": "*",
"@capire/common": "*",
"@sap/cds": ">=4",
"@sap/cds": "^4",
"express": "^4.17.1",
"passport": "^0.4.1"
},

View File

@@ -13,7 +13,7 @@ entity Orders_Items {
up_ : Association to Orders;
product : Association to Products @assert.integrity:false; // REVISIT: this is a temporary workaround for a glitch in cds-runtime
amount : Integer;
title : String; //> intentionally replicated as snapshot from product.title
title : String;
price : Double;
}

View File

@@ -2,6 +2,6 @@
"name": "@capire/orders",
"version": "1.0.0",
"dependencies": {
"@sap/cds": ">=4.3.0"
"@sap/cds": "^4.3.0"
}
}

View File

@@ -17,10 +17,11 @@
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"chai-subset": "^1.6.0",
"sqlite3": "^5.0.0"
"@cucumber/cucumber": "^7.0.0",
"selenium-webdriver": "^4.0.0-beta.1",
"sqlite3": "5.0.0"
},
"scripts": {
"cleanup": "rm -rf node_modules && rm -rf */node_modules && rm -rf */*/node_modules",
"registry": "node .registry/server.js",
"bookshop": "cds watch bookshop",
"fiori": "cds watch fiori",

View File

@@ -7,7 +7,7 @@
"index.cds"
],
"dependencies": {
"@sap/cds": ">=4",
"@sap/cds": "^4",
"express": "^4.17.1"
},
"scripts": {

View File

@@ -2,10 +2,10 @@
## Run all-in-one
Open a terminal window and run the `fiori` app in it:
Open a terminal window and run the bookshop in it:
```sh
npm run fiori
npm run bookshop
```
@@ -17,8 +17,8 @@ Open two terminal windows. In the first one start the reviews service stand-alon
npm run reviews-service
```
In the second one start the `fiori` app:
In the second one start the bookshop:
```sh
npm run fiori
npm run bookshop
```

View File

@@ -17,7 +17,7 @@ service ReviewsService {
annotate Reviews with {
subject @mandatory;
title @mandatory;
rating @assert.range;
rating @assert.enum;
}
}

View File

@@ -0,0 +1,34 @@
Feature: List Books using Vue.js UI
Scenario: Launch cds server for bookshop
When we run the 'bookshop' server
And wait for 1s
Then it should listen at 'http://localhost:4004'
Scenario: Display Books List
When we open page '/vue/index.html'
And wait for 1s
Then it should list these rows in table 'books':
| Wuthering Heights | Emily Brontë |
| Jane Eyre | Charlotte Brontë |
| The Raven | Edgar Allen Poe |
| Eleonora | Edgar Allen Poe |
| Catweazle | Richard Carpenter |
Scenario: Select a Book
When we click on the 1st row in table 'books'
Then it shows '12' in 'stock'
Scenario: Order One Book
When we click on button 'Order:'
Then it succeeds with 'ordered 1 item(s)'
Scenario: Order Four Books
When we enter '4' into 'amount'
And we click on button 'Order:'
Then it succeeds with 'ordered 4 item(s)'
Scenario: Order Amount Exceeding Stock
When we enter '9' into 'amount'
And we click on button 'Order:'
Then it fails with '9 exceeds stock'

View File

@@ -0,0 +1,82 @@
const { Given, When, Then, AfterAll } = require('@cucumber/cucumber')
const { Builder, By } = require('selenium-webdriver')
const browser = (new Builder).forBrowser('safari').build()
const cds = require ('@sap/cds/lib')
process.env.cds_requires_auth_strategy = 'dummy'
let axios = require('axios').default
let {display} = browser
When('we run the {string} server', project => cds.exec('watch', project))
Then('it should listen at {string}', baseURL => {
axios = axios.create({ baseURL })
display = url => browser.get (baseURL+url)
return axios.head()
})
Then('terminate the server', ()=> process.exit())
When(/wait for (\d+)\s*(\w+)/, {timeout:60*1000}, (delay, unit, done) => {
const factor = {
ms: 1,
s: 1000, sec: 1000, second: 1000, seconds: 1000,
m: 60*1000, min: 60*1000, minute: 60*1000, minutes: 60*1000,
h: 60*60*1000, hr: 60*60*1000, hour: 60*60*1000, hours: 60*60*1000,
}[unit]
if (!factor) throw `Unknown duration unit: ${unit}`
setTimeout (done, delay * factor)
})
AfterAll(()=> setTimeout (process.exit, 111))
When('we open page {string}', page => display(page))
Then('it should list these rows in table {string}:', async (id,data) => {
let rows = await browser.findElements(By.css(`#${id} tr`)); rows.shift()
await Promise.all (data.rawTable.map (async (row,i)=>{
const tr = await rows[i].getText()
for (let each of row) if (!tr.match(each)) throw `Didn't find '${each}' in web page as expected`
}))
})
When(/we click on the (\d+)(?:st|nd|rd|th) row in table '(\w+)'/, async (row, id) => {
let rows = await browser.findElements(By.css(`#${id} tr`))
let td = await rows[row].findElement(By.css('td'))
return td.click()
})
When('we enter {string} into {string}', async (value,id) => {
const field = await browser.findElement(By.css(`input#${id}`))
return field.sendKeys('\b\b\b\b\b\b',value)
})
When('we click on button {string}', async (text) => {
const button = await browser.findElement(By.css(`input[value='${text}']`))
return button.click()
})
Then('it succeeds with {string}', async message => {
const element = await browser.wait (browser.findElement(By.css(`span.succeeded`)))
return (await element.getText()).includes(message)
})
Then('it fails with {string}', async message => {
const element = await browser.wait (browser.findElement(By.css(`span.failed`)))
return (await element.getText()).includes(message)
})
Then('it shows {string} in {string}', async (message,id) => {
const element = await browser.wait (browser.findElement(By.id(id)))
return (await element.getText()).includes(message)
})
Given('we login as {string}, {string}', async (username, password) => {
const alert = await browser.switchTo().alert()
return alert.authenticateAs(username, password)
})

View File

@@ -1,10 +1,11 @@
const {expect} = require('../test')
const cds = require('@sap/cds/lib')
// monkey patching older releases:
if (!cds.compile.cdl) cds.compile.cdl = cds.parse
const { parse:cdr } = cds.ql
// should become cds.compile(...) when cds5 is released
const model = cds.compile.to.csn (`
const model = cds.compile.cdl (`
entity Categories {
key ID : Integer;
name : String;

View File

@@ -1,2 +1,6 @@
const cds = require('@sap/cds')
module.exports = cds.test.in(__dirname,'..')
const test = require('@sap/cds/lib/utils/tests').in(__dirname,'..')
module.exports = Object.assign(test,{run:test})
// REVISIT: With upcoming release of @sap/cds this should become:
// module.exports = require('@sap/cds/tests').in(__dirname,'..')

View File

@@ -20,11 +20,11 @@ describe('Messaging', ()=>{
let N=0, received=[], M=0
it ('should add messaging event handlers', ()=>{
srv.on('reviewed', (msg)=> received.push(msg))
srv.on('reviewed', (msg,next)=> { received.push(msg); return next() })
})
it ('should add more messaging event handlers', ()=>{
srv.on('reviewed', ()=> ++M)
srv.on('reviewed', (_,next)=> { ++M; return next() })
})
it ('should add review', async ()=>{