<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arnold Acho</title>
    <description>The latest articles on DEV Community by Arnold Acho (@achoarnold).</description>
    <link>https://dev.to/achoarnold</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F99112%2F58d08e84-100c-467f-8315-4f042abb9e5e.png</url>
      <title>DEV Community: Arnold Acho</title>
      <link>https://dev.to/achoarnold</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/achoarnold"/>
    <language>en</language>
    <item>
      <title>How to forward a text message (SMS) from an android phone into your webhook</title>
      <dc:creator>Arnold Acho</dc:creator>
      <pubDate>Sat, 18 Mar 2023 06:50:31 +0000</pubDate>
      <link>https://dev.to/achoarnold/how-to-foward-a-text-message-sms-from-an-android-phone-into-your-webhook-jhg</link>
      <guid>https://dev.to/achoarnold/how-to-foward-a-text-message-sms-from-an-android-phone-into-your-webhook-jhg</guid>
      <description>&lt;p&gt;You can now program your android phone to forward messages received on your phone to your server and trigger powerful automations with tools like zapper and IFTTFT. I created an open source application called &lt;a href="https://httpsms.com"&gt;httpSMS&lt;/a&gt; that helps you to set this up with ease&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Get your API_KEY
&lt;/h2&gt;

&lt;p&gt;Create an account on the httpSMS web application and copy your API key from the settings page. &lt;a href="https://httpsms.com/settings"&gt;https://httpsms.com/settings&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lWqciYze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rfn9o4mp7ki6k166fx7o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lWqciYze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rfn9o4mp7ki6k166fx7o.png" alt="httpsms.com settings page" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Install the httpSMS android app
&lt;/h2&gt;

&lt;p&gt;Install the &lt;a href="https://github.com/NdoleStudio/httpsms/releases/latest/download/HttpSms.apk"&gt;httpSMS&lt;/a&gt; android app on your phone and sign in using your API KEY which you copied above. This app listens for SMS messages received on your android phone. &lt;a href="https://github.com/NdoleStudio/httpsms/releases/latest/download/HttpSms.apk"&gt;https://github.com/NdoleStudio/httpsms/releases/latest/download/HttpSms.apk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RMd4_Sk4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/og8ctw89jmbha7riwvj4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RMd4_Sk4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/og8ctw89jmbha7riwvj4.png" alt="httpsms android app" width="401" height="858"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Set up a webhook
&lt;/h2&gt;

&lt;p&gt;Once the appliation has been installed, it will be listening for SMS messages received on the android phone. You can configure the application to sent this SMS message to your server URL using a webhook. You can configure this URL under the settings page in the httpSMS application &lt;a href="https://httpsms.com/settings"&gt;https://httpsms.com/settings&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LLf71-S3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/meiddq18bcrvgk5j1bne.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LLf71-S3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/meiddq18bcrvgk5j1bne.png" alt="httpSMS webhook configuration" width="800" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations, you have successfully set up SMS forwarding from your Android phone to a webhook! This powerful automation tool can help you streamline your business workflow and save you time and effort.&lt;/p&gt;

&lt;p&gt;You can also trigger the httpSMS application to send an SMS a simple API. You can find more information on the documentation page at &lt;a href="https://docs.httpsms.com"&gt;https://docs.httpsms.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>webhook</category>
      <category>phone</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Key-Value store built with CockroachDB, .Net 5.0, and Entity Framework</title>
      <dc:creator>Arnold Acho</dc:creator>
      <pubDate>Sun, 07 Nov 2021 19:46:32 +0000</pubDate>
      <link>https://dev.to/achoarnold/key-value-store-built-with-cockroachdb-net-50-and-entity-framework-1kl4</link>
      <guid>https://dev.to/achoarnold/key-value-store-built-with-cockroachdb-net-50-and-entity-framework-1kl4</guid>
      <description>&lt;p&gt;In this article, we are going to build a simple key-value store using Entity Framework 5.0, .Net 5.0, and CockroachDB Serverless.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cockroachlabs.com/docs/cockroachcloud/create-a-serverless-cluster.html"&gt;You have setup your cockroachDB cluster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&amp;amp;tabs=visual-studio"&gt;You have created an empty .net 5.0 web api project using visual studio or jetbrains.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Install NuGet packages
&lt;/h4&gt;

&lt;p&gt;Install the &lt;code&gt;Microsoft.EntityFrameworkCore&lt;/code&gt; and &lt;code&gt;Microsoft.EntityFrameworkCore.Design&lt;/code&gt; nuget packages version &lt;code&gt;5.0.10&lt;/code&gt;. The Design package helps when we want to generate migrations from our model classes.&lt;/p&gt;

&lt;p&gt;Install the entity framework core provider for PostgreSQL called  &lt;code&gt;Npgsql.EntityFrameworkCore.PostgreSQL&lt;/code&gt; version  &lt;code&gt;5.0.10&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;5.0.10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Microsoft.EntityFrameworkCore.Design&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;5.0.10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Npgsql.EntityFrameworkCore.PostgreSQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;5.0.10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Setup connection to CockroachDB cluster
&lt;/h4&gt;

&lt;p&gt;Download the cockroachDB certificate using the command below on powershell. If you use linux/mac, You can find &lt;a href="https://www.cockroachlabs.com/docs/stable/build-a-csharp-app-with-cockroachdb.html?filters=windows#set-up-your-cluster-connection"&gt;alternative commands here&lt;/a&gt;.  Also, replace &lt;code&gt;{cluster-id}&lt;/code&gt; with the id of your cockroachDB cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;appdata&lt;/span&gt;&lt;span class="nx"&gt;\.postgresql\&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Invoke-WebRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Uri&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://cockroachlabs.cloud/clusters/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cluster-id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;/cert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-OutFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;appdata&lt;/span&gt;&lt;span class="nx"&gt;\.postgresql\root.crt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a connection string in the &lt;code&gt;appsettings.json&lt;/code&gt;  file. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;replace &lt;code&gt;{host}&lt;/code&gt; with your cluster host e.g &lt;code&gt;free-tier.gcp-us-central1.cockroachlabs.cloud&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;replace &lt;code&gt;{username}&lt;/code&gt; with your database username&lt;/li&gt;
&lt;li&gt;repalce &lt;code&gt;{password}&lt;/code&gt; with your database password&lt;/li&gt;
&lt;li&gt;replace &lt;code&gt;{cluster.database}&lt;/code&gt; with your cluster databse. e.g  if your cluster name is &lt;code&gt;key-value-store-123&lt;/code&gt; on cockroachDB, and you plan to use the default database, then &lt;code&gt;{cluster.database} = key-value-store-123.defaultdb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;replace &lt;code&gt;{cert-location}&lt;/code&gt; with the directory of the certificate
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"ConnectionStrings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ApplicationDbContext"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Host={host};Port=26257;SslMode=Require;username={username};password={password};Database={cluster.database};Root Certificate={cert-location};"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;**ProTip: **You can use &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-5.0"&gt;dotnet user-secrets&lt;/a&gt; to ensure that your credentials are not commited to git.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup Models and DBConntext
&lt;/h4&gt;

&lt;p&gt;Create an &lt;code&gt;Entities&lt;/code&gt; directory in the root of the api project and add the following entity&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;KeyValueStore.Entities&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KeyValueEntry&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Required&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;StringLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;44&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;!;&lt;/span&gt;

            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Required&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypeName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;!;&lt;/span&gt;

            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Required&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;CreatedAt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;KeyValueEntry entity&lt;br&gt;
Create another directory called &lt;code&gt;Database&lt;/code&gt; in the Api prject and add an &lt;code&gt;ApplicationDbContext&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;KeyValueStore.Database&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationDbContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KeyValueEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;KeyValueEntries&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;!;&lt;/span&gt;

            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ApplicationDbContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbContextOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnModelCreating&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KeyValueEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KeyValueEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;HasKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Database Migrations
&lt;/h4&gt;

&lt;p&gt;First, register the &lt;code&gt;ApplicationDbContext&lt;/code&gt; with the .net dependency injection. Add the following in the &lt;code&gt;ConfigureServices&lt;/code&gt; method in &lt;code&gt;Startup.cs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseNpgsql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationDbContext&lt;/span&gt;&lt;span class="p"&gt;))));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependency Injection&lt;br&gt;
Run the commands below in &lt;code&gt;powershell&lt;/code&gt; to generate migrations and update your database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dotnet-ef&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;migrations&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;InitialCreate&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Migrate Database&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Controller
&lt;/h3&gt;

&lt;p&gt;Create a controller called &lt;code&gt;StoreController&lt;/code&gt; this will have the methods to &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;delete&lt;/code&gt; key value entries from the cockroachDB database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of storing the entire key, we create a &lt;code&gt;sha256&lt;/code&gt; has of the key. This helps reduce the amount of disk space needed to store the key&lt;/li&gt;
&lt;li&gt;The value entries needs to be encoded in &lt;code&gt;base64&lt;/code&gt; this is to prevent all types of encoding issues on &lt;code&gt;utf-x&lt;/code&gt; strings.&lt;/li&gt;
&lt;li&gt;I used &lt;code&gt;FlexLabs.EntityFrameworkCore.Upsert&lt;/code&gt; nuget version 5.0.0 in the &lt;code&gt;PutAsync&lt;/code&gt; method to carry out an &lt;code&gt;upsert&lt;/code&gt; database query.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;KeyValueStore.Controllers&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// Add, update, delete and fetch key-value entries.&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"v1/store/{key:maxlength(256):minlength(1)}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Consumes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaTypeNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Plain&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Produces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaTypeNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Plain&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StoreController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ApplicationDbContext&lt;/span&gt; &lt;span class="n"&gt;_dbContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;StoreController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationDbContext&lt;/span&gt; &lt;span class="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;_dbContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// Get a specific value by the key&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;param name="key" example="995c0628-3fb3-11ec-9356-0242ac130003"&amp;gt;The max length is 256 characters&amp;lt;/param&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;param name="cancellationToken"&amp;gt;Used to cancel the request&amp;lt;/param&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;response code="200" example="dmFsdWU="&amp;gt;Value retrieved&amp;lt;/response&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;response code="404"&amp;gt;There is no entry for the key in the store&amp;lt;/response&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;response code="500"&amp;gt;Internal Server Error&amp;lt;/response&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ProducesResponseType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;StatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status200OK&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ProducesResponseType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status500InternalServerError&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromRoute&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyValueEntries&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OkObjectResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// Upsert a key value entry.&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// The body of the request will be stored as the value for the "key"&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;strong&amp;gt;NOTE:&amp;lt;/strong&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// - The body must be a &amp;lt;see cref="!:https://en.wikipedia.org/wiki/Base64"&amp;gt;base64&amp;lt;/see&amp;gt; encoded string. &amp;lt;br/&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// - The body must be maximum 5kb long. ie. the length should be less than or equal to 5120 characters &lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;param name="key" example="995c0628-3fb3-11ec-9356-0242ac130003"&amp;gt;The max length is 256 characters&amp;lt;/param&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;param name="body" example="dmFsdWU="&amp;gt;The value encoded in base64. e.g the word "value" encoded in base64 is "dmFsdWU="&amp;lt;/param&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;param name="cancellationToken"&amp;gt;Used to cancel the request&amp;lt;/param&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;response code="204"&amp;gt;Value set successfully&amp;lt;/response&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;response code="400"&amp;gt;Validation Error&amp;lt;/response&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;response code="500"&amp;gt;Internal Server Error&amp;lt;/response&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPut&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Produces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaTypeNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Json&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ProducesResponseType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;),&lt;/span&gt; &lt;span class="n"&gt;StatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status400BadRequest&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;PutAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FromRoute&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyValueEntry&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;CreatedAt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;

                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyValueEntries&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Upsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;NoContent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// Delete a key value entry.&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;param name="key" example="995c0628-3fb3-11ec-9356-0242ac130003"&amp;gt;The max length is 256 characters&amp;lt;/param&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;param name="cancellationToken"&amp;gt;Used to cancel the request&amp;lt;/param&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;response code="204"&amp;gt;Value deleted successfully&amp;lt;/response&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;response code="404"&amp;gt;There is no entry for the key in the store&amp;lt;/response&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;/// &amp;lt;response code="500"&amp;gt;Internal Server Error&amp;lt;/response&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpDelete&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ProducesResponseType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status500InternalServerError&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;DeleteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FromRoute&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyValueEntries&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                &lt;span class="n"&gt;_dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyValueEntries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;NoContent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SHA256&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;byteArray&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ComputeHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToBase64String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;byteArray&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The entire code for this project can be found on github &lt;a href="https://github.com/AchoArnold/key-value-store"&gt;https://github.com/AchoArnold/key-value-store&lt;/a&gt;. I also hosted it on azure and you can play with it live on &lt;a href="https://key-value-store.ndolestudio.com/index.html"&gt;https://key-value-store.ndolestudio.com&lt;/a&gt;. Please no DDOS attacks 🙏&lt;/p&gt;

</description>
      <category>cockroachdb</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>azure</category>
    </item>
    <item>
      <title>Least Frequently Used (LFU) Cache with Constant Time Complexity</title>
      <dc:creator>Arnold Acho</dc:creator>
      <pubDate>Fri, 22 Oct 2021 16:18:56 +0000</pubDate>
      <link>https://dev.to/achoarnold/least-frequently-used-lfu-cache-with-constant-time-complexity-3hh0</link>
      <guid>https://dev.to/achoarnold/least-frequently-used-lfu-cache-with-constant-time-complexity-3hh0</guid>
      <description>&lt;p&gt;In this blog post, I will explain to you how to implement an in-memory least frequently used cache(LFU) in Go. The implementation has constant time complexity O(1) for Get, Set and Removing the least frequently used item from the cache when the cache is full.&lt;/p&gt;

&lt;p&gt;The LFU cache algorithm presented here is based on &lt;a href="http://dhruvbird.com/lfu.pdf" rel="noopener noreferrer"&gt;this paper&lt;/a&gt; written by some very very smart people (hey, they even work at FAANG).&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Structure
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Facho.arnold.cm%2Fcontent%2Fimages%2F2020%2F08%2FSchermafdruk-2020-06-24-08.49.19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Facho.arnold.cm%2Fcontent%2Fimages%2F2020%2F08%2FSchermafdruk-2020-06-24-08.49.19.png" alt="Data Structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: An O(1) algorithm for implementing the LFU cache eviction scheme&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The data structure for this cache is a struct with  3 fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;cap&lt;/span&gt;           &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;frequencyList&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;
    &lt;span class="n"&gt;lookupTable&lt;/span&gt;   &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lookupTableNode&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  cap
&lt;/h4&gt;

&lt;p&gt;This represents the capacity of the cache, i.e the maximum number of items the cache can contain. If the cache already has &lt;code&gt;cap&lt;/code&gt; items and you attempt to add a new item in the cache, the least frequently used item will be evicted.&lt;/p&gt;

&lt;h4&gt;
  
  
  frequencyList
&lt;/h4&gt;

&lt;p&gt;This is a doubly linked list which &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A doubly linked list of all the cache items which have a been accessed &lt;code&gt;n&lt;/code&gt; number of times&lt;/li&gt;
&lt;li&gt;n, the frequency weight for items in that node&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This list is represented by &lt;code&gt;[head] -&amp;gt; [1] -&amp;gt; [2] -&amp;gt; [5]-&amp;gt;[9]&lt;/code&gt; in the image above. All the items which have been accessed 1 time will be stored in the node with value [1] so the nodes [x] and [y] have been accessed 1 time while the node [b] has been assessed 5 times since it's under the node [5].&lt;/p&gt;

&lt;p&gt;So as not to re-invent the wheel, I used the &lt;a href="https://pkg.go.dev/container/list" rel="noopener noreferrer"&gt;container/list&lt;/a&gt; package for the doubly linked list. &lt;/p&gt;

&lt;h4&gt;
  
  
  lookupTable
&lt;/h4&gt;

&lt;p&gt;This is a hashmap. i.e basic &lt;code&gt;key =&amp;gt; value&lt;/code&gt; store. The key in this case, is the key of the item in the cache and the value is a pointer to the  item's node in the &lt;code&gt;frequencyList&lt;/code&gt; doubly linked list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache Operations
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Set
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Set&lt;/code&gt; is used to an item in the LFU cache with key and value. It returns ErrInvalidCap if the cache is not initialized&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// check if cache has been initialized.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ErrInvalidCap&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// if the key already exists, change the value.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookupTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookupTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// create a lookup table node.&lt;/span&gt;
    &lt;span class="n"&gt;lookupTableNode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lookupTableNode&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// check if the lookupTable has enough space. If it doesn't, pop the least frequently used item from the Cache.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsFull&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// set the lookup table node.&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookupTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lookupTableNode&lt;/span&gt;

    &lt;span class="c"&gt;// if frequency list is empty or the first item in the list doesn't have weight 1 create a new node with weight 1.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Front&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;frequencyListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;minFrequencyWeight&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;freqListNode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;frequencyListNode&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;minFrequencyWeight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
        &lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PushFront&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// get the first item in the frequency list node. We're sure the item has the weight 1.&lt;/span&gt;
    &lt;span class="n"&gt;freqListNode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Front&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;frequencyListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// set the node parent of the newly set item in the frequency list node Cache.&lt;/span&gt;
    &lt;span class="n"&gt;freqListNodeListNode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;frequencyListNodeListNode&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// set the frequencyListNodeListNode in the lookup table node.&lt;/span&gt;
    &lt;span class="n"&gt;lookupTableNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyListNodeListNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;freqListNodeListNode&lt;/span&gt;

    &lt;span class="c"&gt;// add the newly created frequencyListNodeListNode to the frequencyListNode of weight 1.&lt;/span&gt;
    &lt;span class="n"&gt;freqListNodeListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PushBack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;freqListNodeListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Get
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Get&lt;/code&gt; returns an item for the &lt;code&gt;LFU&lt;/code&gt; cache by a key. It returns ErrCacheMiss if there's a cache miss.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// check if the key exists if it doesn't return with a Cache miss error.&lt;/span&gt;
    &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookupTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ErrCacheMiss&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;freqListNode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyListNodeListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;

    &lt;span class="c"&gt;// check if the next node's weight is equal to current weight +1&lt;/span&gt;
    &lt;span class="c"&gt;// if not, create a new node with weight = current weight + 1 ans insert if after the current node&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;frequencyListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;newFreqListNode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;frequencyListNode&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;newFreqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InsertAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newFreqListNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// gets the list with weight = node weight + 1. This node MUST exist because it was created above&lt;/span&gt;
    &lt;span class="n"&gt;nextFreqListNode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;frequencyListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyListNodeListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nextFreqListNode&lt;/span&gt;

    &lt;span class="c"&gt;// remove node from current frequency list node&lt;/span&gt;
    &lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyListNodeListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// remove freq list node from the cache's freq list if the list node has NO item in it.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;freqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// setting the element of the node in it's new list&lt;/span&gt;
    &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyListNodeListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nextFreqListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PushBack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyListNodeListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  pop
&lt;/h4&gt;

&lt;p&gt;The pop method  removes the least frequently used item from the LFU Cache.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// The frequency list node MUST exist i.e the cache cap.&lt;/span&gt;
    &lt;span class="n"&gt;freqListNodeListNode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Front&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;frequencyListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Front&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;frequencyListNodeListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Remove key from lookup table.&lt;/span&gt;
    &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookupTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freqListNodeListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// remove node from frequency list node.&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Front&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;frequencyListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;freqListNodeListNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// if frequency list node list is now empty, remove the frequency list node from Cache's frequency list.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Front&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;frequencyListNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequencyList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Front&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The code for this &lt;a href="https://github.com/NdoleStudio/lfu-cache" rel="noopener noreferrer"&gt;LFU cache is on github&lt;/a&gt;, One improvement I'm thinking of is to make this cache generic so it can work in cases where the key is a string, int or some other comparible struct/pointer. The generics implementation can be found in &lt;a href="https://github.com/NdoleStudio/lfu-cache/pull/1" rel="noopener noreferrer"&gt;2.0-dev branch on github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>generics</category>
      <category>lfu</category>
      <category>cache</category>
    </item>
    <item>
      <title>One Trick to speed up your unit tests with Laravel</title>
      <dc:creator>Arnold Acho</dc:creator>
      <pubDate>Mon, 17 Aug 2020 13:00:28 +0000</pubDate>
      <link>https://dev.to/achoarnold/one-trick-to-speed-up-your-unit-tests-with-laravel-181a</link>
      <guid>https://dev.to/achoarnold/one-trick-to-speed-up-your-unit-tests-with-laravel-181a</guid>
      <description>&lt;p&gt;&lt;strong&gt;TLDR;&lt;/strong&gt; Don't use the base TestCase which ships with laravel out of the box. If your tests don't require Laravel specific functionality, Using PHPUnit's base TestCase is more than 4 times faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benchmark
&lt;/h3&gt;

&lt;p&gt;For this test, I'm using the latest version of Laravel (7.25.0) on a Macbook Pro with 16GB RAM and a 2.3 GHz Quad-Core Intel Core i5 processor.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Install Laravel from the official guide &lt;a href="https://laravel.com/docs/7.x/installation#installation"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a class called &lt;code&gt;Math&lt;/code&gt; in &lt;code&gt;app/Math.php&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$first&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the test file &lt;code&gt;MathTest.php&lt;/code&gt; in &lt;code&gt;tests/Unit&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Unit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Math&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MathTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @dataProvider provideDataForSum
     *
     * @param int $first
     * @param int $second
     * @param int $expectedResult
     */&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$expectedResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$math&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$actualResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$math&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$second&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$expectedResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$actualResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;provideDataForSum&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'sum two zeros (0 + 0 = 0)'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s1"&gt;'sum negative and positive number (-1 + 3 = 2)'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;2&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s1"&gt;'sum two positive numbers (1 + 6 = 7)'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;7&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s1"&gt;'sum two negative numbers (-4 + -8 = -12)'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the tests using&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./vendor/bin/phpunit tests/Unit/MathTest.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt; Time: 138 ms, Memory: 16.00 MB&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change line 8 in &lt;code&gt;MathTest.php&lt;/code&gt; with &lt;code&gt;use PHPUnit\Framework\TestCase;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the tests again using&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./vendor/bin/phpunit tests/Unit/MathTest.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt; Time: 33 ms, Memory: 6.00 MB&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;The test with laravel's base test case is &lt;code&gt;418%&lt;/code&gt; slower than the tests with PHPUnit's base test case. Also, This is just 1 test, Imagine how much time you will save on a project with more than 1000 test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; From laravel 6.0, The &lt;code&gt;ExampleTest.php&lt;/code&gt; file in &lt;code&gt;tests/Unit&lt;/code&gt; now uses &lt;code&gt;PHPUnit\Framework\TestCase;&lt;/code&gt; but If you are coming from an old version of laravel you may be using the laravel base test &lt;code&gt;Tests\TestCase;&lt;/code&gt; instead.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>testing</category>
    </item>
    <item>
      <title>How to build, run and test go2 files locally</title>
      <dc:creator>Arnold Acho</dc:creator>
      <pubDate>Sun, 16 Aug 2020 14:58:41 +0000</pubDate>
      <link>https://dev.to/achoarnold/how-to-build-run-and-test-go2-files-locally-3gj0</link>
      <guid>https://dev.to/achoarnold/how-to-build-run-and-test-go2-files-locally-3gj0</guid>
      <description>&lt;p&gt;I worked recently on an &lt;a href="https://github.com/NdoleStudio/lfu-cache"&gt;in-memory key, value cache with Go&lt;/a&gt; and I used &lt;code&gt;interface{}&lt;/code&gt; for the &lt;code&gt;key&lt;/code&gt;, &lt;code&gt;value&lt;/code&gt; types since I didn't want to restrict their usage to a specific type. Now with Generics in go, I refactored this package such that you could explicitly set the types of the key and value when instantiating the cache.  I found it difficult to run go2 code locally hence this blogpost.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependencies
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Docker &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Approach
&lt;/h3&gt;

&lt;p&gt;Luckily, there's a docker image with the &lt;code&gt;go2go&lt;/code&gt; tool already installed (&lt;a href="https://hub.docker.com/r/levonet/golang"&gt;levonet/golang:go2go&lt;/a&gt;). The idea here is to build/run/test the go2 code inside this docker container. &lt;/p&gt;

&lt;h4&gt;
  
  
  Build
&lt;/h4&gt;

&lt;p&gt;Write your go2 code in a file ending in &lt;code&gt;.go2&lt;/code&gt; e.g cache.go2. From the directory where the file is located, run the command below to build the it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:/go/src/myapp &lt;span class="nt"&gt;-w&lt;/span&gt; /go/src/myapp levonet/golang:go2go go tool go2go build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run
&lt;/h3&gt;

&lt;p&gt;Similarly, you can run your code using the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:/go/src/myapp &lt;span class="nt"&gt;-w&lt;/span&gt; /go/src/myapp levonet/golang:go2go go tool go2go run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test
&lt;/h3&gt;

&lt;p&gt;You could also test using the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:/go/src/myapp &lt;span class="nt"&gt;-w&lt;/span&gt; /go/src/myapp levonet/golang:go2go go tool go2go &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creavats
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://github.com/golang/go/issues/40061"&gt;go2go command doesn't support go modules&lt;/a&gt;. I had to work around this by creating a custom docker file with steps to download my dependencies manually.&lt;/li&gt;
&lt;li&gt;I can't get test coverage using the go2go test tool. It can do the tests but since it translates the go code inside the same file as the &lt;code&gt;_test.go&lt;/code&gt; file. I couldn't get test coverage for files in this directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workarounds
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;I solved the go.mod problem by creating a custom Dockerfile which downloads my dependencies and adds them to the &lt;code&gt;go2go build path&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; levonet/golang:go2go&lt;/span&gt;

&lt;span class="c"&gt;## "apt-get update" updates package list&lt;/span&gt;
&lt;span class="c"&gt;## "apt-get install git -y" installs 'git' the "-y" flag is there to answer yes to all prompts&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install &lt;/span&gt;git &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# This command clones the dependencies in my GOPATH&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;git clone https://github.com/dgrijalva/lfu-go /go/src/github.com/dgrijalva/lfu-go &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    git clone https://github.com/arschles/assert /go/src/github.com/arschles/assert

&lt;span class="c"&gt;# This command copies all my files in the directory /go/src/myapp in the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./ /go/src/myapp&lt;/span&gt;

&lt;span class="c"&gt;## This changes the working directory&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /go/src/myapp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Build the docker image using the command below the &lt;code&gt;-t cache&lt;/code&gt; is to tag the image as &lt;code&gt;cache&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build . -t cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You can now build/run/test the &lt;code&gt;.go2&lt;/code&gt; code using the commands below
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Test&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; lfucache go tool go2go &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# Build&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; lfucache go tool go2go build

&lt;span class="c"&gt;# Run&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; lfucache go tool go2go run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can also be done with a CI/CD tool like travis. I have the following travis file the &lt;a href="https://pkg.go.dev/github.com/NdoleStudio/lfu-cache?tab=doc"&gt;&lt;code&gt;lfucache&lt;/code&gt;&lt;/a&gt; package&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;

&lt;span class="na"&gt;before_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# This builds the docker file containing the tests&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker build . -t lfucache&lt;/span&gt;

&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# This tests the go2 files&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker run --rm lfucache go tool go2go test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>go</category>
      <category>docker</category>
      <category>generics</category>
    </item>
    <item>
      <title>PHP Test Coverage with Travis CI and Code Climate using Clover</title>
      <dc:creator>Arnold Acho</dc:creator>
      <pubDate>Fri, 19 Oct 2018 07:34:36 +0000</pubDate>
      <link>https://dev.to/acho_arnold/php-test-coverage-with-travis-ci-and-code-climate-using-clover-eih</link>
      <guid>https://dev.to/acho_arnold/php-test-coverage-with-travis-ci-and-code-climate-using-clover-eih</guid>
      <description>&lt;p&gt;This article is a guide on how to set-up a PHP based repository on &lt;a href="https://codeclimate.com"&gt;code climate&lt;/a&gt; such that it reports the test coverage. When you push a commit to your repository on GitHub, the &lt;a href="https://travis-ci.org"&gt;Travis CI&lt;/a&gt; pipelines will run and generate the test coverage report which will then be sent to the code climate platform.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Get your code climate Test Reporter ID
&lt;/h4&gt;

&lt;p&gt;Navigate to "Repo Settings -&amp;gt; Test Coverage" as seen on the image below&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NnDhvnWW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/acho-arnold-cf/image/upload/v1539644048/Screenshot_2018-10-15_23.49.21_gxhz7l.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NnDhvnWW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/acho-arnold-cf/image/upload/v1539644048/Screenshot_2018-10-15_23.49.21_gxhz7l.jpg" alt="Code Climate Image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Configure your .travis.yml file
&lt;/h4&gt;

&lt;p&gt;Grab a sample &lt;code&gt;.travis.yml&lt;/code&gt; file for a PHP project from this repository &lt;a href="https://git.io/fxu0q"&gt;https://git.io/fxu0q&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NOTE: Copy the &lt;code&gt;.travis.yml&lt;/code&gt; file from &lt;strong&gt;Example 2&lt;/strong&gt; since it uses &lt;code&gt;Clover&lt;/code&gt; for test coverage.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;global&lt;/code&gt; section of the &lt;code&gt;.travis.yml&lt;/code&gt; file, replace the &lt;code&gt;CC_TEST_REPORTER_ID&lt;/code&gt; variable with the ID which you copied from step 1 above.&lt;/p&gt;

&lt;p&gt;Change the php version under the &lt;code&gt;php&lt;/code&gt; block to your desired version.&lt;/p&gt;

&lt;p&gt;Also, under the &lt;code&gt;before_install&lt;/code&gt; section, add the script &lt;code&gt;composer install --no-dev&lt;/code&gt; such that your composer dependencies are installed before tests are run. &lt;/p&gt;

&lt;p&gt;Finally, Change the last line from&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; - if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  - if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build  -t clover --exit-code $TRAVIS_TEST_RESULT; fi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Your &lt;code&gt;.travis.yml&lt;/code&gt; file would look like this after the above changes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CC_TEST_REPORTER_ID={put your reporter id here}&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GIT_COMMITTED_AT=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then git log -1 --pretty=format:%ct; else git log -1 --skip 1 --pretty=format:%ct; fi)&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php&lt;/span&gt;
&lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;7.2'&lt;/span&gt;
&lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;composer install --no-dev&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 &amp;gt; ./cc-test-reporter&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chmod +x ./cc-test-reporter&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./cc-test-reporter before-build&lt;/span&gt;
&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;phpunit&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--coverage-text&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--coverage-clover&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;build/logs/clover.xml"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build  -t clover --exit-code $TRAVIS_TEST_RESULT; fi&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="(https://github.com/AchoArnold/GraphDS/blob/master/.travis.yml)"&gt;You can get this &lt;code&gt;.travis.yml&lt;/code&gt; file on github.&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Configure phpunit.xml
&lt;/h4&gt;

&lt;p&gt;It is mandatory to configure a whitelist for telling PHPUnit which source code files to include in the code coverage report. If you don't already have a whitelist filter in your &lt;code&gt;phpunit.xml&lt;/code&gt; file, add one as such&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;filter&amp;gt;
    &amp;lt;whitelist processUncoveredFilesFromWhitelist="true"&amp;gt;
        &amp;lt;directory suffix=".php"&amp;gt;./src&amp;lt;/directory&amp;gt; 
        &amp;lt;exclude&amp;gt;
           &amp;lt;directory&amp;gt;./vendor&amp;lt;/directory&amp;gt;
        &amp;lt;/exclude&amp;gt;
    &amp;lt;/whitelist&amp;gt;
&amp;lt;/filter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the example above, &lt;code&gt;./src&lt;/code&gt; is the path to the directory where your source files are found and &lt;code&gt;./vendor&lt;/code&gt; is the path to a directory which you want to ignore.&lt;/p&gt;

&lt;p&gt;Also, tell PHPUnit where to log the test coverage output by adding a &lt;code&gt;logging&lt;/code&gt; block in the &lt;code&gt;phpunit.xml&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;logging&amp;gt;
    &amp;lt;log type="coverage-clover" target="build/logs/clover.xml"/&amp;gt;
&amp;lt;/logging&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;My complete PHPUnit file looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;phpunit&lt;/span&gt; &lt;span class="na"&gt;backupGlobals=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
         &lt;span class="na"&gt;backupStaticAttributes=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
         &lt;span class="na"&gt;bootstrap=&lt;/span&gt;&lt;span class="s"&gt;"vendor/autoload.php"&lt;/span&gt;
         &lt;span class="na"&gt;colors=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
         &lt;span class="na"&gt;convertErrorsToExceptions=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
         &lt;span class="na"&gt;convertNoticesToExceptions=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
         &lt;span class="na"&gt;convertWarningsToExceptions=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
         &lt;span class="na"&gt;processIsolation=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
         &lt;span class="na"&gt;stopOnFailure=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;testsuites&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;testsuite&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"unit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;directory&lt;/span&gt; &lt;span class="na"&gt;suffix=&lt;/span&gt;&lt;span class="s"&gt;"Test.php"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;./tests&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/testsuite&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/testsuites&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;whitelist&lt;/span&gt; &lt;span class="na"&gt;processUncoveredFilesFromWhitelist=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;directory&lt;/span&gt; &lt;span class="na"&gt;suffix=&lt;/span&gt;&lt;span class="s"&gt;".php"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;./src&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;exclude&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;./vendor&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;./doc&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;./SampleApp_RoadPlanner/&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/exclude&amp;gt;&lt;/span&gt;&amp;gt;
        &lt;span class="nt"&gt;&amp;lt;/whitelist&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;logging&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;log&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"coverage-clover"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"build/logs/clover.xml"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/logging&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/phpunit&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/AchoArnold/GraphDS/blob/master/phpunit.xml"&gt;You can see this code on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  That Is All!
&lt;/h4&gt;

&lt;p&gt;Next time when your push a build on Travis CI, it will run your tests and send the coverage report to Code Climate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/acho-arnold-cf/image/upload/v1540182992/test-coverage-report.jpg"&gt;Sample Test Coverage Report&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>codeclimate</category>
      <category>travisci</category>
    </item>
  </channel>
</rss>
