<?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>VSCode Archives - Philipp Salvisberg&#039;s Blog</title>
	<atom:link href="https://www.salvis.com/blog/tag/vscode/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.salvis.com/blog/tag/vscode/</link>
	<description>Database-centric development</description>
	<lastBuildDate>Wed, 18 Feb 2026 08:23:36 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.2</generator>

<image>
	<url>https://www.salvis.com/blog/wp-content/uploads/2014/04/favicon.png</url>
	<title>VSCode Archives - Philipp Salvisberg&#039;s Blog</title>
	<link>https://www.salvis.com/blog/tag/vscode/</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/vscode/feed/"/>
	<item>
		<title>Fighting Bad PL/SQL &#038; SQL with VS Code</title>
		<link>https://www.salvis.com/blog/2026/01/02/fighting-bad-pl-sql-sql-with-vs-code/</link>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Fri, 02 Jan 2026 21:05:10 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Code Analysis]]></category>
		<category><![CDATA[dbLinter]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[VSCode]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=14289</guid>

					<description><![CDATA[<p>The success of a project or product depends largely on the quality of the code. But how can I improve security, maintainability or performance? More importantly, how can I prevent code with quality defects from entering production? In addition to testing, code analysis plays a central role. These days, code can be<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2026/01/02/fighting-bad-pl-sql-sql-with-vs-code/">Fighting Bad PL/SQL &amp; SQL with VS Code</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The success of a project or product depends largely on the quality of the code. But how can I improve security, maintainability or performance? More importantly, how can I prevent code with quality defects from entering production? In addition to testing, code analysis plays a central role. These days, code can be checked not only in CI/CD pipelines, but also during development. Modern IDEs, such as Visual Studio Code, can automatically detect quality issues and offer quick fixes. The goal is a fast feedback loop.</p>



<p class="wp-block-paragraph">This blog post is based on my German article with the same title, published in issue 1/2026 of the <a href="https://www.salvis.com/blog/wp-content/uploads/2026/02/01_2026-Red_Stack_Magazin-DTk-WEB-Philipp_Salvisberg_Fighting_Bad_PLSQL__SQL_with_VS_Code.pdf" target="_blank" rel="noreferrer noopener nofollow">Red Stack Magazin</a>.</p>



<h2 class="wp-block-heading" id="measuring-software-quality">Measuring Software Quality</h2>



<p class="wp-block-paragraph">Imagine you are part of a team where code changes to a feature or bug fix branch are only merged into the develop or main branch following a review. Sometimes you are the author and sometimes one of the reviewers. I am currently part of a team that works in this way. In addition to quality assurance, knowledge sharing is also an important aspect. But how can we assess code quality?</p>



<figure class="wp-block-image is-style-default"><a href="https://www.osnews.com/story/19266/wtfsm/" target="_blank" rel=" noreferrer noopener"><img fetchpriority="high" decoding="async" width="500" height="471" src="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-1-wtfm.jpg" alt="" class="wp-image-14292" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-1-wtfm.jpg 500w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-1-wtfm-300x283.jpg 300w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-1-wtfm-80x75.jpg 80w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-1-wtfm-480x452.jpg 480w" sizes="(max-width:767px) 480px, 500px" /></a><figcaption class="wp-element-caption">Figure 1: WTFs/m</figcaption></figure>



<p class="wp-block-paragraph">This well-known meme by Thom Holwerda says, &#8220;The only valid measurement of code quality is WTFs per minute.&#8221; This seems to be a good metric. However, this metric does have some flaws.</p>



<ul class="wp-block-list">
<li>It is subjective.</li>



<li>It does not provide any information about what is being assessed.</li>



<li>It does not help new team members to adapt quickly.</li>



<li>And it cannot be automated in a meaningful way.</li>
</ul>



<p class="wp-block-paragraph">Sooner or later, a team has no choice but to agree on a set of rules. They can be informal or formal. Typical coding guidelines cover topics such as naming conventions, formatting, code complexity, and language usage rules. The aim is to define and comply with quality standards relating to maintainability, reliability, performance and security. Written coding guidelines also simplify the onboarding of new team members.</p>



<h2 class="wp-block-heading" id="automation">Automation</h2>



<p class="wp-block-paragraph">Manually checking compliance with coding guidelines as part of a review is so time-consuming that no one can afford to do it properly. Therefore, we have to automate as many checks as possible. This is possible for many aspects. The rest still have to be checked manually.</p>



<p class="wp-block-paragraph">In other words, we need a tool suite for automatic rule checking. <a href="https://grisselbav.github.io/dbLinter/" target="_blank" rel="noreferrer noopener nofollow">dbLinter</a> is such a tool suite. It is a new product developed and continuously improved by <a href="https://www.grisselbav.com/" target="_blank" rel="noreferrer noopener nofollow">Grisselbav</a> and <a href="https://www.united-codes.com/" target="_blank" rel="noreferrer noopener nofollow">United Codes</a>. dbLinter uses the <a href="https://github.com/IslandSQL/IslandSQL" target="_blank" rel="noreferrer noopener nofollow">IslandSQL</a> parser, which is updated quarterly with every release update of the Oracle AI Database for SQL, PL/SQL, SQL*Plus and SQLcl.</p>



<p class="wp-block-paragraph">dbLinter is the successor to the decommissioned db* CODECOP suite. dbLinter consists of a central repository, a web GUI and client tools. These include a CLI, a SonarQube plugin and a VS Code extension.</p>



<h2 class="wp-block-heading" id="visual-studio-code-extension">Visual Studio Code Extension</h2>



<p class="wp-block-paragraph">The VS Code extension is compatible with all IDEs that implement the <a href="https://code.visualstudio.com/api" target="_blank" rel="noreferrer noopener nofollow">Visual Studio Code Extension API</a>. Specifically: Visual Studio Code, Theia IDE, VSCodium, Cursor, Windsurf, Void, Kiro and Antigravity.</p>



<p class="wp-block-paragraph">dbLinter for VS Code is available in both the <a href="https://marketplace.visualstudio.com/items?itemName=Grisselbav.dblinter" target="_blank" rel="noreferrer noopener nofollow">Visual Studio Marketplace</a> and the <a href="https://open-vsx.org/extension/Grisselbav/dblinter" target="_blank" rel="noreferrer noopener nofollow">Open VSX Registry</a>. Therefore, it can be conveniently installed directly from the IDE. The extension is free to use as part of the Anonymous and Starter plans (see <a href="https://www.united-codes.com/products/dblinter/#pricing" target="_blank" rel="noreferrer noopener nofollow">dbLinter Pricing Plans</a>).</p>



<p class="wp-block-paragraph">It is important to note that your code is always analysed locally, meaning that it never leaves your network. The configuration is read from the central repository, enabling the client to identify the active rules and parameters. These configurations, along with others, are managed using the <a href="https://dblinter.app/" target="_blank" rel="noreferrer noopener nofollow">Web GUI</a>.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui.png"><img decoding="async" width="1228" height="1088" src="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui.png" alt="" class="wp-image-14313" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui.png 1228w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui-300x266.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui-1024x907.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui-768x680.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui-85x75.png 85w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-2-dblinter-regel-konfiguration-im-web-gui-480x425.png 480w" sizes="(max-width:767px) 480px, (max-width:1228px) 100vw, 1228px" /></a><figcaption class="wp-element-caption">Figure 2: dbLinter rule configuration in the Web GUI</figcaption></figure>



<p class="wp-block-paragraph">dbLinter currently offers 187 rules. This includes all the rules from the decommissioned Trivadis PL/SQL &amp; SQL Coding Guidelines. Figure 2 shows the configuration of my 14 favourite rules. A violation of one of these rules is a bug. There is almost no room for interpretation here. The following chapters provide two examples.</p>



<h2 class="wp-block-heading top-n-queries-with-rownum">Top-N Queries with ROWNUM</h2>



<p class="wp-block-paragraph">The query in Listing 1 is based on the well-known <code>EMP</code> table owned by the database user <code>SCOTT</code>. It returns two rows.</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:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 1: Defective pre-12c-style top-n query</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>select ename,
       sal,
       hiredate,
       rownum as rank
  from emp
 where rownum &lt;= 2
 order by sal desc;</textarea></pre><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"> ename,</span></span>
<span class="line"><span style="color: #D4D4D4">       sal,</span></span>
<span class="line"><span style="color: #D4D4D4">       hiredate,</span></span>
<span class="line"><span style="color: #D4D4D4">       </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">rank</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> &lt;= </span><span style="color: #B5CEA8">2</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> sal </span><span style="color: #569CD6">desc</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" 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-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>ENAME             SAL HIREDATE         RANK
---------- ---------- ---------- ----------
ALLEN            1600 20.02.1981          2
SMITH             800 17.12.1980          1</textarea></pre><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">ENAME             SAL HIREDATE         RANK</span></span>
<span class="line"><span style="color: #D4D4D4">---------- ---------- ---------- ----------</span></span>
<span class="line"><span style="color: #D4D4D4">ALLEN            1600 20.02.1981          2</span></span>
<span class="line"><span style="color: #D4D4D4">SMITH             800 17.12.1980          1</span></span></code></pre></div>



<p class="wp-block-paragraph">However, the result barely meets the requirements. I would have expected the two employees with the highest salaries to be returned. Why is this not the case? The query is formulated in such a way that two rows are randomly selected and then sorted in descending order by salary. The result depends on the execution plan and the physical storage of the data.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code.png"><img decoding="async" width="913" height="448" src="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code.png" alt="" class="wp-image-14323" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code.png 913w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code-300x147.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code-768x377.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code-150x75.png 150w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-3-g-3185-regelverletzung-in-vs-code-480x236.png 480w" sizes="(max-width:767px) 480px, (max-width:913px) 100vw, 913px" /></a><figcaption class="wp-element-caption">Figure 3: Violation of rule G-3185 in VS Code</figcaption></figure>



<p class="wp-block-paragraph">In VS Code, rule violations are displayed under <code>Problems</code> (see Figure 3). There is also a <a href="https://dblinter.app/ords/r/dblinter/dblinter-console/rules#P1000_SHOW_RULE=core%20g-3185" target="_blank" rel="noreferrer noopener nofollow">Core G-3185</a> link that opens the rule details in the Web GUI.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2.png"><img loading="lazy" decoding="async" width="982" height="1490" src="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2.png" alt="" class="wp-image-14330" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2.png 982w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2-198x300.png 198w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2-675x1024.png 675w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2-768x1165.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2-49x75.png 49w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-4-g-3185-im-dblinter-web-gui-2-480x728.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:982px) 100vw, 982px" /></a><figcaption class="wp-element-caption">Figure 4: Rule G-3185 in the dbLinter Web GUI</figcaption></figure>



<p class="wp-block-paragraph">Rule G-3185 in the web GUI is explained based on a similar case in the HR schema (see Figure 4). There are two solutions here. One that can be applied in all Oracle Database versions and one that works from version 12c onwards. Listing 2 shows the traditional solution, which uses an inline view. Of course, nowadays I would always prefer a solution using the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/26/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__BABBADDD" target="_blank" rel="noreferrer noopener nofollow">row_limiting_clause</a>.</p>



<p class="wp-block-paragraph">We can also see that the rule is used in six configurations. Clicking on &#8220;(details)&#8221; opens a pop-up window in which changes can be made. This allows you to configure the rules directly from the IDE.</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);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">Listing 2: Fixed pre-12c-style top-n query</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>select e.*,
       rownum as rank
  from (
          select ename,
                 sal,
                 hiredate
            from emp
           order by sal desc
       ) e
 where rownum &lt;= 2;</textarea></pre><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"> e.*,</span></span>
<span class="line"><span style="color: #D4D4D4">       </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">rank</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> ename,</span></span>
<span class="line"><span style="color: #D4D4D4">                 sal,</span></span>
<span class="line"><span style="color: #D4D4D4">                 hiredate</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp</span></span>
<span class="line"><span style="color: #D4D4D4">           </span><span style="color: #569CD6">order by</span><span style="color: #D4D4D4"> sal </span><span style="color: #569CD6">desc</span></span>
<span class="line"><span style="color: #D4D4D4">       ) e</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">where</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">rownum</span><span style="color: #D4D4D4"> &lt;= </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" 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-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>ENAME             SAL HIREDATE         RANK
---------- ---------- ---------- ----------
KING             5000 17.11.1981          1
SCOTT            3000 19.04.1987          2</textarea></pre><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">ENAME             SAL HIREDATE         RANK</span></span>
<span class="line"><span style="color: #D4D4D4">---------- ---------- ---------- ----------</span></span>
<span class="line"><span style="color: #D4D4D4">KING             5000 17.11.1981          1</span></span>
<span class="line"><span style="color: #D4D4D4">SCOTT            3000 19.04.1987          2</span></span></code></pre></div>



<h2 class="wp-block-heading nvl-vs-coalesce">NVL vs. COALESCE</h2>



<p class="wp-block-paragraph">One often underestimated rule is &#8220;<a href="https://dblinter.app/ords/r/dblinter/dblinter-console/rules#P1000_SHOW_RULE=core%20g-4230" target="_blank" rel="noreferrer noopener nofollow">G-4230</a>: Always use a COALESCE instead of a NVL command, if parameter 2 of the NVL function is a function call or a SELECT statement&#8221;. This rule is about performance, which is relevant to all of us, especially when it is poor. This is why this rule is important.</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:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">Listing 3: Bad performance with NVL</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>with
   function slow_function return integer is
   begin
      sys.dbms_session.sleep(0.2);
      return null;
   end slow_function;
select ename, nvl(mgr, slow_function()) as mgr
  from emp;</textarea></pre><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">with</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">slow_function</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">integer</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">begin</span></span>
<span class="line"><span style="color: #D4D4D4">      sys.</span><span style="color: #DCDCAA">dbms_session.</span><span style="color: #4EC9B0">sleep</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">0.2</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">end</span><span style="color: #D4D4D4"> slow_function;</span></span>
<span class="line"><span style="color: #569CD6">select</span><span style="color: #D4D4D4"> ename, </span><span style="color: #DCDCAA">nvl</span><span style="color: #D4D4D4">(mgr, slow_function()) </span><span style="color: #569CD6">as</span><span style="color: #D4D4D4"> mgr</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">from</span><span style="color: #D4D4D4"> emp;</span></span></code></pre></div>



<p class="wp-block-paragraph">Listing 3 demonstrates a case in which the use of <code>NVL</code> results in an execution time of approximately 2.8 seconds. If <code>COALESCE</code> is used instead of <code>NVL</code>, the execution time is only about 0.2 seconds. The reason is that <code>NVL</code> always evaluates the second parameter, even if the first parameter is not null. <code>COALESCE</code> works differently: the second parameter is only evaluated if the first parameter is null. This performance difference originates from the fact that the <code>EMP</code> table contains 14 rows, but only one of these returns an empty <code>MGR</code>.</p>



<p class="wp-block-paragraph">In this case, using <code>COALESCE</code> is definitely the better solution. So, should <code>NVL</code> always be replaced by <code>COALESCE</code>? No. There are two special cases:</p>



<ol class="wp-block-list">
<li>NVL supports implicit data type conversion.<br /><code>select nvl(mgr, '1') from emp</code> works, but <code>select coalesce(mgr, '1') from emp</code> causes an <a href="https://docs.oracle.com/en/error-help/db/ora-00932/" target="_blank" rel="noreferrer noopener nofollow">ORA-00932</a> error. However, implicit type conversions should be avoided anyway. The code should be adjusted accordingly.<br /></li>



<li>Optimisations of <code>NVL</code> can lead to better execution plans.<br />Such optimisations currently only exist for <code>NVL</code> and not for <code>COALESCE</code>. Therefore, it is better to continue using <code>NVL</code> in these cases. See <a href="https://how2ora-en.blogspot.com/2025/09/the-magical-nvl-function.html" target="_blank" rel="noreferrer noopener nofollow">The Magical NVL Function</a> by Monika Lewandowska for an example. </li>
</ol>



<h5 class="wp-block-heading">Quick Fixes</h5>



<p class="wp-block-paragraph">dbLinter knows these special cases. It offers appropriate alternative solutions. See Figure 5.</p>



<figure class="wp-block-image size-full"><a href="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode.png"><img loading="lazy" decoding="async" width="1121" height="717" src="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode.png" alt="" class="wp-image-14346" srcset="https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode.png 1121w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode-300x192.png 300w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode-1024x655.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode-768x491.png 768w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode-117x75.png 117w, https://www.salvis.com/blog/wp-content/uploads/2026/01/abbildung-5-g-4230-quick-fixes-in-vscode-480x307.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:1121px) 100vw, 1121px" /></a><figcaption class="wp-element-caption">Figure 5: Quick fixes for G-4230 violation in VS Code.</figcaption></figure>



<p class="wp-block-paragraph">dbLinter can apply quick fixes to different sections. For example, for a single violation of a rule, for all violations of a rule, or for all violations of all rules in the editor window.</p>



<p class="wp-block-paragraph">The &#8220;@dbLinter ignore markers&#8221; are special comments used to ignore rule violations. There are various legitimate reasons for doing this. For example, in the case of false positives (dbLinter bugs) or exceptions to the rule. A comment such as <code>-- @dbLinter ignore(G-4230): NVL forever</code> can have the following scopes: line, statement or file, depending on where the comment is positioned.</p>



<h2 class="wp-block-heading" id="code-analysis-and-ai">Code Analysis and AI</h2>



<p class="wp-block-paragraph">The solution proposals in Figure 5, indicated by the yellow lamp symbol, are quick fixes from dbLinter. However, the last two menu options come from GitHub Copilot.</p>



<p class="wp-block-paragraph">When Copilot suggests a solution to a rule violation, dbLinter provides the necessary context, including the file and the exact location of the violation, as well as the name of the violated rule. This gives Copilot access to the rule definition online, enabling it to suggest a reasonable solution in many cases. In other words, dbLinter enhances the support offered by tools such as Copilot, Cline and Windsurf.</p>



<p class="wp-block-paragraph">Rules are useful for AI tools. They provide a framework that leads to better results. However, there is no guarantee that all rules will be followed. Ultimately, code generated or expanded by AI becomes part of our code base. This is why it is important to check AI-generated code according to the same rules as manually created code.</p>



<p class="wp-block-paragraph">In other words, AI does not enforce standards. But dbLinter can do that.</p>



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



<p class="wp-block-paragraph">Software quality is a matter of definition. dbLinter offers many rules. Not all of them are useful and applicable to every project. The dbLinter rules can therefore be seen as a large buffet. You choose what you like and what is healthy. But not too much at once. Nevertheless, there are some rules that, in my opinion, should be followed in every project. I have presented two of them in this blog post.</p>



<p class="wp-block-paragraph">Install dbLinter for VS Code to identify the rules that will be most helpful for your projects. The rules in Figure 2 are certainly a good starting point.</p>



<p class="wp-block-paragraph">If you have any questions, please feel free to contact me. Alternatively, you can create issues directly in the <a href="https://github.com/Grisselbav/dbLinter" target="_blank" rel="noreferrer noopener nofollow">dbLinter GitHub repository</a>.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://www.salvis.com/blog/2026/01/02/fighting-bad-pl-sql-sql-with-vs-code/">Fighting Bad PL/SQL &amp; SQL with VS Code</a> appeared first on <a href="https://www.salvis.com/blog">Philipp Salvisberg&#039;s Blog</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Installing SQL Developer in IDEs Implementing the VS Code Extension API</title>
		<link>https://www.salvis.com/blog/2025/07/05/installing-sql-developer-in-ides-implementing-the-vs-code-extension-api/</link>
		
		<dc:creator><![CDATA[Philipp Salvisberg]]></dc:creator>
		<pubDate>Sat, 05 Jul 2025 13:56:19 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SQL Developer]]></category>
		<category><![CDATA[VSCode]]></category>
		<guid isPermaLink="false">https://www.salvis.com/blog/?p=13951</guid>

					<description><![CDATA[<p>Introduction The Oracle SQL Developer team is working on bringing the essential functionality built over the last 20 years in the classic SQL Developer IDE—a JDeveloper extension running as a standalone application—to the modern VS Code IDE. The integration with the VS Code ecosystem greatly enhances the developer experience. Is it time<span class="excerpt-hellip"> […]</span></p>
<p>The post <a href="https://www.salvis.com/blog/2025/07/05/installing-sql-developer-in-ides-implementing-the-vs-code-extension-api/">Installing SQL Developer in IDEs Implementing the VS Code Extension API</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" id="introduction">Introduction</h2>



<p class="wp-block-paragraph">The Oracle SQL Developer team is working on bringing the essential functionality built over the last 20 years in the classic SQL Developer IDE—a JDeveloper extension running as a standalone application—to the modern VS Code IDE. The integration with the VS Code ecosystem greatly enhances the developer experience. </p>



<p class="wp-block-paragraph">Is it time to switch? &#8211; Well, it depends on which part of SQL Developer you use and how often. I&#8217;d say it&#8217;s time to start using the SQL Developer extension for VS Code. Use the classic SQL Developer when needed. You will do it less and less over time.</p>



<p class="wp-block-paragraph">The SQL Developer extension is available in the VS Code Marketplace. That simplifies the installation for VS Code users. Unfortunately, this marketplace is not available in forks of VS Code or, more precisely, in IDEs that implement the VS Code extension API, such as <a href="https://vscodium.com/">VSCodium</a>, <a href="https://cursor.com/">Cursor</a>, <a href="https://windsurf.com/editor">Windsurf</a> and <a href="https://theia-ide.org/#theiaide">Theia IDE</a>. So, how do we install VS Code extensions, specifically SQL Developer, in these IDEs? &#8211; I&#8217;ll answer this question in this blog post.</p>



<h2 class="wp-block-heading" id="installing-sql-developer-in-vs-code">Installing SQL Developer in VS Code</h2>



<p class="wp-block-paragraph">The easiest way to install SQL Developer in VS Code is to start VS Code, search for <code>oracle sql developer</code> in the <code>Extensions</code> view, and click on the <code>Install</code> button. That&#8217;s it.</p>



<figure class="wp-block-image size-full is-resized"><a href="https://www.salvis.com/blog/wp-content/uploads/2025/07/image.png"><img loading="lazy" decoding="async" width="1230" height="450" src="https://www.salvis.com/blog/wp-content/uploads/2025/07/image.png" alt="Install SQL Developer within VS Code" class="wp-image-13952" style="width:615px" srcset="https://www.salvis.com/blog/wp-content/uploads/2025/07/image.png 1230w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-300x110.png 300w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-1024x375.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-768x281.png 768w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-150x55.png 150w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-480x176.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:1230px) 100vw, 1230px" /></a></figure>



<p class="wp-block-paragraph">Please note that the second entry shown in the screenshot above is a deprecated/decommissioned extension developed by another team at Oracle. It&#8217;s a completely unrelated product.</p>



<h2 class="wp-block-heading" id="downloading-sql-developer-vsix-file">Downloading SQL Developer&#8217;s .vsix File</h2>



<p class="wp-block-paragraph">At the time of writing, it is not possible (anymore) to download an extension such as SQL Developer directly from the <a href="https://marketplace.visualstudio.com/items?itemName=Oracle.sql-developer">VS Code Marketplace website</a>. At least not officially. However, it&#8217;s possible in VS Code.</p>



<p class="wp-block-paragraph">Instead of clicking on the <code>install</code> button as before, right-click on the extension and select <code>Download VSIX</code>.</p>



<figure class="wp-block-image size-full is-resized"><a href="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-1.png"><img loading="lazy" decoding="async" width="1510" height="748" src="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-1.png" alt="Download VSIX file within VS Code" class="wp-image-13954" style="width:755px" srcset="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-1.png 1510w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-1-300x149.png 300w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-1-1024x507.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-1-768x380.png 768w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-1-150x75.png 150w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-1-480x238.png 480w" sizes="auto, (max-width:767px) 480px, (max-width:1510px) 100vw, 1510px" /></a></figure>



<p class="wp-block-paragraph">and then select the platform architecture.</p>



<figure class="wp-block-image size-large is-resized"><a href="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-4.png"><img loading="lazy" decoding="async" width="1024" height="287" src="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-4-1024x287.png" alt="Select the platform for which you want to download the VSIX" class="wp-image-13960" style="width:595px" srcset="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-4-1024x287.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-4-300x84.png 300w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-4-768x216.png 768w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-4-150x42.png 150w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-4-480x135.png 480w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-4.png 1190w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">This is necessary because SQL Developer comes with a Java Runtime Environment, which contains platform-specific binaries.</p>



<h2 class="wp-block-heading" id="installing-a-vsix-file">Installing a VSIX File</h2>



<p class="wp-block-paragraph">VS Code, VSCodium, Cursor, Windsurf, and Theila IDE provide a <code>Install from VSIX...</code> command. You find it via <code>View -> Command Pallette...</code>. Run it,</p>



<figure class="wp-block-image size-large is-resized"><a href="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-3.png"><img loading="lazy" decoding="async" width="1024" height="109" src="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-3-1024x109.png" alt="Install from VSIX..." class="wp-image-13956" style="width:591px" srcset="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-3-1024x109.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-3-300x32.png 300w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-3-768x82.png 768w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-3-150x16.png 150w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-3-480x51.png 480w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-3.png 1182w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">and select the VSIX file to install, and you&#8217;re done.</p>



<h2 class="wp-block-heading" id="open-vsx-registry">Open VSX Registry</h2>



<p class="wp-block-paragraph">Why are VSCodium, Cursor, Windsurf and Theia IDE not using the VS Code Marketplace? &#8211; Because the <a href="https://www.nuget.org/policies/terms">Terms of Use</a> do not allow this. Here&#8217;s the relevant passage:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">(&#8230;) you may not access, search, obtain or attempt to obtain any Offerings, materials, or information from the Sites through any means other than directly from Microsoft’s publicly supported interfaces (&#8230;)</p>
</blockquote>



<p class="wp-block-paragraph">This is why <a href="https://vscodium.com/">VSCodium</a>, <a href="https://cursor.com/">Cursor</a>, <a href="https://windsurf.com/editor">Windsurf</a> and <a href="https://theia-ide.org/#theiaide">Theia IDE</a> use the alternative marketplace <a href="https://open-vsx.org/">Open VSX Registry</a>.</p>



<p class="wp-block-paragraph">At the time of writing, the Oracle SQL Developer Extension for VSCode is not available in the Open VSX Registry. Here&#8217;s a screenshot of a search in Cursor:</p>



<figure class="wp-block-image size-large is-resized"><a href="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-6.png"><img loading="lazy" decoding="async" width="1024" height="610" src="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-6-1024x610.png" alt="Search for Oracle SQL Developer  within Cursor" class="wp-image-13964" style="width:633px" srcset="https://www.salvis.com/blog/wp-content/uploads/2025/07/image-6-1024x610.png 1024w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-6-300x179.png 300w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-6-768x457.png 768w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-6-126x75.png 126w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-6-480x286.png 480w, https://www.salvis.com/blog/wp-content/uploads/2025/07/image-6.png 1266w" sizes="auto, (max-width:767px) 480px, (max-width:1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">As you see, the deprecated/decommissioned extension is listed, but the successor is missing. </p>



<h2 class="wp-block-heading" id="summary">Summary</h2>



<p class="wp-block-paragraph">Installing an extension in VS Code via the integrated marketplace is super easy. Getting the .vsix file is also straightforward and enables the installation of VS Code extensions in IDEs that implement the VS Code extension API.</p>



<p class="wp-block-paragraph">It would be great if the Oracle SQL Developer team published their SQL Developer extension on the Open VSX Registry too. This would make the initial installation and subsequent updates much simpler.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://www.salvis.com/blog/2025/07/05/installing-sql-developer-in-ides-implementing-the-vs-code-extension-api/">Installing SQL Developer in IDEs Implementing the VS Code Extension API</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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph"></p>



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



<p class="wp-block-paragraph">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 class="wp-block-paragraph">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-6a635ab303df6-1">package.json</a></li><li><a href="#tab-6a635ab303df6-2">tsconfig.json</a></li><li><a href="#tab-6a635ab303df6-3">.eslintrc</a></li><li><a href="#tab-6a635ab303df6-4">.prettierrc</a></li></ul><div id="tab-6a635ab303df6-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 class="wp-block-paragraph"><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-6a635ab303df6-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 class="wp-block-paragraph">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-6a635ab303df6-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 class="wp-block-paragraph">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-6a635ab303df6-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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">Besides the removed types, the file looks very much like its TypeScript pendant.</p>



<p class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">IMO the MLE is the best thing that happened to the Oracle Database since version 7, which brought us PL/SQL.</p>



<p class="wp-block-paragraph">Let&#8217;s find out what works and what should be improved.  </p>


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




<p class="wp-block-paragraph"><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 class="wp-block-paragraph"><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>
