Move from @vercel/postgres to postgres (provider-agnostic) (#989)

* Postgres

* fix

* fix

* prettier-fix

---------

Co-authored-by: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com>
This commit is contained in:
Lee Robinson
2025-01-29 11:39:32 -06:00
committed by GitHub
parent fc3a4e3faa
commit 46d15fa2e5
14 changed files with 3185 additions and 5265 deletions

View File

@@ -1,12 +1,14 @@
'use server';
import { z } from 'zod';
import { sql } from '@vercel/postgres';
import postgres from 'postgres';
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
import { signIn } from '@/auth';
import { AuthError } from 'next-auth';
const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' });
const FormSchema = z.object({
id: z.string(),
customerId: z.string({

View File

@@ -1,4 +1,4 @@
import { sql } from '@vercel/postgres';
import postgres from 'postgres';
import {
CustomerField,
CustomersTableType,
@@ -9,6 +9,8 @@ import {
} from './definitions';
import { formatCurrency } from './utils';
const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' });
export async function fetchRevenue() {
try {
// Artificially delay a response for demo purposes.
@@ -17,11 +19,11 @@ export async function fetchRevenue() {
// console.log('Fetching revenue data...');
// await new Promise((resolve) => setTimeout(resolve, 3000));
const data = await sql<Revenue>`SELECT * FROM revenue`;
const data = await sql<Revenue[]>`SELECT * FROM revenue`;
// console.log('Data fetch completed after 3 seconds.');
return data.rows;
return data;
} catch (error) {
console.error('Database Error:', error);
throw new Error('Failed to fetch revenue data.');
@@ -30,14 +32,14 @@ export async function fetchRevenue() {
export async function fetchLatestInvoices() {
try {
const data = await sql<LatestInvoiceRaw>`
const data = await sql<LatestInvoiceRaw[]>`
SELECT invoices.amount, customers.name, customers.image_url, customers.email, invoices.id
FROM invoices
JOIN customers ON invoices.customer_id = customers.id
ORDER BY invoices.date DESC
LIMIT 5`;
const latestInvoices = data.rows.map((invoice) => ({
const latestInvoices = data.map((invoice) => ({
...invoice,
amount: formatCurrency(invoice.amount),
}));
@@ -66,10 +68,10 @@ export async function fetchCardData() {
invoiceStatusPromise,
]);
const numberOfInvoices = Number(data[0].rows[0].count ?? '0');
const numberOfCustomers = Number(data[1].rows[0].count ?? '0');
const totalPaidInvoices = formatCurrency(data[2].rows[0].paid ?? '0');
const totalPendingInvoices = formatCurrency(data[2].rows[0].pending ?? '0');
const numberOfInvoices = Number(data[0].count ?? '0');
const numberOfCustomers = Number(data[1].count ?? '0');
const totalPaidInvoices = formatCurrency(data[2][0].paid ?? '0');
const totalPendingInvoices = formatCurrency(data[2][0].pending ?? '0');
return {
numberOfCustomers,
@@ -91,7 +93,7 @@ export async function fetchFilteredInvoices(
const offset = (currentPage - 1) * ITEMS_PER_PAGE;
try {
const invoices = await sql<InvoicesTable>`
const invoices = await sql<InvoicesTable[]>`
SELECT
invoices.id,
invoices.amount,
@@ -112,7 +114,7 @@ export async function fetchFilteredInvoices(
LIMIT ${ITEMS_PER_PAGE} OFFSET ${offset}
`;
return invoices.rows;
return invoices;
} catch (error) {
console.error('Database Error:', error);
throw new Error('Failed to fetch invoices.');
@@ -121,7 +123,7 @@ export async function fetchFilteredInvoices(
export async function fetchInvoicesPages(query: string) {
try {
const count = await sql`SELECT COUNT(*)
const data = await sql`SELECT COUNT(*)
FROM invoices
JOIN customers ON invoices.customer_id = customers.id
WHERE
@@ -132,7 +134,7 @@ export async function fetchInvoicesPages(query: string) {
invoices.status ILIKE ${`%${query}%`}
`;
const totalPages = Math.ceil(Number(count.rows[0].count) / ITEMS_PER_PAGE);
const totalPages = Math.ceil(Number(data[0].count) / ITEMS_PER_PAGE);
return totalPages;
} catch (error) {
console.error('Database Error:', error);
@@ -142,7 +144,7 @@ export async function fetchInvoicesPages(query: string) {
export async function fetchInvoiceById(id: string) {
try {
const data = await sql<InvoiceForm>`
const data = await sql<InvoiceForm[]>`
SELECT
invoices.id,
invoices.customer_id,
@@ -152,7 +154,7 @@ export async function fetchInvoiceById(id: string) {
WHERE invoices.id = ${id};
`;
const invoice = data.rows.map((invoice) => ({
const invoice = data.map((invoice) => ({
...invoice,
// Convert amount from cents to dollars
amount: invoice.amount / 100,
@@ -167,7 +169,7 @@ export async function fetchInvoiceById(id: string) {
export async function fetchCustomers() {
try {
const data = await sql<CustomerField>`
const customers = await sql<CustomerField[]>`
SELECT
id,
name
@@ -175,7 +177,6 @@ export async function fetchCustomers() {
ORDER BY name ASC
`;
const customers = data.rows;
return customers;
} catch (err) {
console.error('Database Error:', err);
@@ -185,7 +186,7 @@ export async function fetchCustomers() {
export async function fetchFilteredCustomers(query: string) {
try {
const data = await sql<CustomersTableType>`
const data = await sql<CustomersTableType[]>`
SELECT
customers.id,
customers.name,
@@ -203,7 +204,7 @@ export async function fetchFilteredCustomers(query: string) {
ORDER BY customers.name ASC
`;
const customers = data.rows.map((customer) => ({
const customers = data.map((customer) => ({
...customer,
total_pending: formatCurrency(customer.total_pending),
total_paid: formatCurrency(customer.total_paid),

View File

@@ -1,122 +1,117 @@
// import bcrypt from 'bcrypt';
// import { db } from '@vercel/postgres';
// import { invoices, customers, revenue, users } from '../lib/placeholder-data';
import bcrypt from 'bcrypt';
import postgres from 'postgres';
import { invoices, customers, revenue, users } from '../lib/placeholder-data';
// const client = await db.connect();
const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' });
// async function seedUsers() {
// await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
// await client.sql`
// CREATE TABLE IF NOT EXISTS users (
// id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
// name VARCHAR(255) NOT NULL,
// email TEXT NOT NULL UNIQUE,
// password TEXT NOT NULL
// );
// `;
async function seedUsers() {
await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
await sql`
CREATE TABLE IF NOT EXISTS users (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email TEXT NOT NULL UNIQUE,
password TEXT NOT NULL
);
`;
// const insertedUsers = await Promise.all(
// users.map(async (user) => {
// const hashedPassword = await bcrypt.hash(user.password, 10);
// return client.sql`
// INSERT INTO users (id, name, email, password)
// VALUES (${user.id}, ${user.name}, ${user.email}, ${hashedPassword})
// ON CONFLICT (id) DO NOTHING;
// `;
// }),
// );
const insertedUsers = await Promise.all(
users.map(async (user) => {
const hashedPassword = await bcrypt.hash(user.password, 10);
return sql`
INSERT INTO users (id, name, email, password)
VALUES (${user.id}, ${user.name}, ${user.email}, ${hashedPassword})
ON CONFLICT (id) DO NOTHING;
`;
}),
);
// return insertedUsers;
// }
return insertedUsers;
}
// async function seedInvoices() {
// await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
async function seedInvoices() {
await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
// await client.sql`
// CREATE TABLE IF NOT EXISTS invoices (
// id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
// customer_id UUID NOT NULL,
// amount INT NOT NULL,
// status VARCHAR(255) NOT NULL,
// date DATE NOT NULL
// );
// `;
await sql`
CREATE TABLE IF NOT EXISTS invoices (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
customer_id UUID NOT NULL,
amount INT NOT NULL,
status VARCHAR(255) NOT NULL,
date DATE NOT NULL
);
`;
// const insertedInvoices = await Promise.all(
// invoices.map(
// (invoice) => client.sql`
// INSERT INTO invoices (customer_id, amount, status, date)
// VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
// ON CONFLICT (id) DO NOTHING;
// `,
// ),
// );
const insertedInvoices = await Promise.all(
invoices.map(
(invoice) => sql`
INSERT INTO invoices (customer_id, amount, status, date)
VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
ON CONFLICT (id) DO NOTHING;
`,
),
);
// return insertedInvoices;
// }
return insertedInvoices;
}
// async function seedCustomers() {
// await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
async function seedCustomers() {
await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
// await client.sql`
// CREATE TABLE IF NOT EXISTS customers (
// id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
// name VARCHAR(255) NOT NULL,
// email VARCHAR(255) NOT NULL,
// image_url VARCHAR(255) NOT NULL
// );
// `;
await sql`
CREATE TABLE IF NOT EXISTS customers (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
image_url VARCHAR(255) NOT NULL
);
`;
// const insertedCustomers = await Promise.all(
// customers.map(
// (customer) => client.sql`
// INSERT INTO customers (id, name, email, image_url)
// VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url})
// ON CONFLICT (id) DO NOTHING;
// `,
// ),
// );
const insertedCustomers = await Promise.all(
customers.map(
(customer) => sql`
INSERT INTO customers (id, name, email, image_url)
VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url})
ON CONFLICT (id) DO NOTHING;
`,
),
);
// return insertedCustomers;
// }
return insertedCustomers;
}
// async function seedRevenue() {
// await client.sql`
// CREATE TABLE IF NOT EXISTS revenue (
// month VARCHAR(4) NOT NULL UNIQUE,
// revenue INT NOT NULL
// );
// `;
async function seedRevenue() {
await sql`
CREATE TABLE IF NOT EXISTS revenue (
month VARCHAR(4) NOT NULL UNIQUE,
revenue INT NOT NULL
);
`;
// const insertedRevenue = await Promise.all(
// revenue.map(
// (rev) => client.sql`
// INSERT INTO revenue (month, revenue)
// VALUES (${rev.month}, ${rev.revenue})
// ON CONFLICT (month) DO NOTHING;
// `,
// ),
// );
const insertedRevenue = await Promise.all(
revenue.map(
(rev) => sql`
INSERT INTO revenue (month, revenue)
VALUES (${rev.month}, ${rev.revenue})
ON CONFLICT (month) DO NOTHING;
`,
),
);
// return insertedRevenue;
// }
return insertedRevenue;
}
export async function GET() {
return Response.json({
message:
'Uncomment this file and remove this line. You can delete this file when you are finished.',
});
// try {
// await client.sql`BEGIN`;
// await seedUsers();
// await seedCustomers();
// await seedInvoices();
// await seedRevenue();
// await client.sql`COMMIT`;
try {
const result = await sql.begin((sql) => [
seedUsers(),
seedCustomers(),
seedInvoices(),
seedRevenue(),
]);
// return Response.json({ message: 'Database seeded successfully' });
// } catch (error) {
// await client.sql`ROLLBACK`;
// return Response.json({ error }, { status: 500 });
// }
return Response.json({ message: 'Database seeded successfully' });
} catch (error) {
return Response.json({ error }, { status: 500 });
}
}