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

<channel>
	<title>Mithle.sh</title>
	<atom:link href="https://mithle.sh/feed/" rel="self" type="application/rss+xml" />
	<link>http://mithle.sh/</link>
	<description>The Diary of a Full Stack Developer</description>
	<lastBuildDate>Wed, 20 Dec 2023 17:49:40 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.5.3</generator>

<image>
	<url>https://i0.wp.com/mithle.sh/wp-content/uploads/2023/03/cropped-favicon.png?fit=32%2C32&#038;ssl=1</url>
	<title>Mithle.sh</title>
	<link>http://mithle.sh/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">219607879</site>	<item>
		<title>How to use Drizzle ORM with NestJS</title>
		<link>https://mithle.sh/how-to-use-drizzle-orm-with-nestjs/</link>
					<comments>https://mithle.sh/how-to-use-drizzle-orm-with-nestjs/#respond</comments>
		
		<dc:creator><![CDATA[Mithlesh]]></dc:creator>
		<pubDate>Wed, 20 Dec 2023 17:49:39 +0000</pubDate>
				<category><![CDATA[NestJS]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[nestjs]]></category>
		<category><![CDATA[postgres]]></category>
		<guid isPermaLink="false">https://mithle.sh/?p=1414</guid>

					<description><![CDATA[<p>In this tutorial we will learn how to use Drizzle ORM with NestJS to connect with all the major databases and serverless database providers such...</p>
<p>The post <a href="https://mithle.sh/how-to-use-drizzle-orm-with-nestjs/">How to use Drizzle ORM with NestJS</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this tutorial we will learn how to use Drizzle ORM with NestJS to connect with all the major databases and serverless database providers such as PlanetScale, Turso.</p>



<p>To set up Drizzle ORM in NestJS with each type of databases, follow these steps:</p>



<h2 class="wp-block-heading">1. <span style="text-decoration: underline;">Install Dependencies</span></h2>



<p>Install <strong>Drizzle ORM</strong>, driver of the database that you wish to use and its NestJS <a href="https://github.com/knaadh/nestjs-drizzle" target="_blank" rel="noreferrer noopener">integration module</a> using your favorite package manager.</p>



<h4 class="wp-block-heading">PlanetScale</h4>



<pre class="wp-block-code language-bash"><code>npm install drizzle-orm
npm install @planetscale/database
npm install @knaadh/nestjs-drizzle-planetscale</code></pre>



<h4 class="wp-block-heading">Turso</h4>



<pre class="wp-block-code language-bash"><code>npm install drizzle-orm
npm install @libsql/client
npm install @knaadh/nestjs-drizzle-turso</code></pre>



<h4 class="wp-block-heading">MySQL2</h4>



<pre class="wp-block-code language-bash"><code>npm install drizzle-orm
npm install mysql2
npm install @knaadh/nestjs-drizzle-mysql2</code></pre>



<h4 class="wp-block-heading">Node-Postgres</h4>



<pre class="wp-block-code language-bash"><code>npm install drizzle-orm
npm install pg
npm install @knaadh/nestjs-drizzle-pg</code></pre>



<h4 class="wp-block-heading">Better-SQLite3</h4>



<pre class="wp-block-code language-bash"><code>npm install drizzle-orm
npm install better-sqlite3
npm install @knaadh/nestjs-drizzle-better-sqlite3</code></pre>



<h2 class="wp-block-heading">2. <span style="text-decoration: underline;">Create SQL Schema File</span></h2>



<p>In Drizzle ORM, you need to define your database schema in TypeScript. You can declare your schema in a single <code>schema.ts</code> file or group them logically in multiple files. The schema declaration includes tables, indexes, constraints, foreign keys, and enums as explained <a href="https://orm.drizzle.team/docs/sql-schema-declaration" target="_blank" rel="noreferrer noopener">here</a>. Here&#8217;s an example of declaring tables in a <code>schema.ts</code> file for each of the database types.</p>



<h4 class="wp-block-heading">MySQL</h4>



<pre class="wp-block-code language-typescript"><code>

import { mysqlTable, serial, varchar } from 'drizzle-orm/mysql-core';

export const books = mysqlTable('Books', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 256 }),
});

export const authors = mysqlTable('Authors', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 256 }),
});</code></pre>



<h4 class="wp-block-heading">PostgreSQL</h4>



<pre class="wp-block-code language-typescript"><code>

import { pgTable, serial, varchar } from 'drizzle-orm/pg-core';

export const books = pgTable('Books', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 256 }),
});

export const authors = pgTable('Authors', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 256 }),
});</code></pre>



<h4 class="wp-block-heading">SQLite</h4>



<pre class="wp-block-code language-typescript"><code>

import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';

export const books = sqliteTable('Books', {
  id: integer('id').primaryKey(),
  name: text('name'),
});

export const authors = sqliteTable('Authors', {
  id: integer('id').primaryKey(),
  name: text('name'),
});

</code></pre>



<h2 class="wp-block-heading">3. <span style="text-decoration: underline;">Configure the Module</span>:</h2>



<p><span class=""><span class="">Import the integration module of the respective database driver into the root <code>AppModule</code></span></span> and configure it with your credentials, schema file and injection tag as shown in the sample code below for each of the drivers.</p>



<h4 class="wp-block-heading">PlanetScale</h4>



<pre class="wp-block-code language-typescript"><code>import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import * as schema from '../db/schema';
import { DrizzlePlanetScaleModule } from '@knaadh/nestjs-drizzle-planetscale';

@Module({
  imports: &#91;
    DrizzlePlanetScaleModule.register({
      tag: 'DB_PROD',
      planetscale: {
        config: {
          username: 'PLANETSCALE_USERNAME',
          password: 'PLANETSCALE_PASSWORD',
          host: 'PLANETSCALE_HOST',
        },
      },
      config: { schema: { ...schema } },
    }),
  ],
  controllers: &#91;AppController],
  providers: &#91;AppService],
})
export class AppModule {}

</code></pre>



<h4 class="wp-block-heading">Turso</h4>



<pre class="wp-block-code language-typescript"><code>import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import * as schema from '../db/schema';
import { DrizzleTursoModule } from '@knaadh/nestjs-drizzle-turso';

@Module({
  imports: &#91;
    DrizzleTursoModule.register({
      tag: 'DB_PROD',
      turso: {
        config: {
          url: 'DATABASE_URL',
          authToken: 'DATABASE_AUTH_TOKEN',
        },
      },
      config: { schema: { ...schema } },
    }),
  ],
  controllers: &#91;AppController],
  providers: &#91;AppService],
})
export class AppModule {}</code></pre>



<h4 class="wp-block-heading">MySQL2</h4>



<pre class="wp-block-code language-typescript"><code>import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import * as schema from '../db/schema';
import { DrizzleMySqlModule } from '@knaadh/nestjs-drizzle-mysql2';

@Module({
  imports: &#91;
    DrizzleMySqlModule.register({
      tag: 'DB_PROD',
      mysql: {
        connection: 'client',
        config: {
          host: DATABASE_HOST,
          user: DATABASE_USER,
          password : DATABASE_PASSWORD,
          database: DATABASE_NAME,
        },
      },
      config: { schema: { ...schema }, mode: 'default' },
    }),
  ],
  controllers: &#91;AppController],
  providers: &#91;AppService],
})
export class AppModule {}</code></pre>



<h4 class="wp-block-heading">Node-Postgres</h4>



<pre class="wp-block-code language-typescript"><code>import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import * as schema from '../db/schema';
import { DrizzlePGModule } from '@knaadh/nestjs-drizzle-pg';

@Module({
  imports: &#91;
    DrizzlePGModule.register({
      tag: 'DB_PROD',
      pg: {
        connection: 'client',
        config: {
          connectionString: DATABASE_CONNECTION_URL,
        },
      },
      config: { schema: { ...schema } },
    }),
  ],
  controllers: &#91;AppController],
  providers: &#91;AppService],
})
export class AppModule {}</code></pre>



<h4 class="wp-block-heading">Better-SQLite3</h4>



<pre class="wp-block-code language-typescript"><code>import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import * as schema from '../db/schema';
import { DrizzleBetterSQLiteModule } from '@knaadh/nestjs-drizzle-better-sqlite3';

@Module({
  imports: &#91;
    DrizzleBetterSQLiteModule.register({
      tag: 'DB_PROD',
      sqlite3: {
        filename: DATABASE_FILE,
      },
      config: { schema: { ...schema } },
    }),
  ],
  controllers: &#91;AppController],
  providers: &#91;AppService],
})
export class AppModule {}

</code></pre>



<h2 class="wp-block-heading">4. <span style="text-decoration: underline;">Inject Drizzle Service</span>:</h2>



<p>You can inject the Drizzle instance anywhere using the <code>tag</code> specified in the module configuration of its respective database driver.</p>



<h4 class="wp-block-heading">PlanetScale</h4>



<pre class="wp-block-code language-bash"><code>import { Inject, Injectable } from '@nestjs/common';
import * as schema from '../db/schema';
import { PlanetScaleDatabase } from 'drizzle-orm/planetscale-serverless';
@Injectable()
export class AppService {
  constructor(
    @Inject('DB_PROD') private drizzleProd: PlanetScaleDatabase&lt;typeof schema>
  ) {}
  async getData() {
    const authors = await this.drizzleProd.query.authors.findMany();
    return authors;
  }
}</code></pre>



<h4 class="wp-block-heading">Turso</h4>



<pre class="wp-block-code language-bash"><code>import { Inject, Injectable } from '@nestjs/common';
import * as schema from '../db/schema';
import { LibSQLDatabase } from 'drizzle-orm/libsql';
@Injectable()
export class AppService {
  constructor(
    @Inject('DB_PROD') private drizzleProd: LibSQLDatabase&lt;typeof schema>
  ) {}
  async getData() {
    const authors = await this.drizzleProd.query.authors.findMany();
    return authors;
  }
}</code></pre>



<h4 class="wp-block-heading">MySQL2</h4>



<pre class="wp-block-code language-bash"><code>import { Inject, Injectable } from '@nestjs/common';
import * as schema from '../db/schema';
import { MySql2Database } from 'drizzle-orm/mysql2';
@Injectable()
export class AppService {
  constructor(
    @Inject('DB_PROD') private drizzleProd: MySql2Database&lt;typeof schema>
  ) {}
  async getData() {
    const authors = await this.drizzleProd.query.authors.findMany();
    return authors;
  }
}</code></pre>



<h4 class="wp-block-heading">Node-Postgres</h4>



<pre class="wp-block-code language-bash"><code>import { Inject, Injectable } from '@nestjs/common';
import * as schema from '../db/schema';
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
@Injectable()
export class AppService {
  constructor(
    @Inject('DB_PROD') private drizzleProd: NodePgDatabase&lt;typeof schema>
  ) {}
  async getData() {
    const authors = await this.drizzleProd.query.authors.findMany();
    return authors;
  }
}</code></pre>



<h4 class="wp-block-heading">Better-SQLite3</h4>



<pre class="wp-block-code language-bash"><code>import { Inject, Injectable } from '@nestjs/common';
import * as schema from '../db/schema';
import { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
@Injectable()
export class AppService {
  constructor(
    @Inject('DB_PROD') private drizzleProd: BetterSQLite3Database&lt;typeof schema>
  ) {}
  async getData() {
    const authors = await this.drizzleProd.query.authors.findMany();
    return authors;
  }
}</code></pre>



<p><strong>Note:</strong> You can connect as many databases as you want, provided the <code>tag</code> should always be different for each database module.</p>
<p>The post <a href="https://mithle.sh/how-to-use-drizzle-orm-with-nestjs/">How to use Drizzle ORM with NestJS</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mithle.sh/how-to-use-drizzle-orm-with-nestjs/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1414</post-id>	</item>
		<item>
		<title>Nullish Coalescing Operator (??) vs Logical OR (&#124;&#124;)   in JavaScript</title>
		<link>https://mithle.sh/null-coalescing-vs-logical-or-operator-javascript/</link>
					<comments>https://mithle.sh/null-coalescing-vs-logical-or-operator-javascript/#respond</comments>
		
		<dc:creator><![CDATA[Mithlesh]]></dc:creator>
		<pubDate>Thu, 01 Jun 2023 13:43:46 +0000</pubDate>
				<category><![CDATA[Typescript]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://mithle.sh/?p=1360</guid>

					<description><![CDATA[<p>Nullish Coalescing Operator (??) and Logical OR (&#124;&#124;) are two operators in JavaScript/TypeScript that are used to handle situations where a variable may be null...</p>
<p>The post <a href="https://mithle.sh/null-coalescing-vs-logical-or-operator-javascript/">Nullish Coalescing Operator (??) vs Logical OR (||)   in JavaScript</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><strong>Nullish Coalescing Operator (??)</strong> and <strong>Logical OR (||) </strong>are two operators in JavaScript/TypeScript that are used to handle situations where a variable may be<strong> null</strong> or <strong>undefined</strong>. While they may appear to be similar, there are some subtle differences between them that are important to understand.</p>



<h2 class="wp-block-heading"><strong>Nullish Coalescing Operator (??)</strong> </h2>



<p>The Nullish Coalescing Operator (??) is a <strong>JavaScript/Typescript</strong> operator that provides a concise way to handle <strong>nullish (null or undefined)</strong> values in expressions. It allows you to specify a default value that will be returned if the value on the <strong>left side</strong> of the operator is <strong>nullish</strong>.</p>



<pre class="wp-block-code language-javascript"><code>const result = value1 ?? value2;</code></pre>



<p>If <strong>value1</strong> is <strong>nullish</strong> (null or undefined), it returns <strong>value2</strong>. Otherwise, it returns <strong>value1</strong>.</p>



<p>Here&#8217;s an example to illustrate its usage:</p>



<pre class="wp-block-code language-javascript"><code>const url = null;
const defaultUrl = "https://mithle.sh";
const redirectTo = url ?? defaultUrl

console.log(redirectTo); // Output: "https://mithle.sh"</code></pre>



<p>The nullish coalescing operator <strong><code>??</code></strong> checks if the value on the left side (<strong>url</strong>) is <strong><code>null</code></strong> or <strong><code>undefined</code></strong>. If it is, it uses the value on the right side (<strong>defaultUrl</strong>). In other words, if <strong><code>url</code></strong> is not provided or has no value, <strong><code>redirectTo</code></strong> will be set to the value of <strong><code>defaultUrl</code></strong>. However, if <strong><code>url</code></strong> has a value (not <strong>null</strong> or <strong>undefined</strong>), then<code> <strong>redirectTo</strong></code> will be set to the value of <strong><code>url</code></strong>.</p>



<p>Since <strong><code>url</code></strong> is <strong><code>null</code></strong> in this case, <strong><code>redirectTo</code></strong> will be set to <strong><code><a href="https://mithle.sh">https://mithle.sh</a></code></strong>, and that&#8217;s what will be displayed in the console.</p>



<h2 class="wp-block-heading">Logical OR Operator (||)</h2>



<p>In Javascript/Typescript, the Logical OR Operator <strong>(||)</strong> is used to check if the left-hand side operand is <strong>truthy</strong>. If it is, then the left-hand side operand is returned. Otherwise, the right-hand side operand is returned.</p>



<p>Here&#8217;s an example:</p>



<pre class="wp-block-code language-javascript"><code>const name = null; 
const fullName = name || "John Doe";
console.log(fullName); // Output: "John Doe"
</code></pre>



<p>In this case, if <code>name</code> is truthy (not <code>null</code>, <code>undefined</code>, <code>false</code>, <code>0</code>, <code>empty string</code>, or <code>NaN</code>), the variable <code>name</code> will be assigned the value of <code>fullName</code>. Otherwise, it will be assigned the string <code>'John Doe'</code>.</p>



<p>Remember that the logical OR operator returns the actual value of the operand, not just <code>true</code> or <code>false</code>.</p>



<h2 class="wp-block-heading">What&#8217;s the difference?</h2>



<p>Here are the main differences between the <strong>Nullish Coalescing Operator (??)</strong> and <strong>Logical OR Operator (||)</strong> in JavaScript:</p>



<ol>
<li><strong>Nullish check:</strong> The <strong>Nullish Coalescing Operator</strong> in Javascript only checks for <code>null</code> or <code>undefined</code>, while the <strong>Logical OR Operator</strong> in Javascript checks for any falsy value (such as <code>null</code>, <code>undefined</code>, <code>0</code>, <code>false</code>, <code>empty string</code>, or <code>NaN</code>).</li>



<li><strong>Return value:</strong> The <strong>Nullish Coalescing Operator</strong> returns the right-hand side operand only if the left-hand side operand is <code>null</code> or <code>undefined</code>. <strong>The Logical OR Operator</strong> returns the right-hand side operand if the left-hand side operand is <strong>falsy</strong>.</li>



<li><strong>Precedence:</strong> The <strong>Nullish Coalescing Operator</strong> has <strong>higher precedence</strong> than the <strong>Logical OR Operator</strong>. This means that if both operators are used in the same statement, the Nullish Coalescing Operator will be evaluated first.</li>



<li><strong>Use case:</strong> The <strong>Nullish Coalescing Operator</strong> is typically used to provide default values for variables that could be <code>null</code> or <code>undefined</code>. The <strong>Logical OR Operator</strong> is often used for boolean operations or to provide default values for variables that could be any falsy value.</li>
</ol>



<p>Here&#8217;s an example to illustrate the difference between the two operators:</p>



<pre class="wp-block-code language-javascript"><code>const age = 0;
const defaultAge = 18;

const result1 = age ?? defaultAge;
const result2 = age || defaultAge;

console.log(result1); // Output: 0
console.log(result2); // Output: 18</code></pre>



<p>In this example, <code>age</code> is <code>0</code> and <code>defaultAge</code> is <code>18</code>. When we use the <strong>Nullish Coalescing Operator</strong>, <code>result1</code> is assigned the value of <code>age</code> because <code>age</code> has a defined value (<code>0</code>). When we use the <strong>Logical OR Operator</strong>, <code>result2</code> is assigned the value of <code>defaultAge</code> because <code>age</code> is <strong>falsy</strong> (i.e., <code>0</code>).</p>
<p>The post <a href="https://mithle.sh/null-coalescing-vs-logical-or-operator-javascript/">Nullish Coalescing Operator (??) vs Logical OR (||)   in JavaScript</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mithle.sh/null-coalescing-vs-logical-or-operator-javascript/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1360</post-id>	</item>
		<item>
		<title>How to use Async Await with For Loop in Javascript &#038; Typescript</title>
		<link>https://mithle.sh/javascript-for-loop-async-await/</link>
					<comments>https://mithle.sh/javascript-for-loop-async-await/#respond</comments>
		
		<dc:creator><![CDATA[Mithlesh]]></dc:creator>
		<pubDate>Mon, 20 Mar 2023 23:27:56 +0000</pubDate>
				<category><![CDATA[Typescript]]></category>
		<category><![CDATA[frontend]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://mithle.sh/?p=1321</guid>

					<description><![CDATA[<p>In this quick tutorial we will learn how to use async await with for loops in Javascript and Typescript using simple examples. There are mainly...</p>
<p>The post <a href="https://mithle.sh/javascript-for-loop-async-await/">How to use Async Await with For Loop in Javascript &#038; Typescript</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this quick tutorial we will learn how to use async await with for loops in Javascript and Typescript using simple examples.</p>



<p>There are mainly three types of for loops in JavaScript:</p>



<ol>
<li><strong>for loop:</strong> A <code>for</code> loop allows you to execute a block of code repeatedly for a specified number of times.</li>



<li><strong>for…in loop:</strong> A <code>for/in</code> loop allows you to iterate over the properties of an object, executing the loop body once for each property.</li>



<li><strong>for…of loop:</strong> A <code>for/of</code> loop allows you to iterate over the values of an iterable object, executing the loop body once for each value. </li>
</ol>



<p>Consider the following object array. Suppose we want to iterate over the users array, run some time consuming task on each iteration before logging the user object to the console.</p>



<pre class="wp-block-code line-numbers language-javascript"><code>const users = &#91;
    {
        id: 1,
        name: 'Alan',
    },
    {
        id: 2,
        name: 'Joel',
    },
    {
        id: 3,
        name: 'Triss',
    }
];</code></pre>



<p>To use <code>await</code> in a for loop, you must mark the loop function as <code>async</code>, and then use <code>await</code> inside the loop to wait for each asynchronous operation to complete before moving on to the next iteration. </p>



<p>In the following example, the code is same for each type of the loops except the syntax of the loop method.</p>



<h2 class="wp-block-heading"><u>Async await with for loop</u></h2>



<pre class="wp-block-code line-numbers language-javascript"><code>async function randomWait() {
    await new Promise((resolve) =&gt; setTimeout(resolve, Math.floor(Math.random() * 100)));
    return;
}

async function printUser() {
    for(let i=0; i &lt; users.length; i++) {
        // Wait for some time consuming task to finish
        await randomWait();
        console.log(users&#91;i]);
    }
}

printUser();</code></pre>



<pre class="wp-block-code language-json"><code>OUTPUT: 
{ id: 1, name: 'Alan' }
{ id: 2, name: 'Joel' }
{ id: 3, name: 'Triss' }</code></pre>



<h2 class="wp-block-heading"><u>Async await with for…in loop</u></h2>



<pre class="wp-block-code line-numbers language-javascript"><code>async function printUser() {
    for(const index in users) {
        await randomWait();
        console.log(users&#91;index]);
    }
}</code></pre>



<pre class="wp-block-code language-json"><code>OUTPUT: 
{ id: 1, name: 'Alan' }
{ id: 2, name: 'Joel' }
{ id: 3, name: 'Triss' }</code></pre>



<h2 class="wp-block-heading"><u>Async await with for…of</u></h2>



<pre class="wp-block-code line-numbers language-javascript"><code>async function printUser() {
    for(const user of users) {
        await randomWait();
        console.log(user);
    }
}</code></pre>



<pre class="wp-block-code language-json"><code>OUTPUT: 
{ id: 1, name: 'Alan' }
{ id: 2, name: 'Joel' }
{ id: 3, name: 'Triss' }</code></pre>



<p>This code defines two async functions: <code>randomWait()</code> and <code>printUser()</code>.</p>



<p><code>randomWait()</code> uses the <code>await</code> keyword to pause execution for a random amount of time, chosen using <code>Math.random()</code> and <code>setTimeout()</code>. Once the timer expires, the <code>Promise</code> resolves and the function returns.</p>



<p><code>printUser()</code> is an async function that iterates over an array called <code>users</code>. For each element of the array, it first calls <code>randomWait()</code> to simulate some time-consuming operation, then prints the element to the console using <code>console.log()</code>.</p>



<p>In the result, you can see that the data is printed in the sequential order in each of the three for loops.</p>



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



<p>Using <code>await</code> inside a loop can potentially slow down the loop significantly, especially if the operations being awaited are time-consuming. In some cases, it might be more efficient to use <code>Promise.all()</code> to run multiple promises in parallel rather than awaiting them one at a time in a loop.</p>



<p></p>
<p>The post <a href="https://mithle.sh/javascript-for-loop-async-await/">How to use Async Await with For Loop in Javascript &#038; Typescript</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mithle.sh/javascript-for-loop-async-await/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1321</post-id>	</item>
		<item>
		<title>How to Pass Data between Child and Parent Components in React</title>
		<link>https://mithle.sh/how-to-pass-data-between-child-and-parent-components-in-react/</link>
					<comments>https://mithle.sh/how-to-pass-data-between-child-and-parent-components-in-react/#respond</comments>
		
		<dc:creator><![CDATA[Mithlesh]]></dc:creator>
		<pubDate>Tue, 14 Mar 2023 11:43:18 +0000</pubDate>
				<category><![CDATA[React]]></category>
		<category><![CDATA[frontend]]></category>
		<category><![CDATA[nextjs]]></category>
		<guid isPermaLink="false">https://blog.mithle.sh/?p=1233</guid>

					<description><![CDATA[<p>In this quick tutorial, we will learn how to pass data from the child component to the parent component and vice versa. Parent-to-Child Passing data...</p>
<p>The post <a href="https://mithle.sh/how-to-pass-data-between-child-and-parent-components-in-react/">How to Pass Data between Child and Parent Components in React</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this quick tutorial, we will learn how to pass data from the child component to the parent component and vice versa.</p>



<h2 class="wp-block-heading" id="parent-to-child">Parent-to-Child</h2>



<p>Passing data from parent to child component is very straightforward. You need to define <code>props</code> on the child component and then pass the values to it from the parent component. In the following example, we are rendering the avatar component (child) from the menu component(parent) by passing a <code>criminal</code> object to it.</p>



<h4 class="wp-block-heading" id="child-component">Child Component</h4>



<pre class="wp-block-code line-numbers language-typescript"><code>interface IAvatarProps {
    avatarUrl: string;
    alt: string;
    title: string;
}
const Avatar = (props: IAvatarProps) =&gt; {
  return (
    &lt;img 
        src={props.avatarUrl} 
        title={props.title} alt={props.alt} 
        className="avatar" 
    /&gt;
  );
};

export default Avatar;
</code></pre>



<h4 class="wp-block-heading" id="parent-component">Parent Component</h4>



<pre class="wp-block-code line-numbers language-typescript"><code>const criminal = {
        avatar: 'https://hindugenocide.com/islamic-jihad/9000-hindus-converted-in-madrasa/',
        name: 'Pir Ayub Jan Sarhandi'
    };
const Menu = () =&gt; {
    return (
        &lt;Menu&gt;
          &lt;Avatar 
              avatarUrl={criminal.avatar} 
              title={criminal.name} 
              alt="Hindu Genocide" 
          /&gt;
        &lt;/Menu&gt;
    );
};

export default Menu;
</code></pre>



<h2 class="wp-block-heading" id="child-to-parent">Child-to-Parent</h2>



<p>To pass the data from the child to its parent, we need to first define a <code>callback function</code> on the parent component which would then be passed via props on the child component. The child component would then call that function to pass data to the parent component.</p>



<p>For example, let us create a child component called <code>GenocideCard</code> which links to an article on <a href="https://hindugenocide.com/islamic-jihad/mirpur-massacre-of-hindus-and-sikhs-1947/" target="_blank" rel="noreferrer noopener">Mirpur Massacre.</a> We want that when this card is clicked, the article url should be passed to the parent component from where it is rendered.</p>



<ol>
<li>Define a callback function on the parent component called <code>handleGenocideCardClick</code> that accepts a parameter called <code>articleUrl</code>.</li>



<li>Pass that function in the <code>onCardClick</code> prop on the child component.</li>



<li>On the child component, we execute the <code>callback</code> function passed from the parent component when the <code>&lt;img&gt;</code> tag is clicked. The parameter of the <code>callback</code> function is passed as data to the parent component.</li>
</ol>



<h4 class="wp-block-heading" id="parent-component">Parent Component</h4>



<pre class="wp-block-code line-numbers language-typescript"><code>const handleGenocideCardClick = (articleUrl) =&gt; {
    console.log("You can read about this massacre at: " + articleUrl);
}

const Layout = () =&gt; {
  return (
        &lt;Grid&gt;
          &lt;GenocideCard onCardClick={handleGenocideCardClick}/&gt;
        &lt;/Grid&gt;
    );
};

export default Layout;
</code></pre>



<h4 class="wp-block-heading" id="child-component">Child Component</h4>



<pre class="wp-block-code line-numbers language-typescript"><code>interface IGenocideCardProps {
    onCardClick: any;
}
const HinduMassacre = {
      name: "Mirpur Massacre"
      image: "https://www.dailyexcelsior.com/wp-content/uploads/2020/11/1-176.jpg",
      url: "https://hindugenocide.com/islamic-jihad/mirpur-massacre-of-hindus-and-sikhs-1947/"
}
const GenocideCard = (props: IGenocideCardProps) =&gt; {
  return (
  &lt;div className="card"&gt;
    &lt;img 
        src={HinduMassacre.image} 
        title={HinduMassacre.name} 
        alt="Hindu Genocide" 
        onClick={() =&gt; props.onCardClick(HinduMassacre.url)} 
    /&gt;
    &lt;span class="text-red-400 font-medium"&gt;{HinduMassacre.name}&lt;/span&gt;
  );
};

export default GenocideCard;
</code></pre>
<p>The post <a href="https://mithle.sh/how-to-pass-data-between-child-and-parent-components-in-react/">How to Pass Data between Child and Parent Components in React</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mithle.sh/how-to-pass-data-between-child-and-parent-components-in-react/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1233</post-id>	</item>
		<item>
		<title>The Pagination Dilemma &#8211; Offset vs Cursor (Part II)</title>
		<link>https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-2/</link>
					<comments>https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-2/#respond</comments>
		
		<dc:creator><![CDATA[Mithlesh]]></dc:creator>
		<pubDate>Tue, 14 Mar 2023 11:01:04 +0000</pubDate>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[knex]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[postgres]]></category>
		<guid isPermaLink="false">https://blog.mithle.sh/?p=1228</guid>

					<description><![CDATA[<p>In the previous article, we learned how to implement offset and cursor pagination using SQL and Knex. Now, we will benchmark these paging techniques to...</p>
<p>The post <a href="https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-2/">The Pagination Dilemma &#8211; Offset vs Cursor (Part II)</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In the previous <a href="https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-1" target="_blank" rel="noreferrer noopener">article</a>, we learned how to implement offset and cursor pagination using SQL and Knex. Now, we will benchmark these paging techniques to find out which one is better and discuss their pros and cons.</p>



<h2 class="wp-block-heading" id="benchmarks">Benchmarks</h2>



<p>For benchmarking, we are using the <code>artist</code> table from the <a href="https://musicbrainz.org/doc/MusicBrainz_Database" target="_blank" rel="noreferrer noopener">MusicBrainz </a>database. We are using <a href="https://www.npmjs.com/package/@mithleshjs/knex-nest" target="_blank" rel="noreferrer noopener">Knex-Nest</a> &#8211; pagination included <a href="https://knexjs.org/" target="_blank" rel="noreferrer noopener">Knex </a>module for <a href="https://nestjs.com/" target="_blank" rel="noreferrer noopener">NestJS</a> &#8211; for benchmarking.</p>



<h3 class="wp-block-heading" id="offset-pagination">Offset Pagination</h3>



<pre class="wp-block-code line-numbers language-typescript"><code> async getOffsetPagingBenchmarks(
    from = 1,
    to = 10,
    perPage = 50,
    total?: number
  ) {
    let avgQueryTimeOffset = 0;
    for (let index = from; index &lt;= to; index += 1) {
      const tag = `Page ${index}`;
      const start = hrtime.bigint();
      const query = this.knexPg('artist')
        .select('id', 'name')
        .orderBy('id', 'asc');
      await KnexPagination.offsetPaginate({
        query: query,
        perPage: perPage,
        goToPage: index,
        count: total,
      });
      const end = hrtime.bigint();
      const latency = round(Number(end - start) / 1000000);
      avgQueryTimeOffset += latency;
      console.log(`${tag}: ${latency} ms`);
    }
    avgQueryTimeOffset = round(avgQueryTimeOffset / 10);
    console.log(`Average (offset): ${avgQueryTimeOffset} ms`);
    return avgQueryTimeOffset;
  }
</code></pre>



<h3 class="wp-block-heading" id="cursor-pagination">Cursor Pagination</h3>



<pre class="wp-block-code line-numbers language-typescript"><code> async getCursorPagingBenchmarks(
    from = 'start',
    numOfPages = 10,
    perPage = 50
  ) {
    let avgQueryTimeCursor = 0;
    let cursor = null;
    let index = 0;
    while (numOfPages &gt; 0) {
      const tag = `Page ${index++}`;
      const start = hrtime.bigint();
      const query = this.knexPg('artist').select('id', 'name');
      const result = await KnexPagination.cursorPaginate({
        query: query,
        perPage: perPage,
        cursor: {
          key: 'id',
          order: 'asc',
          value: cursor,
          direction: from === 'start' ? 'next' : 'prev',
        },
      });
      if (result.pagination.cursor) {
        cursor = result.pagination.cursor.next_cursor;
      }
      const end = hrtime.bigint();
      const latency = round(Number(end - start) / 1000000);
      avgQueryTimeCursor += latency;
      console.log(`${tag}: ${latency} ms`);
      numOfPages -= 1;
    }
    avgQueryTimeCursor = round(avgQueryTimeCursor / 10);
    console.log(`Average (cursor): ${avgQueryTimeCursor} ms`);
    return avgQueryTimeCursor;
  }
</code></pre>



<p>Let us fetch the first 10 pages with 50 records per page and see what results we get:</p>



<pre class="wp-block-code line-numbers language-typescript"><code>async getBenchmarks() {
    return {
      'Average Time (Offset)': (await this.getOffsetPagingBenchmarks()) + ' ms',
      'Average Time (Cursor)': (await this.getCursorPagingBenchmarks()) + ' ms',
    };
  }
</code></pre>



<pre class="wp-block-code line-numbers language-json"><code>{
    "Average Time (Offset)": "96.49 ms",
    "Average Time (Cursor)": "0.7 ms"
}
</code></pre>



<p>As you can see, offset pagination is almost 137x times slower than cursor pagination even when we are just fetching the first ten pages. The reason is that for each page a <code>count query</code> is executed and its cost is proportional to the number of records. As there are around 1.9 million entries in <code>artist table,</code> so we are seeing a lot of performance differences.</p>



<p>For a fair comparison, we need to fix that performance issue with offset pagination first. We can either store the row count in a separate table and update it whenever a row is added or deleted, or we can cache it somewhere. Some databases maintain row count internally, so refer to their docs for that.</p>



<pre class="wp-block-code line-numbers language-typescript"><code>async getBenchmarks() {
    const total = getArtistsCount();
    return {
      'Average Time (Offset)':
        (await this.getOffsetPagingBenchmarks(1, 10, 50, total)) + ' ms',
      'Average Time (Cursor)':
        (await this.getCursorPagingBenchmarks('start', 10, 50)) + ' ms',
    };
}
</code></pre>



<pre class="wp-block-code line-numbers language-json"><code>{
    "Average Time (Offset)": "0.79 ms",
    "Average Time (Cursor)": "0.76 ms"
}
</code></pre>



<p>Now, the performance difference is almost negligible after optimisation. For a very small table, you can ignore this optimisation but otherwise, you should always maintain a <code>row count</code> if you ever plan to use offset pagination.</p>



<p>We fetch the last 10 pages with 50 records per page</p>



<pre class="wp-block-code line-numbers language-typescript"><code>async getBenchmarks() {
    const total = getArtistsCount();
    return {
      'Average Time (Offset)':
        (await this.getOffsetPagingBenchmarks(38837, 38847, 50, total)) + ' ms',
      'Average Time (Cursor)':
        (await this.getCursorPagingBenchmarks('end', 10, 50)) + ' ms',
    };
}
</code></pre>



<pre class="wp-block-code line-numbers language-json"><code>{
    "Average Time (Offset)": "1734.32 ms",
    "Average Time (Cursor)": "0.78 ms"
}
</code></pre>



<ol>
<li>The time taken by cursor pagination remained the same, but the performance of the offset pagination dropped to a point where it became impractical and inefficient to use. As the page number increases, so does the time it takes to fetch that page because the <code>OFFSET</code> clause has to traverse through all the preceding pages to reach the current page. In the above example, when the last page was requested, the offset pagination traversed through all the 1.9 million records to get the last 50 records while the cursor pagination got the last 50 records directly. That&#8217;s the main reason why cursor pagination outperformed offset pagination by a huge margin.</li>
</ol>



<h2 class="wp-block-heading" id="pros-and-cons">Pros and Cons</h2>



<h4 class="wp-block-heading" id="offset-pagination">Offset Pagination</h4>



<ul>
<li>Pros
<ul>
<li>Easier to implement</li>



<li>Can jump to a specific page</li>



<li>Can sort data by any column(s)</li>
</ul>
</li>



<li>Cons
<ul>
<li>Not scalable</li>



<li>Not suitable for frequently changing data as page positions may shift when a row is added or deleted from the table</li>
</ul>
</li>
</ul>



<h4 class="wp-block-heading" id="cursor-pagination">Cursor Pagination</h4>



<ul>
<li>Pros
<ul>
<li>Scalable to any database size</li>



<li>Works very well with frequency changing data</li>
</ul>
</li>



<li>Cons
<ul>
<li>Can&#8217;t jump to a specific page</li>



<li>Sorting is very limited as it needs a unique sequential column as a cursor</li>
</ul>
</li>
</ul>



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



<p>As a rule &#8211; <em>always use cursor pagination.</em> It is scalable and efficient for any database size. But if you must use offset pagination then use it only when the dataset is very small such as <em>search results, blog posts etc </em>otherwise it would lead to degraded performance and slower page loads.</p>
<p>The post <a href="https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-2/">The Pagination Dilemma &#8211; Offset vs Cursor (Part II)</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1228</post-id>	</item>
		<item>
		<title>The Pagination Dilemma &#8211; Offset vs Cursor (Part I)</title>
		<link>https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-1/</link>
					<comments>https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-1/#respond</comments>
		
		<dc:creator><![CDATA[Mithlesh]]></dc:creator>
		<pubDate>Mon, 13 Mar 2023 20:17:22 +0000</pubDate>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[knex]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[postgres]]></category>
		<guid isPermaLink="false">https://blog.mithle.sh/?p=1125</guid>

					<description><![CDATA[<p>In this part one of the two-article series on pagination, we will learn how to properly implement offset paging and cursor paging using SQL or...</p>
<p>The post <a href="https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-1/">The Pagination Dilemma &#8211; Offset vs Cursor (Part I)</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this part one of the two-article series on pagination, we will learn how to properly implement offset paging and cursor paging using <a href="https://www.w3schools.com/sql/" target="_blank" rel="noreferrer noopener">SQL</a> or <a href="https://github.com/mithleshjs/knex-nest" target="_blank" rel="noreferrer noopener">Knex</a></p>



<h2 class="wp-block-heading" id="offset">Offset</h2>



<p>It is the most popular and easy-to-implement paging technique. The offset-pagination is used when we want to give users an option to jump to specific pages.</p>



<p>To implement offset pagination we need to write two queries &#8211; one to fetch records and the other to get the total count. We also require two inputs from the user &#8211; the number of records per page and the page number.</p>



<p>Suppose, we want to fetch <code>artists</code> from the <a href="https://musicbrainz.org/doc/MusicBrainz_Database">MusicBrainz</a> database and paginate the data. &nbsp;To achieve that we would use <code><strong>LIMIT</strong></code> and <code><strong>OFFSET</strong></code> clause as shown in the steps below.</p>



<ul>
<li>The first step would be to fetch the specific page using <code>perPage</code> and <code>page</code> parameters provided by the user. For example, with <code>page = 4</code> and <code>perPage = 10</code>, we need to skip the first 30 records and then fetch the subsequent 10 records to get the fourth page of results.
<pre class="language-sql line-numbers"><code>
SELECT * FROM musicbrainz.artist 
ORDER BY ID asc OFFSET 30 LIMIT 10;
</code>
</pre>
<pre class="language-typescript line-numbers"><code>const artists = this.knexPg('artist')
  .select('id', 'name')
  .orderBy('id', 'asc')
  .limit(perPage)
  .offset((page - 1) * perPage);</code></pre>
</li>



<li>We then count all of the <code>artists</code> to determine the total number of pages.
<pre class="wp-block-code line-numbers language-sql"><code>SELECT COUNT(*) FROM musicbrainz.artist</code></pre>
<pre class="wp-block-code language-typescript line-numbers"><code>
const count = await this.knexPg('artist')
  .count({ total: '*' })
  .first();
const total = count.total;
const totalPages = Math.ceil(total / perPage);
</code>
</pre>
</li>



<li>Here&#8217;s the full code for the offset pagination function and a sample response:
<pre class="wp-block-code line-numbers language-typescript"><code>
async getArtists(perPage, page) {
  const artists = await this.knexPg('artist')
    .select('id', 'name')
    .orderBy('id', 'asc')
    .limit(perPage)
    .offset((page - 1) * perPage);
  const count = await this.knexPg('artist').count({ total: '*'}).first();
  const total = parseInt(count.total);
  const totalPages = Math.ceil(total / perPage);
  return {
    artists: artists,
    pagination: {
      perPage: perPage,
      currentPage: page,
      totalPages: totalPages,
      total: total,
   },
 };
}</code></pre>
<pre class="wp-block-code line-numbers language-json"><code>
{
  "artists": [...],
  "pagination": {
    "perPage": 10,
    "currentPage": 2,
    "totalPages": 194233,
    "total": 1942322
   }
}
</code>
</pre>
</li>
</ul>



<h2 class="wp-block-heading" id="cursor">Cursor</h2>



<p>This paging technique works by making use of <code><strong>WHERE</strong></code> and <code><strong>ORDER BY</strong></code> clauses on a unique, sequential column(s). We fetch data from the table and then return a cursor that the user can send in the next request to fetch the subsequent data.</p>



<p>Unlike offset pagination, we can&#8217;t jump to a specific page as there is no such concept in this technique. We can only fetch the first page, the previous page, the next page, and the last page.</p>



<p>In this method, we require the following four inputs from the user:</p>



<ul>
<li>no of records per page</li>



<li>the value of the cursor</li>



<li>the sort order of the cursor &#8211; <code>asc | desc</code></li>



<li>direction &#8211; <em>next</em> to fetch items after the cursor or <em>prev</em> to fetch items before the cursor</li>
</ul>



<p>Now let us fetch the <code>artists</code> again from the <a href="https://musicbrainz.org/doc/MusicBrainz_Database">MusicBrainz</a> database but this time using cursor pagination. To begin with cursor pagination, we need to first choose a cursor &#8211; a column that is both <code>sequential</code> and <code>unique</code>. For this example, we would choose <code><strong>ID</strong></code> column as the cursor.</p>



<p>The <code>ID</code> column can sort the data in <em>ascending</em> or <em>descending </em>order and the user can request the <em>next page</em> or the <em>previous page</em>. So there are a total of four scenarios that we need to handle.</p>



<ul>
<li>order by is <code>asc</code> and direction is <code>next</code></li>



<li>order by is <code>asc</code> and direction is <code>prev</code></li>



<li>order by is <code>desc</code> and direction is <code>next</code></li>



<li>order by is <code>desc</code> and direction is <code>prev</code></li>
</ul>



<h3 class="wp-block-heading">Let us handle each case one by one:</h3>



<h4 class="has-text-align-left wp-block-heading">1. Order &#8211; <code>ASC</code> and Direction &#8211; <code>NEXT</code></h4>



<p>This is pretty straightforward, for example with <code>cursor = 10,</code> <code>perPage = 10,</code> we would write the following query to fetch the next ten records.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>In all the four cases, we set <code>LIMIT = perPage + 1</code> to check if there is a next/prev page.</p>
</blockquote>



<pre class="wp-block-code line-numbers language-sql"><code>SELECT * FROM musicbrainz.artist 
WHERE ID &gt; 10 
ORDER BY ID asc 
LIMIT 11;
</code></pre>



<p>If <code>cursor = null,</code> it means the user is requesting the first page, so the query would be:</p>



<pre class="wp-block-code line-numbers language-sql"><code>SELECT * FROM musicbrainz.artist 
ORDER BY ID asc 
LIMIT 11;
</code></pre>



<ul>
<li>If <code>result.length = perPage</code> or <code>result.length &lt; perPage,</code> it means there is no next page.</li>



<li>If <code>result.length &gt; perPage,</code> it means there is a next page and there is an extra item in the result.</li>
</ul>



<p>The <code>ID</code> of the last item from the result will be returned to the user as <code>next_cursor</code> but if there is a next page, we need to first remove that extra last item from the result.</p>



<h4 class="wp-block-heading">2. Order &#8211; <code>ASC</code> and Direction &#8211; <code>PREV</code></h4>



<p>You must be thinking that flipping the comparison operator in the previous query is all we need to traverse in the opposite direction. Let us try that to see if it works.</p>



<pre class="wp-block-code line-numbers language-sql"><code>SELECT * FROM musicbrainz.artist 
WHERE ID &lt; 11 
ORDER BY ID asc 
LIMIT 11;
</code></pre>



<p>We should the get records from <code>1-10</code>. It did work but is it right? Now, let us assume the <code>cursor = 21</code> and then run the query.</p>



<pre class="wp-block-code line-numbers language-sql"><code>SELECT * FROM musicbrainz.artist 
WHERE ID &lt; 21 
ORDER BY ID asc 
LIMIT 11;
</code></pre>



<p>The query should have output records <code>10-20</code> but instead, we get records <code>1-11</code>, <em>but why?</em> Because we forgot that the data is in ascending order and begins with <code>ID = 1</code> and it is also less than <code>21</code>.</p>



<p>So, to get the correct records, we need to flip the <code>ORDER</code> of the cursor.</p>



<pre class="wp-block-code line-numbers language-sql"><code>SELECT * FROM musicbrainz.artist 
WHERE ID &lt; 21 
ORDER BY ID desc 
LIMIT 11;
</code></pre>



<pre class="wp-block-code line-numbers language-json"><code>results = &#91;
    { id: 20 } ... { id:10 }
]
</code></pre>



<p>The data is correct but the order is incorrect. To fix this, just reverse the results array.</p>



<ul>
<li>If <code>cursor = null,</code> it means the user is requesting the last page, so the query would be: <code>SELECT * FROM musicbrainz.artist ORDER BY ID desc LIMIT 11;</code></li>
</ul>



<ul>
<li>If <code>result.length = perPage</code> or <code>result.length &lt; perPage</code>, it means there is no prev page.</li>



<li>If <code>result.length &gt; perPage,</code> it means there is a prev page and there is an extra item in the result.</li>
</ul>



<p>The <code>ID</code> of the first item in the result will be returned to the user as the <code>prev_cursor</code> but if there is a prev page, we need to first remove that extra item from the top.</p>



<h4 class="wp-block-heading">3. Order &#8211; <code>DESC</code> and Direction &#8211; <code>NEXT</code></h4>



<p>The only difference between this case and the first case is the <code>order</code>. So, we just need to change the comparison operator from <code>&gt;</code> to <code>&lt;</code> and <code>ORDER BY</code> from <code>asc</code> to <code>desc</code> and the rest is exactly the same.</p>



<pre class="wp-block-code line-numbers language-sql"><code>SELECT * FROM musicbrainz.artist 
WHERE ID &lt; 10 
ORDER BY ID desc 
LIMIT 11;
</code></pre>



<h4 class="wp-block-heading">4. Order &#8211; <code>DESC</code> and Direction &#8211; <code>PREV</code></h4>



<p>Change the comparison operator from <code>&lt;</code> to <code>&gt;</code> and flip the <code>ORDER BY</code> from &#8216;desc&#8217; to &#8216;asc&#8217; from the third case and follow the rest.</p>



<pre class="wp-block-code line-numbers language-sql"><code>SELECT * FROM musicbrainz.artist 
WHERE ID &gt; 91 
ORDER BY ID asc 
LIMIT 11;
</code></pre>



<p>Here&#8217;s the full code for the offset pagination function and a sample response</p>



<pre class="wp-block-code line-numbers language-typescript"><code> public static async cursorPaginate(params: ICursorPaginateParams) {
    const { query, cursor, perPage = 10, dataKey = 'data' } = params;
    const cursorMeta = {
      hasNextPage: false,
      next_cursor: null,
      hasPrevPage: false,
      prev_cursor: null,
    };
    const whereOperator = this.getWhereOperator(cursor.order, cursor.direction);
    // if cursor is null, we need to get the first/last page
    if (cursor.value) {
      query.where(cursor.key, whereOperator, cursor.value);
    }
    // if direction is prev, we need to reverse the order
    const order =
      cursor.direction === 'next'
        ? cursor.order
        : cursor.order === 'asc'
        ? 'desc'
        : 'asc';
    // add +1 to the limit to determine if there is a next/prev page
    const result = await query.orderBy(cursor.key, order).limit(perPage + 1);
    // if direction is prev, we need to reverse the result
    if (order !== cursor.order) {
      result.reverse();
    }
    // if we have more than perPage results, we have a next/prev page
    if (result.length &gt; perPage) {
      if (cursor.direction === 'next') {
        result.pop();
        cursorMeta.hasNextPage = true;
        if (cursor.value) {
          cursorMeta.hasPrevPage = true;
          cursorMeta.prev_cursor = result&#91;0]&#91;cursor.key];
        }
        cursorMeta.next_cursor = result&#91;result.length - 1]&#91;cursor.key];
      } else {
        result.shift();
        cursorMeta.hasPrevPage = true;
        if (cursor.value) {
          cursorMeta.hasNextPage = true;
          cursorMeta.next_cursor = result&#91;result.length - 1]&#91;cursor.key];
        }
        cursorMeta.prev_cursor = result&#91;0]&#91;cursor.key];
      }
    } else if (result.length &gt; 0 &amp;&amp; result.length &lt;= perPage) {
      if (cursor.direction === 'next') {
        if (cursor.value) {
          cursorMeta.hasPrevPage = true;
          cursorMeta.prev_cursor = result&#91;0]&#91;cursor.key];
        }
      } else {
        if (cursor.value) {
          cursorMeta.hasNextPage = true;
          cursorMeta.next_cursor = result&#91;result.length - 1]&#91;cursor.key];
        }
      }
    }

    return {
      &#91;dataKey]: result,
      pagination: {
        cursor: cursorMeta,
        per_page: perPage,
      },
    };
  }

  private static getWhereOperator(order, direction) {
    if (order === 'asc') {
      if (direction === 'next') {
        return '&gt;';
      } else {
        return '&lt;';
      }
    } else {
      if (direction === 'prev') {
        return '&gt;';
      } else {
        return '&lt;';
      }
    }
  }
</code></pre>



<pre class="wp-block-code line-numbers language-json"><code>{
    "artists": &#91;...],
    "pagination": {
        "cursor": {
            "hasNextPage": true,
            "next_cursor": 45,
            "hasPrevPage": true,
            "prev_cursor": 41
        },
        "per_page": 10
    }
}
</code></pre>



<p>In the next post of this series, we will discuss their pros and cons and benchmark both of these pagination methods to compare their performances using the <a href="https://musicbrainz.org/doc/MusicBrainz_Database">MusicBrainz</a> database.</p>
<p>The post <a href="https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-1/">The Pagination Dilemma &#8211; Offset vs Cursor (Part I)</a> appeared first on <a href="https://mithle.sh">Mithle.sh</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mithle.sh/the-pagination-dilemma-offset-vs-cursor-part-1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1125</post-id>	</item>
	</channel>
</rss>
