localgreenchain/lib/db/users.ts
Claude 3d2ccdc29a
feat(db): implement PostgreSQL database integration with Prisma ORM
Agent 2 - Database Integration (P0 Critical):

- Add Prisma ORM with PostgreSQL for persistent data storage
- Create comprehensive database schema with 20+ models:
  - User & authentication models
  - Plant & lineage tracking
  - Transport events & supply chain
  - Vertical farming (farms, zones, batches, recipes)
  - Demand & market matching
  - Audit logging & blockchain storage

- Implement complete database service layer (lib/db/):
  - users.ts: User CRUD with search and stats
  - plants.ts: Plant operations with lineage tracking
  - transport.ts: Transport events and carbon tracking
  - farms.ts: Vertical farm and crop batch management
  - demand.ts: Consumer preferences and market matching
  - audit.ts: Audit logging and blockchain integrity

- Add PlantChainDB for database-backed blockchain
- Create development seed script with sample data
- Add database documentation (docs/DATABASE.md)
- Update package.json with Prisma dependencies and scripts

This provides the foundation for all other agents to build upon
with persistent, scalable data storage.
2025-11-23 03:56:40 +00:00

199 lines
4.6 KiB
TypeScript

/**
* User Database Service
* CRUD operations for users
*/
import prisma from './prisma';
import type { User, UserType, Prisma } from '@prisma/client';
import type { PaginationOptions, PaginatedResult } from './types';
import { createPaginatedResult } from './types';
// Create a new user
export async function createUser(data: {
email: string;
name: string;
walletAddress?: string;
passwordHash?: string;
avatarUrl?: string;
bio?: string;
latitude?: number;
longitude?: number;
address?: string;
city?: string;
country?: string;
userType?: UserType;
}): Promise<User> {
return prisma.user.create({
data: {
...data,
userType: data.userType || 'CONSUMER',
},
});
}
// Get user by ID
export async function getUserById(id: string): Promise<User | null> {
return prisma.user.findUnique({
where: { id },
});
}
// Get user by email
export async function getUserByEmail(email: string): Promise<User | null> {
return prisma.user.findUnique({
where: { email },
});
}
// Get user by wallet address
export async function getUserByWalletAddress(walletAddress: string): Promise<User | null> {
return prisma.user.findUnique({
where: { walletAddress },
});
}
// Update user
export async function updateUser(
id: string,
data: Prisma.UserUpdateInput
): Promise<User> {
return prisma.user.update({
where: { id },
data,
});
}
// Delete user
export async function deleteUser(id: string): Promise<User> {
return prisma.user.delete({
where: { id },
});
}
// Get all users with pagination
export async function getUsers(
options: PaginationOptions = {},
filters?: {
userType?: UserType;
city?: string;
country?: string;
}
): Promise<PaginatedResult<User>> {
const page = options.page || 1;
const limit = options.limit || 20;
const skip = (page - 1) * limit;
const where: Prisma.UserWhereInput = {};
if (filters?.userType) where.userType = filters.userType;
if (filters?.city) where.city = { contains: filters.city, mode: 'insensitive' };
if (filters?.country) where.country = { contains: filters.country, mode: 'insensitive' };
const [users, total] = await Promise.all([
prisma.user.findMany({
where,
skip,
take: limit,
orderBy: { createdAt: 'desc' },
}),
prisma.user.count({ where }),
]);
return createPaginatedResult(users, total, page, limit);
}
// Get users by type
export async function getUsersByType(userType: UserType): Promise<User[]> {
return prisma.user.findMany({
where: { userType },
orderBy: { name: 'asc' },
});
}
// Update last login
export async function updateLastLogin(id: string): Promise<User> {
return prisma.user.update({
where: { id },
data: { lastLoginAt: new Date() },
});
}
// Search users
export async function searchUsers(
query: string,
options: PaginationOptions = {}
): Promise<PaginatedResult<User>> {
const page = options.page || 1;
const limit = options.limit || 20;
const skip = (page - 1) * limit;
const where: Prisma.UserWhereInput = {
OR: [
{ name: { contains: query, mode: 'insensitive' } },
{ email: { contains: query, mode: 'insensitive' } },
{ city: { contains: query, mode: 'insensitive' } },
],
};
const [users, total] = await Promise.all([
prisma.user.findMany({
where,
skip,
take: limit,
orderBy: { name: 'asc' },
}),
prisma.user.count({ where }),
]);
return createPaginatedResult(users, total, page, limit);
}
// Get user with their plants
export async function getUserWithPlants(id: string) {
return prisma.user.findUnique({
where: { id },
include: {
ownedPlants: {
orderBy: { registeredAt: 'desc' },
},
},
});
}
// Get user with their farms
export async function getUserWithFarms(id: string) {
return prisma.user.findUnique({
where: { id },
include: {
verticalFarms: {
include: {
zones: true,
},
},
},
});
}
// Get user statistics
export async function getUserStats(id: string) {
const [
plantCount,
farmCount,
transportEventsSent,
transportEventsReceived,
supplyCommitments,
] = await Promise.all([
prisma.plant.count({ where: { ownerId: id } }),
prisma.verticalFarm.count({ where: { ownerId: id } }),
prisma.transportEvent.count({ where: { senderId: id } }),
prisma.transportEvent.count({ where: { receiverId: id } }),
prisma.supplyCommitment.count({ where: { growerId: id } }),
]);
return {
plantCount,
farmCount,
transportEventsSent,
transportEventsReceived,
supplyCommitments,
};
}