localgreenchain/lib/db/types.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

150 lines
3.3 KiB
TypeScript

/**
* Database Types and Utilities
* Type helpers for working with Prisma and the database
*/
import type { Prisma } from '@prisma/client';
// Re-export Prisma types for convenience
export type {
User,
Plant,
TransportEvent,
VerticalFarm,
GrowingZone,
CropBatch,
GrowingRecipe,
SeedBatch,
HarvestBatch,
ConsumerPreference,
DemandSignal,
SupplyCommitment,
MarketMatch,
SeasonalPlan,
DemandForecast,
PlantingRecommendation,
ResourceUsage,
FarmAnalytics,
AuditLog,
BlockchainBlock,
} from '@prisma/client';
// Common query options
export interface PaginationOptions {
page?: number;
limit?: number;
cursor?: string;
}
export interface SortOptions {
field: string;
direction: 'asc' | 'desc';
}
// Location-based query options
export interface LocationFilter {
latitude: number;
longitude: number;
radiusKm: number;
}
// Date range filter
export interface DateRangeFilter {
start: Date;
end: Date;
}
// Create input types for common operations
export type CreateUserInput = Prisma.UserCreateInput;
export type UpdateUserInput = Prisma.UserUpdateInput;
export type CreatePlantInput = Prisma.PlantCreateInput;
export type UpdatePlantInput = Prisma.PlantUpdateInput;
export type CreateTransportEventInput = Prisma.TransportEventCreateInput;
export type UpdateTransportEventInput = Prisma.TransportEventUpdateInput;
export type CreateVerticalFarmInput = Prisma.VerticalFarmCreateInput;
export type UpdateVerticalFarmInput = Prisma.VerticalFarmUpdateInput;
export type CreateCropBatchInput = Prisma.CropBatchCreateInput;
export type UpdateCropBatchInput = Prisma.CropBatchUpdateInput;
// Result types with includes
export type PlantWithOwner = Prisma.PlantGetPayload<{
include: { owner: true };
}>;
export type PlantWithLineage = Prisma.PlantGetPayload<{
include: {
owner: true;
parentPlant: true;
childPlants: true;
};
}>;
export type TransportEventWithParties = Prisma.TransportEventGetPayload<{
include: {
sender: true;
receiver: true;
plants: true;
};
}>;
export type VerticalFarmWithZones = Prisma.VerticalFarmGetPayload<{
include: {
owner: true;
zones: true;
cropBatches: true;
};
}>;
// Utility type for pagination results
export interface PaginatedResult<T> {
items: T[];
total: number;
page: number;
limit: number;
totalPages: number;
hasMore: boolean;
}
// Helper function to calculate distance between two points (Haversine formula)
export function calculateDistanceKm(
lat1: number,
lon1: number,
lat2: number,
lon2: number
): number {
const R = 6371; // Earth's radius in km
const dLat = toRad(lat2 - lat1);
const dLon = toRad(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
function toRad(deg: number): number {
return deg * (Math.PI / 180);
}
// Helper to create pagination result
export function createPaginatedResult<T>(
items: T[],
total: number,
page: number,
limit: number
): PaginatedResult<T> {
const totalPages = Math.ceil(total / limit);
return {
items,
total,
page,
limit,
totalPages,
hasMore: page < totalPages,
};
}