mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
add mongoose orm to the stack builder (#191)
This commit is contained in:
committed by
GitHub
parent
946f3eb421
commit
437cf9a45a
5
.changeset/floppy-fans-cross.md
Normal file
5
.changeset/floppy-fans-cross.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"create-better-t-stack": minor
|
||||
---
|
||||
|
||||
add mongoose orm support to the stack builder
|
||||
@@ -40,6 +40,8 @@ export const dependencyVersionMap = {
|
||||
"@prisma/client": "^6.7.0",
|
||||
prisma: "^6.7.0",
|
||||
|
||||
mongoose: "^8.14.0",
|
||||
|
||||
"vite-plugin-pwa": "^0.21.2",
|
||||
"@vite-pwa/assets-generator": "^0.2.6",
|
||||
|
||||
|
||||
@@ -62,6 +62,12 @@ export async function setupDatabase(config: ProjectConfig): Promise<void> {
|
||||
projectDir: serverDir,
|
||||
});
|
||||
}
|
||||
} else if (orm === "mongoose") {
|
||||
await addPackageDependency({
|
||||
dependencies: ["mongoose"],
|
||||
devDependencies: [],
|
||||
projectDir: serverDir,
|
||||
});
|
||||
}
|
||||
|
||||
if (database === "sqlite" && dbSetup === "turso") {
|
||||
|
||||
@@ -367,6 +367,11 @@ export async function setupAuthTemplate(
|
||||
PKG_ROOT,
|
||||
`templates/auth/server/db/prisma/${db}`,
|
||||
);
|
||||
} else if (orm === "mongoose") {
|
||||
authDbSrc = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/auth/server/db/mongoose/${db}`,
|
||||
)
|
||||
}
|
||||
if (authDbSrc && (await fs.pathExists(authDbSrc))) {
|
||||
await processAndCopyFiles("**/*", authDbSrc, serverAppDir, context);
|
||||
|
||||
@@ -60,7 +60,7 @@ async function main() {
|
||||
.option("orm", {
|
||||
type: "string",
|
||||
describe: "ORM type",
|
||||
choices: ["drizzle", "prisma", "none"],
|
||||
choices: ["drizzle", "prisma", "mongoose", "none"],
|
||||
})
|
||||
.option("auth", {
|
||||
type: "boolean",
|
||||
@@ -446,78 +446,82 @@ function processAndValidateFlags(
|
||||
config.dbSetup = "none";
|
||||
}
|
||||
|
||||
if (effectiveDatabase === "mongodb" && effectiveOrm === "drizzle") {
|
||||
if (effectiveDatabase === "mongodb" && effectiveOrm === "drizzle") {
|
||||
consola.fatal(
|
||||
"Drizzle ORM is not compatible with MongoDB. Please use --orm prisma or --orm mongoose.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (
|
||||
effectiveOrm === "mongoose" &&
|
||||
effectiveDatabase &&
|
||||
effectiveDatabase !== "mongodb"
|
||||
) {
|
||||
consola.fatal(
|
||||
`Mongoose ORM requires MongoDB. Cannot use --orm mongoose with --database ${effectiveDatabase}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (config.dbSetup && config.dbSetup !== "none") {
|
||||
const dbSetup = config.dbSetup;
|
||||
|
||||
if (!effectiveDatabase || effectiveDatabase === "none") {
|
||||
consola.fatal(
|
||||
"MongoDB is only available with Prisma. Cannot use --database mongodb with --orm drizzle",
|
||||
`Database setup '--db-setup ${dbSetup}' requires a database. Cannot use when database is 'none'.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (config.dbSetup && config.dbSetup !== "none") {
|
||||
const dbSetup = config.dbSetup;
|
||||
if (dbSetup === "turso") {
|
||||
if (effectiveDatabase && effectiveDatabase !== "sqlite") {
|
||||
consola.fatal(
|
||||
`Turso setup requires SQLite. Cannot use --db-setup turso with --database ${effectiveDatabase}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (effectiveOrm === "prisma") {
|
||||
consola.fatal(
|
||||
"Turso setup is not compatible with Prisma. Cannot use --db-setup turso with --orm prisma",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
config.database = "sqlite";
|
||||
config.orm = "drizzle";
|
||||
} else if (dbSetup === "prisma-postgres") {
|
||||
if (effectiveDatabase && effectiveDatabase !== "postgres") {
|
||||
consola.fatal(
|
||||
`Prisma PostgreSQL setup requires PostgreSQL. Cannot use --db-setup prisma-postgres with --database ${effectiveDatabase}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (
|
||||
effectiveOrm &&
|
||||
effectiveOrm !== "prisma" &&
|
||||
effectiveOrm !== "none"
|
||||
) {
|
||||
consola.fatal(
|
||||
`Prisma PostgreSQL setup requires Prisma ORM. Cannot use --db-setup prisma-postgres with --orm ${effectiveOrm}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
config.database = "postgres";
|
||||
config.orm = "prisma";
|
||||
} else if (dbSetup === "mongodb-atlas") {
|
||||
if (effectiveDatabase && effectiveDatabase !== "mongodb") {
|
||||
consola.fatal(
|
||||
`MongoDB Atlas setup requires MongoDB. Cannot use --db-setup mongodb-atlas with --database ${effectiveDatabase}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (
|
||||
effectiveOrm &&
|
||||
effectiveOrm !== "prisma" &&
|
||||
effectiveOrm !== "none"
|
||||
) {
|
||||
consola.fatal(
|
||||
`MongoDB Atlas setup requires Prisma ORM. Cannot use --db-setup mongodb-atlas with --orm ${effectiveOrm}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
config.database = "mongodb";
|
||||
config.orm = "prisma";
|
||||
} else if (dbSetup === "neon") {
|
||||
if (effectiveDatabase && effectiveDatabase !== "postgres") {
|
||||
consola.fatal(
|
||||
`Neon PostgreSQL setup requires PostgreSQL. Cannot use --db-setup neon with --database ${effectiveDatabase}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
config.database = "postgres";
|
||||
if (dbSetup === "turso") {
|
||||
if (effectiveDatabase && effectiveDatabase !== "sqlite") {
|
||||
consola.fatal(
|
||||
`Turso setup requires SQLite. Cannot use --db-setup turso with --database ${effectiveDatabase}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (effectiveOrm !== "drizzle") {
|
||||
consola.fatal(
|
||||
`Turso setup requires Drizzle ORM. Cannot use --db-setup turso with --orm ${effectiveOrm ?? "none"}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (dbSetup === "prisma-postgres") {
|
||||
if (effectiveDatabase !== "postgres") {
|
||||
consola.fatal(
|
||||
`Prisma PostgreSQL setup requires PostgreSQL. Cannot use --db-setup prisma-postgres with --database ${effectiveDatabase}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (effectiveOrm !== "prisma") {
|
||||
consola.fatal(
|
||||
`Prisma PostgreSQL setup requires Prisma ORM. Cannot use --db-setup prisma-postgres with --orm ${effectiveOrm}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (dbSetup === "mongodb-atlas") {
|
||||
if (effectiveDatabase !== "mongodb") {
|
||||
consola.fatal(
|
||||
`MongoDB Atlas setup requires MongoDB. Cannot use --db-setup mongodb-atlas with --database ${effectiveDatabase}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (effectiveOrm !== "prisma" && effectiveOrm !== "mongoose") {
|
||||
consola.fatal(
|
||||
`MongoDB Atlas setup requires Prisma or Mongoose ORM. Cannot use --db-setup mongodb-atlas with --orm ${effectiveOrm}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (dbSetup === "neon") {
|
||||
if (effectiveDatabase !== "postgres") {
|
||||
consola.fatal(
|
||||
`Neon PostgreSQL setup requires PostgreSQL. Cannot use --db-setup neon with --database ${effectiveDatabase}.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const includesNuxt = effectiveFrontend?.includes("nuxt");
|
||||
const includesSvelte = effectiveFrontend?.includes("svelte");
|
||||
@@ -576,13 +580,13 @@ function processAndValidateFlags(
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (config.addons.includes("husky") && !config.addons.includes("biome")) {
|
||||
consola.warn(
|
||||
"Husky addon is recommended to be used with Biome for lint-staged configuration.",
|
||||
);
|
||||
}
|
||||
config.addons = [...new Set(config.addons)];
|
||||
if (config.addons.includes("husky") && !config.addons.includes("biome")) {
|
||||
consola.warn(
|
||||
"Husky addon is recommended to be used with Biome for lint-staged configuration.",
|
||||
);
|
||||
}
|
||||
config.addons = [...new Set(config.addons)];
|
||||
}
|
||||
|
||||
const onlyNativeFrontend =
|
||||
effectiveFrontend &&
|
||||
|
||||
@@ -3,6 +3,24 @@ import pc from "picocolors";
|
||||
import { DEFAULT_CONFIG } from "../constants";
|
||||
import type { ProjectBackend, ProjectDatabase, ProjectOrm } from "../types";
|
||||
|
||||
const ormOptions = {
|
||||
prisma: {
|
||||
value: "prisma" as const,
|
||||
label: "Prisma",
|
||||
hint: "Powerful, feature-rich ORM",
|
||||
},
|
||||
mongoose: {
|
||||
value: "mongoose" as const,
|
||||
label: "Mongoose",
|
||||
hint: "Elegant object modeling tool",
|
||||
},
|
||||
drizzle: {
|
||||
value: "drizzle" as const,
|
||||
label: "Drizzle",
|
||||
hint: "Lightweight and performant TypeScript ORM",
|
||||
},
|
||||
};
|
||||
|
||||
export async function getORMChoice(
|
||||
orm: ProjectOrm | undefined,
|
||||
hasDatabase: boolean,
|
||||
@@ -16,26 +34,16 @@ export async function getORMChoice(
|
||||
if (!hasDatabase) return "none";
|
||||
if (orm !== undefined) return orm;
|
||||
|
||||
if (database === "mongodb") {
|
||||
log.info("Only Prisma is supported with MongoDB.");
|
||||
return "prisma";
|
||||
}
|
||||
const options = [
|
||||
...(database === "mongodb"
|
||||
? [ormOptions.prisma, ormOptions.mongoose]
|
||||
: [ormOptions.drizzle, ormOptions.prisma]),
|
||||
];
|
||||
|
||||
const response = await select<ProjectOrm>({
|
||||
message: "Select ORM",
|
||||
options: [
|
||||
{
|
||||
value: "drizzle",
|
||||
label: "Drizzle",
|
||||
hint: "lightweight and performant TypeScript ORM",
|
||||
},
|
||||
{
|
||||
value: "prisma",
|
||||
label: "Prisma",
|
||||
hint: "Powerful, feature-rich ORM",
|
||||
},
|
||||
],
|
||||
initialValue: DEFAULT_CONFIG.orm,
|
||||
options,
|
||||
initialValue: database === "mongodb" ? "prisma" : DEFAULT_CONFIG.orm,
|
||||
});
|
||||
|
||||
if (isCancel(response)) {
|
||||
|
||||
@@ -4,7 +4,7 @@ export type ProjectDatabase =
|
||||
| "mongodb"
|
||||
| "mysql"
|
||||
| "none";
|
||||
export type ProjectOrm = "drizzle" | "prisma" | "none";
|
||||
export type ProjectOrm = "drizzle" | "prisma" | "mongoose" | "none";
|
||||
export type ProjectPackageManager = "npm" | "pnpm" | "bun";
|
||||
export type ProjectAddons =
|
||||
| "pwa"
|
||||
|
||||
@@ -58,6 +58,31 @@ export const auth = betterAuth({
|
||||
});
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq orm "mongoose")}}
|
||||
import { betterAuth } from "better-auth";
|
||||
import { mongodbAdapter } from "better-auth/adapters/mongodb";
|
||||
{{#if (includes frontend "native")}}
|
||||
import { expo } from "@better-auth/expo";
|
||||
{{/if}}
|
||||
import { client } from "../db";
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: mongodbAdapter(client.db()),
|
||||
trustedOrigins: [
|
||||
process.env.CORS_ORIGIN || "",{{#if (includes frontend "native")}}
|
||||
"my-better-t-app://",{{/if}}
|
||||
],
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
}
|
||||
|
||||
{{~#if (includes frontend "native")}}
|
||||
,
|
||||
plugins: [expo()]
|
||||
{{/if~}}
|
||||
});
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq orm "none")}}
|
||||
import { betterAuth } from "better-auth";
|
||||
{{#if (includes frontend "native")}}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
const { Schema, model } = mongoose;
|
||||
|
||||
const userSchema = new Schema(
|
||||
{
|
||||
_id: { type: String },
|
||||
name: { type: String, required: true },
|
||||
email: { type: String, required: true, unique: true },
|
||||
emailVerified: { type: Boolean, required: true },
|
||||
image: { type: String },
|
||||
createdAt: { type: Date, required: true },
|
||||
updatedAt: { type: Date, required: true },
|
||||
},
|
||||
{ collection: 'user' }
|
||||
);
|
||||
|
||||
const sessionSchema = new Schema(
|
||||
{
|
||||
_id: { type: String },
|
||||
expiresAt: { type: Date, required: true },
|
||||
token: { type: String, required: true, unique: true },
|
||||
createdAt: { type: Date, required: true },
|
||||
updatedAt: { type: Date, required: true },
|
||||
ipAddress: { type: String },
|
||||
userAgent: { type: String },
|
||||
userId: { type: String, ref: 'User', required: true },
|
||||
},
|
||||
{ collection: 'session' }
|
||||
);
|
||||
|
||||
const accountSchema = new Schema(
|
||||
{
|
||||
_id: { type: String },
|
||||
accountId: { type: String, required: true },
|
||||
providerId: { type: String, required: true },
|
||||
userId: { type: String, ref: 'User', required: true },
|
||||
accessToken: { type: String },
|
||||
refreshToken: { type: String },
|
||||
idToken: { type: String },
|
||||
accessTokenExpiresAt: { type: Date },
|
||||
refreshTokenExpiresAt: { type: Date },
|
||||
scope: { type: String },
|
||||
password: { type: String },
|
||||
createdAt: { type: Date, required: true },
|
||||
updatedAt: { type: Date, required: true },
|
||||
},
|
||||
{ collection: 'account' }
|
||||
);
|
||||
|
||||
const verificationSchema = new Schema(
|
||||
{
|
||||
_id: { type: String },
|
||||
identifier: { type: String, required: true },
|
||||
value: { type: String, required: true },
|
||||
expiresAt: { type: Date, required: true },
|
||||
createdAt: { type: Date },
|
||||
updatedAt: { type: Date },
|
||||
},
|
||||
{ collection: 'verification' }
|
||||
);
|
||||
|
||||
const User = model('User', userSchema);
|
||||
const Session = model('Session', sessionSchema);
|
||||
const Account = model('Account', accountSchema);
|
||||
const Verification = model('Verification', verificationSchema);
|
||||
|
||||
export { User, Session, Account, Verification };
|
||||
6
apps/cli/templates/db/mongoose/mongodb/src/db/index.ts
Normal file
6
apps/cli/templates/db/mongoose/mongodb/src/db/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
await mongoose.connect(process.env.DATABASE_URL || "");
|
||||
const client = mongoose.connection.getClient();
|
||||
|
||||
export { client };
|
||||
@@ -0,0 +1,66 @@
|
||||
{{#if (eq api "orpc")}}
|
||||
import { z } from "zod";
|
||||
import { publicProcedure } from "../lib/orpc";
|
||||
import { Todo } from "../db/models/todo.model";
|
||||
|
||||
export const todoRouter = {
|
||||
getAll: publicProcedure.handler(async () => {
|
||||
return await Todo.find().lean();
|
||||
}),
|
||||
|
||||
create: publicProcedure
|
||||
.input(z.object({ text: z.string().min(1) }))
|
||||
.handler(async ({ input }) => {
|
||||
const newTodo = await Todo.create({ text: input.text });
|
||||
return newTodo.toObject();
|
||||
}),
|
||||
|
||||
toggle: publicProcedure
|
||||
.input(z.object({ id: z.string(), completed: z.boolean() }))
|
||||
.handler(async ({ input }) => {
|
||||
await Todo.updateOne({ id: input.id }, { completed: input.completed });
|
||||
return { success: true };
|
||||
}),
|
||||
|
||||
delete: publicProcedure
|
||||
.input(z.object({ id: z.string() }))
|
||||
.handler(async ({ input }) => {
|
||||
await Todo.deleteOne({ id: input.id });
|
||||
return { success: true };
|
||||
}),
|
||||
};
|
||||
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq api "trpc")}}
|
||||
import { z } from "zod";
|
||||
import { router, publicProcedure } from "../lib/trpc";
|
||||
import { Todo } from "../db/models/todo.model";
|
||||
|
||||
export const todoRouter = router({
|
||||
getAll: publicProcedure.query(async () => {
|
||||
return await Todo.find().lean();
|
||||
}),
|
||||
|
||||
create: publicProcedure
|
||||
.input(z.object({ text: z.string().min(1) }))
|
||||
.mutation(async ({ input }) => {
|
||||
const newTodo = await Todo.create({ text: input.text });
|
||||
return newTodo.toObject();
|
||||
}),
|
||||
|
||||
toggle: publicProcedure
|
||||
.input(z.object({ id: z.string(), completed: z.boolean() }))
|
||||
.mutation(async ({ input }) => {
|
||||
await Todo.updateOne({ id: input.id }, { completed: input.completed });
|
||||
return { success: true };
|
||||
}),
|
||||
|
||||
delete: publicProcedure
|
||||
.input(z.object({ id: z.string() }))
|
||||
.mutation(async ({ input }) => {
|
||||
await Todo.deleteOne({ id: input.id });
|
||||
return { success: true };
|
||||
}),
|
||||
});
|
||||
{{/if}}
|
||||
@@ -0,0 +1,24 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
const { Schema, model } = mongoose;
|
||||
|
||||
const todoSchema = new Schema({
|
||||
id: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
auto: true,
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
completed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
}, {
|
||||
collection: 'todo'
|
||||
});
|
||||
|
||||
const Todo = model('Todo', todoSchema);
|
||||
|
||||
export { Todo };
|
||||
4
apps/web/public/icon/mongoose.svg
Normal file
4
apps/web/public/icon/mongoose.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.4 KiB |
@@ -224,137 +224,158 @@ const analyzeStackCompatibility = (stack: StackState): CompatibilityResult => {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (nextStack.database === "none") {
|
||||
if (nextStack.orm !== "none") {
|
||||
notes.database.notes.push(
|
||||
"Database 'None' selected: ORM will be set to 'None'.",
|
||||
);
|
||||
notes.orm.notes.push(
|
||||
"ORM requires a database. It will be set to 'None'.",
|
||||
);
|
||||
notes.database.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "none";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.auth === "true") {
|
||||
notes.database.notes.push(
|
||||
"Database 'None' selected: Auth will be disabled.",
|
||||
);
|
||||
notes.auth.notes.push(
|
||||
"Authentication requires a database. It will be disabled.",
|
||||
);
|
||||
notes.database.hasIssue = true;
|
||||
notes.auth.hasIssue = true;
|
||||
nextStack.auth = "false";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.dbSetup !== "none") {
|
||||
notes.database.notes.push(
|
||||
"Database 'None' selected: DB Setup will be set to 'Basic'.",
|
||||
);
|
||||
notes.dbSetup.notes.push(
|
||||
"DB Setup requires a database. It will be set to 'Basic Setup'.",
|
||||
);
|
||||
notes.database.hasIssue = true;
|
||||
notes.dbSetup.hasIssue = true;
|
||||
nextStack.dbSetup = "none";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.database === "mongodb") {
|
||||
if (nextStack.orm !== "prisma" && nextStack.orm !== "none") {
|
||||
notes.database.notes.push(
|
||||
"MongoDB requires Prisma ORM. It will be selected.",
|
||||
);
|
||||
notes.orm.notes.push(
|
||||
"MongoDB requires Prisma ORM. It will be selected.",
|
||||
);
|
||||
notes.database.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.database === "none") {
|
||||
if (nextStack.orm !== "none") {
|
||||
notes.database.notes.push(
|
||||
"Database 'None' selected: ORM will be set to 'None'.",
|
||||
);
|
||||
notes.orm.notes.push(
|
||||
"ORM requires a database. It will be set to 'None'.",
|
||||
);
|
||||
notes.database.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "none";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.auth === "true") {
|
||||
notes.database.notes.push(
|
||||
"Database 'None' selected: Auth will be disabled.",
|
||||
);
|
||||
notes.auth.notes.push(
|
||||
"Authentication requires a database. It will be disabled.",
|
||||
);
|
||||
notes.database.hasIssue = true;
|
||||
notes.auth.hasIssue = true;
|
||||
nextStack.auth = "false";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.dbSetup !== "none") {
|
||||
notes.database.notes.push(
|
||||
"Database 'None' selected: DB Setup will be set to 'Basic'.",
|
||||
);
|
||||
notes.dbSetup.notes.push(
|
||||
"DB Setup requires a database. It will be set to 'Basic Setup'.",
|
||||
);
|
||||
notes.database.hasIssue = true;
|
||||
notes.dbSetup.hasIssue = true;
|
||||
nextStack.dbSetup = "none";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.database === "mongodb") {
|
||||
if (nextStack.orm !== "prisma" && nextStack.orm !== "mongoose") {
|
||||
notes.database.notes.push(
|
||||
"MongoDB requires Prisma or Mongoose ORM. Prisma will be selected.",
|
||||
);
|
||||
notes.orm.notes.push("MongoDB requires Prisma or Mongoose ORM. Prisma will be selected.");
|
||||
notes.database.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (nextStack.orm === "mongoose") {
|
||||
notes.database.notes.push(
|
||||
"Relational databases are not compatible with Mongoose ORM",
|
||||
);
|
||||
notes.orm.notes.push("Relational databases are not compatible with Mongoose ORM");
|
||||
notes.database.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.dbSetup === "mongodb-atlas") {
|
||||
notes.database.notes.push(
|
||||
"Relational databases are not compatible with MongoDB Atlas setup. DB Setup will be reset.",
|
||||
);
|
||||
notes.dbSetup.notes.push(
|
||||
"MongoDB Atlas setup requires MongoDB. It will be reset to 'Basic Setup'.",
|
||||
);
|
||||
notes.database.hasIssue = true;
|
||||
notes.dbSetup.hasIssue = true;
|
||||
nextStack.dbSetup = "none";
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextStack.dbSetup === "turso") {
|
||||
if (nextStack.database !== "sqlite") {
|
||||
notes.dbSetup.notes.push("Turso requires SQLite. It will be selected.");
|
||||
notes.database.notes.push(
|
||||
"Turso DB setup requires SQLite. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.database.hasIssue = true;
|
||||
nextStack.database = "sqlite";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.orm !== "drizzle") {
|
||||
notes.dbSetup.notes.push(
|
||||
"Turso requires Drizzle ORM. It will be selected.",
|
||||
);
|
||||
notes.orm.notes.push(
|
||||
"Turso DB setup requires Drizzle ORM. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "drizzle";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.dbSetup === "prisma-postgres") {
|
||||
if (nextStack.database !== "postgres") {
|
||||
notes.dbSetup.notes.push("Requires PostgreSQL. It will be selected.");
|
||||
notes.database.notes.push(
|
||||
"Prisma PostgreSQL setup requires PostgreSQL. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.database.hasIssue = true;
|
||||
nextStack.database = "postgres";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.orm !== "prisma") {
|
||||
notes.dbSetup.notes.push("Requires Prisma ORM. It will be selected.");
|
||||
notes.orm.notes.push(
|
||||
"Prisma PostgreSQL setup requires Prisma ORM. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.dbSetup === "mongodb-atlas") {
|
||||
if (nextStack.database !== "mongodb") {
|
||||
notes.dbSetup.notes.push("Requires MongoDB. It will be selected.");
|
||||
notes.database.notes.push(
|
||||
"MongoDB Atlas setup requires MongoDB. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.database.hasIssue = true;
|
||||
nextStack.database = "mongodb";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.orm !== "prisma") {
|
||||
notes.dbSetup.notes.push("Requires Prisma ORM. It will be selected.");
|
||||
notes.orm.notes.push(
|
||||
"MongoDB Atlas setup requires Prisma ORM. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.dbSetup === "neon") {
|
||||
if (nextStack.database !== "postgres") {
|
||||
notes.dbSetup.notes.push(
|
||||
"Neon requires PostgreSQL. It will be selected.",
|
||||
);
|
||||
notes.database.notes.push(
|
||||
"Neon DB setup requires PostgreSQL. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.database.hasIssue = true;
|
||||
nextStack.database = "postgres";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.dbSetup === "turso") {
|
||||
if (nextStack.database !== "sqlite") {
|
||||
notes.dbSetup.notes.push("Turso requires SQLite. It will be selected.");
|
||||
notes.database.notes.push(
|
||||
"Turso DB setup requires SQLite. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.database.hasIssue = true;
|
||||
nextStack.database = "sqlite";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.orm !== "drizzle") {
|
||||
notes.dbSetup.notes.push(
|
||||
"Turso requires Drizzle ORM. It will be selected.",
|
||||
);
|
||||
notes.orm.notes.push(
|
||||
"Turso DB setup requires Drizzle ORM. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "drizzle";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.dbSetup === "prisma-postgres") {
|
||||
if (nextStack.database !== "postgres") {
|
||||
notes.dbSetup.notes.push("Requires PostgreSQL. It will be selected.");
|
||||
notes.database.notes.push(
|
||||
"Prisma PostgreSQL setup requires PostgreSQL. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.database.hasIssue = true;
|
||||
nextStack.database = "postgres";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.orm !== "prisma") {
|
||||
notes.dbSetup.notes.push("Requires Prisma ORM. It will be selected.");
|
||||
notes.orm.notes.push(
|
||||
"Prisma PostgreSQL setup requires Prisma ORM. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.dbSetup === "mongodb-atlas") {
|
||||
if (nextStack.database !== "mongodb") {
|
||||
notes.dbSetup.notes.push("Requires MongoDB. It will be selected.");
|
||||
notes.database.notes.push(
|
||||
"MongoDB Atlas setup requires MongoDB. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.database.hasIssue = true;
|
||||
nextStack.database = "mongodb";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.orm !== "prisma" && nextStack.orm !== "mongoose") {
|
||||
notes.dbSetup.notes.push("Requires Prisma or Mongoose ORM. Prisma will be selected.");
|
||||
notes.orm.notes.push(
|
||||
"MongoDB Atlas setup requires Prisma or Mongoose ORM. Prisma will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.orm.hasIssue = true;
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.dbSetup === "neon") {
|
||||
if (nextStack.database !== "postgres") {
|
||||
notes.dbSetup.notes.push(
|
||||
"Neon requires PostgreSQL. It will be selected.",
|
||||
);
|
||||
notes.database.notes.push(
|
||||
"Neon DB setup requires PostgreSQL. It will be selected.",
|
||||
);
|
||||
notes.dbSetup.hasIssue = true;
|
||||
notes.database.hasIssue = true;
|
||||
nextStack.database = "postgres";
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
const isNuxt = nextStack.frontend.includes("nuxt");
|
||||
const isSvelte = nextStack.frontend.includes("svelte");
|
||||
@@ -450,51 +471,48 @@ const analyzeStackCompatibility = (stack: StackState): CompatibilityResult => {
|
||||
}
|
||||
}
|
||||
|
||||
const uniqueIncompatibleExamples = [...new Set(incompatibleExamples)];
|
||||
if (uniqueIncompatibleExamples.length > 0) {
|
||||
if (isNativeOnly) {
|
||||
} else {
|
||||
if (
|
||||
!isWeb &&
|
||||
(uniqueIncompatibleExamples.includes("todo") ||
|
||||
uniqueIncompatibleExamples.includes("ai"))
|
||||
) {
|
||||
notes.frontend.notes.push(
|
||||
"Examples require a web frontend. Incompatible examples will be removed.",
|
||||
);
|
||||
notes.examples.notes.push(
|
||||
"Requires a web frontend. Incompatible examples will be removed.",
|
||||
);
|
||||
notes.frontend.hasIssue = true;
|
||||
notes.examples.hasIssue = true;
|
||||
}
|
||||
if (
|
||||
nextStack.database === "none" &&
|
||||
uniqueIncompatibleExamples.includes("todo")
|
||||
) {
|
||||
notes.database.notes.push(
|
||||
"Todo example requires a database. It will be removed.",
|
||||
);
|
||||
notes.examples.notes.push(
|
||||
"Todo example requires a database. It will be removed.",
|
||||
);
|
||||
notes.database.hasIssue = true;
|
||||
notes.examples.hasIssue = true;
|
||||
}
|
||||
if (
|
||||
nextStack.backend === "elysia" &&
|
||||
uniqueIncompatibleExamples.includes("ai")
|
||||
) {
|
||||
notes.backend.notes.push(
|
||||
"AI example is not compatible with Elysia. It will be removed.",
|
||||
);
|
||||
notes.examples.notes.push(
|
||||
"AI example is not compatible with Elysia. It will be removed.",
|
||||
);
|
||||
notes.backend.hasIssue = true;
|
||||
notes.examples.hasIssue = true;
|
||||
}
|
||||
}
|
||||
const uniqueIncompatibleExamples = [...new Set(incompatibleExamples)];
|
||||
if (uniqueIncompatibleExamples.length > 0) {
|
||||
if (
|
||||
!isWeb &&
|
||||
(uniqueIncompatibleExamples.includes("todo") ||
|
||||
uniqueIncompatibleExamples.includes("ai"))
|
||||
) {
|
||||
notes.frontend.notes.push(
|
||||
"Examples require a web frontend. Incompatible examples will be removed.",
|
||||
);
|
||||
notes.examples.notes.push(
|
||||
"Requires a web frontend. Incompatible examples will be removed.",
|
||||
);
|
||||
notes.frontend.hasIssue = true;
|
||||
notes.examples.hasIssue = true;
|
||||
}
|
||||
if (
|
||||
nextStack.database === "none" &&
|
||||
uniqueIncompatibleExamples.includes("todo")
|
||||
) {
|
||||
notes.database.notes.push(
|
||||
"Todo example requires a database. It will be removed.",
|
||||
);
|
||||
notes.examples.notes.push(
|
||||
"Todo example requires a database. It will be removed.",
|
||||
);
|
||||
notes.database.hasIssue = true;
|
||||
notes.examples.hasIssue = true;
|
||||
}
|
||||
if (
|
||||
nextStack.backend === "elysia" &&
|
||||
uniqueIncompatibleExamples.includes("ai")
|
||||
) {
|
||||
notes.backendFramework.notes.push(
|
||||
"AI example is not compatible with Elysia. It will be removed.",
|
||||
);
|
||||
notes.examples.notes.push(
|
||||
"AI example is not compatible with Elysia. It will be removed.",
|
||||
);
|
||||
notes.backendFramework.hasIssue = true;
|
||||
notes.examples.hasIssue = true;
|
||||
}
|
||||
|
||||
const originalExamplesLength = nextStack.examples.length;
|
||||
nextStack.examples = nextStack.examples.filter(
|
||||
@@ -748,9 +766,10 @@ const StackArchitect = () => {
|
||||
if (
|
||||
currentStack.database === "mongodb" &&
|
||||
techId !== "prisma" &&
|
||||
techId !== "mongoose" &&
|
||||
techId !== "none"
|
||||
)
|
||||
reason = "MongoDB requires the Prisma ORM.";
|
||||
reason = "MongoDB requires the Prisma or Mongoose ORM.";
|
||||
if (
|
||||
currentStack.dbSetup === "turso" &&
|
||||
techId !== "drizzle" &&
|
||||
@@ -766,21 +785,23 @@ const StackArchitect = () => {
|
||||
if (
|
||||
currentStack.dbSetup === "mongodb-atlas" &&
|
||||
techId !== "prisma" &&
|
||||
techId !== "mongoose" &&
|
||||
techId !== "none"
|
||||
)
|
||||
reason = "MongoDB Atlas setup requires Prisma ORM.";
|
||||
reason = "MongoDB Atlas setup requires Prisma or Mongoose ORM.";
|
||||
|
||||
if (techId === "none") {
|
||||
if (currentStack.database === "mongodb")
|
||||
reason = "MongoDB requires Prisma ORM.";
|
||||
reason = "MongoDB requires Prisma or Mongoose ORM.";
|
||||
if (currentStack.dbSetup === "turso")
|
||||
reason = "Turso DB setup requires Drizzle ORM.";
|
||||
if (
|
||||
currentStack.dbSetup === "prisma-postgres" ||
|
||||
currentStack.dbSetup === "mongodb-atlas"
|
||||
)
|
||||
if (currentStack.dbSetup === "prisma-postgres")
|
||||
reason = "This DB setup requires Prisma ORM.";
|
||||
}
|
||||
|
||||
if (techId === "mongoose" && (currentStack.database !== "mongodb")) {
|
||||
reason = "Mongoose ORM is not compatible with relational databases.";
|
||||
}
|
||||
}
|
||||
|
||||
if (catKey === "dbSetup" && techId !== "none") {
|
||||
@@ -809,8 +830,8 @@ const StackArchitect = () => {
|
||||
currentStack.database !== "none"
|
||||
)
|
||||
reason = "Requires MongoDB database.";
|
||||
if (currentStack.orm !== "prisma" && currentStack.orm !== "none")
|
||||
reason = "Requires Prisma ORM.";
|
||||
if (currentStack.orm !== "prisma" && currentStack.orm !== "mongoose" && currentStack.orm !== "none")
|
||||
reason = "Requires Prisma or Mongoose ORM.";
|
||||
} else if (techId === "neon") {
|
||||
if (
|
||||
currentStack.database !== "postgres" &&
|
||||
@@ -1051,7 +1072,7 @@ const StackArchitect = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const copyToClipboard = () => {
|
||||
const copyToClipboard = () => {
|
||||
navigator.clipboard.writeText(command);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
|
||||
@@ -192,6 +192,13 @@ export const TECH_OPTIONS = {
|
||||
icon: "/icon/prisma.svg",
|
||||
color: "from-purple-400 to-purple-600",
|
||||
},
|
||||
{
|
||||
id: "mongoose",
|
||||
name: "Mongoose",
|
||||
description: "Elegant object modeling tool",
|
||||
icon: "/icon/mongoose.svg",
|
||||
color: "from-blue-400 to-blue-600",
|
||||
},
|
||||
{
|
||||
id: "none",
|
||||
name: "No ORM",
|
||||
|
||||
Reference in New Issue
Block a user