From 7a45a6e70f46ecab7d4618de1edec9b7de93e4ca Mon Sep 17 00:00:00 2001 From: Daniele Briggi Date: Mon, 10 Mar 2025 11:18:41 +0100 Subject: [PATCH 1/6] fix(js): example always reconnect to db --- sqlite-cloud/quick-start-next.mdx | 2 -- sqlite-cloud/quick-start-node.mdx | 19 +++---------------- sqlite-cloud/quick-start-react-native.mdx | 4 ++-- sqlite-cloud/quick-start-react.mdx | 23 ++++++++++++++--------- 4 files changed, 19 insertions(+), 29 deletions(-) diff --git a/sqlite-cloud/quick-start-next.mdx b/sqlite-cloud/quick-start-next.mdx index 70b849d..e0e2509 100644 --- a/sqlite-cloud/quick-start-next.mdx +++ b/sqlite-cloud/quick-start-next.mdx @@ -53,8 +53,6 @@ export function DatabaseProvider({ children, config }: DatabaseProviderProps) { const dbRef = useRef(null); useEffect(() => { - if (dbRef.current && dbRef.current.isConnected()) return; // Connection already exists - try { dbRef.current = new Database(config.connectionString); diff --git a/sqlite-cloud/quick-start-node.mdx b/sqlite-cloud/quick-start-node.mdx index cb50f25..2ca563b 100644 --- a/sqlite-cloud/quick-start-node.mdx +++ b/sqlite-cloud/quick-start-node.mdx @@ -32,26 +32,13 @@ npm install express @sqlitecloud/drivers --save const express = require("express"); const { Database } = require("@sqlitecloud/drivers"); +const connectionString = process.env.SQLITECLOUD_CONNECTION_STRING const app = express(); -let db; - -function getDatabase() { - if (!db || !db.isConnected()) { - db = new Database("", (error) => { - if (error) { - console.log("Error during the connection", error); - } else { - console.log("Connected to the database"); - } - }); - } - - return db; -} app.get("/albums", async (req, res) => { try { - const result = await getDatabase().sql(` + const db = new Database(connectionString) + const result = await db.sql(` USE DATABASE chinook.sqlite; SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist FROM albums diff --git a/sqlite-cloud/quick-start-react-native.mdx b/sqlite-cloud/quick-start-react-native.mdx index fb142f8..01d7222 100644 --- a/sqlite-cloud/quick-start-react-native.mdx +++ b/sqlite-cloud/quick-start-react-native.mdx @@ -49,11 +49,11 @@ export default function App() { const db = new Database(''); const result = - await db.sql`USE DATABASE chinook.sqlite; + await db.sql(`USE DATABASE chinook.sqlite; SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist FROM albums INNER JOIN artists - WHERE artists.ArtistId = albums.ArtistId LIMIT 20;`; + WHERE artists.ArtistId = albums.ArtistId LIMIT 20;`); setAlbums(result); } diff --git a/sqlite-cloud/quick-start-react.mdx b/sqlite-cloud/quick-start-react.mdx index 022bb56..0d41622 100644 --- a/sqlite-cloud/quick-start-react.mdx +++ b/sqlite-cloud/quick-start-react.mdx @@ -29,20 +29,25 @@ cd sqlc-quickstart && npm install @sqlitecloud/drivers import { useEffect, useState } from "react"; import { Database } from '@sqlitecloud/drivers'; -const db = new Database(''); +const connectionString = process.env.SQLITECLOUD_CONNECTION_STRING function App() { const [data, setData] = useState([]); const getAlbums = async () => { - const result = await db.sql` - USE DATABASE chinook.sqlite; - SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist - FROM albums - INNER JOIN artists - WHERE artists.ArtistId = albums.ArtistId - LIMIT 20;`; - setData(result); + try { + const db = new Database(connectionString) + const result = await db.sql(` + USE DATABASE chinook.sqlite; + SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist + FROM albums + INNER JOIN artists + WHERE artists.ArtistId = albums.ArtistId + LIMIT 20;`); + setData(result); + } catch (err) { + // manage error case + } }; useEffect(() => { From 17d25798177c637d1c283e826ea80eb6b1c52446 Mon Sep 17 00:00:00 2001 From: Daniele Briggi Date: Mon, 10 Mar 2025 11:54:30 +0100 Subject: [PATCH 2/6] fix(js): handle exception --- sqlite-cloud/quick-start-node.mdx | 5 +++- sqlite-cloud/quick-start-react-native.mdx | 28 +++++++++++++++-------- sqlite-cloud/quick-start-react.mdx | 8 +++++-- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/sqlite-cloud/quick-start-node.mdx b/sqlite-cloud/quick-start-node.mdx index 2ca563b..c6d440b 100644 --- a/sqlite-cloud/quick-start-node.mdx +++ b/sqlite-cloud/quick-start-node.mdx @@ -36,8 +36,9 @@ const connectionString = process.env.SQLITECLOUD_CONNECTION_STRING const app = express(); app.get("/albums", async (req, res) => { + const db; try { - const db = new Database(connectionString) + db = new Database(connectionString) const result = await db.sql(` USE DATABASE chinook.sqlite; SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist @@ -48,6 +49,8 @@ app.get("/albums", async (req, res) => { res.json(result); } catch (error) { res.status(500).json({ error: error.message }); + } finally { + db?.close(); } }); diff --git a/sqlite-cloud/quick-start-react-native.mdx b/sqlite-cloud/quick-start-react-native.mdx index 01d7222..b6506e2 100644 --- a/sqlite-cloud/quick-start-react-native.mdx +++ b/sqlite-cloud/quick-start-react-native.mdx @@ -46,16 +46,24 @@ export default function App() { useEffect(() => { async function getAlbums() { - const db = new Database(''); - - const result = - await db.sql(`USE DATABASE chinook.sqlite; - SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist - FROM albums - INNER JOIN artists - WHERE artists.ArtistId = albums.ArtistId LIMIT 20;`); - - setAlbums(result); + const db; + try { + db = new Database(''); + + const result = + await db.sql(`USE DATABASE chinook.sqlite; + SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist + FROM albums + INNER JOIN artists + WHERE artists.ArtistId = albums.ArtistId LIMIT 20;`); + + setAlbums(result); + } + } catch (error) { + // manage error state + console.error(`getAlbums - ${error}`, error) + } finally { + db?.close(); } getAlbums(); diff --git a/sqlite-cloud/quick-start-react.mdx b/sqlite-cloud/quick-start-react.mdx index 0d41622..8b78bad 100644 --- a/sqlite-cloud/quick-start-react.mdx +++ b/sqlite-cloud/quick-start-react.mdx @@ -35,8 +35,9 @@ function App() { const [data, setData] = useState([]); const getAlbums = async () => { + const db; try { - const db = new Database(connectionString) + db = new Database(connectionString) const result = await db.sql(` USE DATABASE chinook.sqlite; SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist @@ -46,7 +47,10 @@ function App() { LIMIT 20;`); setData(result); } catch (err) { - // manage error case + // manage error state + console.error(`getAlbums - ${error}`, error); + } finally { + db?.close(); } }; From 2323c29db3b927ccd4cca7e2301ea6741f5d576c Mon Sep 17 00:00:00 2001 From: TizianoT Date: Tue, 11 Mar 2025 08:33:49 +0100 Subject: [PATCH 3/6] improving next.js quick start --- sqlite-cloud/quick-start-next.mdx | 177 +++++++----------------------- 1 file changed, 42 insertions(+), 135 deletions(-) diff --git a/sqlite-cloud/quick-start-next.mdx b/sqlite-cloud/quick-start-next.mdx index e0e2509..42d7a36 100644 --- a/sqlite-cloud/quick-start-next.mdx +++ b/sqlite-cloud/quick-start-next.mdx @@ -23,155 +23,62 @@ npx create-next-app@latest sqlc-quickstart --js --no-tailwind --eslint --app --s cd sqlc-quickstart && npm install @sqlitecloud/drivers ``` 4. **Instantiate a connection** + - Create a `.env.local` file in the root of your Next.js project and add your SQLiteCloud connection string: +``bash +SQLITECLOUD_URL=your_connection_string_here +``` - The Database driver establishes a TLS connection when used in Node.js, and a websocket connection when used in the browser. - - It is recommended that you use the Database driver in client-side components. - - To share the connection across pages, you can instantiate the connection in a context provider with the ```use client``` directive. Below is a simplified sample implementation. - -```tsx -// src/app/context/DatabaseContext.tsx -'use client'; - -import { Database } from '@sqlitecloud/drivers'; -import { createContext, useContext, useEffect, useRef, useState } from 'react'; - -interface DatabaseContextType { - db: Database | null; - isConnecting: boolean; - error: Error | null; -} - -const DatabaseContext = createContext(undefined); - -interface DatabaseProviderProps { - children: React.ReactNode; - config: { connectionString: string } -} - -export function DatabaseProvider({ children, config }: DatabaseProviderProps) { - const [isConnecting, setIsConnecting] = useState(true); - const [error, setError] = useState(null); - const dbRef = useRef(null); - - useEffect(() => { - try { - dbRef.current = new Database(config.connectionString); - - // Handle connection events - dbRef.current.on('open', () => { - console.log('open') - setIsConnecting(false); - setError(null); - }); - - dbRef.current.on('error', (err: Error) => { - console.log('error') - setError(err); - setIsConnecting(false); - }); - - dbRef.current.on('close', () => { - console.log('closing') - setIsConnecting(false); - dbRef.current = null; - }); - - } catch (err) { - setError(err instanceof Error ? err : new Error('Failed to initialize database')); - setIsConnecting(false); - } - // Cleanup function - return () => { - if (dbRef.current) { - dbRef.current.close(); - dbRef.current = null; - } - }; - }, [config]); - return ( - - {children} - - ); -} - -export function useDatabaseConnection() { - const context = useContext(DatabaseContext); - - if (context === undefined) { - throw new Error('useDatabaseConnection must be used within a DatabaseProvider'); - } +--- - return context; -} -``` -5. **Query data** - - Click the ```Connect``` button in your account dashboard and copy the connection string. Replace `````` in ```page.js``` with your connection string. - - Replace the code in ```layout.js``` and ```page.js``` with the following snippets. +### Using SQLiteCloud in Next.js (App Router) -```jsx -// src/app/layout.js -export default function RootLayout({ children }) { - return ( - - - ' }}> - {children} - - - - ); -} -``` +#### Fetching Data in a Server Component -```jsx -// src/app/page.js -import { useDatabaseConnection } from './context/DatabaseContext'; -import { useEffect, useState } from "react"; -import { useDatabaseConnection } from "./useDatabaseConnection"; +If you want to fetch data directly from the server and render it in a Server Component, you can do: -export default function Home() { - const { db } = useDatabaseConnection(); - const [albums, setAlbums] = useState([]); - - useEffect(() => { - const getAlbums = async () => { - const result = await db.sql`USE DATABASE chinook.sqlite; +**app/albums/page.tsx (Server Component)** +```tsx +import { Database } from "sqlitecloud"; +import { unstable_noStore as noStore } from "next/cache"; + +export default async function AlbumsPage() { + noStore(); // Prevents Next.js from caching the database request + const db = new Database(process.env.SQLITECLOUD_URL!); + + try { + const result = await db.sql(` + USE DATABASE chinook.sqlite; SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist FROM albums INNER JOIN artists WHERE artists.ArtistId = albums.ArtistId - LIMIT 20;`; - return result; - }; - - if (db) { - getAlbums().then((result) => { - setAlbums(result); - }); - } - }, [db]); - - return ( -
-

Albums

-
    - {albums.map((album) => ( -
    {album.title}
    - ))} -
-
- ); + LIMIT 20; + `); + + return ( +
+

Albums

+
    + {result.map((album: any) => ( +
  • + {album.title} - {album.artist} +
  • + ))} +
+
+ ); + } catch (error) { + return

Error loading albums: {error.message}

; + } finally { + db.close(); + } } ``` + + 5. **Run your app** ```bash npm run dev From 043b43393c28ff8c3df196ba596bea7320aa8aaf Mon Sep 17 00:00:00 2001 From: Daniele Briggi Date: Tue, 11 Mar 2025 09:40:14 +0100 Subject: [PATCH 4/6] fix(js): typo --- sqlite-cloud/quick-start-node.mdx | 2 +- sqlite-cloud/quick-start-react-native.mdx | 12 ++++++------ sqlite-cloud/quick-start-react.mdx | 6 ++---- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/sqlite-cloud/quick-start-node.mdx b/sqlite-cloud/quick-start-node.mdx index c6d440b..d68a932 100644 --- a/sqlite-cloud/quick-start-node.mdx +++ b/sqlite-cloud/quick-start-node.mdx @@ -36,7 +36,7 @@ const connectionString = process.env.SQLITECLOUD_CONNECTION_STRING const app = express(); app.get("/albums", async (req, res) => { - const db; + let db = null; try { db = new Database(connectionString) const result = await db.sql(` diff --git a/sqlite-cloud/quick-start-react-native.mdx b/sqlite-cloud/quick-start-react-native.mdx index b6506e2..b3e59cc 100644 --- a/sqlite-cloud/quick-start-react-native.mdx +++ b/sqlite-cloud/quick-start-react-native.mdx @@ -46,9 +46,9 @@ export default function App() { useEffect(() => { async function getAlbums() { - const db; + let db = null; try { - db = new Database(''); + db = new Database(''); const result = await db.sql(`USE DATABASE chinook.sqlite; @@ -58,12 +58,12 @@ export default function App() { WHERE artists.ArtistId = albums.ArtistId LIMIT 20;`); setAlbums(result); - } - } catch (error) { + } catch (error) { // manage error state console.error(`getAlbums - ${error}`, error) - } finally { - db?.close(); + } finally { + db?.close(); + } } getAlbums(); diff --git a/sqlite-cloud/quick-start-react.mdx b/sqlite-cloud/quick-start-react.mdx index 8b78bad..51fcb77 100644 --- a/sqlite-cloud/quick-start-react.mdx +++ b/sqlite-cloud/quick-start-react.mdx @@ -29,15 +29,13 @@ cd sqlc-quickstart && npm install @sqlitecloud/drivers import { useEffect, useState } from "react"; import { Database } from '@sqlitecloud/drivers'; -const connectionString = process.env.SQLITECLOUD_CONNECTION_STRING - function App() { const [data, setData] = useState([]); const getAlbums = async () => { - const db; + let db = null; try { - db = new Database(connectionString) + db = new Database('') const result = await db.sql(` USE DATABASE chinook.sqlite; SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist From b3e64ba92193e5b08ff6b0c9ad5adb4e98b2675d Mon Sep 17 00:00:00 2001 From: TizianoT Date: Tue, 11 Mar 2025 11:06:09 +0100 Subject: [PATCH 5/6] updated next.js example --- sqlite-cloud/quick-start-next.mdx | 423 +++++++++++++++++++++++++++--- 1 file changed, 385 insertions(+), 38 deletions(-) diff --git a/sqlite-cloud/quick-start-next.mdx b/sqlite-cloud/quick-start-next.mdx index 42d7a36..646aa4a 100644 --- a/sqlite-cloud/quick-start-next.mdx +++ b/sqlite-cloud/quick-start-next.mdx @@ -6,84 +6,431 @@ status: publish slug: quick-start-next --- -In this quickstart, we will show you how to get started with SQLite Cloud and Next.js by building a simple application that connects to and reads from a SQLite Cloud database. +This quick start guide will walk you through setting up a Next.js application that connects to and queries a SQLite Cloud database. --- 1. **Set up a SQLite Cloud account** - If you haven't already, [sign up for a SQLite Cloud account](https://dashboard.sqlitecloud.io/auth/sign-in) and create a new project. - - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. + - For this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. + 2. **Create a Next.js app** - - Create a Next app using ```create-next-app```. The following command creates a very simple app (JS, no Tailwind, uses the latest App Router) to keep the focus on querying the data. + - Use ```create-next-app``` to set up a new Next.js project. The following command creates a minimal app with TypeScript and the latest App Router, keeping the focus on querying data. ```bash -npx create-next-app@latest sqlc-quickstart --js --no-tailwind --eslint --app --src-dir --import-alias "@/*" --use-npm +npx create-next-app@latest sqlc-quickstart --ts --no-tailwind --eslint --app --src-dir --import-alias "@/*" --use-npm ``` + 3. **Install the SQLite Cloud SDK** ```bash cd sqlc-quickstart && npm install @sqlitecloud/drivers ``` -4. **Instantiate a connection** - - Create a `.env.local` file in the root of your Next.js project and add your SQLiteCloud connection string: -``bash -SQLITECLOUD_URL=your_connection_string_here + +4. **Configure the Database Connection** + - Create a `.env.local` file in the root of your Next.js project and add your SQLite Cloud connection string: +```bash +SQLITECLOUD_URL=sqlitecloud://abcd1234.global1.qwerty.sqlite.cloud:8860/chinook.sqlite?apikey=your-api-key +NEXT_PUBLIC_SQLITECLOUD_URL=sqlitecloud://abcd1234.global1.qwerty.sqlite.cloud:8860/chinook.sqlite?apikey=your-api-key ``` - - The Database driver establishes a TLS connection when used in Node.js, and a websocket connection when used in the browser. + - The database driver establishes a TLS connection in Node.js and a WebSocket connection in the browser. ---- +5. **Set Up the Folder Structure** +```bash +mkdir -p sqlc-quickstart/src/app/api/albums \ + sqlc-quickstart/src/app/components \ + sqlc-quickstart/src/constants + +touch sqlc-quickstart/src/app/api/albums/route.ts \ + sqlc-quickstart/src/app/components/GetAlbumsClient.tsx \ + sqlc-quickstart/src/app/components/GetAlbumsServer.tsx \ + sqlc-quickstart/src/app/components/UpdateAlbumsClient.tsx \ + sqlc-quickstart/src/constants/queries.ts \ + sqlc-quickstart/src/types.ts +``` + +6. **Define Data Types** +```ts +// +// src/type.ts (Server Component) +// + +export interface Album { + id: number; + title: string; + artist: string; +} + +``` + +7. **Define Queries** +```ts +// +// src/constants/queries.ts +// + +export const GET_ALBUMS = ` + USE DATABASE chinook.sqlite; + SELECT albums.AlbumId AS id, albums.Title AS title, artists.Name AS artist + FROM albums + INNER JOIN artists ON albums.ArtistId = artists.ArtistId + LIMIT 20; +`; + +export const GET_LAST_TEN_ALBUMS = ` + USE DATABASE chinook.sqlite; + SELECT albums.AlbumId AS id, albums.Title AS title, artists.Name AS artist + FROM albums + INNER JOIN artists ON albums.ArtistId = artists.ArtistId + ORDER BY albums.AlbumId DESC + LIMIT 10; +`; + +export const INSERT_ALBUM = ` + USE DATABASE chinook.sqlite; + INSERT INTO albums (Title, ArtistId) VALUES (?, ?); +`; +``` + +8. **Fetch Data via a Route Handler** + +You can create a route handler for handling `GET` and `POST` requests. + +```ts +// +// src/app/api/albums/route.ts (Route Handler) +// + +import { NextResponse } from "next/server"; +import { Database } from "@sqlitecloud/drivers"; +import { GET_LAST_TEN_ALBUMS, INSERT_ALBUM } from "@/constants/queries"; + +export async function GET() { + let db; + + try { + db = new Database(process.env.SQLITECLOUD_URL!); + const result = await db.sql(GET_LAST_TEN_ALBUMS); + + return NextResponse.json(result); + } catch (error) { + let message = "An unknown error occurred"; -### Using SQLiteCloud in Next.js (App Router) + if (error instanceof Error) { + message = error.message; + } -#### Fetching Data in a Server Component + return NextResponse.json({ error: message }, { status: 500 }); + } finally { + db?.close(); + } +} + +export async function POST(req: Request) { + const { title, artistId } = await req.json(); + let db; + + try { + db = new Database(process.env.SQLITECLOUD_URL!); + await db.sql(INSERT_ALBUM, ...[title, artistId]); + + return NextResponse.json({ success: true }); + } catch (error) { + let message = "An unknown error occurred"; + + if (error instanceof Error) { + message = error.message; + } + + return NextResponse.json({ error: message }, { status: 500 }); + } finally { + db?.close(); + } +} +``` -If you want to fetch data directly from the server and render it in a Server Component, you can do: +9. **Fetch Data in a Server Component** + +To fetch data directly from the server and render it in a Server Component: -**app/albums/page.tsx (Server Component)** ```tsx -import { Database } from "sqlitecloud"; +// +// src/app/components/GetAlbumsServer.tsx (Server Component) +// + +import { GET_ALBUMS } from "@/constants/queries"; +import { Album } from "@/types"; +import { Database } from "@sqlitecloud/drivers"; import { unstable_noStore as noStore } from "next/cache"; -export default async function AlbumsPage() { +export default async function GetAlbumsServer() { noStore(); // Prevents Next.js from caching the database request - const db = new Database(process.env.SQLITECLOUD_URL!); - + let db; + try { - const result = await db.sql(` - USE DATABASE chinook.sqlite; - SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist - FROM albums - INNER JOIN artists - WHERE artists.ArtistId = albums.ArtistId - LIMIT 20; - `); - + db = new Database(process.env.SQLITECLOUD_URL!); + const result = await db.sql(GET_ALBUMS); + return (
-

Albums

-
    - {result.map((album: any) => ( -
  • - {album.title} - {album.artist} +

    + Albums (Server Component) +

    +
      + {result.map((album: Album) => ( +
    • + {album.title} -{" "} + {album.artist}
    • ))}
); } catch (error) { - return

Error loading albums: {error.message}

; + let message = "An unknown error occurred"; + + if (error instanceof Error) { + message = error.message; + } + return

Error loading albums: {message}

; } finally { - db.close(); + db?.close(); } } ``` +10. **Fetch Data in a Client Component** +Since the SQLite Cloud driver can run in the browser, you can use it directly in a Client Component without needing an API route. + +```tsx +// +// src/app/components/GetAlbumsClient.tsx (Client Component) +// + +"use client"; + +import { useEffect, useState } from "react"; +import { Database } from "@sqlitecloud/drivers"; +import { Album } from "@/types"; +import { GET_ALBUMS } from "@/constants/queries"; + +export default function GetAlbumsClient() { + const [albums, setAlbums] = useState([]); + const [error, setError] = useState(null); + + useEffect(() => { + async function fetchAlbums() { + let db; + try { + console.log(process.env.NEXT_PUBLIC_SQLITECLOUD_URL); + db = new Database(process.env.NEXT_PUBLIC_SQLITECLOUD_URL!); + const result = await db.sql(GET_ALBUMS); + setAlbums(result); + } catch (error) { + let message = "An unknown error occurred"; + + if (error instanceof Error) { + message = error.message; + } + setError(message); + } finally { + db?.close(); + } + } + + fetchAlbums(); + }, []); + if (error) return

Error: {error}

; -5. **Run your app** + return ( +
+

Albums (Client Component)

+ {error ? ( +

Error: {error}

+ ) : ( +
    + {albums.map((album) => ( +
  • + {album.title} -{" "} + {album.artist} +
  • + ))} +
+ )} +
+ ); +} +``` + +11. **Update Data in a Client Component** +You can also update data directly from a Client Component: + +```tsx +// +// src/app/components/UpdateAlbumsClient.tsx (Client Component) +// + +"use client"; + +import { useState, useEffect } from "react"; + +export default function UpdateAlbumsClient() { + const [albums, setAlbums] = useState< + { id: number; title: string; artist: string }[] + >([]); + const [loading, setLoading] = useState(false); + + // Function to fetch albums from the API route + async function fetchAlbums() { + try { + const res = await fetch("/api/albums"); + if (!res.ok) throw new Error("Failed to fetch albums"); + const data = await res.json(); + setAlbums(data); + } catch (error) { + console.error("Error fetching albums:", error); + } + } + + // Function to add a new album and then reload the albums list + async function addAlbum() { + setLoading(true); + + try { + // Generate a random album name + const randomAlbumTitle = `Album ${Math.random() + .toString(36) + .substring(7)}`; + + // Generate a random artist ID between 1 and 100 + const randomArtistId = Math.floor(Math.random() * 100) + 1; + + const res = await fetch("/api/albums", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + title: randomAlbumTitle, + artistId: randomArtistId, + }), + }); + + if (!res.ok) throw new Error("Failed to add album"); + + await fetchAlbums(); // Refresh album list after adding + } catch (error) { + console.error("Error adding album:", error); + } finally { + setLoading(false); + } + } + + // Fetch albums when component mounts + useEffect(() => { + fetchAlbums(); + }, []); + + return ( +
+ + +

Latest Albums

+ {albums.length === 0 ? ( +

No albums found.

+ ) : ( +
    + {albums.map((album) => ( +
  • + {album.title} -{" "} + {album.artist} +
  • + ))} +
+ )} +
+ ); +} + +``` + +12. **Create a Page to Display Components** + +Replace the content of `page.tsx` with: + +```tsx +// +// src/app/page.tsx (Unified Page) +// + +import GetAlbumsClient from "./components/GetAlbumsClient"; +import GetAlbumsServer from "./components/GetAlbumsServer"; +import UpdateAlbumsClient from "./components/UpdateAlbumsClient"; + +export default function page() { + return ( +
+
+

Albums Overview

+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ ); +} +``` + +Replace the content of `layout.tsx` with: + +```tsx +// +// src/app/layout.tsx +// + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + {/* ✅ Add Tailwind CDN */} + + + {children} + + ); +} + +``` + +13. **Run Your App** ```bash npm run dev ``` -6. **View your app** - - Open your browser and navigate to the localhost link provided by the previous command to see your app data. -And that's it! You've successfully built a Next app that reads data from a SQLite Cloud database. \ No newline at end of file +14. **View Your App** + - Open your browser and navigate to the provided localhost link to see your app in action. + + +--- + +Congratulations! You’ve successfully built a Next.js app that interacts with a SQLite Cloud database. \ No newline at end of file From fae66e8f313e809b1069f9719e9f33de4ffdcea8 Mon Sep 17 00:00:00 2001 From: TizianoT Date: Tue, 11 Mar 2025 11:52:16 +0100 Subject: [PATCH 6/6] fixed Set Up the Folder Structure --- sqlite-cloud/quick-start-next.mdx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sqlite-cloud/quick-start-next.mdx b/sqlite-cloud/quick-start-next.mdx index 646aa4a..905e552 100644 --- a/sqlite-cloud/quick-start-next.mdx +++ b/sqlite-cloud/quick-start-next.mdx @@ -36,16 +36,16 @@ NEXT_PUBLIC_SQLITECLOUD_URL=sqlitecloud://abcd1234.global1.qwerty.sqlite.cloud:8 5. **Set Up the Folder Structure** ```bash -mkdir -p sqlc-quickstart/src/app/api/albums \ - sqlc-quickstart/src/app/components \ - sqlc-quickstart/src/constants - -touch sqlc-quickstart/src/app/api/albums/route.ts \ - sqlc-quickstart/src/app/components/GetAlbumsClient.tsx \ - sqlc-quickstart/src/app/components/GetAlbumsServer.tsx \ - sqlc-quickstart/src/app/components/UpdateAlbumsClient.tsx \ - sqlc-quickstart/src/constants/queries.ts \ - sqlc-quickstart/src/types.ts +mkdir -p src/app/api/albums +mkdir -p src/app/components +mkdir -p src/constants + +touch src/app/api/albums/route.ts +touch src/app/components/GetAlbumsClient.tsx +touch src/app/components/GetAlbumsServer.tsx +touch src/app/components/UpdateAlbumsClient.tsx +touch src/constants/queries.ts +touch src/types.ts ``` 6. **Define Data Types**