fix mongodb templates and add migrate and generate scripts

This commit is contained in:
Aman Varshney
2025-05-02 22:17:51 +05:30
parent 437cf9a45a
commit 0cb24b1494
13 changed files with 765 additions and 443 deletions

View File

@@ -0,0 +1,5 @@
---
"create-better-t-stack": patch
---
add migrate and generate scripts

View File

@@ -58,8 +58,8 @@ async function updateRootPackageJson(
const needsDbScripts = const needsDbScripts =
options.backend !== "convex" && options.backend !== "convex" &&
options.database !== "none" && options.database !== "none" &&
options.orm !== "none"; options.orm !== "none" &&
options.orm !== "mongoose";
if (options.addons.includes("turborepo")) { if (options.addons.includes("turborepo")) {
scripts.dev = "turbo dev"; scripts.dev = "turbo dev";
scripts.build = "turbo build"; scripts.build = "turbo build";
@@ -73,6 +73,13 @@ async function updateRootPackageJson(
if (needsDbScripts) { if (needsDbScripts) {
scripts["db:push"] = `turbo -F ${backendPackageName} db:push`; scripts["db:push"] = `turbo -F ${backendPackageName} db:push`;
scripts["db:studio"] = `turbo -F ${backendPackageName} db:studio`; scripts["db:studio"] = `turbo -F ${backendPackageName} db:studio`;
if (options.orm === "prisma") {
scripts["db:generate"] = `turbo -F ${backendPackageName} db:generate`;
scripts["db:migrate"] = `turbo -F ${backendPackageName} db:migrate`;
} else if (options.orm === "drizzle") {
scripts["db:generate"] = `turbo -F ${backendPackageName} db:generate`;
scripts["db:migrate"] = `turbo -F ${backendPackageName} db:migrate`;
}
} }
} else if (options.packageManager === "pnpm") { } else if (options.packageManager === "pnpm") {
scripts.dev = devScript; scripts.dev = devScript;
@@ -87,6 +94,17 @@ async function updateRootPackageJson(
if (needsDbScripts) { if (needsDbScripts) {
scripts["db:push"] = `pnpm --filter ${backendPackageName} db:push`; scripts["db:push"] = `pnpm --filter ${backendPackageName} db:push`;
scripts["db:studio"] = `pnpm --filter ${backendPackageName} db:studio`; scripts["db:studio"] = `pnpm --filter ${backendPackageName} db:studio`;
if (options.orm === "prisma") {
scripts["db:generate"] =
`pnpm --filter ${backendPackageName} db:generate`;
scripts["db:migrate"] =
`pnpm --filter ${backendPackageName} db:migrate`;
} else if (options.orm === "drizzle") {
scripts["db:generate"] =
`pnpm --filter ${backendPackageName} db:generate`;
scripts["db:migrate"] =
`pnpm --filter ${backendPackageName} db:migrate`;
}
} }
} else if (options.packageManager === "npm") { } else if (options.packageManager === "npm") {
scripts.dev = devScript; scripts.dev = devScript;
@@ -102,6 +120,17 @@ async function updateRootPackageJson(
scripts["db:push"] = `npm run db:push --workspace ${backendPackageName}`; scripts["db:push"] = `npm run db:push --workspace ${backendPackageName}`;
scripts["db:studio"] = scripts["db:studio"] =
`npm run db:studio --workspace ${backendPackageName}`; `npm run db:studio --workspace ${backendPackageName}`;
if (options.orm === "prisma") {
scripts["db:generate"] =
`npm run db:generate --workspace ${backendPackageName}`;
scripts["db:migrate"] =
`npm run db:migrate --workspace ${backendPackageName}`;
} else if (options.orm === "drizzle") {
scripts["db:generate"] =
`npm run db:generate --workspace ${backendPackageName}`;
scripts["db:migrate"] =
`npm run db:migrate --workspace ${backendPackageName}`;
}
} }
} else if (options.packageManager === "bun") { } else if (options.packageManager === "bun") {
scripts.dev = devScript; scripts.dev = devScript;
@@ -116,6 +145,17 @@ async function updateRootPackageJson(
if (needsDbScripts) { if (needsDbScripts) {
scripts["db:push"] = `bun run --filter ${backendPackageName} db:push`; scripts["db:push"] = `bun run --filter ${backendPackageName} db:push`;
scripts["db:studio"] = `bun run --filter ${backendPackageName} db:studio`; scripts["db:studio"] = `bun run --filter ${backendPackageName} db:studio`;
if (options.orm === "prisma") {
scripts["db:generate"] =
`bun run --filter ${backendPackageName} db:generate`;
scripts["db:migrate"] =
`bun run --filter ${backendPackageName} db:migrate`;
} else if (options.orm === "drizzle") {
scripts["db:generate"] =
`bun run --filter ${backendPackageName} db:generate`;
scripts["db:migrate"] =
`bun run --filter ${backendPackageName} db:migrate`;
}
} }
} }
@@ -192,9 +232,13 @@ async function updateServerPackageJson(
if (options.orm === "prisma") { if (options.orm === "prisma") {
scripts["db:push"] = "prisma db push --schema ./prisma/schema"; scripts["db:push"] = "prisma db push --schema ./prisma/schema";
scripts["db:studio"] = "prisma studio"; scripts["db:studio"] = "prisma studio";
scripts["db:generate"] = "prisma generate --schema ./prisma/schema";
scripts["db:migrate"] = "prisma migrate dev";
} else if (options.orm === "drizzle") { } else if (options.orm === "drizzle") {
scripts["db:push"] = "drizzle-kit push"; scripts["db:push"] = "drizzle-kit push";
scripts["db:studio"] = "drizzle-kit studio"; scripts["db:studio"] = "drizzle-kit studio";
scripts["db:generate"] = "drizzle-kit generate";
scripts["db:migrate"] = "drizzle-kit migrate";
} }
} }

View File

@@ -371,7 +371,7 @@ export async function setupAuthTemplate(
authDbSrc = path.join( authDbSrc = path.join(
PKG_ROOT, PKG_ROOT,
`templates/auth/server/db/mongoose/${db}`, `templates/auth/server/db/mongoose/${db}`,
) );
} }
if (authDbSrc && (await fs.pathExists(authDbSrc))) { if (authDbSrc && (await fs.pathExists(authDbSrc))) {
await processAndCopyFiles("**/*", authDbSrc, serverAppDir, context); await processAndCopyFiles("**/*", authDbSrc, serverAppDir, context);

View File

@@ -446,82 +446,86 @@ function processAndValidateFlags(
config.dbSetup = "none"; config.dbSetup = "none";
} }
if (effectiveDatabase === "mongodb" && effectiveOrm === "drizzle") { if (config.orm === "mongoose" && !providedFlags.has("database")) {
consola.fatal( config.database = "mongodb";
"Drizzle ORM is not compatible with MongoDB. Please use --orm prisma or --orm mongoose.", }
);
process.exit(1);
}
if ( if (effectiveDatabase === "mongodb" && effectiveOrm === "drizzle") {
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( consola.fatal(
`Database setup '--db-setup ${dbSetup}' requires a database. Cannot use when database is 'none'.`, "Drizzle ORM is not compatible with MongoDB. Please use --orm prisma or --orm mongoose.",
); );
process.exit(1); process.exit(1);
} }
if (dbSetup === "turso") { if (
if (effectiveDatabase && effectiveDatabase !== "sqlite") { 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( consola.fatal(
`Turso setup requires SQLite. Cannot use --db-setup turso with --database ${effectiveDatabase}`, `Database setup '--db-setup ${dbSetup}' requires a database. Cannot use when database is 'none'.`,
); );
process.exit(1); process.exit(1);
} }
if (effectiveOrm !== "drizzle") {
consola.fatal( if (dbSetup === "turso") {
`Turso setup requires Drizzle ORM. Cannot use --db-setup turso with --orm ${effectiveOrm ?? "none"}.`, if (effectiveDatabase && effectiveDatabase !== "sqlite") {
); consola.fatal(
process.exit(1); `Turso setup requires SQLite. Cannot use --db-setup turso with --database ${effectiveDatabase}`,
} );
} else if (dbSetup === "prisma-postgres") { process.exit(1);
if (effectiveDatabase !== "postgres") { }
consola.fatal( if (effectiveOrm !== "drizzle") {
`Prisma PostgreSQL setup requires PostgreSQL. Cannot use --db-setup prisma-postgres with --database ${effectiveDatabase}.`, consola.fatal(
); `Turso setup requires Drizzle ORM. Cannot use --db-setup turso with --orm ${effectiveOrm ?? "none"}.`,
process.exit(1); );
} process.exit(1);
if (effectiveOrm !== "prisma") { }
consola.fatal( } else if (dbSetup === "prisma-postgres") {
`Prisma PostgreSQL setup requires Prisma ORM. Cannot use --db-setup prisma-postgres with --orm ${effectiveOrm}.`, if (effectiveDatabase !== "postgres") {
); consola.fatal(
process.exit(1); `Prisma PostgreSQL setup requires PostgreSQL. Cannot use --db-setup prisma-postgres with --database ${effectiveDatabase}.`,
} );
} else if (dbSetup === "mongodb-atlas") { process.exit(1);
if (effectiveDatabase !== "mongodb") { }
consola.fatal( if (effectiveOrm !== "prisma") {
`MongoDB Atlas setup requires MongoDB. Cannot use --db-setup mongodb-atlas with --database ${effectiveDatabase}.`, consola.fatal(
); `Prisma PostgreSQL setup requires Prisma ORM. Cannot use --db-setup prisma-postgres with --orm ${effectiveOrm}.`,
process.exit(1); );
} process.exit(1);
if (effectiveOrm !== "prisma" && effectiveOrm !== "mongoose") { }
consola.fatal( } else if (dbSetup === "mongodb-atlas") {
`MongoDB Atlas setup requires Prisma or Mongoose ORM. Cannot use --db-setup mongodb-atlas with --orm ${effectiveOrm}.`, if (effectiveDatabase !== "mongodb") {
); consola.fatal(
process.exit(1); `MongoDB Atlas setup requires MongoDB. Cannot use --db-setup mongodb-atlas with --database ${effectiveDatabase}.`,
} );
} else if (dbSetup === "neon") { process.exit(1);
if (effectiveDatabase !== "postgres") { }
consola.fatal( if (effectiveOrm !== "prisma" && effectiveOrm !== "mongoose") {
`Neon PostgreSQL setup requires PostgreSQL. Cannot use --db-setup neon with --database ${effectiveDatabase}.`, consola.fatal(
); `MongoDB Atlas setup requires Prisma or Mongoose ORM. Cannot use --db-setup mongodb-atlas with --orm ${effectiveOrm}.`,
process.exit(1); );
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 includesNuxt = effectiveFrontend?.includes("nuxt");
const includesSvelte = effectiveFrontend?.includes("svelte"); const includesSvelte = effectiveFrontend?.includes("svelte");
@@ -580,13 +584,13 @@ function processAndValidateFlags(
process.exit(1); process.exit(1);
} }
if (config.addons.includes("husky") && !config.addons.includes("biome")) { if (config.addons.includes("husky") && !config.addons.includes("biome")) {
consola.warn( consola.warn(
"Husky addon is recommended to be used with Biome for lint-staged configuration.", "Husky addon is recommended to be used with Biome for lint-staged configuration.",
); );
}
config.addons = [...new Set(config.addons)];
} }
config.addons = [...new Set(config.addons)];
}
const onlyNativeFrontend = const onlyNativeFrontend =
effectiveFrontend && effectiveFrontend &&

View File

@@ -29,6 +29,14 @@
"db:studio": { "db:studio": {
"cache": false, "cache": false,
"persistent": true "persistent": true
},
"db:migrate": {
"cache": false,
"persistent": true
},
"db:generate": {
"cache": false,
"persistent": true
} }
{{/unless}}{{/if}} {{/unless}}{{/if}}
} }

View File

@@ -11,6 +11,7 @@ export const auth = betterAuth({
{{#if (eq database "postgres")}}provider: "postgresql"{{/if}} {{#if (eq database "postgres")}}provider: "postgresql"{{/if}}
{{#if (eq database "sqlite")}}provider: "sqlite"{{/if}} {{#if (eq database "sqlite")}}provider: "sqlite"{{/if}}
{{#if (eq database "mysql")}}provider: "mysql"{{/if}} {{#if (eq database "mysql")}}provider: "mysql"{{/if}}
{{#if (eq database "mongodb")}}provider: "mongodb"{{/if}}
}), }),
trustedOrigins: [ trustedOrigins: [
process.env.CORS_ORIGIN || "",{{#if (includes frontend "native")}} process.env.CORS_ORIGIN || "",{{#if (includes frontend "native")}}
@@ -67,7 +68,7 @@ import { expo } from "@better-auth/expo";
import { client } from "../db"; import { client } from "../db";
export const auth = betterAuth({ export const auth = betterAuth({
database: mongodbAdapter(client.db()), database: mongodbAdapter(client),
trustedOrigins: [ trustedOrigins: [
process.env.CORS_ORIGIN || "",{{#if (includes frontend "native")}} process.env.CORS_ORIGIN || "",{{#if (includes frontend "native")}}
"my-better-t-app://",{{/if}} "my-better-t-app://",{{/if}}
@@ -104,4 +105,4 @@ export const auth = betterAuth({
plugins: [expo()] plugins: [expo()]
{{/if~}} {{/if~}}
}); });
{{/if}} {{/if}}

View File

@@ -1,6 +1,9 @@
import mongoose from 'mongoose'; import mongoose from "mongoose";
await mongoose.connect(process.env.DATABASE_URL || ""); await mongoose.connect(process.env.DATABASE_URL || "").catch((error) => {
const client = mongoose.connection.getClient(); console.log("Error connecting to database:", error);
});
export { client }; const client = mongoose.connection.getClient().db("myDB");
export { client };

View File

@@ -23,7 +23,11 @@ export const todoRouter = {
}), }),
toggle: publicProcedure toggle: publicProcedure
{{#if (eq database "mongodb")}}
.input(z.object({ id: z.string(), completed: z.boolean() }))
{{else}}
.input(z.object({ id: z.number(), completed: z.boolean() })) .input(z.object({ id: z.number(), completed: z.boolean() }))
{{/if}}
.handler(async ({ input }) => { .handler(async ({ input }) => {
await prisma.todo.update({ await prisma.todo.update({
where: { id: input.id }, where: { id: input.id },
@@ -33,7 +37,11 @@ export const todoRouter = {
}), }),
delete: publicProcedure delete: publicProcedure
{{#if (eq database "mongodb")}}
.input(z.object({ id: z.string() }))
{{else}}
.input(z.object({ id: z.number() })) .input(z.object({ id: z.number() }))
{{/if}}
.handler(async ({ input }) => { .handler(async ({ input }) => {
await prisma.todo.delete({ await prisma.todo.delete({
where: { id: input.id }, where: { id: input.id },
@@ -69,7 +77,11 @@ export const todoRouter = router({
}), }),
toggle: publicProcedure toggle: publicProcedure
{{#if (eq database "mongodb")}}
.input(z.object({ id: z.string(), completed: z.boolean() }))
{{else}}
.input(z.object({ id: z.number(), completed: z.boolean() })) .input(z.object({ id: z.number(), completed: z.boolean() }))
{{/if}}
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
try { try {
return await prisma.todo.update({ return await prisma.todo.update({
@@ -85,7 +97,11 @@ export const todoRouter = router({
}), }),
delete: publicProcedure delete: publicProcedure
{{#if (eq database "mongodb")}}
.input(z.object({ id: z.string() }))
{{else}}
.input(z.object({ id: z.number() })) .input(z.object({ id: z.number() }))
{{/if}}
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
try { try {
return await prisma.todo.delete({ return await prisma.todo.delete({

View File

@@ -22,10 +22,12 @@
"lucide-react": "^0.503.0", "lucide-react": "^0.503.0",
"motion": "^12.8.0", "motion": "^12.8.0",
"next": "15.3.1", "next": "15.3.1",
"next-themes": "^0.4.6",
"nuqs": "^2.4.3", "nuqs": "^2.4.3",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-tweet": "^3.2.2", "react-tweet": "^3.2.2",
"sonner": "^2.0.3",
"tailwind-merge": "^3.2.0" "tailwind-merge": "^3.2.0"
}, },
"devDependencies": { "devDependencies": {

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@ import { Poppins } from "next/font/google";
import { NuqsAdapter } from "nuqs/adapters/next/app"; import { NuqsAdapter } from "nuqs/adapters/next/app";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import "./global.css"; import "./global.css";
import { Toaster } from "@/components/ui/sonner";
const poppins = Poppins({ const poppins = Poppins({
subsets: ["latin"], subsets: ["latin"],
@@ -96,6 +97,7 @@ export default function Layout({ children }: { children: ReactNode }) {
}} }}
> >
<NuqsAdapter>{children}</NuqsAdapter> <NuqsAdapter>{children}</NuqsAdapter>
<Toaster />
</RootProvider> </RootProvider>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,25 @@
"use client";
import { useTheme } from "next-themes";
import { Toaster as Sonner, type ToasterProps } from "sonner";
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme();
return (
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
style={
{
"--normal-bg": "var(--popover)",
"--normal-text": "var(--popover-foreground)",
"--normal-border": "var(--border)",
} as React.CSSProperties
}
{...props}
/>
);
};
export { Toaster };

View File

@@ -14,7 +14,7 @@
}, },
"apps/cli": { "apps/cli": {
"name": "create-better-t-stack", "name": "create-better-t-stack",
"version": "2.5.1", "version": "2.6.1",
"bin": { "bin": {
"create-better-t-stack": "dist/index.js", "create-better-t-stack": "dist/index.js",
}, },
@@ -54,10 +54,12 @@
"lucide-react": "^0.503.0", "lucide-react": "^0.503.0",
"motion": "^12.8.0", "motion": "^12.8.0",
"next": "15.3.1", "next": "15.3.1",
"next-themes": "^0.4.6",
"nuqs": "^2.4.3", "nuqs": "^2.4.3",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-tweet": "^3.2.2", "react-tweet": "^3.2.2",
"sonner": "^2.0.3",
"tailwind-merge": "^3.2.0", "tailwind-merge": "^3.2.0",
}, },
"devDependencies": { "devDependencies": {
@@ -1524,6 +1526,8 @@
"slice-ansi": ["slice-ansi@5.0.0", "", { "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ=="], "slice-ansi": ["slice-ansi@5.0.0", "", { "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ=="],
"sonner": ["sonner@2.0.3", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-njQ4Hht92m0sMqqHVDL32V2Oun9W1+PHO9NDv9FHfJjT3JT22IG4Jpo3FPQy+mouRKCXFWO+r67v6MrHX2zeIA=="],
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],