<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>MLE Archives - Philipp Salvisberg&#039;s Blog</title>
	<atom:link href="https://www.salvis.com/blog/tag/mle/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.salvis.com/blog/tag/mle/</link>
	<description>Database-centric development</description>
	<lastBuildDate>Tue, 19 Dec 2023 11:11:47 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.salvis.com/blog/wp-content/uploads/2014/04/favicon.png</url>
	<title>MLE Archives - Philipp Salvisberg&#039;s Blog</title>
	<link>https://www.salvis.com/blog/tag/mle/</link>
	<width>32</width>
	<height>32</height>
</image> 
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/>
<atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/>
<atom:link rel="hub" href="https://websubhub.com/hub"/>
<atom:link rel="self" href="https://www.salvis.com/blog/tag/mle/feed/"/>
	<item>
		<title>Installing MLE Modules in the Oracle Database</title>
		<link>https://www.salvis.com/blog/2023/11/26/installing-mle-modules-in-the-oracle-database/</link>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Sun, 26 Nov 2023 17:56:09 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[MLE]]></category>
		<category><![CDATA[Oracle 26ai]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQLcl]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=12931</guid>

					<description><![CDATA[<p>Introduction In my previous blog post, I&#8217;ve shown how you can deploy an npm module from a URL and a custom ESM module from a local file into a remote Oracle Database 23c using JavaScript and SQLcl. This works well. However, for two MLE modules, I had to write 22 lines of<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2023/11/26/installing-mle-modules-in-the-oracle-database/">Installing MLE Modules in the Oracle Database</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Introduction</h2>



<p>In my <a href="https://www.salvis.com/blog/2023/11/12/mle-typescript-javascript-modules/#deployment">previous blog post</a>, I&#8217;ve shown how you can deploy an npm module from a URL and a custom ESM module from a local file into a remote Oracle Database 23c using JavaScript and SQLcl. This works well. However, for two MLE modules, I had to write 22 lines of code with duplications. I do not like that. I have therefore developed a small SQLcl custom command that greatly simplifies the installation of MLE modules in the Oracle Database.</p>



<h2 class="wp-block-heading">Installing the <code>mle</code> Custom Command</h2>



<p>Start SQLcl and run the following command to install the custom command <code>mle</code> in the current session.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="script https://raw.githubusercontent.com/PhilippSalvisberg/mle-sqlcl/main/mle.js register" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">script https://raw.githubusercontent.com/PhilippSalvisberg/mle-sqlcl/main/mle.js register</span></span></code></pre></div>



<p>The SQLcl script command can read a JavaScript file from the local file system or from a URL. If you feel uncomfortable running JavaScript files directly from a URL, you can have a look at the <a href="https://github.com/PhilippSalvisberg/mle-sqlcl">GitHub repo</a> first and download and run a chosen version of the script from the local file system.</p>



<p>The <code>register</code> subcommand registers the <code>mle</code> script as an SQLcl command. However, this registration is not permanent. It will be lost after closing SQLcl. To make the custom command available in every new SQLcl session add the command above to your <code>login.sql</code> or <code>startup.sql</code>. SQLcl executes these files on start-up or after establishing a new connection. Just make sure that you have configured the <code>SQLPATH</code> environment variable accordingly. </p>



<h2 class="wp-block-heading">Providing Help</h2>



<p>Now you can run the <code>mle</code> command like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="mle" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">mle</span></span></code></pre></div>



<p>Without parameters, an error message is displayed along with information on how to use this command.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-2.png"><img fetchpriority="high" decoding="async" width="650" height="498" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-2.png" alt="Output of mle command without parameters" class="wp-image-12934" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-2.png 650w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-2-300x230.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-2-98x75.png 98w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-2-480x368.png 480w" sizes="(max-width:767px) 480px, 650px" /></a></figure>



<h2 class="wp-block-heading">Installing Validator</h2>



<p>Now we know the syntax to install an MLE module from a URL. However, what&#8217;s the URL for an npm module? We use the free OpenSource CDN <a href="https://www.jsdelivr.com/?docs=esm">jsDelivr</a> for that. They provide a service returning an npm module as an ECMAScript module. The result can be used in a browser and also in an Oracle Database. The URL looks like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="https://esm.run/npm-package-name@npm-package-version" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">https://esm.run/npm-package-name@npm-package-version</span></span></code></pre></div>



<p>We want to install the current version 13.11.0 of the npm module <a href="https://www.npmjs.com/package/validator">validator</a>. Based on the information provided above our SQLcl command for that looks like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="mle install validator_mod https://esm.run/validator@13.11.0 13.11.0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">mle install validator_mod https://esm.run/validator@13.</span><span style="color: #B5CEA8">11</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">13</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">11</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">0</span></span></code></pre></div>



<p>And here is the result in SQLcl :</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-9.png"><img decoding="async" width="642" height="194" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-9.png" alt="Output of successfully executed mle command to install the validator module from npm" class="wp-image-12945" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-9.png 642w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-9-300x91.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-9-150x45.png 150w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-9-480x145.png 480w" sizes="(max-width:767px) 480px, 642px" /></a></figure>



<p>Please note that the response message by SQLcl 23.3 is not 100% correct for MLE modules. However, our module is installed correctly. We verify that later.</p>



<p>Maybe you&#8217;d like to know what the SQL statement looks like to install this module. The last statement is still in SQLcl&#8217;s buffer. Therefore we can type <code>l</code> followed by <code>enter</code> to see the content of the buffer.</p>


<div class="accordion"><div class="mfn-acc accordion_wrapper  toggle"><br />
<div class="question"><div class="title"><i class="icon-plus acc-icon-plus" aria-hidden="true"></i><i class="icon-minus acc-icon-minus" aria-hidden="true"></i>SQLcl's buffer</div><div class="answer"></p>



<p>The first line contains the start of the SQL statement. Lines 2 to 7 are comments generated by jsDelivr. Line 8 contains the complete module. Yes, as a single line. The code is minified. All unnecessary whitespace is gone and internally used identifiers are shortened to save space. On line 9 we would see a JavaScript comment with a pointer to a map file that points to the original, nicely formatted source code. This is interesting when debugging in other environments. It&#8217;s currently not used in the database.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-7.png"><img decoding="async" width="1050" height="17704" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-7.png" alt="SQLcl buffer containing the SQL command to install the validator module" class="wp-image-12937"/></a></figure>


<p></div></div>
<br />
</div></div>




<h2 class="wp-block-heading">Querying MLE Modules</h2>



<p>The following SQL statement shows some data regarding the previously deployed MLE module:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="set sqlformat ansiconsole
select module_name, version, language_name, length(module)
  from user_mle_modules;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> sqlformat ansiconsole</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> module_name, </span><span style="color: #569CD6">version</span><span style="color: #D4D4D4">, language_name, </span><span style="color: #569CD6">length</span><span style="color: #D4D4D4">(module)</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> user_mle_modules;</span></span></code></pre></div>



<p>The result in SQLcl looks like this:</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-8.png"><img loading="lazy" decoding="async" width="642" height="171" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-8.png" alt="" class="wp-image-12944" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-8.png 642w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-8-300x80.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-8-150x40.png 150w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-8-480x128.png 480w" sizes="auto, (max-width:767px) 480px, 642px" /></a></figure>



<p>We see the version of the module and also the size in bytes of the blob column where the module is stored. It is one byte larger than the result of the URL since It contains a final line feed character due to the way we built the SQL statement.</p>



<p>IMO it is helpful to provide the version of the external ESM as long as there is no proper package registry within the Oracle Database.</p>



<h2 class="wp-block-heading">Verifying Installation</h2>



<p>Let&#8217;s write a call specification in order to verify the successful installation of the validator module.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="create or replace function is_email(
   in_email in varchar2
) return boolean as mle module validator_mod signature 'default.isEmail(string)';
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">create or replace</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">is_email</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">   in_email </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">varchar2</span></span>
<span class="line"><span style="color: #D4D4D4">) </span><span style="color: #569CD6">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">boolean</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> mle module validator_mod </span><span style="color: #569CD6">signature</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;default.isEmail(string)&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<p>Now we can run the following query to verify e-mail addresses and the installation of the validator module:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="select is_email('jane.doe@example.org') as jane_doe,
       is_email('john.doe@example') as john_doe;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> is_email(</span><span style="color: #CE9178">&#39;jane.doe@example.org&#39;</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> jane_doe,</span></span>
<span class="line"><span style="color: #D4D4D4">       is_email(</span><span style="color: #CE9178">&#39;john.doe@example&#39;</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> john_doe;</span></span></code></pre></div>



<p>In SQLcl 23.3 the result looks like this (boolean values as <code>1</code> and <code>0</code>):</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-10.png"><img loading="lazy" decoding="async" width="642" height="189" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-10.png" alt="Result of calling the is_email validator function in SQLcl" class="wp-image-12949" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-10.png 642w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-10-300x88.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-10-150x44.png 150w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-10-480x141.png 480w" sizes="auto, (max-width:767px) 480px, 642px" /></a></figure>



<p>And in SQL*Plus 23.3 the result looks like this (boolean values as <code>TRUE</code> and <code>FALSE</code>):</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-12.png"><img loading="lazy" decoding="async" width="642" height="193" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-12.png" alt="Result of calling the is_email validator function in SQL*Plus" class="wp-image-12952" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-12.png 642w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-12-300x90.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-12-150x45.png 150w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-12-480x144.png 480w" sizes="auto, (max-width:767px) 480px, 642px" /></a></figure>



<h2 class="wp-block-heading">Installing More Modules</h2>



<p>Let&#8217;s install some other modules I find useful. You find them on <a href="https://www.npmjs.com/">npm</a> if you want to know what they do.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="mle install sentiment_mod https://esm.run/sentiment@5.0.2 5.0.22
mle install jimp_mod https://esm.run/jimp@0.22.10/browser/lib/jimp.js 0.22.10
mle install sql_assert_mod https://esm.run/sql-assert@1.0.3 1.0.3
mle install lodash_mod https://esm.run/lodash@4.17.21 4.17.21
mle install js_yaml_mod https://esm.run/js-yaml@4.1.0 4.1.0
mle install minimist_mod https://esm.run/minimist@1.2.8 1.2.8
mle install typeorm_mod https://esm.run/typeorm@0.3.17 0.3.17" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">mle install sentiment_mod https://esm.run/sentiment@5.</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">5</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">22</span></span>
<span class="line"><span style="color: #D4D4D4">mle install jimp_mod https://esm.run/jimp@0.</span><span style="color: #B5CEA8">22</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">/browser/lib/jimp.js </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">22</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">10</span></span>
<span class="line"><span style="color: #D4D4D4">mle install sql_assert_mod https://esm.run/</span><span style="color: #569CD6">sql</span><span style="color: #D4D4D4">-assert@1.</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">3</span></span>
<span class="line"><span style="color: #D4D4D4">mle install lodash_mod https://esm.run/lodash@4.</span><span style="color: #B5CEA8">17</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">21</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">17</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">21</span></span>
<span class="line"><span style="color: #D4D4D4">mle install js_yaml_mod https://esm.run/js-yaml@4.</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">0</span></span>
<span class="line"><span style="color: #D4D4D4">mle install minimist_mod https://esm.run/minimist@1.</span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">8</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">8</span></span>
<span class="line"><span style="color: #D4D4D4">mle install typeorm_mod https://esm.run/typeorm@0.</span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">17</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">17</span></span></code></pre></div>



<p>Installing all modules is just a matter of a few seconds. </p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>Using the SQLcl custom <code>mle</code> command to install ECMAScript modules from a file or from a URL is not only easy and fast, but it is also an excellent way to provide tested functionality within the database. </p>



<p>Technically it should be possible to generate the PL/SQL call specifications based on the information that is provided for IDEs to better support code completion (type definitions). I hope that Oracle will provide such a feature in one of the coming releases of SQLcl or as part of a dedicated MLE tool (similar to <code>dbjs</code> which was part of the experimental version of the MLE back in 2017). Even if I do not want to provide access to all underlying functionality of an MLE module within the database or provide the functionality with the same signature, a PL/SQL package with all call specifications would simplify the work for a wrapper PL/SQL package that exposes just the relevant subset in a suitable way for the use in PL/SQL or SQL.</p>
<p>The post <a href="https://www.salvis.com/blog/2023/11/26/installing-mle-modules-in-the-oracle-database/">Installing MLE Modules in the Oracle Database</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>MLE TypeScript &#038; JavaScript Modules</title>
		<link>https://www.salvis.com/blog/2023/11/12/mle-typescript-javascript-modules/</link>
					<comments>https://www.salvis.com/blog/2023/11/12/mle-typescript-javascript-modules/#comments</comments>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Sun, 12 Nov 2023 11:45:56 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[MLE]]></category>
		<category><![CDATA[Oracle 26ai]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[VSCode]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=12530</guid>

					<description><![CDATA[<p>Introduction The Oracle Database 23c supports MLE JavaScript modules. MLE modules are standard ECMAScript 2022 modules. The easiest way to develop such modules is outside the database. This allows us to take advantage of the extensive JavaScript ecosystem and develop MLE modules in TypeScript instead of JavaScript. In this blog post, I<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2023/11/12/mle-typescript-javascript-modules/">MLE TypeScript &#038; JavaScript Modules</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Introduction</h2>



<p>The Oracle Database 23c supports MLE JavaScript modules. MLE modules are standard ECMAScript 2022 modules. The easiest way to develop such modules is outside the database. This allows us to take advantage of the extensive JavaScript ecosystem and develop MLE modules in TypeScript instead of JavaScript.</p>



<p>In this blog post, I demonstrate how to develop and test an MLE module in TypeScript and deploy it into the database. I will use Node and VS Code.</p>



<h2 class="wp-block-heading">TL;DR</h2>



<p>See the <a href="#conclusion">conclusion</a> and explore the code on <a href="https://github.com/PhilippSalvisberg/js23c/tree/main/sandbox2">GitHub</a>.</p>



<h2 class="wp-block-heading">Requirements</h2>



<p>The idea is to provide a public stored procedure in the database that creates and populates the well-known tables <code>dept</code> and <code>emp</code> in the current schema. The function accepts different table names. The tables are not re-created if they already exist. However, the original data should be reset to their initial state while other rows should be left unchanged. Problems are reported via exceptions.</p>



<p>Nothing fancy. However, we will have to deal with SQL and address potential SQL injection vulnerabilities. Furthermore, it allows us to demonstrate how to test an MLE module outside the database.</p>



<h2 class="wp-block-heading">Design</h2>



<p>The following image visualizes the solution design.</p>



<figure class="wp-block-image size-large is-resized is-style-default"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/overview.png"><img loading="lazy" decoding="async" width="876" height="1024" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/overview-876x1024.png" alt="Solution design of the demo application" class="wp-image-12809" style="width:auto;height:447px" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/11/overview-876x1024.png 876w, https://www.salvis.com/blog/wp-content/uploads/2023/11/overview-257x300.png 257w, https://www.salvis.com/blog/wp-content/uploads/2023/11/overview-768x898.png 768w, https://www.salvis.com/blog/wp-content/uploads/2023/11/overview-1314x1536.png 1314w, https://www.salvis.com/blog/wp-content/uploads/2023/11/overview-64x75.png 64w, https://www.salvis.com/blog/wp-content/uploads/2023/11/overview-480x561.png 480w, https://www.salvis.com/blog/wp-content/uploads/2023/11/overview.png 1529w" sizes="auto, (max-width:767px) 480px, (max-width:876px) 100vw, 876px" /></a></figure>



<p>We create an Oracle Database user <code>demotab</code> and deploy an npm and a self-made module as MLE modules into this schema, along with an MLE environment and a PL/SQL package as an interface. We grant the package to public and create a public synonym for it. As a result, any user in the database instance (e.g. the user <code>otheruser</code>) can execute the following code to install and populate the tables <code>dept</code> and <code>emp</code> within their schema.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="begin
   demo.create_tabs;
end;
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   demo.create_tabs;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<p>We can also pass alternative table names like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="begin
   demo.create_tabs('departments', 'employees');
end;
/" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">   demo.create_tabs(</span><span style="color: #CE9178">&#39;departments&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;employees&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span></code></pre></div>



<p></p>



<h2 class="wp-block-heading">Prerequisites</h2>



<p>You need the following to build this MLE module yourself:</p>



<ul class="wp-block-list">
<li>Full access to an <a href="https://www.oracle.com/database/free/get-started/#installing">Oracle Database 23c Free</a> (&gt;=23.3). This means you know how to connect as <code>sysdba</code>.</li>



<li>A machine with <a href="https://code.visualstudio.com/download">VS Code</a> (&gt;=1.83.1), <a href="https://nodejs.org/en/download">Node</a> (&gt;=20.9.0) and <a href="https://www.oracle.com/database/sqldeveloper/technologies/sqlcl/download/">SQLcl</a> (&gt;=23.3.0, must be found in the OS path).</li>



<li>Internet access and the rights to install npm modules and VS Code extensions.</li>
</ul>



<h2 class="wp-block-heading">Prepare Node Project</h2>



<p>Open a folder in VS Code where you want to develop the MLE module. And create the files <code>package.json</code>, <code>tsconfig.json</code>, <code>.eslintrc</code> and <code>.prettier</code>. The content of each file is shown below.</p>


<div class="jq-tabs tabs_wrapper tabs_horizontal"><ul><li><a href="#tab-69d67a37b7076-1">package.json</a></li><li><a href="#tab-69d67a37b7076-2">tsconfig.json</a></li><li><a href="#tab-69d67a37b7076-3">.eslintrc</a></li><li><a href="#tab-69d67a37b7076-4">.prettierrc</a></li></ul><div id="tab-69d67a37b7076-1" ></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">package.json</span><span role="button" tabindex="0" data-code="{
    &quot;name&quot;: &quot;demotab&quot;,
    &quot;version&quot;: &quot;1.0.0&quot;,
    &quot;description&quot;: &quot;Create and populate demo tables.&quot;,
    &quot;type&quot;: &quot;module&quot;,
    &quot;scripts&quot;: {
        &quot;build&quot;: &quot;npm run format &amp;&amp; npm run lint &amp;&amp; npm run tsc &amp;&amp; npm run coverage&quot;,
        &quot;tsc&quot;: &quot;tsc --project tsconfig.json&quot;,
        &quot;lint&quot;: &quot;eslint . --ext .ts&quot;,
        &quot;format&quot;: &quot;prettier --write './**/*{.ts,.eslintrc,.prettierrc,.json}'&quot;,
        &quot;test&quot;: &quot;vitest --no-threads --reporter=verbose --dir ./test&quot;,
        &quot;coverage&quot;: &quot;vitest --no-threads --dir ./test run --coverage&quot;
    },
    &quot;devDependencies&quot;: {
        &quot;@types/oracledb&quot;: &quot;^6.0.3&quot;,
        &quot;@typescript-eslint/eslint-plugin&quot;: &quot;^6.9.1&quot;,
        &quot;@typescript-eslint/parser&quot;: &quot;^6.9.1&quot;,
        &quot;@vitest/coverage-v8&quot;: &quot;^0.34.6&quot;,
        &quot;eslint&quot;: &quot;^8.52.0&quot;,
        &quot;eslint-config-prettier&quot;: &quot;^9.0.0&quot;,
        &quot;oracledb&quot;: &quot;^6.2.0&quot;,
        &quot;prettier&quot;: &quot;^3.0.3&quot;,
        &quot;typescript&quot;: &quot;^5.2.2&quot;,
        &quot;vitest&quot;: &quot;^0.34.6&quot;
    },
    &quot;dependencies&quot;: {
        &quot;sql-assert&quot;: &quot;^1.0.3&quot;
    }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;name&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;demotab&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;version&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;1.0.0&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;description&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;Create and populate demo tables.&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;type&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;module&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;scripts&quot;</span><span style="color: #D4D4D4">: {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;build&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;npm run format &amp;&amp; npm run lint &amp;&amp; npm run tsc &amp;&amp; npm run coverage&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;tsc&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;tsc --project tsconfig.json&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;lint&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;eslint . --ext .ts&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;format&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;prettier --write &#39;./**/*{.ts,.eslintrc,.prettierrc,.json}&#39;&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;test&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;vitest --no-threads --reporter=verbose --dir ./test&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;coverage&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;vitest --no-threads --dir ./test run --coverage&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    },</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;devDependencies&quot;</span><span style="color: #D4D4D4">: {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;@types/oracledb&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^6.0.3&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;@typescript-eslint/eslint-plugin&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^6.9.1&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;@typescript-eslint/parser&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^6.9.1&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;@vitest/coverage-v8&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^0.34.6&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;eslint&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^8.52.0&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;eslint-config-prettier&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^9.0.0&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;oracledb&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^6.2.0&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;prettier&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^3.0.3&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;typescript&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^5.2.2&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;vitest&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^0.34.6&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    },</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;dependencies&quot;</span><span style="color: #D4D4D4">: {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;sql-assert&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;^1.0.3&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p><a href="https://nodejs.org/api/packages.html#nodejs-packagejson-field-definitions">Node</a> uses some of these JSON fields. However, most of the fields are required by <a href="https://docs.npmjs.com/cli/v10/configuring-npm/package-json">npm</a> and its command-line interface. The type on line 5 defines that we build an ECMAScript module. Important are the dependencies. Our module needs the <code>sql-assert</code> module at runtime.  Other dependencies are for developing purposes only.</p>


<p></div><div id="tab-69d67a37b7076-2" ></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">tsconfig.json</span><span role="button" tabindex="0" data-code="{
    &quot;compilerOptions&quot;: {
        &quot;rootDir&quot;: &quot;./src&quot;,
        &quot;target&quot;: &quot;ES2017&quot;,
        &quot;module&quot;: &quot;ES2022&quot;,
        &quot;moduleResolution&quot;: &quot;node&quot;,
        &quot;esModuleInterop&quot;: true,
        &quot;forceConsistentCasingInFileNames&quot;: true,
        &quot;strict&quot;: true,
        &quot;skipLibCheck&quot;: true,
        &quot;sourceMap&quot;: true,
        &quot;outDir&quot;: &quot;esm&quot;
    },
    &quot;include&quot;: &#091;&quot;./src/**/*&quot;&#093;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;compilerOptions&quot;</span><span style="color: #D4D4D4">: {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;rootDir&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;./src&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;target&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;ES2017&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;module&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;ES2022&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;moduleResolution&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;node&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;esModuleInterop&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;forceConsistentCasingInFileNames&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;strict&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;skipLibCheck&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;sourceMap&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;outDir&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;esm&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    },</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;include&quot;</span><span style="color: #D4D4D4">: [</span><span style="color: #CE9178">&quot;./src/**/*&quot;</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p>This is the <a href="https://www.typescriptlang.org/tsconfig">configuration for the TypeScript compiler</a>. On lines 5 and 6 we define the ECMAScript versions to be used. We develop in TypeScript with ECMAScript 2022 features and generate a JavaScript file using ECMAScript 2017, the version in which the async/await feature was introduced. This makes the generated JavaScript module a bit more readable. However, for MLE we could also use ECMAScript 2022. Using older ECMAScript targets makes sense when you want to use it in environments with an older JavaScript engine, for example, old browsers.</p>


<p></div><div id="tab-69d67a37b7076-3" ></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">.eslintrc</span><span role="button" tabindex="0" data-code="{
    &quot;root&quot;: true,
    &quot;parser&quot;: &quot;@typescript-eslint/parser&quot;,
    &quot;plugins&quot;: &#091;&quot;@typescript-eslint&quot;&#093;,
    &quot;extends&quot;: &#091;
        &quot;eslint:recommended&quot;,
        &quot;plugin:@typescript-eslint/eslint-recommended&quot;,
        &quot;plugin:@typescript-eslint/recommended&quot;,
        &quot;prettier&quot;
    &#093;,
    &quot;rules&quot;: {
        &quot;no-console&quot;: &quot;error&quot;
    }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;root&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;parser&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;@typescript-eslint/parser&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;plugins&quot;</span><span style="color: #D4D4D4">: [</span><span style="color: #CE9178">&quot;@typescript-eslint&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;extends&quot;</span><span style="color: #D4D4D4">: [</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;eslint:recommended&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;plugin:@typescript-eslint/eslint-recommended&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;plugin:@typescript-eslint/recommended&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;prettier&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    ],</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;rules&quot;</span><span style="color: #D4D4D4">: {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">&quot;no-console&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;error&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p>Here we define the <a href="https://eslint.org/docs/latest/use/configure/">configuration for ESlint</a>. We configure the linter for TypeScript with a recommended rule set. However, we do not want <code>console.log</code> statements in our code. Therefore we treat them as errors.</p>


<p></div><div id="tab-69d67a37b7076-4" ></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">.prettierrc</span><span role="button" tabindex="0" data-code="{
    &quot;semi&quot;: true,
    &quot;printWidth&quot;: 120,
    &quot;singleQuote&quot;: false,
    &quot;tabWidth&quot;: 4,
    &quot;trailingComma&quot;: &quot;none&quot;,
    &quot;arrowParens&quot;: &quot;always&quot;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;semi&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;printWidth&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">120</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;singleQuote&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;tabWidth&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;trailingComma&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;none&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">&quot;arrowParens&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;always&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p>The last configuration file is for <a href="https://prettier.io/docs/en/options">Prettier</a>, a popular formatter for various languages. </p>


<p></div></div>



<h2 class="wp-block-heading">Initialize Node Project</h2>



<p>Now we are ready to initialize the Node project. Open a terminal window in VS Code and execute the following command:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="npm install" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">install</span></span></code></pre></div>



<p>This will create a file named <code>package-lock.json</code> and a <code>node_modules</code> folder. <code>package-lock.json</code> is the table of contents for the <code>node_modules</code> folder. It contains the recursively resolved dependencies with their versions. Dependencies can be defined with <a href="https://docs.npmjs.com/about-semantic-versioning#using-semantic-versioning-to-specify-update-types-your-package-can-accept">version ranges</a>. Therefore, they are not unambiguous and can lead to different results depending on the time of analysis.</p>



<p>When you delete the <code>node_modules</code> folder and re-run <code>npm install</code>, it will produce the same content based on the module versions registered in <code>package-lock.json</code>. As a result, it might be useful to add this file to your version control system. To make things reproducible.</p>



<h2 class="wp-block-heading">Original TypeScript Module</h2>



<p>Let&#8217;s create a file named <code>demotab.ts</code> in a new folder <code>src</code> with the following content:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">src/demotab.ts</span><span role="button" tabindex="0" data-code="import { simpleSqlName } from &quot;sql-assert&quot;;
import oracledb from &quot;oracledb&quot;;

// global variable for default connection in the database
declare const session: oracledb.Connection;

/**
 * Creates demo tables with initial data for the well-known tables `dept` and `emp`.
 * Alternative table names can be passed to this function. The tables are not re-created
 * if they already exist. However, the rows for the 4 departments and the 14 employees
 * should be reset to their initial state while other rows are left unchanged.
 * Problems are reported via exceptions.
 *
 * @param [deptName=&quot;dept&quot;] name of the dept table.
 * @param [empName=&quot;emp&quot;] name of the emp table.
 * @returns {Promise&lt;void&gt;}.
 */
export async function create(deptName: string = &quot;dept&quot;, empName: string = &quot;emp&quot;): Promise&lt;void&gt; {
    const dept = simpleSqlName(deptName);
    const emp = simpleSqlName(empName);
    await session.execute(`
        create table if not exists ${dept} (
           deptno number(2, 0)      not null constraint ${dept}_pk primary key,
           dname  varchar2(14 char) not null,
           loc    varchar2(13 char) not null
        )
    `);
    await session.execute(`
        merge into ${dept} t
        using (values 
                 (10, 'ACCOUNTING', 'NEW YORK'),
                 (20, 'RESEARCH',   'DALLAS'),
                 (30, 'SALES',      'CHICAGO'),
                 (40, 'OPERATIONS', 'BOSTON')
              ) s (deptno, dname, loc)
           on (t.deptno = s.deptno)
         when matched then
              update
                 set t.dname = s.dname,
                     t.loc = s.loc
         when not matched then
              insert (t.deptno, t.dname, t.loc)
              values (s.deptno, s.dname, s.loc)
    `);
    await session.execute(`
        create table if not exists ${emp} (
            empno    number(4, 0)      not null  constraint ${emp}_pk primary key,
            ename    varchar2(10 char) not null,
            job      varchar2(9 char)  not null,
            mgr      number(4, 0)                constraint ${emp}_mgr_fk references ${emp},
            hiredate date              not null,
            sal      number(7, 2),
            comm     number(7, 2),
            deptno   number(2, 0)      not null  constraint ${emp}_deptno_fk references ${dept}
        )
    `);
    await session.execute(`create index if not exists ${emp}_mgr_fk_i on ${emp} (mgr)`);
    await session.execute(`create index if not exists ${emp}_deptno_fk_i on ${emp} (deptno)`);
    await session.execute(`alter table ${emp} disable constraint ${emp}_mgr_fk`);
    await session.execute(`
        merge into ${emp} t
        using (values
                 (7839, 'KING',   'PRESIDENT', null, date '1981-11-17', 5000, null, 10),
                 (7566, 'JONES',  'MANAGER',   7839, date '1981-04-02', 2975, null, 20),
                 (7698, 'BLAKE',  'MANAGER',   7839, date '1981-05-01', 2850, null, 30),
                 (7782, 'CLARK',  'MANAGER',   7839, date '1981-06-09', 2450, null, 10),
                 (7788, 'SCOTT',  'ANALYST',   7566, date '1987-04-19', 3000, null, 20),
                 (7902, 'FORD',   'ANALYST',   7566, date '1981-12-03', 3000, null, 20),
                 (7499, 'ALLEN',  'SALESMAN',  7698, date '1981-02-20', 1600,  300, 30),
                 (7521, 'WARD',   'SALESMAN',  7698, date '1981-02-22', 1250,  500, 30),
                 (7654, 'MARTIN', 'SALESMAN',  7698, date '1981-09-28', 1250, 1400, 30),
                 (7844, 'TURNER', 'SALESMAN',  7698, date '1981-09-08', 1500,    0, 30),
                 (7900, 'JAMES',  'CLERK',     7698, date '1981-12-03',  950, null, 30),
                 (7934, 'MILLER', 'CLERK',     7782, date '1982-01-23', 1300, null, 10),
                 (7369, 'SMITH',  'CLERK',     7902, date '1980-12-17',  800, null, 20),
                 (7876, 'ADAMS',  'CLERK',     7788, date '1987-05-23', 1100, null, 20)                        
              ) s (empno, ename, job, mgr, hiredate, sal, comm, deptno)
           on (t.empno = s.empno)
         when matched then
              update
                 set t.ename = s.ename,
                     t.job = s.job,
                     t.mgr = s.mgr,
                     t.hiredate = s.hiredate,
                     t.sal = s.sal,
                     t.comm = s.comm,
                     t.deptno = s.deptno
         when not matched then
              insert (t.empno, t.ename, t.job, t.mgr, t.hiredate, t.sal, t.comm, t.deptno)
              values (s.empno, s.ename, s.job, s.mgr, s.hiredate, s.sal, s.comm, s.deptno)
    `);
    await session.execute(`alter table ${emp} enable constraint ${emp}_mgr_fk`);
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">simpleSqlName</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;sql-assert&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">oracledb</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;oracledb&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// global variable for default connection in the database</span></span>
<span class="line cbp-line-highlight"><span style="color: #569CD6">declare</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">session</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Connection</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Creates demo tables with initial data for the well-known tables `dept` and `emp`.</span></span>
<span class="line"><span style="color: #6A9955"> * Alternative table names can be passed to this function. The tables are not re-created</span></span>
<span class="line"><span style="color: #6A9955"> * if they already exist. However, the rows for the 4 departments and the 14 employees</span></span>
<span class="line"><span style="color: #6A9955"> * should be reset to their initial state while other rows are left unchanged.</span></span>
<span class="line"><span style="color: #6A9955"> * Problems are reported via exceptions.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@param</span><span style="color: #6A9955"> [deptName=&quot;dept&quot;] name of the dept table.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@param</span><span style="color: #6A9955"> [empName=&quot;emp&quot;] name of the emp table.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@returns</span><span style="color: #6A9955"> </span><span style="color: #4EC9B0">{Promise&lt;void&gt;}</span><span style="color: #6A9955">.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line cbp-line-highlight"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">create</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">deptName</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">string</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;dept&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">empName</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">string</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;emp&quot;</span><span style="color: #D4D4D4">): </span><span style="color: #4EC9B0">Promise</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4">&gt; {</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">dept</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">simpleSqlName</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">deptName</span><span style="color: #D4D4D4">);</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">emp</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">simpleSqlName</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">empName</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">        create table if not exists </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">dept</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> (</span></span>
<span class="line"><span style="color: #CE9178">           deptno number(2, 0)      not null constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">dept</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_pk primary key,</span></span>
<span class="line"><span style="color: #CE9178">           dname  varchar2(14 char) not null,</span></span>
<span class="line"><span style="color: #CE9178">           loc    varchar2(13 char) not null</span></span>
<span class="line"><span style="color: #CE9178">        )</span></span>
<span class="line"><span style="color: #CE9178">    `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">        merge into </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">dept</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> t</span></span>
<span class="line"><span style="color: #CE9178">        using (values </span></span>
<span class="line"><span style="color: #CE9178">                 (10, &#39;ACCOUNTING&#39;, &#39;NEW YORK&#39;),</span></span>
<span class="line"><span style="color: #CE9178">                 (20, &#39;RESEARCH&#39;,   &#39;DALLAS&#39;),</span></span>
<span class="line"><span style="color: #CE9178">                 (30, &#39;SALES&#39;,      &#39;CHICAGO&#39;),</span></span>
<span class="line"><span style="color: #CE9178">                 (40, &#39;OPERATIONS&#39;, &#39;BOSTON&#39;)</span></span>
<span class="line"><span style="color: #CE9178">              ) s (deptno, dname, loc)</span></span>
<span class="line"><span style="color: #CE9178">           on (t.deptno = s.deptno)</span></span>
<span class="line"><span style="color: #CE9178">         when matched then</span></span>
<span class="line"><span style="color: #CE9178">              update</span></span>
<span class="line"><span style="color: #CE9178">                 set t.dname = s.dname,</span></span>
<span class="line"><span style="color: #CE9178">                     t.loc = s.loc</span></span>
<span class="line"><span style="color: #CE9178">         when not matched then</span></span>
<span class="line"><span style="color: #CE9178">              insert (t.deptno, t.dname, t.loc)</span></span>
<span class="line"><span style="color: #CE9178">              values (s.deptno, s.dname, s.loc)</span></span>
<span class="line"><span style="color: #CE9178">    `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">        create table if not exists </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> (</span></span>
<span class="line"><span style="color: #CE9178">            empno    number(4, 0)      not null  constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_pk primary key,</span></span>
<span class="line"><span style="color: #CE9178">            ename    varchar2(10 char) not null,</span></span>
<span class="line"><span style="color: #CE9178">            job      varchar2(9 char)  not null,</span></span>
<span class="line"><span style="color: #CE9178">            mgr      number(4, 0)                constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_mgr_fk references </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">,</span></span>
<span class="line"><span style="color: #CE9178">            hiredate date              not null,</span></span>
<span class="line"><span style="color: #CE9178">            sal      number(7, 2),</span></span>
<span class="line"><span style="color: #CE9178">            comm     number(7, 2),</span></span>
<span class="line"><span style="color: #CE9178">            deptno   number(2, 0)      not null  constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_deptno_fk references </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">dept</span><span style="color: #569CD6">}</span></span>
<span class="line"><span style="color: #CE9178">        )</span></span>
<span class="line"><span style="color: #CE9178">    `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`create index if not exists </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_mgr_fk_i on </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> (mgr)`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`create index if not exists </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_deptno_fk_i on </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> (deptno)`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`alter table </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> disable constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_mgr_fk`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">        merge into </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> t</span></span>
<span class="line"><span style="color: #CE9178">        using (values</span></span>
<span class="line"><span style="color: #CE9178">                 (7839, &#39;KING&#39;,   &#39;PRESIDENT&#39;, null, date &#39;1981-11-17&#39;, 5000, null, 10),</span></span>
<span class="line"><span style="color: #CE9178">                 (7566, &#39;JONES&#39;,  &#39;MANAGER&#39;,   7839, date &#39;1981-04-02&#39;, 2975, null, 20),</span></span>
<span class="line"><span style="color: #CE9178">                 (7698, &#39;BLAKE&#39;,  &#39;MANAGER&#39;,   7839, date &#39;1981-05-01&#39;, 2850, null, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7782, &#39;CLARK&#39;,  &#39;MANAGER&#39;,   7839, date &#39;1981-06-09&#39;, 2450, null, 10),</span></span>
<span class="line"><span style="color: #CE9178">                 (7788, &#39;SCOTT&#39;,  &#39;ANALYST&#39;,   7566, date &#39;1987-04-19&#39;, 3000, null, 20),</span></span>
<span class="line"><span style="color: #CE9178">                 (7902, &#39;FORD&#39;,   &#39;ANALYST&#39;,   7566, date &#39;1981-12-03&#39;, 3000, null, 20),</span></span>
<span class="line"><span style="color: #CE9178">                 (7499, &#39;ALLEN&#39;,  &#39;SALESMAN&#39;,  7698, date &#39;1981-02-20&#39;, 1600,  300, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7521, &#39;WARD&#39;,   &#39;SALESMAN&#39;,  7698, date &#39;1981-02-22&#39;, 1250,  500, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7654, &#39;MARTIN&#39;, &#39;SALESMAN&#39;,  7698, date &#39;1981-09-28&#39;, 1250, 1400, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7844, &#39;TURNER&#39;, &#39;SALESMAN&#39;,  7698, date &#39;1981-09-08&#39;, 1500,    0, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7900, &#39;JAMES&#39;,  &#39;CLERK&#39;,     7698, date &#39;1981-12-03&#39;,  950, null, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7934, &#39;MILLER&#39;, &#39;CLERK&#39;,     7782, date &#39;1982-01-23&#39;, 1300, null, 10),</span></span>
<span class="line"><span style="color: #CE9178">                 (7369, &#39;SMITH&#39;,  &#39;CLERK&#39;,     7902, date &#39;1980-12-17&#39;,  800, null, 20),</span></span>
<span class="line"><span style="color: #CE9178">                 (7876, &#39;ADAMS&#39;,  &#39;CLERK&#39;,     7788, date &#39;1987-05-23&#39;, 1100, null, 20)                        </span></span>
<span class="line"><span style="color: #CE9178">              ) s (empno, ename, job, mgr, hiredate, sal, comm, deptno)</span></span>
<span class="line"><span style="color: #CE9178">           on (t.empno = s.empno)</span></span>
<span class="line"><span style="color: #CE9178">         when matched then</span></span>
<span class="line"><span style="color: #CE9178">              update</span></span>
<span class="line"><span style="color: #CE9178">                 set t.ename = s.ename,</span></span>
<span class="line"><span style="color: #CE9178">                     t.job = s.job,</span></span>
<span class="line"><span style="color: #CE9178">                     t.mgr = s.mgr,</span></span>
<span class="line"><span style="color: #CE9178">                     t.hiredate = s.hiredate,</span></span>
<span class="line"><span style="color: #CE9178">                     t.sal = s.sal,</span></span>
<span class="line"><span style="color: #CE9178">                     t.comm = s.comm,</span></span>
<span class="line"><span style="color: #CE9178">                     t.deptno = s.deptno</span></span>
<span class="line"><span style="color: #CE9178">         when not matched then</span></span>
<span class="line"><span style="color: #CE9178">              insert (t.empno, t.ename, t.job, t.mgr, t.hiredate, t.sal, t.comm, t.deptno)</span></span>
<span class="line"><span style="color: #CE9178">              values (s.empno, s.ename, s.job, s.mgr, s.hiredate, s.sal, s.comm, s.deptno)</span></span>
<span class="line"><span style="color: #CE9178">    `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`alter table </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> enable constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_mgr_fk`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h5 class="wp-block-heading"> Global <code>session</code> Variable</h5>



<p>On line 5 we <a href="https://www.typescriptlang.org/docs/handbook/declaration-files/by-example.html">declare</a> a constant named <code>session</code>. This way we tell the TypeScript compiler that a read-only <code>session</code> variable of type <code>oracledb.Connection</code> is available. As a result, we have code completion enabled for <code>session</code>. </p>



<h5 class="wp-block-heading">Asynchronous Function</h5>



<p>On line 18 we define the signature of the <code>create</code> function. Please note that this is an asynchronous function. We need that to use <code>await</code> in Node. However, functions in MLE modules run always synchronously within the Oracle Database, even if a function is declared as <code>async</code>. So, <code>async</code> would not be necessary if the code runs exclusively in the database.</p>



<h5 class="wp-block-heading">Preventing SQL Injection</h5>



<p>We call <code>simpleSqlName</code> on lines 19 and 20 to ensure that no SQL injection is possible. This makes the variables <code>dept</code> and <code>emp</code> in the <a href="https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html">template literals</a> safe. The function <code>simpleSqlName</code> has the advantage that it runs outside of the database. It has the same logic as its sibling <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/DBMS_ASSERT.html#GUID-4074EA91-3824-42D0-8A1B-D7B74C7A1955">dbms_assert.simple_sql_name</a>.</p>



<h2 class="wp-block-heading">Generated JavaScript Module</h2>



<p>We run the TypeScript compiler as follows in a terminal window within VS Code:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="npm run tsc" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">run</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">tsc</span></span></code></pre></div>



<p>This will execute <code>tsc --project tsconfig.json</code> as defined in <code>package.json</code> and produce a <code>demotab.js</code> file in the <code>esm</code> folder.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">esm/demotab.js</span><span role="button" tabindex="0" data-code="import { simpleSqlName } from &quot;sql-assert&quot;;
/**
 * Creates demo tables with initial data for the well-known tables `dept` and `emp`.
 * Alternative table names can be passed to this function. The tables are not re-created
 * if they already exist. However, the rows for the 4 departments and the 14 employees
 * should be reset to their initial state while other rows are left unchanged.
 * Problems are reported via exceptions.
 *
 * @param [deptName=&quot;dept&quot;] name of the dept table.
 * @param [empName=&quot;emp&quot;] name of the emp table.
 * @returns {Promise&lt;void&gt;}.
 */
export async function create(deptName = &quot;dept&quot;, empName = &quot;emp&quot;) {
    const dept = simpleSqlName(deptName);
    const emp = simpleSqlName(empName);
    await session.execute(`
        create table if not exists ${dept} (
           deptno number(2, 0)      not null constraint ${dept}_pk primary key,
           dname  varchar2(14 char) not null,
           loc    varchar2(13 char) not null
        )
    `);
    await session.execute(`
        merge into ${dept} t
        using (values 
                 (10, 'ACCOUNTING', 'NEW YORK'),
                 (20, 'RESEARCH',   'DALLAS'),
                 (30, 'SALES',      'CHICAGO'),
                 (40, 'OPERATIONS', 'BOSTON')
              ) s (deptno, dname, loc)
           on (t.deptno = s.deptno)
         when matched then
              update
                 set t.dname = s.dname,
                     t.loc = s.loc
         when not matched then
              insert (t.deptno, t.dname, t.loc)
              values (s.deptno, s.dname, s.loc)
    `);
    await session.execute(`
        create table if not exists ${emp} (
            empno    number(4, 0)      not null  constraint ${emp}_pk primary key,
            ename    varchar2(10 char) not null,
            job      varchar2(9 char)  not null,
            mgr      number(4, 0)                constraint ${emp}_mgr_fk references ${emp},
            hiredate date              not null,
            sal      number(7, 2),
            comm     number(7, 2),
            deptno   number(2, 0)      not null  constraint ${emp}_deptno_fk references ${dept}
        )
    `);
    await session.execute(`create index if not exists ${emp}_mgr_fk_i on ${emp} (mgr)`);
    await session.execute(`create index if not exists ${emp}_deptno_fk_i on ${emp} (deptno)`);
    await session.execute(`alter table ${emp} disable constraint ${emp}_mgr_fk`);
    await session.execute(`
        merge into ${emp} t
        using (values
                 (7839, 'KING',   'PRESIDENT', null, date '1981-11-17', 5000, null, 10),
                 (7566, 'JONES',  'MANAGER',   7839, date '1981-04-02', 2975, null, 20),
                 (7698, 'BLAKE',  'MANAGER',   7839, date '1981-05-01', 2850, null, 30),
                 (7782, 'CLARK',  'MANAGER',   7839, date '1981-06-09', 2450, null, 10),
                 (7788, 'SCOTT',  'ANALYST',   7566, date '1987-04-19', 3000, null, 20),
                 (7902, 'FORD',   'ANALYST',   7566, date '1981-12-03', 3000, null, 20),
                 (7499, 'ALLEN',  'SALESMAN',  7698, date '1981-02-20', 1600,  300, 30),
                 (7521, 'WARD',   'SALESMAN',  7698, date '1981-02-22', 1250,  500, 30),
                 (7654, 'MARTIN', 'SALESMAN',  7698, date '1981-09-28', 1250, 1400, 30),
                 (7844, 'TURNER', 'SALESMAN',  7698, date '1981-09-08', 1500,    0, 30),
                 (7900, 'JAMES',  'CLERK',     7698, date '1981-12-03',  950, null, 30),
                 (7934, 'MILLER', 'CLERK',     7782, date '1982-01-23', 1300, null, 10),
                 (7369, 'SMITH',  'CLERK',     7902, date '1980-12-17',  800, null, 20),
                 (7876, 'ADAMS',  'CLERK',     7788, date '1987-05-23', 1100, null, 20)                        
              ) s (empno, ename, job, mgr, hiredate, sal, comm, deptno)
           on (t.empno = s.empno)
         when matched then
              update
                 set t.ename = s.ename,
                     t.job = s.job,
                     t.mgr = s.mgr,
                     t.hiredate = s.hiredate,
                     t.sal = s.sal,
                     t.comm = s.comm,
                     t.deptno = s.deptno
         when not matched then
              insert (t.empno, t.ename, t.job, t.mgr, t.hiredate, t.sal, t.comm, t.deptno)
              values (s.empno, s.ename, s.job, s.mgr, s.hiredate, s.sal, s.comm, s.deptno)
    `);
    await session.execute(`alter table ${emp} enable constraint ${emp}_mgr_fk`);
}
//# sourceMappingURL=demotab.js.map" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">simpleSqlName</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;sql-assert&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Creates demo tables with initial data for the well-known tables `dept` and `emp`.</span></span>
<span class="line"><span style="color: #6A9955"> * Alternative table names can be passed to this function. The tables are not re-created</span></span>
<span class="line"><span style="color: #6A9955"> * if they already exist. However, the rows for the 4 departments and the 14 employees</span></span>
<span class="line"><span style="color: #6A9955"> * should be reset to their initial state while other rows are left unchanged.</span></span>
<span class="line"><span style="color: #6A9955"> * Problems are reported via exceptions.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@param</span><span style="color: #6A9955"> [deptName=&quot;dept&quot;] name of the dept table.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@param</span><span style="color: #6A9955"> [empName=&quot;emp&quot;] name of the emp table.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@returns</span><span style="color: #6A9955"> </span><span style="color: #4EC9B0">{Promise&lt;void&gt;}</span><span style="color: #6A9955">.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line cbp-line-highlight"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">create</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">deptName</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;dept&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">empName</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;emp&quot;</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">dept</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">simpleSqlName</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">deptName</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">emp</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">simpleSqlName</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">empName</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">        create table if not exists </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">dept</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> (</span></span>
<span class="line"><span style="color: #CE9178">           deptno number(2, 0)      not null constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">dept</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_pk primary key,</span></span>
<span class="line"><span style="color: #CE9178">           dname  varchar2(14 char) not null,</span></span>
<span class="line"><span style="color: #CE9178">           loc    varchar2(13 char) not null</span></span>
<span class="line"><span style="color: #CE9178">        )</span></span>
<span class="line"><span style="color: #CE9178">    `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">        merge into </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">dept</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> t</span></span>
<span class="line"><span style="color: #CE9178">        using (values </span></span>
<span class="line"><span style="color: #CE9178">                 (10, &#39;ACCOUNTING&#39;, &#39;NEW YORK&#39;),</span></span>
<span class="line"><span style="color: #CE9178">                 (20, &#39;RESEARCH&#39;,   &#39;DALLAS&#39;),</span></span>
<span class="line"><span style="color: #CE9178">                 (30, &#39;SALES&#39;,      &#39;CHICAGO&#39;),</span></span>
<span class="line"><span style="color: #CE9178">                 (40, &#39;OPERATIONS&#39;, &#39;BOSTON&#39;)</span></span>
<span class="line"><span style="color: #CE9178">              ) s (deptno, dname, loc)</span></span>
<span class="line"><span style="color: #CE9178">           on (t.deptno = s.deptno)</span></span>
<span class="line"><span style="color: #CE9178">         when matched then</span></span>
<span class="line"><span style="color: #CE9178">              update</span></span>
<span class="line"><span style="color: #CE9178">                 set t.dname = s.dname,</span></span>
<span class="line"><span style="color: #CE9178">                     t.loc = s.loc</span></span>
<span class="line"><span style="color: #CE9178">         when not matched then</span></span>
<span class="line"><span style="color: #CE9178">              insert (t.deptno, t.dname, t.loc)</span></span>
<span class="line"><span style="color: #CE9178">              values (s.deptno, s.dname, s.loc)</span></span>
<span class="line"><span style="color: #CE9178">    `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">        create table if not exists </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> (</span></span>
<span class="line"><span style="color: #CE9178">            empno    number(4, 0)      not null  constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_pk primary key,</span></span>
<span class="line"><span style="color: #CE9178">            ename    varchar2(10 char) not null,</span></span>
<span class="line"><span style="color: #CE9178">            job      varchar2(9 char)  not null,</span></span>
<span class="line"><span style="color: #CE9178">            mgr      number(4, 0)                constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_mgr_fk references </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">,</span></span>
<span class="line"><span style="color: #CE9178">            hiredate date              not null,</span></span>
<span class="line"><span style="color: #CE9178">            sal      number(7, 2),</span></span>
<span class="line"><span style="color: #CE9178">            comm     number(7, 2),</span></span>
<span class="line"><span style="color: #CE9178">            deptno   number(2, 0)      not null  constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_deptno_fk references </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">dept</span><span style="color: #569CD6">}</span></span>
<span class="line"><span style="color: #CE9178">        )</span></span>
<span class="line"><span style="color: #CE9178">    `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`create index if not exists </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_mgr_fk_i on </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> (mgr)`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`create index if not exists </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_deptno_fk_i on </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> (deptno)`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`alter table </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> disable constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_mgr_fk`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">        merge into </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> t</span></span>
<span class="line"><span style="color: #CE9178">        using (values</span></span>
<span class="line"><span style="color: #CE9178">                 (7839, &#39;KING&#39;,   &#39;PRESIDENT&#39;, null, date &#39;1981-11-17&#39;, 5000, null, 10),</span></span>
<span class="line"><span style="color: #CE9178">                 (7566, &#39;JONES&#39;,  &#39;MANAGER&#39;,   7839, date &#39;1981-04-02&#39;, 2975, null, 20),</span></span>
<span class="line"><span style="color: #CE9178">                 (7698, &#39;BLAKE&#39;,  &#39;MANAGER&#39;,   7839, date &#39;1981-05-01&#39;, 2850, null, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7782, &#39;CLARK&#39;,  &#39;MANAGER&#39;,   7839, date &#39;1981-06-09&#39;, 2450, null, 10),</span></span>
<span class="line"><span style="color: #CE9178">                 (7788, &#39;SCOTT&#39;,  &#39;ANALYST&#39;,   7566, date &#39;1987-04-19&#39;, 3000, null, 20),</span></span>
<span class="line"><span style="color: #CE9178">                 (7902, &#39;FORD&#39;,   &#39;ANALYST&#39;,   7566, date &#39;1981-12-03&#39;, 3000, null, 20),</span></span>
<span class="line"><span style="color: #CE9178">                 (7499, &#39;ALLEN&#39;,  &#39;SALESMAN&#39;,  7698, date &#39;1981-02-20&#39;, 1600,  300, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7521, &#39;WARD&#39;,   &#39;SALESMAN&#39;,  7698, date &#39;1981-02-22&#39;, 1250,  500, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7654, &#39;MARTIN&#39;, &#39;SALESMAN&#39;,  7698, date &#39;1981-09-28&#39;, 1250, 1400, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7844, &#39;TURNER&#39;, &#39;SALESMAN&#39;,  7698, date &#39;1981-09-08&#39;, 1500,    0, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7900, &#39;JAMES&#39;,  &#39;CLERK&#39;,     7698, date &#39;1981-12-03&#39;,  950, null, 30),</span></span>
<span class="line"><span style="color: #CE9178">                 (7934, &#39;MILLER&#39;, &#39;CLERK&#39;,     7782, date &#39;1982-01-23&#39;, 1300, null, 10),</span></span>
<span class="line"><span style="color: #CE9178">                 (7369, &#39;SMITH&#39;,  &#39;CLERK&#39;,     7902, date &#39;1980-12-17&#39;,  800, null, 20),</span></span>
<span class="line"><span style="color: #CE9178">                 (7876, &#39;ADAMS&#39;,  &#39;CLERK&#39;,     7788, date &#39;1987-05-23&#39;, 1100, null, 20)                        </span></span>
<span class="line"><span style="color: #CE9178">              ) s (empno, ename, job, mgr, hiredate, sal, comm, deptno)</span></span>
<span class="line"><span style="color: #CE9178">           on (t.empno = s.empno)</span></span>
<span class="line"><span style="color: #CE9178">         when matched then</span></span>
<span class="line"><span style="color: #CE9178">              update</span></span>
<span class="line"><span style="color: #CE9178">                 set t.ename = s.ename,</span></span>
<span class="line"><span style="color: #CE9178">                     t.job = s.job,</span></span>
<span class="line"><span style="color: #CE9178">                     t.mgr = s.mgr,</span></span>
<span class="line"><span style="color: #CE9178">                     t.hiredate = s.hiredate,</span></span>
<span class="line"><span style="color: #CE9178">                     t.sal = s.sal,</span></span>
<span class="line"><span style="color: #CE9178">                     t.comm = s.comm,</span></span>
<span class="line"><span style="color: #CE9178">                     t.deptno = s.deptno</span></span>
<span class="line"><span style="color: #CE9178">         when not matched then</span></span>
<span class="line"><span style="color: #CE9178">              insert (t.empno, t.ename, t.job, t.mgr, t.hiredate, t.sal, t.comm, t.deptno)</span></span>
<span class="line"><span style="color: #CE9178">              values (s.empno, s.ename, s.job, s.mgr, s.hiredate, s.sal, s.comm, s.deptno)</span></span>
<span class="line"><span style="color: #CE9178">    `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`alter table </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> enable constraint </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">emp</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_mgr_fk`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line cbp-line-highlight"><span style="color: #6A9955">//# sourceMappingURL=demotab.js.map</span></span></code></pre></div>



<p>As you see on line 13, all type definitions are gone including the <code>oracledb</code> import. So, the JavaScript file has no dependencies on a database driver. As a result, we can use <a href="https://www.npmjs.com/package/node-oracledb">node-oracledb</a> outside the database and <a href="https://www.npmjs.com/package/mle-js-oracledb">mle-js-oracledb</a> within the database.</p>



<p>Besides the removed types, the file looks very much like its TypeScript pendant.</p>



<p>On line 89 there&#8217;s a comment mentioning a map file. This map file was also generated by the TypeScript compiler. It improves the developer experience during a debugging session so that the developer can work on the original TypeScript files. The JavaScript files are only used behind the scenes. </p>



<h2 class="wp-block-heading" id="testing">Testing</h2>



<h3 class="wp-block-heading">1. Framework</h3>



<p>I decided to use <a href="https://vitest.dev/">Vitest</a> for this project. Why not <a href="https://jestjs.io/">Jest</a> or <a href="https://mochajs.org/">Mocha</a>? </p>



<p>I tried Mocha with a plain JavaScript project. It felt a bit outdated and I did not like the fact that I had to opt-in for an assertion library. IMO this should be part of the framework. It&#8217;s too much freedom. Too many unnecessary variants when googling for solutions.</p>



<p>Jest is a full-fletched and very popular testing framework. It would have been a natural choice. However, I stumbled over Vitest with a Jest-compatible API which claims to be faster and easier to use with TypeScript. So I thought to give it a try.</p>



<h3 class="wp-block-heading">2. Database Configuration</h3>



<p>We create a file named <code>dbconfig.ts</code> in a new folder <code>test</code> with the following content:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">test/dbconfig.ts</span><span role="button" tabindex="0" data-code="import oracledb from &quot;oracledb&quot;;

let sysSession: oracledb.Connection;
export let demotabSession: oracledb.Connection;
export let otheruserSession: oracledb.Connection;

const connectString = &quot;192.168.1.8:51007/freepdb1&quot;;

const sysConfig: oracledb.ConnectionAttributes = {
    user: &quot;sys&quot;,
    password: &quot;oracle&quot;,
    connectString: connectString,
    privilege: oracledb.SYSDBA
};

export const demotabConfig: oracledb.ConnectionAttributes = {
    user: &quot;demotab&quot;,
    password: &quot;demotab&quot;,
    connectString: connectString
};

export const otheruserConfig: oracledb.ConnectionAttributes = {
    user: &quot;otheruser&quot;,
    password: &quot;otheruser&quot;,
    connectString: connectString
};

export async function createSessions(): Promise&lt;void&gt; {
    sysSession = await oracledb.getConnection(sysConfig);
    await createUser(demotabConfig);
    await createUser(otheruserConfig);
    await sysSession.execute(&quot;grant create public synonym to demotab&quot;);
    await sysSession.execute(&quot;grant execute on javascript to public&quot;);
    sysSession.close();
    demotabSession = await oracledb.getConnection(demotabConfig);
    otheruserSession = await oracledb.getConnection(otheruserConfig);
}

async function createUser(config: oracledb.ConnectionAttributes): Promise&lt;void&gt; {
    await sysSession.execute(`drop user if exists ${config.user} cascade`);
    await sysSession.execute(`
        create user ${config.user} identified by ${config.password}
           default tablespace users
           temporary tablespace temp
           quota 1m on users
    `);
    await sysSession.execute(`grant db_developer_role to ${config.user}`);
}

export async function closeSessions(): Promise&lt;void&gt; {
    await demotabSession?.close();
    await otheruserSession?.close();
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">oracledb</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;oracledb&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sysSession</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Connection</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Connection</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">otheruserSession</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Connection</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line cbp-line-highlight"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">connectString</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;192.168.1.8:51007/freepdb1&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">sysConfig</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">ConnectionAttributes</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">user:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;sys&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">password:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;oracle&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">connectString:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">connectString</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">privilege:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #4FC1FF">SYSDBA</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">demotabConfig</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">ConnectionAttributes</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">user:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;demotab&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">password:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;demotab&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">connectString:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">connectString</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">otheruserConfig</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">ConnectionAttributes</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">user:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;otheruser&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">password:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;otheruser&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">connectString:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">connectString</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">createSessions</span><span style="color: #D4D4D4">(): </span><span style="color: #4EC9B0">Promise</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4">&gt; {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">sysSession</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getConnection</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">sysConfig</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">createUser</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">demotabConfig</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">createUser</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">otheruserConfig</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sysSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;grant create public synonym to demotab&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sysSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;grant execute on javascript to public&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">sysSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">close</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getConnection</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">demotabConfig</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">otheruserSession</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getConnection</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">otheruserConfig</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">createUser</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">config</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">ConnectionAttributes</span><span style="color: #D4D4D4">): </span><span style="color: #4EC9B0">Promise</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4">&gt; {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sysSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`drop user if exists </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">config</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">user</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> cascade`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sysSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">        create user </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">config</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">user</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> identified by </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">config</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">password</span><span style="color: #569CD6">}</span></span>
<span class="line"><span style="color: #CE9178">           default tablespace users</span></span>
<span class="line"><span style="color: #CE9178">           temporary tablespace temp</span></span>
<span class="line"><span style="color: #CE9178">           quota 1m on users</span></span>
<span class="line"><span style="color: #CE9178">    `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sysSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`grant db_developer_role to </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">config</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">user</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">closeSessions</span><span style="color: #D4D4D4">(): </span><span style="color: #4EC9B0">Promise</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4">&gt; {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">?.</span><span style="color: #DCDCAA">close</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">otheruserSession</span><span style="color: #D4D4D4">?.</span><span style="color: #DCDCAA">close</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p>To make the configuration work in your environment, you need to change the lines 7 and 11. The connect string and the password of the Oracle user <code>sys</code>. Everything else could be left &#8220;as is&#8221;.</p>



<p>This module creates the database users <code>demotab</code> and <code>otheruser</code> and manages database sessions.</p>



<h3 class="wp-block-heading">3. Test TypeScript Module Outside of the Database</h3>



<p>We create a file named <code>demotab.test.ts</code> in the folder <code>test</code> with the following content:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(3 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">test/demotab.test.ts</span><span role="button" tabindex="0" data-code="import { beforeAll, afterAll, describe, it, expect } from &quot;vitest&quot;;
import { createSessions, closeSessions, demotabSession } from &quot;./dbconfig&quot;;
import { create } from &quot;../src/demotab&quot;;

describe(&quot;TypeScript outside of the database&quot;, () =&gt; {
    const timeout = 10000;

    beforeAll(async () =&gt; {
        await createSessions();
        global.session = demotabSession;
    });

    describe(&quot;invalid input causing 'Invalid SQL name.'&quot;, () =&gt; {
        // error is thrown in JavaScript (no ORA-04161 outside of the database)
        it(&quot;should throw an error with invalid deptName&quot;, () =&gt; {
            expect(async () =&gt; await create(&quot;a-dept-table&quot;)).rejects.toThrowError(/invalid sql/i);
        });
        it(&quot;should throw an error with invalid empName&quot;, () =&gt; {
            expect(async () =&gt; await create(&quot;dept&quot;, &quot;a-emp-table&quot;)).rejects.toThrowError(/invalid sql/i);
        });
    });

    describe(&quot;invalid input causing 'ORA-00911: _: invalid character after &lt;identifier&gt;'&quot;, () =&gt; {
        // error is thrown by the Oracle Database while trying to execute a SQL statement
        it(&quot;should throw an error with quoted deptName&quot;, () =&gt; {
            expect(async () =&gt; await create('&quot;dept&quot;')).rejects.toThrowError(/ORA-00911.+invalid/);
        });
        it(&quot;should throw an error with quoted empName&quot;, () =&gt; {
            expect(async () =&gt; await create(&quot;dept&quot;, '&quot;emp&quot;')).rejects.toThrowError(/ORA-00911.+invalid/);
        });
    });

    describe(
        &quot;valid input&quot;,
        () =&gt; {
            it(&quot;should create 'dept' and 'emp' without parameters)&quot;, async () =&gt; {
                await create();
                const dept = await demotabSession.execute(&quot;select * from dept order by deptno&quot;);
                expect(dept.rows).toEqual([
                    [10, &quot;ACCOUNTING&quot;, &quot;NEW YORK&quot;],
                    [20, &quot;RESEARCH&quot;, &quot;DALLAS&quot;],
                    [30, &quot;SALES&quot;, &quot;CHICAGO&quot;],
                    [40, &quot;OPERATIONS&quot;, &quot;BOSTON&quot;]
                ]);
                const emp = await demotabSession.execute(`
                    select empno, ename, job, mgr, to_char(hiredate,'YYYY-MM-DD'), sal, comm, deptno 
                    from emp 
                    order by empno
                `);
                expect(emp.rows).toEqual([
                    [7369, &quot;SMITH&quot;, &quot;CLERK&quot;, 7902, &quot;1980-12-17&quot;, 800, null, 20],
                    [7499, &quot;ALLEN&quot;, &quot;SALESMAN&quot;, 7698, &quot;1981-02-20&quot;, 1600, 300, 30],
                    [7521, &quot;WARD&quot;, &quot;SALESMAN&quot;, 7698, &quot;1981-02-22&quot;, 1250, 500, 30],
                    [7566, &quot;JONES&quot;, &quot;MANAGER&quot;, 7839, &quot;1981-04-02&quot;, 2975, null, 20],
                    [7654, &quot;MARTIN&quot;, &quot;SALESMAN&quot;, 7698, &quot;1981-09-28&quot;, 1250, 1400, 30],
                    [7698, &quot;BLAKE&quot;, &quot;MANAGER&quot;, 7839, &quot;1981-05-01&quot;, 2850, null, 30],
                    [7782, &quot;CLARK&quot;, &quot;MANAGER&quot;, 7839, &quot;1981-06-09&quot;, 2450, null, 10],
                    [7788, &quot;SCOTT&quot;, &quot;ANALYST&quot;, 7566, &quot;1987-04-19&quot;, 3000, null, 20],
                    [7839, &quot;KING&quot;, &quot;PRESIDENT&quot;, null, &quot;1981-11-17&quot;, 5000, null, 10],
                    [7844, &quot;TURNER&quot;, &quot;SALESMAN&quot;, 7698, &quot;1981-09-08&quot;, 1500, 0, 30],
                    [7876, &quot;ADAMS&quot;, &quot;CLERK&quot;, 7788, &quot;1987-05-23&quot;, 1100, null, 20],
                    [7900, &quot;JAMES&quot;, &quot;CLERK&quot;, 7698, &quot;1981-12-03&quot;, 950, null, 30],
                    [7902, &quot;FORD&quot;, &quot;ANALYST&quot;, 7566, &quot;1981-12-03&quot;, 3000, null, 20],
                    [7934, &quot;MILLER&quot;, &quot;CLERK&quot;, 7782, &quot;1982-01-23&quot;, 1300, null, 10]
                ]);
            });
            it(&quot;should create 'dept2' and 'emp2' with both parameters)&quot;, async () =&gt; {
                await create(&quot;dept2&quot;, &quot;emp2&quot;);
                const dept = await demotabSession.execute(&quot;select * from dept minus select * from dept2&quot;);
                expect(dept.rows).toEqual([]);
                const emp = await demotabSession.execute(&quot;select * from emp minus select * from emp2&quot;);
                expect(emp.rows).toEqual([]);
            });
            it(&quot;should fix data in 'dept' and 'emp' after changing data and using default parameters&quot;, async () =&gt; {
                await demotabSession.execute(`
                    begin
                        delete dept where deptno = 40;
                        update dept set loc = initcap(loc);
                        insert into dept(deptno, dname, loc) values(50, 'utPLSQL', 'Winterthur');
                        delete emp where empno = 7876;
                        update emp set sal = sal * 2;
                        insert into emp(empno, ename, job, hiredate, sal, deptno)
                        values (4242, 'Salvisberg', 'Tester', date '2000-01-01', 9999, '50');
                    end;
                `);
                await create();
                const dept = await demotabSession.execute(&quot;select * from dept minus select * from dept2&quot;);
                expect(dept.rows).toEqual([[50, &quot;utPLSQL&quot;, &quot;Winterthur&quot;]]);
                const emp = await demotabSession.execute(`
                    select empno, ename, job, mgr, to_char(hiredate,'YYYY-MM-DD'), sal, comm, deptno 
                    from emp 
                    minus 
                    select empno, ename, job, mgr, to_char(hiredate,'YYYY-MM-DD'), sal, comm, deptno
                    from emp2
                `);
                expect(emp.rows).toEqual([[4242, &quot;Salvisberg&quot;, &quot;Tester&quot;, null, &quot;2000-01-01&quot;, 9999, null, 50]]);
            });
        },
        timeout
    );

    afterAll(async () =&gt; {
        await closeSessions();
    });
});" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">beforeAll</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">afterAll</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">describe</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">it</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">expect</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;vitest&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">createSessions</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">closeSessions</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;./dbconfig&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">create</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;../src/demotab&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">describe</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;TypeScript outside of the database&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">timeout</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">10000</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">beforeAll</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">createSessions</span><span style="color: #D4D4D4">();</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">global</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">session</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">describe</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;invalid input causing &#39;Invalid SQL name.&#39;&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// error is thrown in JavaScript (no ORA-04161 outside of the database)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should throw an error with invalid deptName&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">create</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;a-dept-table&quot;</span><span style="color: #D4D4D4">)).</span><span style="color: #9CDCFE">rejects</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">toThrowError</span><span style="color: #D4D4D4">(</span><span style="color: #D16969">/invalid sql/</span><span style="color: #569CD6">i</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should throw an error with invalid empName&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">create</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;dept&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;a-emp-table&quot;</span><span style="color: #D4D4D4">)).</span><span style="color: #9CDCFE">rejects</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">toThrowError</span><span style="color: #D4D4D4">(</span><span style="color: #D16969">/invalid sql/</span><span style="color: #569CD6">i</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">describe</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;invalid input causing &#39;ORA-00911: _: invalid character after &lt;identifier&gt;&#39;&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// error is thrown by the Oracle Database while trying to execute a SQL statement</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should throw an error with quoted deptName&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">create</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;&quot;dept&quot;&#39;</span><span style="color: #D4D4D4">)).</span><span style="color: #9CDCFE">rejects</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">toThrowError</span><span style="color: #D4D4D4">(</span><span style="color: #D16969">/ORA-00911.</span><span style="color: #D7BA7D">+</span><span style="color: #D16969">invalid/</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should throw an error with quoted empName&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">create</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;dept&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;&quot;emp&quot;&#39;</span><span style="color: #D4D4D4">)).</span><span style="color: #9CDCFE">rejects</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">toThrowError</span><span style="color: #D4D4D4">(</span><span style="color: #D16969">/ORA-00911.</span><span style="color: #D7BA7D">+</span><span style="color: #D16969">invalid/</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">describe</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;valid input&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should create &#39;dept&#39; and &#39;emp&#39; without parameters)&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">create</span><span style="color: #D4D4D4">();</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">dept</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;select * from dept order by deptno&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">dept</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toEqual</span><span style="color: #D4D4D4">([</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;ACCOUNTING&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;NEW YORK&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;RESEARCH&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;DALLAS&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;SALES&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;CHICAGO&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">40</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;OPERATIONS&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;BOSTON&quot;</span><span style="color: #D4D4D4">]</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                ]);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">emp</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">                    select empno, ename, job, mgr, to_char(hiredate,&#39;YYYY-MM-DD&#39;), sal, comm, deptno </span></span>
<span class="line"><span style="color: #CE9178">                    from emp </span></span>
<span class="line"><span style="color: #CE9178">                    order by empno</span></span>
<span class="line"><span style="color: #CE9178">                `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">emp</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toEqual</span><span style="color: #D4D4D4">([</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7369</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;SMITH&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;CLERK&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7902</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1980-12-17&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">800</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7499</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;ALLEN&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;SALESMAN&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1981-02-20&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1600</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">300</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7521</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;WARD&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;SALESMAN&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1981-02-22&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1250</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">500</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7566</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;JONES&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;MANAGER&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7839</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1981-04-02&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2975</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7654</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;MARTIN&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;SALESMAN&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1981-09-28&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1250</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1400</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;BLAKE&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;MANAGER&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7839</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1981-05-01&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2850</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7782</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;CLARK&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;MANAGER&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7839</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1981-06-09&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2450</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7788</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;SCOTT&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;ANALYST&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7566</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1987-04-19&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">3000</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7839</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;KING&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;PRESIDENT&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1981-11-17&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">5000</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7844</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;TURNER&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;SALESMAN&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1981-09-08&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1500</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7876</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;ADAMS&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;CLERK&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7788</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1987-05-23&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1100</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7900</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;JAMES&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;CLERK&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7698</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1981-12-03&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">950</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">30</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7902</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;FORD&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;ANALYST&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7566</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1981-12-03&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">3000</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                    [</span><span style="color: #B5CEA8">7934</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;MILLER&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;CLERK&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">7782</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;1982-01-23&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1300</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">                ]);</span></span>
<span class="line"><span style="color: #D4D4D4">            });</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should create &#39;dept2&#39; and &#39;emp2&#39; with both parameters)&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">create</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;dept2&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;emp2&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">dept</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;select * from dept minus select * from dept2&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">dept</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toEqual</span><span style="color: #D4D4D4">([]);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">emp</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;select * from emp minus select * from emp2&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">emp</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toEqual</span><span style="color: #D4D4D4">([]);</span></span>
<span class="line"><span style="color: #D4D4D4">            });</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should fix data in &#39;dept&#39; and &#39;emp&#39; after changing data and using default parameters&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">                    begin</span></span>
<span class="line"><span style="color: #CE9178">                        delete dept where deptno = 40;</span></span>
<span class="line"><span style="color: #CE9178">                        update dept set loc = initcap(loc);</span></span>
<span class="line"><span style="color: #CE9178">                        insert into dept(deptno, dname, loc) values(50, &#39;utPLSQL&#39;, &#39;Winterthur&#39;);</span></span>
<span class="line"><span style="color: #CE9178">                        delete emp where empno = 7876;</span></span>
<span class="line"><span style="color: #CE9178">                        update emp set sal = sal * 2;</span></span>
<span class="line"><span style="color: #CE9178">                        insert into emp(empno, ename, job, hiredate, sal, deptno)</span></span>
<span class="line"><span style="color: #CE9178">                        values (4242, &#39;Salvisberg&#39;, &#39;Tester&#39;, date &#39;2000-01-01&#39;, 9999, &#39;50&#39;);</span></span>
<span class="line"><span style="color: #CE9178">                    end;</span></span>
<span class="line"><span style="color: #CE9178">                `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">create</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">dept</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;select * from dept minus select * from dept2&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">dept</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toEqual</span><span style="color: #D4D4D4">([[</span><span style="color: #B5CEA8">50</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;utPLSQL&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;Winterthur&quot;</span><span style="color: #D4D4D4">]]);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">emp</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">                    select empno, ename, job, mgr, to_char(hiredate,&#39;YYYY-MM-DD&#39;), sal, comm, deptno </span></span>
<span class="line"><span style="color: #CE9178">                    from emp </span></span>
<span class="line"><span style="color: #CE9178">                    minus </span></span>
<span class="line"><span style="color: #CE9178">                    select empno, ename, job, mgr, to_char(hiredate,&#39;YYYY-MM-DD&#39;), sal, comm, deptno</span></span>
<span class="line"><span style="color: #CE9178">                    from emp2</span></span>
<span class="line"><span style="color: #CE9178">                `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">emp</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toEqual</span><span style="color: #D4D4D4">([[</span><span style="color: #B5CEA8">4242</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;Salvisberg&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;Tester&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;2000-01-01&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">9999</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">50</span><span style="color: #D4D4D4">]]);</span></span>
<span class="line"><span style="color: #D4D4D4">            });</span></span>
<span class="line"><span style="color: #D4D4D4">        },</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">timeout</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">afterAll</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">closeSessions</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span></code></pre></div>



<h5 class="wp-block-heading">Test Suite</h5>



<p>The main test suite starts on line 5 and ends on line 105. The Vitest configuration enforces serial execution. As a result, the tests are executed according to their order in the file.</p>



<h5 class="wp-block-heading">Global <code>session</code> Variable</h5>



<p>On line 11 we initialize the global variable <code>session</code> with a database session to the Oracle user <code>demotab</code>. We use this global variable in the function <code>create</code>. See <code>demotab.ts</code>.</p>



<h5 class="wp-block-heading">Test Case &#8211; Assertions</h5>



<p>Look at line 36. It looks similar to the English sentence &#8220;it should create &#8216;dept&#8217; and &#8217;emp&#8217; without parameters&#8221;. That&#8217;s why the testing framework provides the alias <code>it</code> for the function <code>test</code>. This notation leads to test names that are easier to understand in the code and other contexts where the <code>it</code> is not shown, during test execution, for example.</p>



<p>On line 37 we call the <code>create</code> function without parameters. We read the content of the table <code>dept</code> into a variable <code>dept</code> on line 38. And finally on lines 39 to 44 we assert if the 4 expected rows are stored in the table <code>dept</code>.  </p>



<p>A difference between the expected and actual results would be reported like this. I changed the expected output in the code to produce this result:</p>



<figure class="wp-block-image size-large"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/image.png"><img loading="lazy" decoding="async" width="1024" height="649" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-1024x649.png" alt="Failed test: example of how difference between expected and actual results are visualized in VS Code's terminal window" class="wp-image-12828" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-1024x649.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-300x190.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-768x487.png 768w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-118x75.png 118w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-480x304.png 480w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image.png 1080w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<h3 class="wp-block-heading">4. Run All Tests</h3>



<p>To run all tests open a terminal window in VS Code and execute the following command:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="npm run test" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">run</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">test</span></span></code></pre></div>



<p>This will produce an output similar to this:</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-1.png"><img loading="lazy" decoding="async" width="866" height="470" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-1.png" alt="Console output of &quot;npm run test&quot; for demotab.test.ts" class="wp-image-12830" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-1.png 866w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-1-300x163.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-1-768x417.png 768w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-1-138x75.png 138w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-1-480x261.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:866px) 100vw, 866px" /></a></figure>



<h3 class="wp-block-heading">5. Build with Test Coverage</h3>



<p>Open a terminal window in VS Code and execute the following to format, lint and compile the code, and run all tests with a code coverage report:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="npm run build" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">run</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">build</span></span></code></pre></div>



<p>This will produce an output similar to this:</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-3.png"><img loading="lazy" decoding="async" width="881" height="910" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-3.png" alt="Console output of &quot;npm run build&quot;" class="wp-image-12835" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-3.png 881w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-3-290x300.png 290w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-3-768x793.png 768w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-3-73x75.png 73w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-3-480x496.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:881px) 100vw, 881px" /></a></figure>



<h2 class="wp-block-heading" id="deployment">Deployment</h2>



<p>We tested the module successfully outside of the database. Now it&#8217;s time to deploy it into the database. For that, we create the SQL script <code>deploy.sql</code> in the root folder of our project with the following content:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">deploy.sql</span><span role="button" tabindex="0" data-code="set define off
script
var url = new java.net.URL(&quot;https://esm.run/sql-assert@1.0.3&quot;);
var content = new java.lang.String(url.openStream().readAllBytes(),
                  java.nio.charset.StandardCharsets.UTF_8);
var script = 'create or replace mle module sql_assert_mod '
               + 'language javascript as ' + '\n'
               + content + &quot;\n&quot;
               + '/' + &quot;\n&quot;;
sqlcl.setStmt(script);
sqlcl.run();
/

script
var path = java.nio.file.Path.of(&quot;./esm/demotab.js&quot;);
var content = java.nio.file.Files.readString(path);
var script = 'create or replace mle module demotab_mod '
               + 'language javascript as ' + '\n'
               + content + &quot;\n&quot;
               + '/' + &quot;\n&quot;;
sqlcl.setStmt(script);
sqlcl.run();
/

create or replace mle env demotab_env
   imports('sql-assert' module sql_assert_mod)
   language options 'js.strict=true, js.console=false, js.polyglot-builtin=true';

create or replace package demo authid current_user is
   procedure create_tabs as 
   mle module demotab_mod env demotab_env signature 'create()';

   procedure create_tabs(
      in_dept_table_name in varchar2
   ) as mle module demotab_mod env demotab_env signature 'create(string)';

   procedure create_tabs(
      in_dept_table_name in varchar2,
      in_emp_table_name  in varchar2
   ) as mle module demotab_mod env demotab_env signature 'create(string, string)';
end demo;
/

-- required &quot;execute on javascript&quot; was granted to public in test
grant execute on demo to public;
create or replace public synonym demo for demotab.demo;

exit" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">set</span><span style="color: #D4D4D4"> define </span><span style="color: #569CD6">off</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">script</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">var </span><span style="color: #569CD6">url</span><span style="color: #D4D4D4"> = new java.net.</span><span style="color: #569CD6">URL</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;https://esm.run/sql-assert@1.0.3&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">var content = new java.lang.String(url.openStream().readAllBytes(),</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                  java.nio.charset.StandardCharsets.UTF_8);</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">var script = </span><span style="color: #CE9178">&#39;create or replace mle module sql_assert_mod &#39;</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">               + </span><span style="color: #CE9178">&#39;language javascript as &#39;</span><span style="color: #D4D4D4"> + </span><span style="color: #CE9178">&#39;\n&#39;</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">               + content + </span><span style="color: #CE9178">&quot;\n&quot;</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">               + </span><span style="color: #CE9178">&#39;/&#39;</span><span style="color: #D4D4D4"> + </span><span style="color: #CE9178">&quot;\n&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">sqlcl.setStmt(script);</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">sqlcl.run();</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">script</span></span>
<span class="line"><span style="color: #D4D4D4">var </span><span style="color: #569CD6">path</span><span style="color: #D4D4D4"> = java.nio.file.Path.of(</span><span style="color: #CE9178">&quot;./esm/demotab.js&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">var content = java.nio.file.Files.readString(</span><span style="color: #569CD6">path</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">var script = </span><span style="color: #CE9178">&#39;create or replace mle module demotab_mod &#39;</span></span>
<span class="line"><span style="color: #D4D4D4">               + </span><span style="color: #CE9178">&#39;language javascript as &#39;</span><span style="color: #D4D4D4"> + </span><span style="color: #CE9178">&#39;\n&#39;</span></span>
<span class="line"><span style="color: #D4D4D4">               + content + </span><span style="color: #CE9178">&quot;\n&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">               + </span><span style="color: #CE9178">&#39;/&#39;</span><span style="color: #D4D4D4"> + </span><span style="color: #CE9178">&quot;\n&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">sqlcl.setStmt(script);</span></span>
<span class="line"><span style="color: #D4D4D4">sqlcl.run();</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">create</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">replace</span><span style="color: #D4D4D4"> mle env demotab_env</span></span>
<span class="line"><span style="color: #D4D4D4">   imports(</span><span style="color: #CE9178">&#39;sql-assert&#39;</span><span style="color: #D4D4D4"> module sql_assert_mod)</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">language</span><span style="color: #D4D4D4"> options </span><span style="color: #CE9178">&#39;js.strict=true, js.console=false, js.polyglot-builtin=true&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">create</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">replace</span><span style="color: #D4D4D4"> package demo authid current_user </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">procedure</span><span style="color: #D4D4D4"> create_tabs </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">   mle module demotab_mod env demotab_env </span><span style="color: #569CD6">signature</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;create()&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">procedure</span><span style="color: #D4D4D4"> create_tabs(</span></span>
<span class="line"><span style="color: #D4D4D4">      in_dept_table_name </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">varchar2</span></span>
<span class="line"><span style="color: #D4D4D4">   ) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> mle module demotab_mod env demotab_env </span><span style="color: #569CD6">signature</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;create(string)&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">procedure</span><span style="color: #D4D4D4"> create_tabs(</span></span>
<span class="line"><span style="color: #D4D4D4">      in_dept_table_name </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">varchar2</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      in_emp_table_name  </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">varchar2</span></span>
<span class="line"><span style="color: #D4D4D4">   ) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> mle module demotab_mod env demotab_env </span><span style="color: #569CD6">signature</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;create(string, string)&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">end</span><span style="color: #D4D4D4"> demo;</span></span>
<span class="line"><span style="color: #D4D4D4">/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">-- required &quot;execute on javascript&quot; was granted to public in test</span></span>
<span class="line"><span style="color: #569CD6">grant</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">execute</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">on</span><span style="color: #D4D4D4"> demo </span><span style="color: #569CD6">to</span><span style="color: #D4D4D4"> public;</span></span>
<span class="line"><span style="color: #569CD6">create</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">replace</span><span style="color: #D4D4D4"> public </span><span style="color: #569CD6">synonym</span><span style="color: #D4D4D4"> demo </span><span style="color: #569CD6">for</span><span style="color: #D4D4D4"> demotab.demo;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">exit</span></span></code></pre></div>



<h5 class="wp-block-heading">npm Module sql-assert (MLE Module <code>sql_assert_mod</code>)</h5>



<p>On lines 2-12, we load version 1.0.3 of the npm module <a href="https://www.npmjs.com/package/sql-assert">sql-assert</a> as MLE module <code>sql_assert_mod</code> into the database. We dynamically build a <code>create or replace mle module</code> statement and execute it with the help of SQLcl&#8217;s script command.</p>



<p>The URL <a href="https://esm.run/sql-assert@1.0.3">https://esm.run/sql-assert@1.0.3</a> provides a minimized file of the npm module. In other words, it is optimized for use in browsers where the modules are loaded over the network at runtime.</p>



<p>Minimized code works in the database, of course. However, it might make it a bit harder to understand the error stack.</p>



<h5 class="wp-block-heading">No Template Literals? </h5>



<p>You might wonder why we do not use  ECMAScript template literals to populate the <code>script</code> variable. The reason is, that SQLcl does not provide a JavaScript engine. It relies on the JDK&#8217;s JavaScript engine. Unfortunately, the Nashorn JavaScript engine is decommissioned in current JDKs. The last JDK with a JavaScript engine is JDK 11, based on ECMAScript 2011 (5.1), which does not support template literals.</p>



<p>The GraalVM JDK is an exception. Versions 17 and 21 come with a current GraalVM JavaScript engine that supports template literals. And this JDK can be used with SQLcl.</p>



<p>However, there is an additional reason to avoid JavaScript features introduced after ECMAScript 2011 and that&#8217;s SQL Developer. You can run the SQL script <code>deploy.sql</code> also in an SQL Developer worksheet. SQL Developer requires a JDK 11. You cannot use a newer JDK in SQL Developer, because you would lose some important features such as Real Time SQL Monitor which requires JavaFX. Another decommissioned component in the JDK. And the GraalVM JDK does not provide JavaFX.</p>



<p>So for compatibility reasons, we have to stick to old JavaScript features available in ECMAScript 2011 when using the script command in SQLcl or SQL Developer.</p>



<h5 class="wp-block-heading">Local Module demotab (MLE Module <code>demotab_mod</code>)</h5>



<p>On lines 14-23, we load the JavaScript MLE module <code>demotab</code> from our local file system into the database. The process is similar to the npm module. The only difference is that we get the module from the local disk and not over the network.</p>



<h5 class="wp-block-heading">MLE Environment <code>demotab_env</code></h5>



<p>On lines 25-27, we create an MLE environment. Besides configuring compiler options, we tell the JavaScript compiler what modules are available and where to find them.</p>



<h5 class="wp-block-heading">PL/SQL Call Interface</h5>



<p>On lines 29-42, we create a PL/SQL package <code>demo</code>. It contains three procedures with call specifications for the function <code>create</code> in the MLE module <code>demotab_mod</code>. Why three procedures and not just one? Because the MLE call specifications do not support default values for parameters. However, we can work around it by providing three procedures. One without parameters, one with a single parameter and another one with two parameters.</p>



<h2 class="wp-block-heading">Test JavaScript MLE Module within the Database</h2>



<p>To test if the deployed code works we create the file <code>mle-demotab.test.ts</code> in the folder <code>test</code> with the following content:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">test/mle-demotab.test.ts</span><span role="button" tabindex="0" data-code="import { beforeAll, afterAll, describe, it, expect, beforeEach } from &quot;vitest&quot;;
import { createSessions, closeSessions, otheruserSession, demotabSession, demotabConfig } from &quot;./dbconfig&quot;;
import oracledb from &quot;oracledb&quot;;
import { exec } from &quot;child_process&quot;;
import util from &quot;node:util&quot;;

describe(&quot;MLE JavaScript module within the database&quot;, () =&gt; {
    const timeout = 15000;

    async function userTables(): Promise&lt;oracledb.Result&lt;unknown&gt;&gt; {
        return await otheruserSession.execute(`
            with
               function num_rows(in_table_name in varchar2) return integer is
                  l_rows integer;
               begin
                  execute immediate 'select count(*) from ' || in_table_name 
                     into l_rows;
                  return l_rows;
               end;
            select table_name, num_rows(table_name) as num_rows
              from user_tables
             order by table_name
        `);
    }

    beforeAll(async () =&gt; {
        await createSessions();
        const execAsync = util.promisify(exec);
        await execAsync(
            `sql -S ${demotabConfig.user}/${demotabConfig.password}@${demotabConfig.connectString} @deploy.sql`
        );
    }, timeout);

    beforeEach(async () =&gt; {
        await otheruserSession.execute(`
            begin
               for r in (select table_name from user_tables) loop
                  execute immediate 'drop table ' 
                     || r.table_name
                     || ' cascade constraints purge';
               end loop;
            end;
        `);
    });

    describe(&quot;deployment&quot;, () =&gt; {
        it(&quot;should have valid database objects in demotab user&quot;, async () =&gt; {
            const mods = await demotabSession.execute(`
                select object_type, object_name, status 
                  from user_objects 
                 order by object_type, object_name
            `);
            expect(mods.rows).toEqual([
                [&quot;MLE ENVIRONMENT&quot;, &quot;DEMOTAB_ENV&quot;, &quot;VALID&quot;],
                [&quot;MLE MODULE&quot;, &quot;DEMOTAB_MOD&quot;, &quot;VALID&quot;],
                [&quot;MLE MODULE&quot;, &quot;SQL_ASSERT_MOD&quot;, &quot;VALID&quot;],
                [&quot;PACKAGE&quot;, &quot;DEMO&quot;, &quot;VALID&quot;]
            ]);
        });
    });

    describe(&quot;run MLE module from otheruser&quot;, () =&gt; {
        it(&quot;should create 'dept' and 'emp' without parameters&quot;, async () =&gt; {
            await otheruserSession.execute(&quot;begin demo.create_tabs; end;&quot;);
            expect((await userTables()).rows).toEqual([
                [&quot;DEPT&quot;, 4],
                [&quot;EMP&quot;, 14]
            ]);
        });
        it(&quot;should create 'd' and 'emp' with first parameter only&quot;, async () =&gt; {
            await otheruserSession.execute(&quot;begin demo.create_tabs('d'); end;&quot;);
            expect((await userTables()).rows).toEqual([
                [&quot;D&quot;, 4],
                [&quot;EMP&quot;, 14]
            ]);
        });
        it(&quot;should create 'd' and 'e' with both parameters&quot;, async () =&gt; {
            await otheruserSession.execute(&quot;begin demo.create_tabs('d', 'e'); end;&quot;);
            expect((await userTables()).rows).toEqual([
                [&quot;D&quot;, 4],
                [&quot;E&quot;, 14]
            ]);
        });
    });

    afterAll(async () =&gt; {
        await closeSessions();
    });
});" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">beforeAll</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">afterAll</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">describe</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">it</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">expect</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">beforeEach</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;vitest&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">createSessions</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">closeSessions</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">otheruserSession</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">demotabConfig</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;./dbconfig&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">oracledb</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;oracledb&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">exec</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;child_process&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">util</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;node:util&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">describe</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;MLE JavaScript module within the database&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">timeout</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">15000</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">userTables</span><span style="color: #D4D4D4">(): </span><span style="color: #4EC9B0">Promise</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">oracledb</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Result</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">unknown</span><span style="color: #D4D4D4">&gt;&gt; {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">otheruserSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">            with</span></span>
<span class="line"><span style="color: #CE9178">               function num_rows(in_table_name in varchar2) return integer is</span></span>
<span class="line"><span style="color: #CE9178">                  l_rows integer;</span></span>
<span class="line"><span style="color: #CE9178">               begin</span></span>
<span class="line"><span style="color: #CE9178">                  execute immediate &#39;select count(*) from &#39; || in_table_name </span></span>
<span class="line"><span style="color: #CE9178">                     into l_rows;</span></span>
<span class="line"><span style="color: #CE9178">                  return l_rows;</span></span>
<span class="line"><span style="color: #CE9178">               end;</span></span>
<span class="line"><span style="color: #CE9178">            select table_name, num_rows(table_name) as num_rows</span></span>
<span class="line"><span style="color: #CE9178">              from user_tables</span></span>
<span class="line"><span style="color: #CE9178">             order by table_name</span></span>
<span class="line"><span style="color: #CE9178">        `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">beforeAll</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">createSessions</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">execAsync</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">util</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">promisify</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">exec</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">execAsync</span><span style="color: #D4D4D4">(</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">            </span><span style="color: #CE9178">`sql -S </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">demotabConfig</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">user</span><span style="color: #569CD6">}</span><span style="color: #CE9178">/</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">demotabConfig</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">password</span><span style="color: #569CD6">}</span><span style="color: #CE9178">@</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">demotabConfig</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">connectString</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> @deploy.sql`</span></span>
<span class="line"><span style="color: #D4D4D4">        );</span></span>
<span class="line"><span style="color: #D4D4D4">    }, </span><span style="color: #9CDCFE">timeout</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">beforeEach</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">otheruserSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">            begin</span></span>
<span class="line"><span style="color: #CE9178">               for r in (select table_name from user_tables) loop</span></span>
<span class="line"><span style="color: #CE9178">                  execute immediate &#39;drop table &#39; </span></span>
<span class="line"><span style="color: #CE9178">                     || r.table_name</span></span>
<span class="line"><span style="color: #CE9178">                     || &#39; cascade constraints purge&#39;;</span></span>
<span class="line"><span style="color: #CE9178">               end loop;</span></span>
<span class="line"><span style="color: #CE9178">            end;</span></span>
<span class="line"><span style="color: #CE9178">        `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">describe</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;deployment&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should have valid database objects in demotab user&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">mods</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">demotabSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`</span></span>
<span class="line"><span style="color: #CE9178">                select object_type, object_name, status </span></span>
<span class="line"><span style="color: #CE9178">                  from user_objects </span></span>
<span class="line"><span style="color: #CE9178">                 order by object_type, object_name</span></span>
<span class="line"><span style="color: #CE9178">            `</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">mods</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toEqual</span><span style="color: #D4D4D4">([</span></span>
<span class="line"><span style="color: #D4D4D4">                [</span><span style="color: #CE9178">&quot;MLE ENVIRONMENT&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;DEMOTAB_ENV&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;VALID&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                [</span><span style="color: #CE9178">&quot;MLE MODULE&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;DEMOTAB_MOD&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;VALID&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                [</span><span style="color: #CE9178">&quot;MLE MODULE&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;SQL_ASSERT_MOD&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;VALID&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                [</span><span style="color: #CE9178">&quot;PACKAGE&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;DEMO&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;VALID&quot;</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">            ]);</span></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">describe</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;run MLE module from otheruser&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should create &#39;dept&#39; and &#39;emp&#39; without parameters&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">otheruserSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;begin demo.create_tabs; end;&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">((</span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">userTables</span><span style="color: #D4D4D4">()).</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toEqual</span><span style="color: #D4D4D4">([</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                [</span><span style="color: #CE9178">&quot;DEPT&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">],</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">                [</span><span style="color: #CE9178">&quot;EMP&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">14</span><span style="color: #D4D4D4">]</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">            ]);</span></span>
<span class="line cbp-line-highlight"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should create &#39;d&#39; and &#39;emp&#39; with first parameter only&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">otheruserSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;begin demo.create_tabs(&#39;d&#39;); end;&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">((</span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">userTables</span><span style="color: #D4D4D4">()).</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toEqual</span><span style="color: #D4D4D4">([</span></span>
<span class="line"><span style="color: #D4D4D4">                [</span><span style="color: #CE9178">&quot;D&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                [</span><span style="color: #CE9178">&quot;EMP&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">14</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">            ]);</span></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;should create &#39;d&#39; and &#39;e&#39; with both parameters&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">otheruserSession</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">execute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;begin demo.create_tabs(&#39;d&#39;, &#39;e&#39;); end;&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">((</span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">userTables</span><span style="color: #D4D4D4">()).</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toEqual</span><span style="color: #D4D4D4">([</span></span>
<span class="line"><span style="color: #D4D4D4">                [</span><span style="color: #CE9178">&quot;D&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">                [</span><span style="color: #CE9178">&quot;E&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">14</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">            ]);</span></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">afterAll</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">closeSessions</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span></code></pre></div>



<p>On line 30 we run the SQL script <code>deploy.sql</code> with SQLcl. We connect as <code>demotab</code> with the credentials and connect string configured in <code>dbconfig.ts</code>.</p>



<p>We test the default PL/SQL call interface on lines 63-69 by executing <code>begin demo.create_tabs; end;</code>. Then we check the number of rows in the tables <code>dept</code> and <code>emp</code>. That&#8217;s enough. We do not need to repeat the tests of the <code>demotab</code> module since the module was already successfully tested. </p>



<h2 class="wp-block-heading">Re-Run All Tests</h2>



<p>To re-run all tests open a terminal window in VS Code and execute the following command:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="npm run test" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">run</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">test</span></span></code></pre></div>



<p>This will produce an output similar to this:</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-4.png"><img loading="lazy" decoding="async" width="872" height="625" src="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-4.png" alt="Console output of &quot;npm run test&quot; for mle-demotab.test.ts and demotab.test.ts" class="wp-image-12844" srcset="https://www.salvis.com/blog/wp-content/uploads/2023/11/image-4.png 872w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-4-300x215.png 300w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-4-768x550.png 768w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-4-105x75.png 105w, https://www.salvis.com/blog/wp-content/uploads/2023/11/image-4-480x344.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:872px) 100vw, 872px" /></a></figure>



<h2 class="wp-block-heading" id="conclusion">Conclusion</h2>



<p>For years I&#8217;ve been advocating file-based database development. With moderate success. All of my customers are using a version control system and automated deployments. However, the way the files in the version control system are maintained is suboptimal. In most cases, the developers use an IDE such as SQL Developer or PL/SQL Developer to read the source code from the database, change it in the editor of the IDE and then save (=deploy) it in the database. Updating the files in the version control system is a postponed, sometimes half-automated task. This leads to all kinds of bugs detected in the CI (or in later stages) which should have been detected during development. Sometimes code changes are lost, for example, when the underlying database instance has been replaced by a newer clone.</p>



<p>Why is it so hard to change the behaviour of the database developers? Changing the files first and then deploying them into the database? One reason is that the IDEs do not support the file-based development process well enough. They favour the let-us-read-everything-from-the-database approach, which makes sense for application data but is not ideal for code.</p>



<p>The MLE is not supported by the current IDEs. Oracle Database Actions (SQL Developer Web) is an exception, it provides basic support for MLE. However, I guess it will take years until a reasonable functionality is provided, if at all.</p>



<p>So when we want to develop MLE modules efficiently we have to use the currently available IDEs for TypeScript or JavaScript. They are great. Excellent editor, VCS integration, testing tools, debugger, formatter, linter and packaging system. The ecosystem is mature and is constantly improving. I very much like the fact that we have a global module registry npm which supports also private modules. As a result, being forced to use this ecosystem is not a bad thing. Quite the contrary. It&#8217;s the best that could have happened to database development.</p>



<p>When I look at the code of this MLE demo module, I&#8217;m quite happy with it. I&#8217;m confident that this approach can be used on a larger scale.</p>



<p>IMO the MLE is the best thing that happened to the Oracle Database since version 7, which brought us PL/SQL.</p>



<p>Let&#8217;s find out what works and what should be improved.  </p>


<hr class="" style="margin:0 auto 30px;"/>




<p><em>Updated on 2023-11-13, using <code>npm install</code> to initialize the Node project; using <code>var</code> instead of <code>const</code> in <code>deploy.sql</code> to make it compatible with ECMAScript 2011 (ES 5.1).</em></p>



<p><em>Updated on 2023-11-14, using <code>declare const session: oracledb.Connection;</code> on line 5 of <code>demotab.ts</code> (instead of <code>any</code>) and amended all related parts (removed <code>"@typescript-eslint/no-explicit-any": "off"</code> in <code>.eslintrc</code>; changed description of  <code>.eslintrc</code>; changed description of &#8220;Global <code>session</code> variable&#8221;; changed description of <code>demotab.js</code>) </em></p>
<p>The post <a href="https://www.salvis.com/blog/2023/11/12/mle-typescript-javascript-modules/">MLE TypeScript &#038; JavaScript Modules</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.salvis.com/blog/2023/11/12/mle-typescript-javascript-modules/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
