<?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>Forem: Sachin Gaggar</title>
    <description>The latest articles on Forem by Sachin Gaggar (@sachingaggar).</description>
    <link>https://forem.com/sachingaggar</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%2F1190520%2Fd27be78f-f61a-48b6-a7b1-16860d54fbbc.JPG</url>
      <title>Forem: Sachin Gaggar</title>
      <link>https://forem.com/sachingaggar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sachingaggar"/>
    <language>en</language>
    <item>
      <title>React Native with WatermelonDB: A Lightweight and Reactive Database for Scalable Apps</title>
      <dc:creator>Sachin Gaggar</dc:creator>
      <pubDate>Fri, 27 Sep 2024 05:46:29 +0000</pubDate>
      <link>https://forem.com/sachingaggar/react-native-with-watermelondb-a-lightweight-and-reactive-database-for-scalable-apps-l88</link>
      <guid>https://forem.com/sachingaggar/react-native-with-watermelondb-a-lightweight-and-reactive-database-for-scalable-apps-l88</guid>
      <description>&lt;p&gt;When it comes to building scalable React Native applications, WatermelonDB is an excellent lightweight database solution. Adding only about 2MB to your app's size, it offers excellent performance, real-time reactivity, and allows you to manage complex relationships between data models efficiently. With WatermelonDB, you can easily handle operations like creating, reading, updating, and deleting records, and manage relationships using decorators like @children and @relation. It also provides you with sync functionality to remote databse.&lt;/p&gt;

&lt;p&gt;In this blog, we'll cover how to set up WatermelonDB, define more complex models with relationships, and perform CRUD operations, including setting children and related records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up WatermelonDB in React Native
&lt;/h2&gt;

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

&lt;p&gt;Start by installing WatermelonDB in your React Native project:&lt;br&gt;
&lt;code&gt;npm install @nozbe/watermelondb&lt;br&gt;
npm install @nozbe/watermelondb/native --save&lt;br&gt;
npx pod-install&lt;br&gt;
&lt;/code&gt; &lt;/p&gt;
&lt;h3&gt;
  
  
  2. Define the Schema
&lt;/h3&gt;

&lt;p&gt;Define the schema for your database. We’ll add some extra fields like &lt;code&gt;age&lt;/code&gt; for &lt;code&gt;users&lt;/code&gt; and &lt;code&gt;content&lt;/code&gt; for posts, plus we’ll establish a relationship where &lt;code&gt;users&lt;/code&gt; have multiple &lt;code&gt;posts&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// schema.js
import { tableSchema } from '@nozbe/watermelondb/Schema';

export const mySchema = {
  version: 1,
  tables: [
    tableSchema({
      name: 'users',
      columns: [
        { name: 'name', type: 'string' },
        { name: 'email', type: 'string' },  // New field for email
        { name: 'age', type: 'number' },    // New field for age
      ],
    }),
    tableSchema({
      name: 'posts',
      columns: [
        { name: 'user_id', type: 'string', isIndexed: true },  // Foreign key to users
        { name: 'title', type: 'string' },
        { name: 'content', type: 'string' },  // New field for content
        { name: 'created_at', type: 'number' },  // New timestamp field
      ],
    }),
  ],
};

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Define Models with Relationships
&lt;/h3&gt;

&lt;p&gt;WatermelonDB uses decorators like @field, @children, and @relation to manage fields and relationships between models. Let’s define a User model that has many Post records, and a Post model that belongs to a User.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// User.js
import { Model } from '@nozbe/watermelondb';
import { text, field, date, children } from '@nozbe/watermelondb/decorators';

export default class User extends Model {
  static table = 'users';

  @text('name') name;
  @text('email') email;      // New field for email
  @field('age') age;          // New field for age

  @children('posts') posts;   // One-to-many relationship with posts
}

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Post.js
import { Model } from '@nozbe/watermelondb';
import { text, date, relation } from '@nozbe/watermelondb/decorators';

export default class Post extends Model {
  static table = 'posts';

  @text('title') title;
  @text('content') content;        // New field for content
  @date('created_at') createdAt;   // New timestamp field

  @relation('users', 'user_id') user;  // Relation to the users table
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Set Up the Database
&lt;/h3&gt;

&lt;p&gt;You now need to set up the database with the schema and models you defined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// database.js
import { Database } from '@nozbe/watermelondb';
import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite';
import { mySchema } from './schema';
import User from './User';
import Post from './Post';

const adapter = new SQLiteAdapter({
  schema: mySchema,
});

export const database = new Database({
  adapter,
  modelClasses: [User, Post],
  actionsEnabled: true,
});

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  CRUD Operations with WatermelonDB
&lt;/h2&gt;

&lt;p&gt;Let’s walk through performing CRUD operations with WatermelonDB, including handling relations between users and posts.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create a User and a Post
&lt;/h3&gt;

&lt;p&gt;You can create new users and posts by using the create method inside a database.write block. Remember always write crud operation inside write block. Now here you have freedom either, we can create this method directly inside models or write a separate file.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create a User
const addUser = async (name, email, age) =&amp;gt; {
  await database.write(async () =&amp;gt; {
    await database.collections.get('users').create(user =&amp;gt; {
      user.name = name;
      user.email = email;  // Setting email field
      user.age = age;      // Setting age field
    });
  });
};

// Create a Post for a User
const addPost = async (user, title, content) =&amp;gt; {
  await database.write(async () =&amp;gt; {
    await database.collections.get('posts').create(post =&amp;gt; {
  /**
  * Setting relation to User. This is very very important.
  * Without this set you can't take advantage of flexibilty provided by children decorator
  **/
      post.user.set(user);  
      post.title = title;
      post.content = content;  // Setting content field
      post.createdAt = Date.now();  // Setting timestamp
    });
  });
};

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Read Records
&lt;/h2&gt;

&lt;p&gt;Fetching records is straightforward, and you can query related data like posts belonging to a user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Fetch all users
const fetchUsers = async () =&amp;gt; {
  const users = await database.collections.get('users').query().fetch();
  return users;
};

// Fetch posts for a specific user
const fetchUserPosts = async (user) =&amp;gt; {
  const posts = await user.posts.fetch();  
// Using @children decorator all posts will be collected 
// related to this user
  return posts;
};

// Fetch the user who owns a post
const fetchPostOwner = async (post) =&amp;gt; {
  const user = await post.user.fetch();  // Fetches the related user using @relation
  return user;
};

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Update Records
&lt;/h2&gt;

&lt;p&gt;Updating records is done by fetching a record and modifying it within a database.write block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Update a User
const updateUser = async (user, newName, newAge) =&amp;gt; {
  await database.write(async () =&amp;gt; {
    await user.update(u =&amp;gt; {
      u.name = newName;
      u.age = newAge;
    });
  });
};

// Update a Post
const updatePost = async (post, newTitle, newContent) =&amp;gt; {
  await database.write(async () =&amp;gt; {
    await post.update(p =&amp;gt; {
      p.title = newTitle;
      p.content = newContent;
    });
  });
};

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Delete Records
&lt;/h3&gt;

&lt;p&gt;WatermelonDB allows both soft delete (marks as deleted) and hard delete (permanently removes the record):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Soft delete a User
const softDeleteUser = async (user) =&amp;gt; {
  await database.write(async () =&amp;gt; {
    await user.markAsDeleted();
  });
};

// Hard delete a User
const hardDeleteUser = async (user) =&amp;gt; {
  await database.write(async () =&amp;gt; {
    await user.destroyPermanently();
  });
};

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

&lt;/div&gt;



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

&lt;p&gt;WatermelonDB is a lightweight, high-performance solution for React Native apps, adding only 2MB to your app size while providing efficient data handling for large datasets. By leveraging decorators like @children and @relation, you can easily define and manage relationships between records. The asynchronous CRUD operations ensure smooth UI performance, making it an ideal database choice for both small and large-scale applications.&lt;/p&gt;

&lt;p&gt;Whether you're handling complex relationships or just starting with simple data, WatermelonDB’s combination of reactivity, performance, and ease of use makes it a great option for React Native developers.&lt;/p&gt;

&lt;p&gt;Feel free to drop a comment if you have any questions. Also, take a look at withObservables, a Higher-Order Component (HOC) that automatically re-renders your UI whenever there are changes in the database values.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>watermelondb</category>
      <category>database</category>
      <category>react</category>
    </item>
    <item>
      <title>GraphQl Integration With React Native</title>
      <dc:creator>Sachin Gaggar</dc:creator>
      <pubDate>Sat, 21 Oct 2023 07:07:00 +0000</pubDate>
      <link>https://forem.com/sachingaggar/graphql-integration-with-react-native-531a</link>
      <guid>https://forem.com/sachingaggar/graphql-integration-with-react-native-531a</guid>
      <description>&lt;p&gt;GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.&lt;br&gt;
Let's integrate this with React Native App.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Basic Setup:
&lt;/h3&gt;

&lt;p&gt;Create a react native project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx react-native init GraphqlDemo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install apollo client and graphQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @apollo/client graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Apollo Client Integration:
&lt;/h3&gt;

&lt;p&gt;In this step, we will initialize Apollo client with Graphql &lt;br&gt;
API Endpoint. After that, we have to wrap our App with ApolloProvider. &lt;br&gt;
ApolloProvider wraps the app and places Apollo Client on the context, enabling us to access it from anywhere in our component tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import {SafeAreaView, StyleSheet, useColorScheme} from 'react-native';

import {Colors} from 'react-native/Libraries/NewAppScreen';
import {ApolloClient, ApolloProvider, InMemoryCache} from '@apollo/client';
import HomePage from './src/screenModules/HomePage';

const client = new ApolloClient({
  // create an apollo link instance, a network interface for apollo client
  uri: 'https://swapi-graphql.netlify.app/.netlify/functions/index',
  // create an in memory cache instance for caching graphql data
  cache: new InMemoryCache(),
});

function App(): JSX.Element {
  const isDarkMode = useColorScheme() === 'dark';

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  return (
    &amp;lt;SafeAreaView style={backgroundStyle}&amp;gt;
      &amp;lt;ApolloProvider client={client}&amp;gt;
        &amp;lt;HomePage /&amp;gt;
      &amp;lt;/ApolloProvider&amp;gt;
    &amp;lt;/SafeAreaView&amp;gt;
  );
}

export default App;

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

&lt;/div&gt;



&lt;p&gt;In the above code, we are using a demo API endpoint which gives us data about Star Wars movies. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: GraphQl Request Query:
&lt;/h3&gt;

&lt;p&gt;Now lets create our query to fetch data from the endPoint. &lt;br&gt;
You can also play around in the explorer by opening the same end point in your browser: &lt;a href="https://studio.apollographql.com/public/star-wars-swapi/variant/current/explorer"&gt;https://studio.apollographql.com/public/star-wars-swapi/variant/current/explorer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The gql template literal tag can be used to concisely write a GraphQL query that is parsed into a standard GraphQL AST. It is the recommended method for passing queries to Apollo Client. While it is primarily built for Apollo Client, it generates a generic GraphQL AST which can be used by any GraphQL client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {gql} from '@apollo/client';

export const AllFilms = gql`
  query Query {
    allFilms {
      films {
        title
        director
        releaseDate
      }
    }
  }
`;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: HomePage.tsx:
&lt;/h3&gt;

&lt;p&gt;Now Apollo Client prove us with hook useQuery. This hook gives us 3 states: &lt;br&gt;
⇒loading: When data is being fetch this will be true&lt;br&gt;
⇒error: When there is error in fetching data&lt;br&gt;
⇒data: Requested data in the format specified in query&lt;/p&gt;

&lt;p&gt;Now we can use this to create our homepage as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import {FlatList, StyleSheet, Text, View} from 'react-native';
import {useQuery} from '@apollo/client';
import {AllFilms} from '../../GraphQL/Query';

const HomePage = () =&amp;gt; {
  const {data, loading} = useQuery(AllFilms);
  const header = () =&amp;gt; {
    return (
      &amp;lt;View style={styles.headerView}&amp;gt;
        &amp;lt;Text style={styles.headerTitle}&amp;gt;Star Wars Films&amp;lt;/Text&amp;gt;
      &amp;lt;/View&amp;gt;
    );
  };
  const AllFilmsItem = ({item}) =&amp;gt; {
    const {title, director, releaseDate} = item;
    return (
      &amp;lt;View style={styles.cards}&amp;gt;
        &amp;lt;View&amp;gt;
          &amp;lt;Text style={styles.title}&amp;gt;Title: {title}&amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
        &amp;lt;View&amp;gt;
          &amp;lt;Text style={styles.description}&amp;gt;Director: {director}&amp;lt;/Text&amp;gt;
          &amp;lt;Text style={styles.description}&amp;gt;Release Date: {releaseDate}&amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
      &amp;lt;/View&amp;gt;
    );
  };
  if (loading) {
    return &amp;lt;Text&amp;gt;Data loading&amp;lt;/Text&amp;gt;;
  }
  return (
    &amp;lt;FlatList
      style={styles.container}
      data={data.allFilms.films}
      contentContainerStyle={styles.contentContainer}
      renderItem={({item}) =&amp;gt; &amp;lt;AllFilmsItem item={item} /&amp;gt;}
      keyExtractor={(_, index) =&amp;gt; index.toString()}
      ListHeaderComponent={header}
    /&amp;gt;
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: 'white',
  },
  headerView: {
    padding: 16,
  },
  headerTitle: {
    fontSize: 18,
    color: 'black',
    fontWeight: '600',
    textAlign: 'center',
  },
  cards: {
    padding: 16,
    backgroundColor: 'white',
    elevation: 2,
    shadowColor: 'black',
    shadowOpacity: 0.2,
    shadowRadius: 2,
    marginBottom: 8,
    borderRadius: 8,
  },
  contentContainer: {
    padding: 16,
  },
  title: {
    fontSize: 16,
    color: 'black',
    fontWeight: '600',
  },
  description: {
    fontSize: 14,
    color: 'black',
    fontWeight: '600',
  },
});

export default HomePage;

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

&lt;/div&gt;



&lt;p&gt;Final Product will look like this:&lt;/p&gt;

&lt;p&gt;In Loading state: &lt;/p&gt;

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

&lt;p&gt;When Data is fetched: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ByLhOGGX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zewncuwzjmyc96xkgan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ByLhOGGX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zewncuwzjmyc96xkgan.png" alt="Image description" width="800" height="1555"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>graphql</category>
      <category>javascript</category>
      <category>api</category>
    </item>
  </channel>
</rss>
