Database collection models

This commit is contained in:
Timothy Armes
2024-04-10 15:50:30 +02:00
parent 6a3b58f02d
commit 1da389a24a
12 changed files with 139 additions and 77 deletions
+4 -9
View File
@@ -1,7 +1,7 @@
import { unstable_cache } from "next/cache"; import { unstable_cache } from "next/cache";
import clientPromise from "@/lib/mongodb"; import { collections, dbConnect } from "@/server/mongodb";
import { Club, ClubData } from "@/types"; import { Club } from "@/types";
import { errorLog } from "@/utils/logger"; import { errorLog } from "@/utils/logger";
import ClubsDisplay from "./ClubsDisplay"; import ClubsDisplay from "./ClubsDisplay";
@@ -10,13 +10,8 @@ export const revalidate = 3600; // Revalidate cache every 6 hours
const getClubs = async () => { const getClubs = async () => {
try { try {
const client = await clientPromise; await dbConnect();
const db = client.db("tournamentsFranceDB"); const data = await collections.clubs!.find({}).sort({ name: 1 }).toArray();
const data = await db
.collection("clubs")
.find<ClubData>({})
.sort({ name: 1 })
.toArray();
return data return data
.filter((c) => !!c.coordinates) .filter((c) => !!c.coordinates)
+8 -9
View File
@@ -9,9 +9,9 @@ import { fr } from "date-fns/locale";
import { groupBy } from "lodash"; import { groupBy } from "lodash";
import { unstable_cache } from "next/cache"; import { unstable_cache } from "next/cache";
import clientPromise from "@/lib/mongodb"; import { tournamentModelSchema } from "@/server/models/tournamentModel";
import { TournamentData } from "@/types"; import { collections, dbConnect } from "@/server/mongodb";
import { TimeControl, Tournament, tcMap, tournamentDataSchema } from "@/types"; import { TimeControl, Tournament, tcMap } from "@/types";
import { errorLog } from "@/utils/logger"; import { errorLog } from "@/utils/logger";
import TournamentsDisplay from "./TournamentsDisplay"; import TournamentsDisplay from "./TournamentsDisplay";
@@ -20,11 +20,10 @@ setDefaultOptions({ locale: fr });
const getTournaments = async () => { const getTournaments = async () => {
try { try {
const client = await clientPromise; await dbConnect();
const db = client.db("tournamentsFranceDB");
const data = await db const data = await collections
.collection("tournaments") .tournaments!.aggregate([
.aggregate<TournamentData>([
{ {
$addFields: { $addFields: {
dateParts: { dateParts: {
@@ -52,7 +51,7 @@ const getTournaments = async () => {
.toArray(); .toArray();
const bad = data.filter((t) => { const bad = data.filter((t) => {
const result = tournamentDataSchema.safeParse(t); const result = tournamentModelSchema.safeParse(t);
if (result.success === false) { if (result.success === false) {
console.log(JSON.stringify(result, null, 2)); console.log(JSON.stringify(result, null, 2));
console.log(JSON.stringify(t, null, 2)); console.log(JSON.stringify(t, null, 2));
+1 -1
View File
@@ -1,7 +1,7 @@
import { MongoDBAdapter } from "@auth/mongodb-adapter"; import { MongoDBAdapter } from "@auth/mongodb-adapter";
import NextAuth from "next-auth"; import NextAuth from "next-auth";
import clientPromise from "@/lib/mongodb"; import { clientPromise } from "@/server/mongodb";
import Email from "@/utils/nodemailerProvider"; import Email from "@/utils/nodemailerProvider";
export const { export const {
-34
View File
@@ -1,34 +0,0 @@
import { MongoClient } from "mongodb";
if (!process.env.MONGODB_URI) {
throw new Error('Invalid environment variable: "MONGODB_URI"');
}
const uri = process.env.MONGODB_URI;
const options = {};
let client;
let clientPromise: Promise<MongoClient>;
if (!process.env.MONGODB_URI) {
throw new Error("Please add your Mongo URI to .env.local");
}
if (process.env.NODE_ENV === "development") {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
//@ts-ignore
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options);
//@ts-ignore
global._mongoClientPromise = client.connect();
}
//@ts-ignore
clientPromise = global._mongoClientPromise;
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options);
clientPromise = client.connect();
}
export default clientPromise;
+6 -8
View File
@@ -1,17 +1,16 @@
"use server"; "use server";
import { format } from "date-fns"; import { format } from "date-fns";
import { z } from "zod";
import clientPromise from "@/lib/mongodb";
import { addTournamentSchema } from "@/schemas"; import { addTournamentSchema } from "@/schemas";
import { TournamentData } from "@/types"; import { collections, dbConnect } from "@/server/mongodb";
import { TimeControl } from "@/types"; import { TimeControl } from "@/types";
import { errorLog } from "@/utils/logger"; import { errorLog } from "@/utils/logger";
import { TournamentModel } from "./models/tournamentModel";
import { action } from "./safeAction"; import { action } from "./safeAction";
const tcMap: Record<TimeControl, TournamentData["time_control"]> = { const tcMap: Record<TimeControl, TournamentModel["time_control"]> = {
[TimeControl.Classic]: "Cadence Lente", [TimeControl.Classic]: "Cadence Lente",
[TimeControl.Rapid]: "Rapide", [TimeControl.Rapid]: "Rapide",
[TimeControl.Blitz]: "Blitz", [TimeControl.Blitz]: "Blitz",
@@ -20,12 +19,11 @@ const tcMap: Record<TimeControl, TournamentData["time_control"]> = {
export const addTournament = action(addTournamentSchema, async (input) => { export const addTournament = action(addTournamentSchema, async (input) => {
try { try {
const client = await clientPromise; await dbConnect();
const db = client.db("tournamentsFranceDB").collection("tournaments");
const { name, email, message, tournament } = input; const { name, email, message, tournament } = input;
const tournamentData: Omit<TournamentData, "_id" | "tournament_id"> = { const tournamentData: Omit<TournamentModel, "_id" | "tournament_id"> = {
...tournament, ...tournament,
date: format(tournament.date, "dd/MM/yyyy"), date: format(tournament.date, "dd/MM/yyyy"),
start_date: format(tournament.date, "dd/MM/yyyy"), start_date: format(tournament.date, "dd/MM/yyyy"),
@@ -37,7 +35,7 @@ export const addTournament = action(addTournamentSchema, async (input) => {
status: "scheduled", status: "scheduled",
}; };
const result = await db.insertOne(tournamentData); const result = await collections.tournaments!.insertOne(tournamentData);
if (result.insertedId) { if (result.insertedId) {
const { tournament, country, date, time_control } = tournamentData; const { tournament, country, date, time_control } = tournamentData;
+6 -8
View File
@@ -2,8 +2,7 @@
import { z } from "zod"; import { z } from "zod";
import clientPromise from "@/lib/mongodb"; import { collections, dbConnect } from "@/server/mongodb";
import { TournamentData } from "@/types";
import { TimeControl, tcMap } from "@/types"; import { TimeControl, tcMap } from "@/types";
import { errorLog } from "@/utils/logger"; import { errorLog } from "@/utils/logger";
@@ -15,11 +14,10 @@ const inputSchema = z.object({
export const getTournamentDetails = action(inputSchema, async (input) => { export const getTournamentDetails = action(inputSchema, async (input) => {
try { try {
const client = await clientPromise; await dbConnect();
const db = client.db("tournamentsFranceDB"); const t = await collections.tournaments!.findOne({
const t = await db tournament_id: input.ffeId,
.collection("tournaments") });
.findOne<TournamentData>({ tournament_id: input.ffeId });
if (t === null) { if (t === null) {
return null; return null;
@@ -29,7 +27,7 @@ export const getTournamentDetails = action(inputSchema, async (input) => {
return { return {
id: t._id.toString(), id: t._id.toString(),
ffeId: t.tournament_id, ffeId: t.tournament_id!,
tournament: t.tournament, tournament: t.tournament,
town: t.town, town: t.town,
department: t.department, department: t.department,
+11
View File
@@ -0,0 +1,11 @@
import { ObjectId } from "mongodb";
export type ClubModel = {
_id: ObjectId;
name: string;
url?: string;
address?: string;
email?: string;
website?: string;
coordinates: [number, number];
};
+22
View File
@@ -0,0 +1,22 @@
import { ObjectId } from "mongodb";
import { z } from "zod";
export const tournamentModelSchema = z.object({
tournament_id: z.string().nullish(),
town: z.string(),
department: z.string(),
country: z.string(),
tournament: z.string(),
url: z.string(),
time_control: z.string(),
norm_tournament: z.boolean().optional(),
date: z.string(),
start_date: z.string(),
end_date: z.string(),
coordinates: z.array(z.number()).min(2).max(2),
entry_method: z.enum(["manual", "auto"]),
pending: z.boolean().optional(),
status: z.enum(["scheduled", "ongoing", "finished", "in-play"]),
});
export type TournamentModel = z.infer<typeof tournamentModelSchema>;
+6
View File
@@ -0,0 +1,6 @@
import { ObjectId } from "mongodb";
export type UserModel = {
email: string;
emailVerified?: Date;
};
+41
View File
@@ -0,0 +1,41 @@
import mongoDB, { MongoClient } from "mongodb";
import { TournamentModel } from "@/server/models/tournamentModel";
import { UserModel } from "@/server/models/userModel";
import { ZoneModel } from "@/server/models/zoneModel";
import { ClubModel } from "./models/clubModel";
export const collections: {
tournaments?: mongoDB.Collection<TournamentModel>;
clubs?: mongoDB.Collection<ClubModel>;
users?: mongoDB.Collection<UserModel>;
} = {};
if (!process.env.MONGODB_URI) {
throw new Error('Invalid environment variable: "MONGODB_URI"');
}
const uri = process.env.MONGODB_URI;
const options = {};
let client: mongoDB.MongoClient;
export let clientPromise: Promise<MongoClient>;
if (!process.env.MONGODB_URI) {
throw new Error("Please add your Mongo URI to .env.local");
}
client = new MongoClient(uri, options);
clientPromise = client.connect();
export async function dbConnect() {
await clientPromise;
const userData: mongoDB.Db = client!.db("userData");
collections.users = userData.collection("userData");
const tournamentData: mongoDB.Db = client!.db("tournamentsFranceDB");
collections.tournaments = tournamentData.collection("tournaments");
collections.clubs = tournamentData.collection("clubs");
}
+4 -8
View File
@@ -3,10 +3,8 @@
import { endOfDay } from "date-fns"; import { endOfDay } from "date-fns";
import { z } from "zod"; import { z } from "zod";
import clientPromise from "@/lib/mongodb"; import { collections, dbConnect } from "@/server/mongodb";
import { TournamentData } from "@/types";
import { TimeControl, Tournament, tcMap } from "@/types"; import { TimeControl, Tournament, tcMap } from "@/types";
import { ExtractSafeActionResult } from "@/types";
import { errorLog } from "@/utils/logger"; import { errorLog } from "@/utils/logger";
import { removeDiacritics } from "@/utils/string"; import { removeDiacritics } from "@/utils/string";
@@ -32,8 +30,7 @@ export type SearchedTournament = Pick<
export const searchTournaments = action(inputSchema, async (input) => { export const searchTournaments = action(inputSchema, async (input) => {
try { try {
const client = await clientPromise; await dbConnect();
const db = client.db("tournamentsFranceDB");
const searchTerms = input.searchValue const searchTerms = input.searchValue
.split(" ") .split(" ")
@@ -41,9 +38,8 @@ export const searchTournaments = action(inputSchema, async (input) => {
.filter((s) => s !== "") .filter((s) => s !== "")
.map((s) => ({ tournament_index: { $regex: s, $options: "i" } })); .map((s) => ({ tournament_index: { $regex: s, $options: "i" } }));
const data = await db const data = await collections
.collection("tournaments") .tournaments!.aggregate([
.aggregate<TournamentData>([
{ {
$addFields: { $addFields: {
dateParts: { dateParts: {
+30
View File
@@ -1409,6 +1409,13 @@
resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.3.tgz#a94e1028f180666f97fd51e35c4ad092d7704ef0" resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.3.tgz#a94e1028f180666f97fd51e35c4ad092d7704ef0"
integrity sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g== integrity sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==
"@infra-blocks/zod-utils@^0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@infra-blocks/zod-utils/-/zod-utils-0.4.2.tgz#d2817aade012e26481091fa4b9092764b06fe28e"
integrity sha512-LXvfIA/tsHwfit2CBjkhA0MTr+JfpNMP2z3rTPWN734KeCyuaZPBP6yhTKyPY+X1MoPDbd3RQUVfoM+x8Rodxg==
dependencies:
zod "^3.22.4"
"@isaacs/cliui@^8.0.2": "@isaacs/cliui@^8.0.2":
version "8.0.2" version "8.0.2"
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
@@ -3308,6 +3315,11 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
geojson@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/geojson/-/geojson-0.5.0.tgz#3cd6c96399be65b56ee55596116fe9191ce701c0"
integrity sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==
get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
version "1.2.4" version "1.2.4"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
@@ -4018,6 +4030,11 @@ leaflet-defaulticon-compatibility@^0.1.2:
resolved "https://registry.yarnpkg.com/leaflet-defaulticon-compatibility/-/leaflet-defaulticon-compatibility-0.1.2.tgz#f5e1a5841aeab9d1682d17887348855a741b3c2a" resolved "https://registry.yarnpkg.com/leaflet-defaulticon-compatibility/-/leaflet-defaulticon-compatibility-0.1.2.tgz#f5e1a5841aeab9d1682d17887348855a741b3c2a"
integrity sha512-IrKagWxkTwzxUkFIumy/Zmo3ksjuAu3zEadtOuJcKzuXaD76Gwvg2Z1mLyx7y52ykOzM8rAH5ChBs4DnfdGa6Q== integrity sha512-IrKagWxkTwzxUkFIumy/Zmo3ksjuAu3zEadtOuJcKzuXaD76Gwvg2Z1mLyx7y52ykOzM8rAH5ChBs4DnfdGa6Q==
leaflet-draw@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/leaflet-draw/-/leaflet-draw-1.0.4.tgz#45be92f378ed253e7202fdeda1fcc71885198d46"
integrity sha512-rsQ6saQO5ST5Aj6XRFylr5zvarWgzWnrg46zQ1MEOEIHsppdC/8hnN8qMoFvACsPvTioAuysya/TVtog15tyAQ==
leaflet-gesture-handling@^1.2.2: leaflet-gesture-handling@^1.2.2:
version "1.2.2" version "1.2.2"
resolved "https://registry.yarnpkg.com/leaflet-gesture-handling/-/leaflet-gesture-handling-1.2.2.tgz#ea10afb94f2d477d77d47beb21e409ed327df07a" resolved "https://registry.yarnpkg.com/leaflet-gesture-handling/-/leaflet-gesture-handling-1.2.2.tgz#ea10afb94f2d477d77d47beb21e409ed327df07a"
@@ -4089,6 +4106,11 @@ locate-path@^6.0.0:
dependencies: dependencies:
p-locate "^5.0.0" p-locate "^5.0.0"
lodash-es@^4.17.15:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash.debounce@^4.0.8: lodash.debounce@^4.0.8:
version "4.0.8" version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
@@ -4834,6 +4856,14 @@ react-leaflet-cluster@^2.1.0:
dependencies: dependencies:
leaflet.markercluster "^1.5.3" leaflet.markercluster "^1.5.3"
react-leaflet-draw@^0.20.4:
version "0.20.4"
resolved "https://registry.yarnpkg.com/react-leaflet-draw/-/react-leaflet-draw-0.20.4.tgz#e3f68dc783cbe00d24ff3f2e02d5208c49f7c971"
integrity sha512-u5JHdow2Z9G2AveyUEOTWHXhdhzXdEVQifkNfSaVbEn0gvD+2xW03TQN444zVqovDBvIrBcVWo1VajL4zgl6yg==
dependencies:
fast-deep-equal "^3.1.3"
lodash-es "^4.17.15"
react-leaflet@^4.2.1: react-leaflet@^4.2.1:
version "4.2.1" version "4.2.1"
resolved "https://registry.yarnpkg.com/react-leaflet/-/react-leaflet-4.2.1.tgz#c300e9eccaf15cb40757552e181200aa10b94780" resolved "https://registry.yarnpkg.com/react-leaflet/-/react-leaflet-4.2.1.tgz#c300e9eccaf15cb40757552e181200aa10b94780"