<?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: Tin Chung</title>
    <description>The latest articles on DEV Community by Tin Chung (@chungquantin).</description>
    <link>https://dev.to/chungquantin</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%2F444896%2Fdbb08d29-aa06-41cf-913f-5f8b53f4e541.jpeg</url>
      <title>DEV Community: Tin Chung</title>
      <link>https://dev.to/chungquantin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chungquantin"/>
    <language>en</language>
    <item>
      <title>Introducing terminal tool to manage embedded database</title>
      <dc:creator>Tin Chung</dc:creator>
      <pubDate>Sat, 08 Apr 2023 15:00:33 +0000</pubDate>
      <link>https://dev.to/chungquantin/introducing-terminal-tool-to-manage-embedded-database-4c3f</link>
      <guid>https://dev.to/chungquantin/introducing-terminal-tool-to-manage-embedded-database-4c3f</guid>
      <description>&lt;p&gt;Hello everyone, a few months ago I wrote a terminal tool in Rust to help view data stored in embedded databases like RocksDB or Sled. As someone who enjoys coding low-level systems, I found it very difficult when there were almost no tools available to view the byte data of embedded databases. That's why EDMA was created to solve that problem.&lt;br&gt;
The project is still in its early stages, but it already encompasses some of the main features. I hope it will be useful for those who are into low-level or embedded programming.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NAnG-KRL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ny2iycel1j9opttmo2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NAnG-KRL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ny2iycel1j9opttmo2g.png" alt="EDMA banner" width="657" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;EDMA is a command-line tool that allows users to interact with embedded databases at a byte level. It provides a simple yet powerful interface to view, modify, and delete data in databases like RocksDB or Sled. The tool is built using Rust, a systems programming language known for its safety, speed, and concurrency.&lt;/p&gt;

&lt;p&gt;One of the key features of EDMA is its ability to work with a wide range of data types. Users can view and modify data in the database in different formats, including binary, hexadecimal, and ASCII. They can also specify the type of data stored in the database and EDMA will interpret it accordingly.&lt;/p&gt;

&lt;p&gt;Another useful feature of EDMA is its support for filtering and sorting data. Users can search for specific data based on a range of criteria, such as key or value length, and sort the data by key or value. This makes it easy to find and analyze specific data in the database.&lt;/p&gt;

&lt;p&gt;EDMA is designed to be easy to use and customizable. Users can configure the tool to work with their specific database and data format requirements. They can also extend the functionality of the tool by creating custom plugins.&lt;/p&gt;

&lt;p&gt;Overall, EDMA is a valuable tool for developers working with embedded databases. It simplifies the process of working with low-level data and provides a convenient interface for analyzing and modifying data in embedded databases.&lt;/p&gt;

&lt;p&gt;Link to Github repository: &lt;a href="https://github.com/nomadiz/edma"&gt;https://github.com/nomadiz/edma&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>database</category>
      <category>opensource</category>
      <category>terminal</category>
    </item>
    <item>
      <title>Rust Blog Series: What is Rust programming language?</title>
      <dc:creator>Tin Chung</dc:creator>
      <pubDate>Fri, 20 Jan 2023 19:30:48 +0000</pubDate>
      <link>https://dev.to/chungquantin/rust-blog-series-what-is-rust-programming-language-39eg</link>
      <guid>https://dev.to/chungquantin/rust-blog-series-what-is-rust-programming-language-39eg</guid>
      <description>&lt;p&gt;Rust is a systems programming language that is designed to be safe, concurrent, and fast. It is an open-source programming language that is gaining popularity among developers for its unique approach to memory safety, which eliminates many of the common issues that plague other systems programming languages like C and C++.&lt;/p&gt;

&lt;p&gt;One of the most notable features of Rust is its ownership model, which ensures that resources are only accessed in a safe and controlled way. In Rust, each value has a unique owner, and when the owner goes out of scope, the value is automatically cleaned up. This eliminates the need for manual memory management, and greatly reduces the likelihood of common programming errors such as null pointer dereferences and buffer overflows.&lt;/p&gt;

&lt;p&gt;Rust also has built-in support for concurrency, which allows for the creation of multi-threaded applications that can take full advantage of modern multi-core CPUs. The language's built-in support for message passing concurrency makes it easy to create concurrent code that is also safe and easy to reason about.&lt;/p&gt;

&lt;p&gt;In addition to its focus on safety and concurrency, Rust is also designed to be fast. The language's strict type system and low-level control over memory layout allows for the creation of highly performant code that is on par with C and C++. Rust's built-in support for inline assembly and FFI also makes it easy to interface with existing C and C++ code, allowing for the reuse of existing libraries and frameworks.&lt;/p&gt;

&lt;p&gt;Another strong point of Rust is its active and welcoming community, which is made up of both experienced and new developers. The community provides a wide range of resources and support for learning Rust, including documentation, tutorials, and a large number of open-source libraries and frameworks.&lt;/p&gt;

&lt;p&gt;Rust is also used in a wide range of applications, from web development to embedded systems, and has been adopted by companies such as Amazon, Dropbox, and Microsoft.&lt;/p&gt;

&lt;p&gt;In summary, Rust is a systems programming language that is designed to be safe, concurrent, and fast. Its ownership model and built-in support for concurrency make it easy to create safe and concurrent code that is also highly performant. The language's strong type system, low-level control over memory layout, and active community make it a powerful choice for a wide range of applications.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>SolomonDB Weekly Update (#2): Palmon</title>
      <dc:creator>Tin Chung</dc:creator>
      <pubDate>Wed, 30 Nov 2022 07:55:47 +0000</pubDate>
      <link>https://dev.to/chungquantin/solomondb-weekly-update-2-palmon-3emb</link>
      <guid>https://dev.to/chungquantin/solomondb-weekly-update-2-palmon-3emb</guid>
      <description>&lt;p&gt;Support my project by visiting &lt;a href="https://github.com/nomadiz/solomon-db"&gt;SolomonDB Github&lt;/a&gt; and give me a star ⭐️&lt;/p&gt;

&lt;h2&gt;
  
  
  Weekly Update #2: Palmon
&lt;/h2&gt;

&lt;p&gt;Date: November 2022 (1-7/11/2022)&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kGlZEjuS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/Paimon.jpg/180px-Paimon.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kGlZEjuS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/Paimon.jpg/180px-Paimon.jpg" width="180" height="196"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Palmon is one of the Kings of Hell, more obedient to Lucifer than other kings are, and has two hundred legions of demons under his rule. He has a great voice and roars as soon as he comes, speaking in this manner for a while until the conjurer compels him and then he answers clearly the questions he is asked. When a conjurer invokes this demon he must look towards the northwest, the direction of Paimon's house, and when Paimon appears he must be allowed to ask the conjurer what he wishes and be answered, in order to obtain the same from him. - Wikipedia&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Commits on Nov 1, 2022
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;The prior implementation of &lt;code&gt;RocksDBDriver&lt;/code&gt; was using the database instance initialized using &lt;code&gt;DB&lt;/code&gt; object. And all methods are called from the object &lt;code&gt;DB&lt;/code&gt; instance too. However, this approach has some limitations in terms of concurrency operations. Briefly, I migrate it from using &lt;code&gt;DB&lt;/code&gt; to handling operations using transactions - a better control flow approach. Instead of using &lt;code&gt;TransactionDB&lt;/code&gt;, I choose &lt;code&gt;OptimisticTransactionDB&lt;/code&gt; which is more efficient for read contention database, correct me if I am wrong.&lt;/p&gt;

&lt;p&gt;You can read more about this in &lt;a href="https://github.com/facebook/rocksdb/wiki/Transactions#optimistictransactiondb"&gt;RocksDB Wiki&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Detail explanation
&lt;/h3&gt;

&lt;p&gt;Even though there is only one commit and only today, this commit has a lot of code refractors. An obvious refractor is migrating from &lt;code&gt;Driver&lt;/code&gt; to &lt;code&gt;Adapter&lt;/code&gt; which follows adapter pattern.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;StorageDriver&lt;/code&gt; to &lt;code&gt;StorageAdapter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;RocksDBDriver&lt;/code&gt; to &lt;code&gt;RocksDBAdapter&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Walk through the implementation of &lt;code&gt;StorageAdapter&lt;/code&gt;, we have&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;StorageAdapter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;StorageAdapterName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;db_instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Pin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;StorageVariant&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;You may notice the use of generic type &lt;code&gt;Pin&amp;lt;Arc&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;. Explain more about why I wrote this. &lt;code&gt;Pin&lt;/code&gt; trait will pin the object in a memory, which means it can't be move to a different location in a memory, for example, using &lt;code&gt;std::mem::swap&lt;/code&gt;. Inside the &lt;code&gt;Pin&lt;/code&gt; type, we have &lt;code&gt;Arc&lt;/code&gt; or &lt;strong&gt;Atomically Reference Counted&lt;/strong&gt;.&lt;code&gt;Arc&lt;/code&gt; type shares ownership between threads, which is different from single threaded type &lt;code&gt;Rc&lt;/code&gt;. Hence, this is usually used for handling multi-threaded operations and it is suitable for our distributed database design.&lt;/p&gt;

&lt;p&gt;New method added to &lt;code&gt;RocksDBAdapter&lt;/code&gt; to create a transaction&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Transaction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TxType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.get_inner&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;db_instance&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;inner&lt;/span&gt;&lt;span class="py"&gt;.db_instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db_instance&lt;/span&gt;&lt;span class="nf"&gt;.transaction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// The database reference must always outlive&lt;/span&gt;
        &lt;span class="c1"&gt;// the transaction. If it doesn't then this&lt;/span&gt;
        &lt;span class="c1"&gt;// is undefined behaviour. This unsafe block&lt;/span&gt;
        &lt;span class="c1"&gt;// ensures that the transaction reference is&lt;/span&gt;
        &lt;span class="c1"&gt;// static, but will cause a crash if the&lt;/span&gt;
        &lt;span class="c1"&gt;// datastore is dropped prematurely.&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;transmute&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
                &lt;span class="nn"&gt;rocksdb&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Transaction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OptimisticTransactionDB&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nn"&gt;rocksdb&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Transaction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OptimisticTransactionDB&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;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TxType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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;There is a head-aching concept in this method, we have an unsafe method use &lt;code&gt;std::mem::transmute&lt;/code&gt;. This is not recommended to use as it transform the lifetime of an object. The reason why we use this method here is because, we need to cast the original lifetime of &lt;code&gt;OptimisticTransactionDB&lt;/code&gt; to static as we want the transaction remains as long as it can until the program stops. This is referenced from the source code of &lt;strong&gt;SurrealDB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On the other hand, we have an implementation for internal transaction&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Transaction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TxType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any storage adapter can be understand as a bridge to create transaction, it does not store any transaction value. This separation provides the ability to control a single transaction each operation instead of a whole &lt;code&gt;db_instance&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contributors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Chung Quan Tin (&lt;a href="https://github.com/chungquantin"&gt;@chungquantin&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Commits on Nov 2, 2022
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Enhancing the development experience by configuring the CI/CD pipeline using Github Actions.&lt;/li&gt;
&lt;li&gt;  Implement basic methods of RocksDB OptimisticDB transaction&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Detail explanation
&lt;/h3&gt;

&lt;p&gt;There are two workflows added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Formatter (check + apply) workflow: Use &lt;code&gt;cargo clippy&lt;/code&gt; and &lt;code&gt;cargo fmt&lt;/code&gt; to format and lint the repo.&lt;/li&gt;
&lt;li&gt;  Test: Run &lt;code&gt;cargo test&lt;/code&gt; on the workspace whenever there's an update to &lt;code&gt;master&lt;/code&gt; branch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every datastore transaction will be marked generically as DBTransaction or Distributed Database Transaction. This is implied by Solomon DB technical directory. Transaction will implement a trait that requires these below method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Check if closed&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;closed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Cancel a transaction&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Commit a transaction&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Check if a key exists&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;exi&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&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;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&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;K&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt;
&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Into&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Fetch a key from the database&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&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;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&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;K&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Val&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Insert or update a key in the database&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&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;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&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;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Insert a key if it doesn't exist in the database&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&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;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&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;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Delete a key&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;del&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&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;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&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;K&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Contributors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Chung Quan Tin (&lt;a href="https://github.com/chungquantin"&gt;@chungquantin&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Commits on Nov 4, 2022
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;Write a new macro to auto generate test code for datastore adapter. Whenever there's a new datastore implemented, we can add it to the test suite easily by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;full_test_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;RocksDBAdapter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code implementation is referenced from &lt;a href="https://github.com/indradb/indradb/blob/master/lib/src/tests/macros.rs"&gt;IndraDB&lt;/a&gt;. On the other hand, these commits add a new feature tag called &lt;code&gt;test-suite&lt;/code&gt; which must be declared to allow all test runs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;[features]&lt;/span&gt;
default = ["kv-rocksdb"]
&lt;span class="p"&gt;kv-rocksdb = ["dep:rocksdb"]
&lt;/span&gt;&lt;span class="gi"&gt;+ test-suite = []
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run &lt;code&gt;cargo test&lt;/code&gt; or &lt;code&gt;cargo nextest&lt;/code&gt; enabling the &lt;code&gt;test-suite&lt;/code&gt; feature, can follow these commands to run&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;cargo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--features&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test-suite&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;cargo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nextest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--features&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test-suite&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Detail explanations
&lt;/h3&gt;

&lt;p&gt;The logic behind the new macro is not too complicated, the macro &lt;code&gt;define_test!&lt;/code&gt; receive any &lt;code&gt;datastore_adapter&lt;/code&gt; as an input along with the name for the test. This name is also a name of methods exported from crate &lt;code&gt;tests&lt;/code&gt;. This approach is required to overpass the type strictness of &lt;code&gt;DatastoreAdapter&lt;/code&gt; as we will support multiple types of datastore adapter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// Defines a unit test function.&lt;/span&gt;
&lt;span class="nd"&gt;#[macro_export]&lt;/span&gt;
&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;define_test&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$datastore_adapter:expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;#[tokio::test]&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;datastore_adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$datastore_adapter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nv"&gt;$crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datastore_adapter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&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;span class="cd"&gt;/// Use this macro to enable the entire standard test suite.&lt;/span&gt;
&lt;span class="nd"&gt;#[macro_export]&lt;/span&gt;
&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;full_test_impl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$code:expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;#[cfg(test)]&lt;/span&gt;
        &lt;span class="nd"&gt;define_test!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;should_delete_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$code&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;
  
  
  Contributors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Chung Quan Tin (&lt;a href="https://github.com/chungquantin"&gt;@chungquantin&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Commits on Nov 5, 2022
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;Introducing a new struct &lt;code&gt;DatastoreManager&lt;/code&gt; which is generated using macro &lt;code&gt;impl_datastore_manager&lt;/code&gt;. The idea behinds this implementation is to manage all datastore adapter in the cleanest way.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Adding method to generate a random datastore path
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;///&lt;/span&gt; Generate a path to store data for RocksDB
&lt;span class="p"&gt;fn generate_path(id: Option&amp;lt;i32&amp;gt;) -&amp;gt; String {
&lt;/span&gt;     let random_id: i32 = generate_random_i32();
     let id = &amp;amp;id.unwrap_or(random_id).to_string();
&lt;span class="gd"&gt;- String::from("./.temp/rocks-") + id + ".db"
&lt;/span&gt;&lt;span class="gi"&gt;+ let path = if cfg!(target_os = "linux") {
+    "/dev/shm/".into()
+ } else {
+    temp_dir()
+ }
+ .join(format!("solomon-rocksdb-{}", id));
+
+   path_to_string(&amp;amp;path).unwrap()
&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  Adding column family to RocksDB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adding models for graph related struct: &lt;code&gt;Node - Label - Property - Relationship&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Detail explanation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://github.com/EighteenZi/rocksdb_wiki/blob/master/Column-Families.md"&gt;RocksDB Column Family&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;As being stated in the RocksDB Wiki:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Each key-value pair in RocksDB is associated with exactly one Column Family.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In SolomonDB design, there will be multiple column families specified for different set of data. For example: &lt;strong&gt;vertex, vertex-property, edge, edge-property and&lt;/strong&gt; &lt;strong&gt;label&lt;/strong&gt;. All methods of RocksDB transaction will include a column family attribute. For example, the &lt;code&gt;get&lt;/code&gt; method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;///&lt;/span&gt; Fetch a key from the database
&lt;span class="gd"&gt;- async fn get&amp;lt;K: Into&amp;lt;Key&amp;gt; + Send&amp;gt;(&amp;amp;mut self, key: K) -&amp;gt; Result&amp;lt;Option&amp;lt;Val&amp;gt;, Error&amp;gt;;
&lt;/span&gt;&lt;span class="gi"&gt;+ async fn get&amp;lt;K: Into&amp;lt;Key&amp;gt; + Send&amp;gt;(&amp;amp;mut self, cf: CF, key: K) -&amp;gt; Result&amp;lt;Option&amp;lt;Val&amp;gt;, Error&amp;gt;;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;a href="https://github.com/opencypher/openCypher/blob/master/docs/property-graph-model.adoc"&gt;Property Graph Design&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Not sure but I remember this has been mentioned in a very first commit log, our graph database will follow the structure of &lt;code&gt;Property Graph&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Vertex&lt;/strong&gt;: Common object in every graph model. In Property Graph, vertex is more versatile. It has multiple properties, it can be considered as a document in NoSQL database. Vertex can also have multiple labels to identify itself.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Relationship&lt;/strong&gt;: Or edge in single relational database. Indicates the link between two vertex. However, relationship can have properties too. It also has a type, for example, if two &lt;code&gt;LOVER&lt;/code&gt; nodes connect, the relationship type should be &lt;code&gt;LOVE&lt;/code&gt;. Defined as &lt;code&gt;source_vertex -&amp;gt; relationship -&amp;gt; target_vertex&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Property&lt;/strong&gt;: Define attribute type and name of object field. For example, vertex (or node) can have name, age, birthday and relationship can also have name. Structure of &lt;code&gt;property&lt;/code&gt; is &lt;code&gt;uuid | name | type&lt;/code&gt;. Property of each core objects (node and relationship) will be stored in a &lt;code&gt;HashMap&amp;lt;Uuid, Vec&amp;lt;u8&amp;gt;&amp;gt;&lt;/code&gt; where &lt;code&gt;Uuid = Property ID&lt;/code&gt; and &lt;code&gt;Vec&amp;lt;u8&amp;gt; = Byte value for that property&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Label&lt;/strong&gt;: Vertex can have multiple labels. For example, one vertex can be a Person, Programmer and Employee at the same time. This can be misunderstood with &lt;code&gt;Property&lt;/code&gt;. However, they are not the same. Labels are used for marking node instead of defining attributes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Contributors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Chung Quan Tin (&lt;a href="https://github.com/chungquantin"&gt;@chungquantin&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Commits on Nov 6, 2022
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Write DEVLOG for 2022 October CHANGLOG and November 1st commits&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Detail explanation
&lt;/h3&gt;

&lt;p&gt;In facts, I did try to add a Github Actions workflows to auto generate Github CHANGELOG. However, it did not work as expected so I just decide to write CHANGELOG on my own.&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Changelog&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;created&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;changelog&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-20.04&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;✏️&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Generate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;release&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;changelog"&lt;/span&gt;
              &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;heinrichreimer/github-changelog-generator-action@v2.3&lt;/span&gt;
              &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Contributors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Chung Quan Tin (&lt;a href="https://github.com/chungquantin"&gt;@chungquantin&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Commits on Nov 7, 2022
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Updating Rust compiler version to support new feature in Rust &lt;code&gt;1.65.0&lt;/code&gt;: &lt;code&gt;Generic Associated Type&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Adding &lt;code&gt;CassandraDB&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Write two new methods for &lt;code&gt;Vertex&lt;/code&gt; controller&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Detail explanation
&lt;/h3&gt;

&lt;p&gt;Generic Associated Type is not new and it is common in Rust &lt;code&gt;nightly&lt;/code&gt; channel. However, it was only officially released to &lt;code&gt;stable&lt;/code&gt; channel in the latest version. Based on the given definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generic associated types are an extension that permit associated types to have generic parameters. This allows associated types to capture types that may include generic parameters that came from a trait method. These can be lifetime or type parameters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is how GAT used in SolomonDB code. We no longer have to care about &lt;code&gt;Generic Type&lt;/code&gt; passed between structs. On the other hand, &lt;code&gt;GAT Transaction&lt;/code&gt; force all implemented &lt;code&gt;Transaction&lt;/code&gt; type to be SimpleTransaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;#[async_trait]&lt;/span&gt;
- pub trait DatastoreAdapter&amp;lt;T: SimpleTransaction&amp;gt; {
&lt;span class="gi"&gt;+ pub trait DatastoreAdapter {
+   type Transaction: SimpleTransaction;
&lt;/span&gt;    // # Create new database transaction
    // Set `rw` default to false means readable but not readable
&lt;span class="gd"&gt;- fn transaction(&amp;amp;self, rw: bool) -&amp;gt; Result&amp;lt;T, Error&amp;gt;;
&lt;/span&gt;&lt;span class="gi"&gt;+ fn transaction(&amp;amp;self, rw: bool) -&amp;gt; Result&amp;lt;Self::Transaction, Error&amp;gt;;
&lt;/span&gt;
    fn default() -&amp;gt; Self;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With GAT, we can make a fully reusable struct &lt;code&gt;DatastoreAdapter&lt;/code&gt; and get rid of declaring &lt;code&gt;Transaction&lt;/code&gt; generic type like &lt;code&gt;RocksDBTransaction&lt;/code&gt;. The implementation of &lt;code&gt;DatastoreAdapter&lt;/code&gt; instance for &lt;code&gt;RocksDB&lt;/code&gt; will be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;#[async_trait]&lt;/span&gt;
- impl DatastoreAdapter&amp;lt;RocksDBTransaction&amp;gt; for RocksDBAdapter {
&lt;span class="gi"&gt;+ impl DatastoreAdapter for RocksDBAdapter {
+ type Transaction = RocksDBTransaction;
&lt;/span&gt;
    fn default() -&amp;gt; Self {
        let path = &amp;amp;RocksDBAdapter::generate_path(None);
        RocksDBAdapter::new(path, None).unwrap()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Super clean right? Worth a try if you have not updated yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contributors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Chung Quan Tin (&lt;a href="https://github.com/chungquantin"&gt;@chungquantin&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>solomondb</category>
      <category>database</category>
      <category>rust</category>
      <category>opensource</category>
    </item>
    <item>
      <title>SolomonDB Weekly Update (#1): Baal</title>
      <dc:creator>Tin Chung</dc:creator>
      <pubDate>Wed, 30 Nov 2022 07:52:00 +0000</pubDate>
      <link>https://dev.to/chungquantin/solomondb-weekly-update-1-baal-1hp7</link>
      <guid>https://dev.to/chungquantin/solomondb-weekly-update-1-baal-1hp7</guid>
      <description>&lt;p&gt;Support my project by visiting &lt;a href="https://github.com/nomadiz/solomon-db" rel="noopener noreferrer"&gt;SolomonDB Github&lt;/a&gt; and give me a star ⭐️&lt;/p&gt;

&lt;h2&gt;
  
  
  Weekly Update #1: Baal
&lt;/h2&gt;

&lt;p&gt;Date: October 2022 (26-28/11/2022)&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F4%2F44%2FBael.jpg%2F220px-Bael.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F4%2F44%2FBael.jpg%2F220px-Bael.jpg" width="800" height="400"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;According to the Grand Grimoire, Baal (or Bael) is the head of the infernal powers. He is also the first demon listed in Wierus' Pseudomonarchia daemonum. According to Wierus, Bael is the first king of Hell with estates in the east. He has three heads: a toad, a man, and a cat. He also speaks in a raucous, but well-formed voice, and commands 66 legions. Bael teaches the art of invisibility, and may be the equivalent of Baal or Baalzebub, one of the Seven princes of Hell. - Wikipedia&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Commits on Oct 26, 2022
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;A soft beginning. I just spend some time to read graph database book and learning concepts, requirements needed to construct Solomon DB.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detail explanation
&lt;/h3&gt;

&lt;p&gt;There are a few interesting learning outcomes acquired here:&lt;/p&gt;

&lt;p&gt;These concepts are not too complicated actually. Not talking about native graph database, non-native graph database is more like a database wrapper which has internals built on top of other databases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt;   Underlying storage
&lt;span class="p"&gt;-&lt;/span&gt;   Processing engine
&lt;span class="p"&gt;-&lt;/span&gt;   Graph compute engine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Learnt and noted down these concepts in &lt;strong&gt;WIKI.md&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As this is the first commit, it only includes code to initialize a codebase and its basic layout for Rust project using &lt;code&gt;cargo new&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// A simple hello world program (db/src/main.rs)&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, world!"&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;
  
  
  Contributors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Chung Quan Tin (&lt;a href="https://github.com/chungquantin" rel="noopener noreferrer"&gt;@chungquantin&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Commits on Oct 28, 2022
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;StorageDriver&lt;/code&gt;, new type &lt;code&gt;RocksDBDriver&lt;/code&gt;, macro &lt;code&gt;impl_driver_core&lt;/code&gt; and misc implementation for &lt;code&gt;StorageErr&lt;/code&gt; and &lt;code&gt;Status&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detail explanation
&lt;/h3&gt;

&lt;p&gt;Things getting more exciting when we touch advanced syntaxes in Rust: &lt;a href="https://doc.rust-lang.org/rust-by-example/generics/new_types.html" rel="noopener noreferrer"&gt;&lt;code&gt;New Type&lt;/code&gt;&lt;/a&gt; design pattern and &lt;a href="https://doc.rust-lang.org/book/ch19-06-macros.html" rel="noopener noreferrer"&gt;&lt;code&gt;Macro&lt;/code&gt;&lt;/a&gt;. Before jumping right into the main point of today changes, one of a missing features in Rust compared to other OOP languages must be mentioned first is the ability to do &lt;strong&gt;inheritance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With what Rust provides so far, it is quite tricky to construct an inheritable &lt;code&gt;struct&lt;/code&gt; object. At first, you may think doing OOP in Rust is quite bad as inheritance is a core component of any OOP design. However, if you learn more about OOP, you will know &lt;code&gt;Inheritance &amp;lt; Composition&lt;/code&gt;. This is quite off topic, but there is a few discussions and articles related to the way Rust do OOP that you should read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://internals.rust-lang.org/t/why-not-inheritance/5738/14" rel="noopener noreferrer"&gt;Rust Internals | Discussion - Why not inheritance?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://smallcultfollowing.com/babysteps/blog/2015/05/05/where-rusts-enum-shines/" rel="noopener noreferrer"&gt;Where Rust enum shines?&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Briefly, even though Rust does not have an obvious OOP feature like inheritance, it still provides several approaches: &lt;code&gt;Trait&lt;/code&gt;, &lt;code&gt;New type&lt;/code&gt;, &lt;code&gt;Macro&lt;/code&gt; or &lt;code&gt;Enum&lt;/code&gt; to do thing in a inheritance way but cleaner as things are separated elegantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New Type design pattern for RocksDB Driver&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"&lt;em&gt;The &lt;code&gt;newtype&lt;/code&gt; idiom gives compile time guarantees that the right type of value is supplied to a program&lt;/em&gt;" - Rust book.&lt;/p&gt;

&lt;p&gt;I apply the design to implement RocksDB Driver. The idea is to have a parent &lt;code&gt;struct&lt;/code&gt; called &lt;code&gt;StorageDriver&lt;/code&gt; and we will build a new type &lt;code&gt;RocksDBDriver&lt;/code&gt; from that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;StorageDriver&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;db_instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;RocksDBDriver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StorageDriver&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, &lt;code&gt;NewType&lt;/code&gt; design does not exactly like inheritance. For example, if you want to get field &lt;code&gt;db_instance&lt;/code&gt; from &lt;code&gt;RocksDBDriver&lt;/code&gt;, you can't do &lt;code&gt;self.db_instance&lt;/code&gt; but &lt;code&gt;self.0.db.instance&lt;/code&gt;. Can imagine &lt;code&gt;db_instance&lt;/code&gt; is inside &lt;code&gt;StorageDriver&lt;/code&gt; while &lt;code&gt;StorageDriver&lt;/code&gt; is wrapped inside new type &lt;code&gt;RocksDBDriver&lt;/code&gt;. This would make the syntax looks a bit dirty. The solution I used to handle this case is &lt;code&gt;Macro&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Macro provides an ability to maximize the power of Rust syntax. I wrote a macro to implement all below methods used inside any &lt;code&gt;impl&lt;/code&gt; calling to &lt;code&gt;impl_driver_core&lt;/code&gt;. Then to get the inner of new type, we just have to use &lt;code&gt;get_core&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;impl_driver_core&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$DbType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_core&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;StorageDriver&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$DbType&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;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&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;pub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;impl_driver_core&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Struct &lt;code&gt;RocksDBDriver&lt;/code&gt; now becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;RocksDBDriver&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;impl_driver_core!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="cd"&gt;/// # Initializing RocksDB driver&lt;/span&gt;
 &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cf_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;String&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="nn"&gt;rocksdb&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.get_core&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="o"&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;
  
  
  Contributors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Chung Quan Tin (&lt;a href="https://github.com/chungquantin" rel="noopener noreferrer"&gt;@chungquantin&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>watercooler</category>
      <category>jokes</category>
      <category>ai</category>
    </item>
    <item>
      <title>List of No-code tools that will enhance your productivity 10x ⚡️</title>
      <dc:creator>Tin Chung</dc:creator>
      <pubDate>Tue, 29 Nov 2022 14:04:14 +0000</pubDate>
      <link>https://dev.to/chungquantin/list-of-no-code-tools-that-will-enhance-your-productivity-10x-1o71</link>
      <guid>https://dev.to/chungquantin/list-of-no-code-tools-that-will-enhance-your-productivity-10x-1o71</guid>
      <description>&lt;p&gt;Original Twitter thread: &lt;a href="https://twitter.com/chasechung111/status/1597466428546121728"&gt;https://twitter.com/chasechung111/status/1597466428546121728&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is No-code?
&lt;/h2&gt;

&lt;p&gt;No-code is the next era of the Internet. It enhances the development experience and also reduce cost waste for building unnecessary tools for management or analytics. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why should you use No-code tools?
&lt;/h2&gt;

&lt;p&gt;No-code tools will be a core infrastructure of every new era business. If you are a developer, don't reinvent the wheel, save your time by using other people products.&lt;/p&gt;

&lt;p&gt;Here are 5 no-code tools to try give it a try today:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Auth0
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://auth0.com"&gt;https://auth0.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try it today for "Sign in with Github" feature. Just a few click and the feature is done. Auth0 is an essential tool for every startup which want to kickstart their login functionality in a few minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ChgvLa62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7yuuzle8nttxsexyvpo1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ChgvLa62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7yuuzle8nttxsexyvpo1.png" alt="Auth0 banner" width="880" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Novu
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://novu.co"&gt;https://novu.co&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A brand new open-source notification infrastructure which is trending on Github. Implementing notification on your own is a pain in the ass, trust me. Novu is a right painkiller for project to keep user up-to-date&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LfUv_0bZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4alz4z0ekn699kvqh13d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LfUv_0bZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4alz4z0ekn699kvqh13d.png" alt="Novu banner" width="880" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Hashnode
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://hashnode.com"&gt;https://hashnode.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a developer, I used to write a whole website with JAMstack then realized it was a bad decision. Hashnode has good community, analytic tools, rick markdown editor...for every tech guy to start writing blog&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w1I43oXU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/co2ag4xw6n8zxr6fkobs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w1I43oXU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/co2ag4xw6n8zxr6fkobs.png" alt="hasnode banenr" width="880" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Mixpanel
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://mixpanel.com"&gt;https://mixpanel.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mixpanel is a powerful UX analytics tool to track the engagement of users with your product. It is sophisticated and easy to embed to your site. This tool will turn your data into profit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4ekiJapN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zvl7g72yasdor9iiwr2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4ekiJapN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zvl7g72yasdor9iiwr2.png" alt="Mixpanel" width="880" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Moralis Web3
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://moralis.io"&gt;https://moralis.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tasks like connecting to wallet, retrieving data from blockchain, signing a transaction are duplicated across the blockchain industry. Moralis empowers your app with its services to eradicate those.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gNjIqONV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7tpsl46djmjon8rgng46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gNjIqONV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7tpsl46djmjon8rgng46.png" alt="Moralis Web3" width="880" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nocode</category>
      <category>tooling</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How did I promote my open source project to get a first star ⭐️?</title>
      <dc:creator>Tin Chung</dc:creator>
      <pubDate>Mon, 28 Nov 2022 05:47:35 +0000</pubDate>
      <link>https://dev.to/chungquantin/how-did-i-promote-my-open-source-project-to-get-a-first-star--o6m</link>
      <guid>https://dev.to/chungquantin/how-did-i-promote-my-open-source-project-to-get-a-first-star--o6m</guid>
      <description>&lt;p&gt;Building in public has gained traction in recent years. Instead of building on somebody's dream and earn money, digital nomads start inclining to build on their own dream and make revenue. I am also really into working publicly and contributing to open source projects. Hence, I decided to work on my own project to learn more how this community drives.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the project I am working on?
&lt;/h2&gt;

&lt;p&gt;The open source project I mention is &lt;a href="https://github.com/nomadiz/solomon-db"&gt;SolomonDB: A distributed Gremlin-compatible graph database written in Rust 🦀&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LxgTVvPw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ubguvcsjdbpu7ixnl2vk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LxgTVvPw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ubguvcsjdbpu7ixnl2vk.png" alt="SolomonDB Github Banner" width="880" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SolomonDB&lt;/strong&gt; is briefly a graph database that supports Gremlin as a primary query language. The key point of this article is about how did I promote my project SolomonDB to get a first star from stranger on Github. The current status of SolomonDB is that I already get around &lt;strong&gt;4 stars&lt;/strong&gt; ⭐️ under a week from strange Github users. &lt;/p&gt;

&lt;h2&gt;
  
  
  How did I get my first star?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Each project can have different approach to gain traction. This is shared based on my personal experience so it might not be suitable to your project but hope it will be helpful.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ytBotLDB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/etw58x0twlhe24s2dplz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ytBotLDB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/etw58x0twlhe24s2dplz.png" alt="SolomonDB Github Star Chart" width="880" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To me, getting a first step of everything is important, as it shows you are having a progress. For example, building a startup, first step would be first customer. In this case, my very first goal of working on an open source project has been accomplished, getting the first star.&lt;/p&gt;

&lt;p&gt;SEO (Search Engine Optimization) for Github repository is quite bad in a first place actually. Not until your project has around couple of hundreds star, it won't be found on Google. So the strategy would be&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create a minimal website of your repository
&lt;/h3&gt;

&lt;p&gt;A minimal website can be any kind of website: a landing page, a documentation page or a progress update page. This web page will enhance the SEO of your Github repository as you can give user more information about the repository inside a page which links to your Github repo. In my case, I design a documentation page using Rust &lt;code&gt;mdboook&lt;/code&gt; and &lt;code&gt;Github Pages&lt;/code&gt;. My page is easily deployed and edited just by using &lt;code&gt;Github Actions&lt;/code&gt; and &lt;code&gt;Markdown&lt;/code&gt; file. If your project is a Rust app, you can try the stack, it is quite easy to use.&lt;/p&gt;

&lt;p&gt;Link to &lt;a href="https://nomadiz.github.io/solomon-db/"&gt;SolomonDB Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--25j4hzMv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g6fmsm34u9ivkf94ev34.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--25j4hzMv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g6fmsm34u9ivkf94ev34.png" alt="SolomonDB Documentaiton" width="880" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Write a good README file
&lt;/h3&gt;

&lt;p&gt;Imagine a README is a frontend of your project. If you are a web designer, you definitely understand that a backend only does not make a project works. A README in this case can be considered in a same way. README file gives a clear introduction on what is the project offers and how can user use it for their own purpose. A good README file will bring a good impression to the user that could land you a first Github star easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2_ow46Pc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mtoz7osajsyuxdb3me4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2_ow46Pc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mtoz7osajsyuxdb3me4c.png" alt="SolomonDB README file" width="880" height="875"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Update the CHANGELOG frequently
&lt;/h3&gt;

&lt;p&gt;A CHANGELOG is a diary of your project. It reports an update of the project daily, weekly or monthly. The purpose of writing a CHANGELOG is to keep the user up-to-date with changes made to the repo. CHANGELOG is also very necessary if you want to onboard a new contributor smoothly to the open source project. This is an example of one CHANGELOG.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jnL0Vala--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z8jcaxgym5aw7azses4l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jnL0Vala--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z8jcaxgym5aw7azses4l.png" alt="SolomonDB Changelog" width="880" height="838"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Maximize the benefits of social networking
&lt;/h3&gt;

&lt;p&gt;As a programmer, I can confirm that engineering is usually overvalued and marketing is undervalued in tech community. Normal user or even other developers won't understand you 1000 lines of code as they don't want to waste their time on something that does not bring them any benefit in a first place. &lt;/p&gt;

&lt;p&gt;On the other hand, choosing a correct social network to build your project brand gains you a lot of expansion in social branding as well. The main social network I choose to deliver my product update is Twitter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OuFWGLFr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pd71e3gqcctuvetjwv6h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OuFWGLFr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pd71e3gqcctuvetjwv6h.png" alt="Twitter Statistics" width="880" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With SolomonDB, I try to keep have daily tweet about a product with hashtag and tagging to bring it to more targeted user on the platform. &lt;/p&gt;

&lt;p&gt;Choosing a right hashtag and right accounts to tag is a strategy. To build your account from scratch is a very challenging task. However, when you reach a certain level, the connection will be automatically expanded due to the power of social network.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Active in tech community
&lt;/h3&gt;

&lt;p&gt;Every technology has its own tech community or tech channel (Discord or Reddit). It is fulfilled with people who interested in the technology and its ecosystem. Therefore, announcing your project in those places would improve your project position. In my case, as the main technology I use to build SolomonDB is Rust, I post an announcement in &lt;strong&gt;Rust User Forum&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xb_oT3xM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbphi28r6g8r7e7sq5s0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xb_oT3xM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbphi28r6g8r7e7sq5s0.png" alt="SolomonDB Announcement" width="880" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep building and connecting
&lt;/h2&gt;

&lt;p&gt;Those above approaches won't bring you an overnight success. It claims to be a long-term journey and persistence is a key. Hence, keep building and connecting with people on social media incrementally. Try to make the loop of feedback and development keeps running and you will see the result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6HlpGuY3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kaq978aiut170quy89cz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6HlpGuY3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kaq978aiut170quy89cz.png" alt="Github contribution chart" width="880" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading until now. Hope this article is beneficial to your open source project. Even though my project SolomonDB is not a successful open source project yet, it is in a beginning and I believe persistence will prevail.&lt;/p&gt;

&lt;p&gt;If you are interested with my article. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Please follow my Twitter: &lt;a href="https://twitter.com/chasechung111"&gt;https://twitter.com/chasechung111&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Give my project a star: &lt;a href="https://github.com/nomadiz/solomon-db"&gt;https://github.com/nomadiz/solomon-db&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>github</category>
      <category>opensource</category>
      <category>rust</category>
    </item>
    <item>
      <title>Correct me if my new STARTUP idea is WRONG!</title>
      <dc:creator>Tin Chung</dc:creator>
      <pubDate>Mon, 21 Nov 2022 09:57:32 +0000</pubDate>
      <link>https://dev.to/chungquantin/correct-me-if-my-new-startup-idea-is-wrong-1h15</link>
      <guid>https://dev.to/chungquantin/correct-me-if-my-new-startup-idea-is-wrong-1h15</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Idea is cheap, execution is everything&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This statement is widely popular in a startup world. We all know and understand but it is hard to apply it well in a real world. The ideation stage is the most dreamy and easiest stage kickstarting a startup, no one would want to dig deeper into the later stages. I have a new idea today but tomorrow, it might be obsolete already. &lt;/p&gt;

&lt;p&gt;Reflect upon my own experience, there has been thousands of times I surrounded myself with new startup ideas for a few hours and then decide to pick one which I feel most feasible. After a few days coding, I started losing motivation due to the large gap between ideation stage and execution stage. I did not measure thoroughly the workload and essential resources needed for my project. Hence, most of my projects just become unknown repositories and never got released.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do I tell you about that shit?
&lt;/h2&gt;

&lt;p&gt;Well, before, whenever I think about doing startup, I envisage something huge and mysterious. Mysterious enough that nobody know the fancy technologies I used for that project so they can't copy it. But it is not a good strategy, what I learnt is that&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The more you give, the more you receive&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I think this could be a wise move to share what am I doing with the community and if there's anyone who get interested in the project, I can make a new friend. You know, working on side project feels a little bit lonely.&lt;/p&gt;

&lt;h2&gt;
  
  
  What am I building?
&lt;/h2&gt;

&lt;p&gt;Enough for beating around the bush, we will jump into the main part now. There's an application on mobile that I am really into called Forest and it is a very good app for tracking productivity. However, it is not free and the feature is quite limited. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TBNFdi5C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/38tlg6fshm6wjwewe3z5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TBNFdi5C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/38tlg6fshm6wjwewe3z5.png" alt="Forest app" width="880" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And Github is my most favorite platform. The community on Github is so huge and I am also a big fan of it. I started thinking why does not anyone build an app to track the contribution activity on Github. Imaging if you can receive an in-game reward for every contribution on Github, it would motivate programmers a lot. After brainstorming the idea out on paper, I estimate the resources will be spent for this app and it is not much. We have the Github API and all UI libraries in React ecosystem to quick develop this app under two months. &lt;/p&gt;

&lt;p&gt;But I want something a little bit adventurous, something like a Pokemon game. Github Octocat can be a base character of the app, instead of planting a tree whenever user finish their goal, we will give user Experience for their Pokemon whenever a contribution goal reached.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current progress
&lt;/h2&gt;

&lt;p&gt;I kickstarted the project two days ago and already have a very simple version for the app, I named the app GitPet - reference to VoidPet - a very cool Pokemon-like web game. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8kBp4VAx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u9d5z8nb5o7chjdne3u0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8kBp4VAx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u9d5z8nb5o7chjdne3u0.png" alt="Github Productivity Pokemon" width="880" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So what do you feel about this project idea? Your opinion would be a great contribution to the app. I will work on the app and try to deliver it to the community as soon as possible.&lt;/p&gt;

&lt;p&gt;Thanks for reading to the end of the blog post.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>github</category>
    </item>
    <item>
      <title>10 months building a crypto startup and BUMP!</title>
      <dc:creator>Tin Chung</dc:creator>
      <pubDate>Sun, 20 Nov 2022 03:23:25 +0000</pubDate>
      <link>https://dev.to/chungquantin/10-months-building-a-crypto-startup-and-bump-2kc</link>
      <guid>https://dev.to/chungquantin/10-months-building-a-crypto-startup-and-bump-2kc</guid>
      <description>&lt;p&gt;Let's see where to begin with. I have been working on crypto startup for around 1 year since the great correction happened with a whole crypto market. That is also a period of time which I help to cofound a crypto startup. The startup is in Solana blockchain. &lt;/p&gt;

&lt;h2&gt;
  
  
  Where does the story begin?
&lt;/h2&gt;

&lt;p&gt;If you follows the market sentiment for Solana blockchain in the upcoming days, it was not in a very good condition, or I can say, extremely negative. It was the worst year for Solana ecosystem since its launch a few years ago. Several large projects got hacked and manipulated by their own DeFi models. Following that, a story of FTX is what pushed the position of Solana in the whole market deviated. FTX was a huge supporter of the Solana ecosystem. With what happened, our Solana believers were devastated. Enough flashback and quick update on Solana current position. However, this incident brought me back to the main track. I gave myself some time to contemplate a right track of my personal career and the direction of a startup. &lt;/p&gt;

&lt;h2&gt;
  
  
  Career path in crypto
&lt;/h2&gt;

&lt;p&gt;What can I say? Working in crypto does not give you a very good start for your career. I am a final year undergraduate and to be honest, there is too many factors affecting the growth of your career. The good side of crypto is you will gain a lot of money in this field due to the hype of the community in a bull market. But the bad thing that consolidate my point of view is the technical aspect. &lt;/p&gt;

&lt;p&gt;There are dozens of blockchain network maintained and released every month. They can be compatible with the existing blockchains virtual machine like EVM-compatible or they will just release a whole new smart contract language and let the marketing team do the rest. As an engineer, you will have to learn several languages if you want to survive in the market. Imagine learning only &lt;strong&gt;Solidity&lt;/strong&gt; and one day Ethereum crashes, your career just become volatile. &lt;/p&gt;

&lt;p&gt;As the blockchain is designed to be your project core system, your project relies a lot on how well the core team behinds of that blockchain manage the project. If they just accidentally corrupt the network, you will be affected too. Even though decentralized is an attributed used to grade any blockchain network, the ecosystem is not decentralized on its self. &lt;/p&gt;

&lt;p&gt;According to EarthWeb's statistics: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Currently, there are at least 1,000 blockchains with at least four types of blockchain networks. While the idea of blockchain is a singular data transfer type, there are multiple platforms provided in this industry.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes, every blockchain will have a specific use cases. But for public blockchains, the way they grow the ecosystem and destroy it with a few clicks is not worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The direction of a startup
&lt;/h2&gt;

&lt;p&gt;What we are facing is unexpected and it is not a fault of the management team or something. We have been building a startup wholeheartedly and candidly. I discussed with my team and what we decided is to keep building on the chain but trying to reach out to a more Web 2.5 user. Web 2.5 user is more off-chain, for example, people who keep their fund on CEX like Binance or OKX. We try to reposition ourselves as a more Web 2 crypto product instead of relying entirely on the onchain technology. From my perspective, there won't be one chain for all. In the end, multi chain should be a right path for every crypto startup. Targeting at one chain is like neglecting the pompousness of other blockchains.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't neglect personal branding
&lt;/h2&gt;

&lt;p&gt;Running a startup is actually fun and I learnt a lot along side with my startup founder and the team. However, I realized I had neglected my own startup: My personal brand. There's a good blog I read recently about growing personal brand: &lt;br&gt;
&lt;a href="https://kevoncheung.com/blog/building-in-public-guide-behind-the-scenes"&gt;Building in Public - Behind the scenes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The author declared that&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But, everything I worked hard for was for the startup, I didn't build up my brand or voice at all in the last couple of years. "Where do I even start?" That was at the top of my mind.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And this is the same thing what I feel when there was a correction in crypto market. It did not only correct the market but also correct my mindset. The trail of most programmers follow is that they think programming is all what their life needed. &lt;/p&gt;

&lt;p&gt;However, it's not. Mental health, family, social life and communication is what I would prefer more in life. Programming is still my passion but I truly f*cked up my old life by spending 12 hours a day programming, not until I got some health issues. As a programmer, whatever we do, running a startup or working for a large corporation, does not matter. Both can be destroyed by a financial crisis. But personal branding is what remains after all.&lt;/p&gt;

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

&lt;p&gt;Well, this article is not that I am trying to be a life advisor or something. I hope this can be considered as a self reflection that other pals who in the same situation like I was can take this personally.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>programming</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Solana DEV #02: Retrieve all Deposit transactions of your wallet</title>
      <dc:creator>Tin Chung</dc:creator>
      <pubDate>Mon, 29 Aug 2022 14:07:28 +0000</pubDate>
      <link>https://dev.to/chungquantin/solana-dev-02-retrieve-all-deposit-transactions-of-your-wallet-39ke</link>
      <guid>https://dev.to/chungquantin/solana-dev-02-retrieve-all-deposit-transactions-of-your-wallet-39ke</guid>
      <description>&lt;p&gt;If you use Phantom wallet to pay for transactions on Solana blockchain, you may recognize that every time you send SOL or SPL tokens to another address, that transaction will be recorded and listed on Phantom wallet interface. &lt;/p&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frhhfn8drqbe9endnk0kt.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frhhfn8drqbe9endnk0kt.png" alt="Phantom deposit transaction interface"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first, I thought that it is just similar to any other data fetched by using &lt;strong&gt;&lt;code&gt;getProgramAccounts&lt;/code&gt;&lt;/strong&gt; with filtering stuffs. However, it does not work that way. &lt;/p&gt;

&lt;h2&gt;
  
  
  Fetching signatures and transactions
&lt;/h2&gt;

&lt;p&gt;To fetch all deposit transactions of one address, you must get all signatures of that address by using the method &lt;code&gt;getSignaturesForAddress&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signatureInfos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignaturesForAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vaultAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And then map the info to get only transaction signatures&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signatureInfos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getParsedTransactions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signatures&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This approach has a very big problem. It does not allow you to filter out fetched signatures like what you usually do with &lt;code&gt;getProgramAccounts&lt;/code&gt;. And in that way, it will just fetch a bulk load of transactions from your address as your address have other wallet interaction beside receive and send coins. To make it more efficient, I try to filter out success signatures from the return data&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredSignatureInfos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signatureInfos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;But unlucky, if your wallet has around 300 or more transactions, the RPC won't allow you to fetch as there's a rate limit. I don't know if there are any other better approaches but this is the one that I found. &lt;/p&gt;

&lt;h3&gt;
  
  
  How to improve the approach?
&lt;/h3&gt;

&lt;p&gt;This might not be an acceptable answer but there's a few ways that you can improve the case.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trying to separate a &lt;strong&gt;vault&lt;/strong&gt; from a &lt;strong&gt;wallet&lt;/strong&gt;. A vault will be a &lt;strong&gt;PDA&lt;/strong&gt; that use the wallet address as a seed. In that way, all transactions that the vault includes will be related to tokens and native SOL only. Even the most traffic vault can only have around &lt;strong&gt;50-100 transactions&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;Using cache database, partition and event listener: This technique is commonly used in tradition backend development. If you have around 300 transactions for an address, try to partition those into smaller parts: &lt;strong&gt;50 transactions&lt;/strong&gt; per each. Cache those data and then only update the database if there is a new data coming (use &lt;code&gt;onAccountChange&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Filtering transactions
&lt;/h2&gt;

&lt;p&gt;There will be two types of transactions that you may want to fetch to display a similar result from Phantom: Native SOL deposit transactions and SPL tokens deposit transactions. If you use &lt;code&gt;getParsedTransactions&lt;/code&gt; like what I did above, all the data is already converted into human readable language. The raw transactions using &lt;code&gt;getTransactions&lt;/code&gt; return only hexadecimal data. I wrote these two methods so that you can reuse it, it's quite simple because all data is parsed already.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// Filter SPL token deposit transaction&lt;/span&gt;
&lt;span class="nf"&gt;isSplTokenDepositTx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ixs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ixs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ixs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;ix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;programId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TOKEN_PROGRAM_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;transfer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;ix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;transferChecked&lt;/span&gt;&lt;span class="dl"&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;span class="c1"&gt;// Filter Native SOL deposit transaction&lt;/span&gt;
&lt;span class="nf"&gt;isSolDepositTx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instructions&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;programId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SYSTEM_PROGRAM_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;ix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;transfer&lt;/span&gt;&lt;span class="dl"&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;

</description>
      <category>solana</category>
      <category>webdev</category>
      <category>typescript</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Solana DEV #01: Fetching onchain data in a right way</title>
      <dc:creator>Tin Chung</dc:creator>
      <pubDate>Mon, 29 Aug 2022 12:55:00 +0000</pubDate>
      <link>https://dev.to/chungquantin/solana-dev-01-fetching-onchain-data-in-a-right-way-23da</link>
      <guid>https://dev.to/chungquantin/solana-dev-01-fetching-onchain-data-in-a-right-way-23da</guid>
      <description>&lt;p&gt;Working with Solana decentralized app from a client side can be a core part of the Solana app development. Before being comfortable with the process, I thought smart contract programming is the one and only concern that we should thoroughly care about. However, similar to traditional website development, data fetching on client side is impactful to the experience delivered to user. In this article, I will list out key notes of data fetching. &lt;/p&gt;

&lt;h2&gt;
  
  
  Get filtered program accounts
&lt;/h2&gt;

&lt;p&gt;First and foremost best practice is using &lt;code&gt;getProgramAccounts&lt;/code&gt; with a filter. This &lt;code&gt;getProgramAccounts&lt;/code&gt; method in &lt;code&gt;@solana/web3.js&lt;/code&gt; package is extremely useful for fetching all accounts of a provided program ID. However, as in a smart contract, there would be multiple type of accounts, filtering is required for best performance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * A filter object for getProgramAccounts
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetProgramAccountsFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MemcmpFilter&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;DataSizeFilter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we play with the source code a bit. There are two filtering types that we can reference &lt;code&gt;MemcmpFilter&lt;/code&gt; and &lt;code&gt;DataSizeFilter&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  DataSizeFilter
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Data size comparison filter for getProgramAccounts
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DataSizeFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/** Size of data for program account data length comparison */&lt;/span&gt;
  &lt;span class="na"&gt;dataSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;&lt;code&gt;DataSizeFilter&lt;/code&gt; is used to filter accounts of a program matched with a declared data size. Simple right? This filtering type is useful for accounts with fixed data size. With accounts contain dynamic size fields such as &lt;strong&gt;&lt;code&gt;vector&lt;/code&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;code&gt;str&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  MemcmpFilter
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Memory comparison filter for getProgramAccounts
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MemcmpFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;memcmp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/** offset into program account data to start comparison */&lt;/span&gt;
    &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="cm"&gt;/** data to match, as base-58 encoded string and limited to less than 129 bytes */&lt;/span&gt;
    &lt;span class="nl"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;Between the two filtering types, I find this approach is used more as it allows you to filter accounts in a more dynamic and selective way. &lt;code&gt;MemcmpFilter&lt;/code&gt; or &lt;code&gt;Memory comparison filter&lt;/code&gt; has two fields: &lt;code&gt;offset&lt;/code&gt; and &lt;code&gt;bytes&lt;/code&gt;. Every account data is a set of bytes, you can use offset to choose specific data field to compare and bytes is a the later part of a comparison. &lt;/p&gt;

&lt;p&gt;For example, if I want to get all program accounts with a specific account discriminator, I can set the offset as 0 and get the bytes of the compared account discriminator. This is a trick to get specific type program accounts without using Anchor (as the framework already handle this process under the hood).&lt;/p&gt;

&lt;p&gt;I usually use this filtering types to filter out which accounts that a specific wallet owned. To do this, in the Rust program, you must store the wallet address of the owner in the account. For example, I have this account data (using &lt;strong&gt;Anchor&lt;/strong&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[account]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;WalletAddressContainer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PubKey&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fetch every &lt;strong&gt;WalletAddressContainer&lt;/strong&gt; accounts of a specific wallet address, I would do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// using Anchor&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;memcmp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toBase58&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;span class="c1"&gt;// without Anchor&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getProgramAccounts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nx"&gt;programID&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="na"&gt;filters&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="na"&gt;memcmp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;offset&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="na"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/** Account discriminator bytes of WalletAddressContainer **/&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;span class="na"&gt;memcmp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toBase58&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;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;In an Anchor way, as mentioned, Anchor framework handles comparing account discriminator under the hood, so we don't have to compare it again. In that way, we only need one &lt;code&gt;memcmp&lt;/code&gt; filter to compare the public key of the wallet but the offset is still have to be 8 because the first 8 bytes are for account discriminator. &lt;/p&gt;

&lt;p&gt;On the other hand, &lt;strong&gt;getProgramAccounts&lt;/strong&gt; without Anchor requires two comparison. First the account discriminator and second the wallet address.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>solana</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
