Added pings

This commit is contained in:
Fergal Moran
2024-01-28 18:36:12 +00:00
parent 4ff6990ac0
commit 55e22d8dbf
8 changed files with 600 additions and 1 deletions

View File

@@ -7,6 +7,7 @@ import {
children,
} from "@/server/db/schema/children";
import { devices } from "@/server/db/schema/devices";
import { pings } from "@/server/db/schema/pings";
export const getChildren = async () => {
const { session } = await getUserAuth();
@@ -14,6 +15,8 @@ export const getChildren = async () => {
.select()
.from(children)
.where(eq(children.userId, session?.user.id!))
.innerJoin(devices, eq(devices.childId, children.id))
.innerJoin(pings, eq(pings.deviceId, devices.id))
.orderBy(children.name);
return { children: c.map((c) => ({ ...c, devices: [] })) };
};

View File

@@ -0,0 +1,58 @@
import { db } from "@/server/db/index";
import { and, eq } from "drizzle-orm";
import {
PingId,
NewPingParams,
UpdatePingParams,
updatePingSchema,
insertPingSchema,
pings,
pingIdSchema
} from "@/server/db/schema/pings";
import { getUserAuth } from "@/lib/auth/utils";
export const createPing = async (ping: NewPingParams) => {
const { session } = await getUserAuth();
const newPing = insertPingSchema.parse({ ...ping, userId: session?.user.id! });
try {
const [p] = await db.insert(pings).values(newPing).returning();
return { ping: p };
} catch (err) {
const message = (err as Error).message ?? "Error, please try again";
console.error(message);
throw { error: message };
}
};
export const updatePing = async (id: PingId, ping: UpdatePingParams) => {
const { session } = await getUserAuth();
const { id: pingId } = pingIdSchema.parse({ id });
const newPing = updatePingSchema.parse({ ...ping, userId: session?.user.id! });
try {
const [p] = await db
.update(pings)
.set(newPing)
.where(and(eq(pings.id, pingId!), eq(pings.userId, session?.user.id!)))
.returning();
return { ping: p };
} catch (err) {
const message = (err as Error).message ?? "Error, please try again";
console.error(message);
throw { error: message };
}
};
export const deletePing = async (id: PingId) => {
const { session } = await getUserAuth();
const { id: pingId } = pingIdSchema.parse({ id });
try {
const [p] = await db.delete(pings).where(and(eq(pings.id, pingId!), eq(pings.userId, session?.user.id!)))
.returning();
return { ping: p };
} catch (err) {
const message = (err as Error).message ?? "Error, please try again";
console.error(message);
throw { error: message };
}
};

View File

@@ -0,0 +1,19 @@
import { db } from "@/server/db/index";
import { eq, and } from "drizzle-orm";
import { getUserAuth } from "@/lib/auth/utils";
import { type PingId, pingIdSchema, pings } from "@/server/db/schema/pings";
import { devices } from "@/server/db/schema/devices";
export const getPings = async () => {
const { session } = await getUserAuth();
const p = await db.select({ ping: pings, device: devices }).from(pings).leftJoin(devices, eq(pings.deviceId, devices.id)).where(eq(pings.userId, session?.user.id!));
return { pings: p };
};
export const getPingById = async (id: PingId) => {
const { session } = await getUserAuth();
const { id: pingId } = pingIdSchema.parse({ id });
const [p] = await db.select().from(pings).where(and(eq(pings.id, pingId), eq(pings.userId, session?.user.id!))).leftJoin(devices, eq(pings.deviceId, devices.id));
return { ping: p };
};

View File

@@ -0,0 +1,20 @@
CREATE TABLE IF NOT EXISTS "pings" (
"id" varchar(191) PRIMARY KEY NOT NULL,
"latitude" real NOT NULL,
"longitude" real NOT NULL,
"timestamp" timestamp NOT NULL,
"device_id" varchar(256) NOT NULL,
"user_id" varchar(256) NOT NULL
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "pings" ADD CONSTRAINT "pings_device_id_devices_id_fk" FOREIGN KEY ("device_id") REFERENCES "devices"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "pings" ADD CONSTRAINT "pings_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -0,0 +1,425 @@
{
"id": "34d0a88b-b9f0-4d72-a427-5f9a72104706",
"prevId": "3520a784-4841-418f-8cf4-7e58249c843f",
"version": "5",
"dialect": "pg",
"tables": {
"account": {
"name": "account",
"schema": "",
"columns": {
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"provider": {
"name": "provider",
"type": "text",
"primaryKey": false,
"notNull": true
},
"providerAccountId": {
"name": "providerAccountId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"refresh_token": {
"name": "refresh_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"access_token": {
"name": "access_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"token_type": {
"name": "token_type",
"type": "text",
"primaryKey": false,
"notNull": false
},
"scope": {
"name": "scope",
"type": "text",
"primaryKey": false,
"notNull": false
},
"id_token": {
"name": "id_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"session_state": {
"name": "session_state",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"account_userId_user_id_fk": {
"name": "account_userId_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"account_provider_providerAccountId_pk": {
"name": "account_provider_providerAccountId_pk",
"columns": [
"provider",
"providerAccountId"
]
}
},
"uniqueConstraints": {}
},
"children": {
"name": "children",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(191)",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
},
"avatar": {
"name": "avatar",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"children_user_id_user_id_fk": {
"name": "children_user_id_user_id_fk",
"tableFrom": "children",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"devices": {
"name": "devices",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(191)",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
},
"device_id": {
"name": "device_id",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
},
"child_id": {
"name": "child_id",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"devices_child_id_children_id_fk": {
"name": "devices_child_id_children_id_fk",
"tableFrom": "devices",
"tableTo": "children",
"columnsFrom": [
"child_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"devices_user_id_user_id_fk": {
"name": "devices_user_id_user_id_fk",
"tableFrom": "devices",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"pings": {
"name": "pings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(191)",
"primaryKey": true,
"notNull": true
},
"latitude": {
"name": "latitude",
"type": "real",
"primaryKey": false,
"notNull": true
},
"longitude": {
"name": "longitude",
"type": "real",
"primaryKey": false,
"notNull": true
},
"timestamp": {
"name": "timestamp",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"device_id": {
"name": "device_id",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "varchar(256)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"pings_device_id_devices_id_fk": {
"name": "pings_device_id_devices_id_fk",
"tableFrom": "pings",
"tableTo": "devices",
"columnsFrom": [
"device_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"pings_user_id_user_id_fk": {
"name": "pings_user_id_user_id_fk",
"tableFrom": "pings",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"session": {
"name": "session",
"schema": "",
"columns": {
"sessionToken": {
"name": "sessionToken",
"type": "text",
"primaryKey": true,
"notNull": true
},
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"expires": {
"name": "expires",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"session_userId_user_id_fk": {
"name": "session_userId_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user": {
"name": "user",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"emailVerified": {
"name": "emailVerified",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"verificationToken": {
"name": "verificationToken",
"schema": "",
"columns": {
"identifier": {
"name": "identifier",
"type": "text",
"primaryKey": false,
"notNull": true
},
"token": {
"name": "token",
"type": "text",
"primaryKey": false,
"notNull": true
},
"expires": {
"name": "expires",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"verificationToken_identifier_token_pk": {
"name": "verificationToken_identifier_token_pk",
"columns": [
"identifier",
"token"
]
}
},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -15,6 +15,13 @@
"when": 1705877897654,
"tag": "0001_sticky_frightful_four",
"breakpoints": true
},
{
"idx": 2,
"version": "5",
"when": 1706464847221,
"tag": "0002_abandoned_luckman",
"breakpoints": true
}
]
}

View File

@@ -1,5 +1,6 @@
import { users, accounts, sessions, verificationTokens } from "./auth"
import { children } from "./children";
import { devices } from "./devices";
import { pings } from "./pings";
export { devices, children, users, accounts, sessions, verificationTokens }
export { pings, devices, children, users, accounts, sessions, verificationTokens }

View File

@@ -0,0 +1,66 @@
import {
real,
timestamp,
varchar,
pgTable,
} from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";
import { devices } from "./devices";
import { users } from "@/server/db/schema/auth";
import { type getPings } from "@/lib/api/pings/queries";
import { randomUUID } from "crypto";
export const pings = pgTable("pings", {
id: varchar("id", { length: 191 })
.primaryKey()
.$defaultFn(() => randomUUID()),
latitude: real("latitude").notNull(),
longitude: real("longitude").notNull(),
timestamp: timestamp("timestamp").notNull(),
deviceId: varchar("device_id", { length: 256 })
.references(() => devices.id, { onDelete: "cascade" })
.notNull(),
userId: varchar("user_id", { length: 256 })
.references(() => users.id, { onDelete: "cascade" })
.notNull(),
});
// Schema for pings - used to validate API requests
export const insertPingSchema = createInsertSchema(pings);
export const insertPingParams = createSelectSchema(pings, {
latitude: z.coerce.number(),
longitude: z.coerce.number(),
timestamp: z.coerce.string().min(1),
deviceId: z.coerce.string().min(1),
}).omit({
id: true,
userId: true,
});
export const updatePingSchema = createSelectSchema(pings);
export const updatePingParams = createSelectSchema(pings, {
latitude: z.coerce.number(),
longitude: z.coerce.number(),
timestamp: z.coerce.string().min(1),
deviceId: z.coerce.string().min(1),
}).omit({
userId: true,
});
export const pingIdSchema = updatePingSchema.pick({ id: true });
// Types for pings - used to type API request params and within Components
export type Ping = z.infer<typeof updatePingSchema>;
export type NewPing = z.infer<typeof insertPingSchema>;
export type NewPingParams = z.infer<typeof insertPingParams>;
export type UpdatePingParams = z.infer<typeof updatePingParams>;
export type PingId = z.infer<typeof pingIdSchema>["id"];
// this type infers the return from getPings() - meaning it will include any joins
export type CompletePing = Awaited<
ReturnType<typeof getPings>
>["pings"][number];