···
1
-
import type { z } from "zod";
1
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
···
import { ObjectId } from "mongodb";
import { getDb } from "./client.ts";
15
-
import type { InsertType } from "./schema.ts";
17
-
export class Model<T extends z.ZodObject> {
18
-
private collection: Collection<z.infer<T>>;
16
+
export class Model<T extends StandardSchemaV1<unknown, Document>> {
17
+
private collection: Collection<StandardSchemaV1.InferOutput<T>>;
constructor(collectionName: string, schema: T) {
22
-
this.collection = getDb().collection<z.infer<T>>(collectionName);
21
+
this.collection = getDb().collection<
22
+
StandardSchemaV1.InferOutput<T> & Document
26
-
async insertOne(data: InsertType<T>): Promise<InsertOneResult<z.infer<T>>> {
27
-
const validatedData = this.schema.parse(data);
30
+
data: StandardSchemaV1.InferInput<T>,
31
+
): Promise<InsertOneResult<StandardSchemaV1.InferOutput<T>>> {
32
+
const result = this.schema["~standard"].validate(data);
33
+
if (result instanceof Promise) {
34
+
throw new Error("Async validation not supported");
36
+
if (result.issues) {
37
+
throw new Error(`Validation failed: ${JSON.stringify(result.issues)}`);
return await this.collection.insertOne(
29
-
validatedData as OptionalUnlessRequiredId<z.infer<T>>,
40
+
result.value as OptionalUnlessRequiredId<StandardSchemaV1.InferOutput<T>>,
34
-
data: InsertType<T>[],
35
-
): Promise<InsertManyResult<z.infer<T>>> {
36
-
const validatedData = data.map((item) => this.schema.parse(item));
45
+
data: StandardSchemaV1.InferInput<T>[],
46
+
): Promise<InsertManyResult<StandardSchemaV1.InferOutput<T>>> {
47
+
const validatedData = data.map((item) => {
48
+
const result = this.schema["~standard"].validate(item);
49
+
if (result instanceof Promise) {
50
+
throw new Error("Async validation not supported");
52
+
if (result.issues) {
53
+
throw new Error(`Validation failed: ${JSON.stringify(result.issues)}`);
55
+
return result.value;
return await this.collection.insertMany(
38
-
validatedData as OptionalUnlessRequiredId<z.infer<T>>[],
58
+
validatedData as OptionalUnlessRequiredId<
59
+
StandardSchemaV1.InferOutput<T>
42
-
async find(query: Filter<z.infer<T>>): Promise<(WithId<z.infer<T>>)[]> {
65
+
query: Filter<StandardSchemaV1.InferOutput<T>>,
66
+
): Promise<(WithId<StandardSchemaV1.InferOutput<T>>)[]> {
return await this.collection.find(query).toArray();
46
-
async findOne(query: Filter<z.infer<T>>): Promise<WithId<z.infer<T>> | null> {
71
+
query: Filter<StandardSchemaV1.InferOutput<T>>,
72
+
): Promise<WithId<StandardSchemaV1.InferOutput<T>> | null> {
return await this.collection.findOne(query);
50
-
async findById(id: string | ObjectId): Promise<WithId<z.infer<T>> | null> {
77
+
id: string | ObjectId,
78
+
): Promise<WithId<StandardSchemaV1.InferOutput<T>> | null> {
const objectId = typeof id === "string" ? new ObjectId(id) : id;
52
-
return await this.findOne({ _id: objectId } as Filter<z.infer<T>>);
80
+
return await this.findOne(
81
+
{ _id: objectId } as Filter<StandardSchemaV1.InferOutput<T>>,
56
-
query: Filter<z.infer<T>>,
57
-
data: Partial<z.infer<T>>,
86
+
query: Filter<StandardSchemaV1.InferOutput<T>>,
87
+
data: Partial<StandardSchemaV1.InferOutput<T>>,
): Promise<UpdateResult> {
return await this.collection.updateMany(query, { $set: data });
63
-
query: Filter<z.infer<T>>,
64
-
data: Partial<z.infer<T>>,
93
+
query: Filter<StandardSchemaV1.InferOutput<T>>,
94
+
data: Partial<StandardSchemaV1.InferOutput<T>>,
): Promise<UpdateResult> {
return await this.collection.updateOne(query, { $set: data });
70
-
query: Filter<z.infer<T>>,
71
-
data: InsertType<T>,
100
+
query: Filter<StandardSchemaV1.InferOutput<T>>,
101
+
data: StandardSchemaV1.InferInput<T>,
): Promise<UpdateResult> {
73
-
const validatedData = this.schema.parse(data);
103
+
const result = this.schema["~standard"].validate(data);
104
+
if (result instanceof Promise) {
105
+
throw new Error("Async validation not supported");
107
+
if (result.issues) {
108
+
throw new Error(`Validation failed: ${JSON.stringify(result.issues)}`);
return await this.collection.replaceOne(
76
-
validatedData as OptionalUnlessRequiredId<z.infer<T>>,
112
+
result.value as OptionalUnlessRequiredId<StandardSchemaV1.InferOutput<T>>,
80
-
async delete(query: Filter<z.infer<T>>): Promise<DeleteResult> {
117
+
query: Filter<StandardSchemaV1.InferOutput<T>>,
118
+
): Promise<DeleteResult> {
return await this.collection.deleteMany(query);
84
-
async deleteOne(query: Filter<z.infer<T>>): Promise<DeleteResult> {
123
+
query: Filter<StandardSchemaV1.InferOutput<T>>,
124
+
): Promise<DeleteResult> {
return await this.collection.deleteOne(query);
88
-
async count(query: Filter<z.infer<T>>): Promise<number> {
128
+
async count(query: Filter<StandardSchemaV1.InferOutput<T>>): Promise<number> {
return await this.collection.countDocuments(query);
···
// Pagination support for find
98
-
query: Filter<z.infer<T>>,
138
+
query: Filter<StandardSchemaV1.InferOutput<T>>,
options: { skip?: number; limit?: number; sort?: Document } = {},
100
-
): Promise<(WithId<z.infer<T>>)[]> {
140
+
): Promise<(WithId<StandardSchemaV1.InferOutput<T>>)[]> {
return await this.collection