Skip to content

Commit 1cc4b4d

Browse files
authored
GraphQL+JavaScript Demo using MLE in APEX (oracle-samples#280)
* MLE Demo * Add files via upload * Rename readme.md to README.md * Rename * Rename MLE Demo to MLE-Demo * Rename book-schema.mjs to book-schema.mjs * Rename MLE Demo to MLE-Demo * Rename MLE Demo to MLE-Demo * Rename MLE Demo to MLE-Demo * Rename MLE Demo to MLE-Demo * Rename MLE Demo to MLE-Demo * Delete javascript/MLE Demo directory * Add files via upload Add sample inventory data * Update book-schema.mjs * Delete graphql.mjs * add link of the upcoming blog * Add files via upload * Delete inventory.xlsx * add license & copyright header * license & copyright header * add license & copyright header * add license & copyright header * add license & copyright header * add license & copyright header * Add files via upload add cleanup.sql to put the database back into a clean state * Update cleanup.sql * add license and copyright to cleanup.sql
1 parent c1994a1 commit 1cc4b4d

File tree

9 files changed

+434
-0
lines changed

9 files changed

+434
-0
lines changed

javascript/MLE-Demo/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Bookstore App in APEX with JavaScript/MLE and GraphQL
2+
3+
## Introduction
4+
5+
This repository contains the source code and documentation for the blog post titled "Building an end-to-end Bookstore App in APEX using JavaScript/MLE and GraphQL," which will be published soon. The blog post will provide a detailed walkthrough of the steps involved in creating a comprehensive Bookstore App using Oracle Application Express (APEX), JavaScript/MLE, and GraphQL.
6+
For more information, please refer to our [upcoming blog post](link will be available soon) that will provide the full context and detailed instructions.
7+
8+
## Acknowledgements
9+
10+
- Author/Contributors - Lucas Braun, Principal Program Manager, Salma Elbekraoui, MLE team intern
11+
- Last Updated By/Date - Lucas Braun, Principal Program Manager, Salma Elbekraoui, MLE team intern, July 2023

javascript/MLE-Demo/book-schema.mjs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*Copyright 2023 Oracle and/or its affiliates.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
import {
17+
GraphQLSchema,
18+
GraphQLObjectType,
19+
GraphQLString,
20+
GraphQLInt,
21+
GraphQLFloat,
22+
GraphQLList
23+
} from 'graphql';
24+
import 'mle-js-fetch';
25+
import oracledb from 'mle-js-oracledb';
26+
27+
const BASE_URL = "https://www.googleapis.com/books/v1/volumes?q=";
28+
29+
const getBooks = async (SEARCH_URL) => {
30+
const conn = oracledb.defaultConnection();
31+
conn.execute(`
32+
begin
33+
utl_http.set_wallet('file:/<absolute-path-to-your-wallet-directory>');
34+
end;
35+
`);
36+
37+
const response = await fetch(`${BASE_URL}${SEARCH_URL}`, { credentials: "include" });
38+
const result = await response.json();
39+
return result;
40+
}
41+
42+
const imageLinks = new GraphQLObjectType({
43+
name: 'IMAGE_LINKS',
44+
fields: () => ({
45+
thumbnail: {
46+
type: GraphQLString,
47+
},
48+
})
49+
});
50+
51+
const author = new GraphQLObjectType({
52+
name: 'AUTHOR',
53+
fields: () => ({
54+
name: {
55+
type: GraphQLString,
56+
resolve: (author) => author || "Unknown",
57+
},
58+
})
59+
});
60+
61+
const volumeInfo = new GraphQLObjectType({
62+
name: 'VOLUME_INFO',
63+
fields: () => ({
64+
title: {
65+
type: GraphQLString,
66+
},
67+
subtitle: {
68+
type: GraphQLString,
69+
},
70+
publisher: {
71+
type: GraphQLString,
72+
},
73+
description: {
74+
type: GraphQLString,
75+
},
76+
authors: {
77+
type: new GraphQLList(author),
78+
resolve: (volumeInfo) => volumeInfo.authors || [],
79+
},
80+
publishedDate: {
81+
type: GraphQLString,
82+
},
83+
imageLinks: {
84+
type: imageLinks,
85+
},
86+
averageRating: {
87+
type: GraphQLFloat,
88+
},
89+
pageCount: {
90+
type: GraphQLInt,
91+
},
92+
language: {
93+
type: GraphQLString,
94+
}
95+
})
96+
});
97+
98+
const book = new GraphQLObjectType({
99+
name: 'BOOK',
100+
fields: () => ({
101+
id: {
102+
type: GraphQLString,
103+
description: 'The id of the book.',
104+
},
105+
kind: {
106+
type: GraphQLString,
107+
description: 'The kind of the book.',
108+
},
109+
etag: {
110+
type: GraphQLString,
111+
description: 'The etag of the book.',
112+
},
113+
volumeInfo: {
114+
type: volumeInfo,
115+
},
116+
stock: {
117+
type: GraphQLInt,
118+
resolve: (book) => {
119+
const result = session.execute('select stock from inventory where id = :id', [book.id]);
120+
if (result.rows.length > 0) {
121+
return result.rows[0][0];
122+
} else {
123+
return 0;
124+
}
125+
}
126+
},
127+
})
128+
});
129+
130+
const volumes = new GraphQLObjectType({
131+
name: 'VOLUMES',
132+
fields: () => ({
133+
kind: {
134+
type: GraphQLString,
135+
},
136+
totalItems: {
137+
type: GraphQLInt,
138+
},
139+
items: {
140+
type: new GraphQLList(book),
141+
},
142+
}),
143+
});
144+
145+
const queryType = new GraphQLObjectType({
146+
name: 'Query',
147+
fields: () => ({
148+
library: {
149+
args: {
150+
research: {
151+
type: GraphQLString,
152+
},
153+
},
154+
type: volumes,
155+
resolve: async (_source, {research}) => await getBooks(research),
156+
},
157+
}),
158+
});
159+
160+
export const schema = new GraphQLSchema({
161+
query: queryType,
162+
types: [volumes, book, volumeInfo, author, imageLinks]
163+
});

javascript/MLE-Demo/card-region.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*Copyright 2023 Oracle and/or its affiliates.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
select title,
17+
subtitle,
18+
thumbnail as imageLinks
19+
from json_table( query(:P1_SEARCH), '$[*]'
20+
columns(
21+
title varchar2(100) path '$.title',
22+
subtitle varchar2(100) path '$.subtitle',
23+
thumbnail VARCHAR2(4000) path '$.imageLinks.thumbnail'
24+
) );

javascript/MLE-Demo/cleanup.sql

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*Copyright 2023 Oracle and/or its affiliates.
2+
Licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
http://www.apache.org/licenses/LICENSE-2.0
6+
Unless required by applicable law or agreed to in writing, software
7+
distributed under the License is distributed on an "AS IS" BASIS,
8+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
See the License for the specific language governing permissions and
10+
limitations under the License.
11+
*/
12+
13+
DECLARE
14+
l_acl_name VARCHAR2(100);
15+
CURSOR c_network_acls IS
16+
SELECT acl FROM dba_network_acls WHERE host = '*.googleapis.com';
17+
BEGIN
18+
-- Drop the INVENTORY table
19+
BEGIN
20+
EXECUTE IMMEDIATE 'DROP TABLE INVENTORY';
21+
DBMS_OUTPUT.PUT_LINE('Table INVENTORY dropped successfully.');
22+
EXCEPTION
23+
WHEN NO_DATA_FOUND THEN
24+
DBMS_OUTPUT.PUT_LINE('Table INVENTORY does not exist.');
25+
WHEN OTHERS THEN
26+
DBMS_OUTPUT.PUT_LINE('An error occurred: ' || SQLERRM);
27+
END;
28+
29+
-- Find the ACL name for host '*.googleapis.com'
30+
OPEN c_network_acls;
31+
FETCH c_network_acls INTO l_acl_name;
32+
33+
-- Process each row returned by the cursor
34+
WHILE c_network_acls%FOUND LOOP
35+
-- Unassign the ACL
36+
DBMS_NETWORK_ACL_ADMIN.UNASSIGN_ACL(acl => l_acl_name);
37+
FETCH c_network_acls INTO l_acl_name;
38+
END LOOP;
39+
40+
CLOSE c_network_acls;
41+
42+
COMMIT;
43+
END;
44+
/
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*Copyright 2023 Oracle and/or its affiliates.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
drop table if exists inventory;
17+
create table inventory(
18+
id VARCHAR(128) PRIMARY KEY NOT NULL,
19+
stock NUMBER
20+
);

javascript/MLE-Demo/info.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*Copyright 2023 Oracle and/or its affiliates.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
import { graphql } from "graphql";
17+
import { schema } from "schema";
18+
19+
const queryTemplate = `
20+
query BookQuery($searchTerm: String){
21+
library(research:$searchTerm){
22+
<<FIELDS>>
23+
}
24+
}
25+
`;
26+
27+
export const getInfo = async (search, query) => {
28+
const fields = query.split(",").map(field => field.trim()).join("\n");
29+
const finalQuery = queryTemplate.replace("<<FIELDS>>", fields);
30+
const formattedSearch = search.replace(/\s/g, "+");
31+
const result = await graphql({ schema, source: finalQuery, variableValues:{searchTerm: formattedSearch }});
32+
return result.data ? result.data.library.items : [];
33+
};

javascript/MLE-Demo/inventory.csv

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
ID,STOCK
2+
ImZuBgAAQBAJ,72
3+
oxy9zGDxN5kC,55
4+
D_rpBpU316YC,63
5+
zm1qhFRl940C,16
6+
5HVBAgAAQBAJ,19
7+
6f6cc9YlR_wC,95
8+
Vvx9Tof4ZrUC,7
9+
jGcazfSMBZ0C,22
10+
IdafwX80SdoC,41
11+
KhEJBAAAQBAJ,4
12+
wyKpDwAAQBAJ,93
13+
w5LZAwAAQBAJ,16
14+
yqNQAAAAMAAJ,61
15+
jxwPwLsSJqIC,71
16+
N7yxDwAAQBAJ,99
17+
MR-SCgAAQBAJ,85
18+
Vr4ktwAACAAJ,35
19+
oqmW4BwSteoC,32
20+
zGOxoQEACAAJ,94
21+
tpquCcasMDQC,75
22+
vTP4sUJukzgC,30
23+
bYCnywEACAAJ,50
24+
UA343fijDE8C,20
25+
oqK4tzQ0xBoC,42
26+
M_ORBAAAQBAJ,84
27+
ZnOozwEACAAJ,35
28+
zanEwAEACAAJ,45
29+
J4Z2QgAACAAJ,7
30+
2YL0HAAACAAJ,58
31+
9YG4jwEACAAJ,84

javascript/MLE-Demo/service.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*Copyright 2023 Oracle and/or its affiliates.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
import { graphql } from "graphql";
17+
import { schema } from "schema";
18+
19+
const queryTemplate = `
20+
query BookQuery($searchTerm: String) {
21+
library(research: $searchTerm) {
22+
items {
23+
volumeInfo{
24+
title,
25+
subtitle,
26+
description,
27+
imageLinks{
28+
thumbnail,
29+
},
30+
authors{
31+
name,
32+
},
33+
}
34+
}
35+
}
36+
}
37+
`;
38+
39+
async function getInfo(search) {
40+
try {
41+
const result = await graphql({
42+
schema,
43+
source: queryTemplate,
44+
variableValues: {
45+
searchTerm: search
46+
}
47+
});
48+
49+
if (!result || !result.data) {
50+
const errorMessage = result && result.errors ? result.errors[0].message : 'No data found';
51+
throw new Error(errorMessage);
52+
}
53+
54+
const volumeInfos = result.data.library.items.map(item => item.volumeInfo);
55+
return volumeInfos;
56+
} catch (error) {
57+
throw new Error(`Error retrieving information: ${error.message}`);
58+
}
59+
}

0 commit comments

Comments
 (0)