create-backlist 6.0.6 → 6.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +141 -0
- package/package.json +4 -10
- package/src/analyzer.js +105 -308
- package/src/generators/dotnet.js +94 -120
- package/src/generators/java.js +109 -157
- package/src/generators/node.js +85 -262
- package/src/generators/template.js +2 -38
- package/src/templates/dotnet/partials/Controller.cs.ejs +14 -7
- package/src/templates/java-spring/partials/ApplicationSeeder.java.ejs +2 -7
- package/src/templates/java-spring/partials/AuthController.java.ejs +10 -23
- package/src/templates/java-spring/partials/Controller.java.ejs +6 -17
- package/src/templates/java-spring/partials/Dockerfile.ejs +1 -6
- package/src/templates/java-spring/partials/Entity.java.ejs +5 -15
- package/src/templates/java-spring/partials/JwtAuthFilter.java.ejs +7 -30
- package/src/templates/java-spring/partials/JwtService.java.ejs +10 -38
- package/src/templates/java-spring/partials/Repository.java.ejs +1 -10
- package/src/templates/java-spring/partials/Service.java.ejs +7 -45
- package/src/templates/java-spring/partials/User.java.ejs +4 -17
- package/src/templates/java-spring/partials/UserDetailsServiceImpl.java.ejs +4 -10
- package/src/templates/java-spring/partials/UserRepository.java.ejs +0 -8
- package/src/templates/java-spring/partials/docker-compose.yml.ejs +8 -16
- package/src/templates/node-ts-express/base/server.ts +6 -13
- package/src/templates/node-ts-express/base/tsconfig.json +3 -13
- package/src/templates/node-ts-express/partials/ApiDocs.ts.ejs +7 -17
- package/src/templates/node-ts-express/partials/App.test.ts.ejs +26 -49
- package/src/templates/node-ts-express/partials/Auth.controller.ts.ejs +62 -56
- package/src/templates/node-ts-express/partials/Auth.middleware.ts.ejs +10 -21
- package/src/templates/node-ts-express/partials/Controller.ts.ejs +40 -40
- package/src/templates/node-ts-express/partials/DbContext.cs.ejs +3 -3
- package/src/templates/node-ts-express/partials/Dockerfile.ejs +11 -9
- package/src/templates/node-ts-express/partials/Model.cs.ejs +7 -25
- package/src/templates/node-ts-express/partials/Model.ts.ejs +12 -20
- package/src/templates/node-ts-express/partials/PrismaController.ts.ejs +55 -72
- package/src/templates/node-ts-express/partials/PrismaSchema.prisma.ejs +12 -27
- package/src/templates/node-ts-express/partials/README.md.ejs +12 -9
- package/src/templates/node-ts-express/partials/Seeder.ts.ejs +64 -44
- package/src/templates/node-ts-express/partials/docker-compose.yml.ejs +16 -31
- package/src/templates/node-ts-express/partials/package.json.ejs +1 -3
- package/src/templates/node-ts-express/partials/routes.ts.ejs +24 -35
- package/src/utils.js +4 -19
- package/bin/backlist.js +0 -227
- package/src/db/prisma.ts +0 -4
- package/src/scanner/analyzeFrontend.js +0 -146
- package/src/scanner/index.js +0 -99
- package/src/templates/dotnet/partials/Dto.cs.ejs +0 -8
- package/src/templates/node-ts-express/partials/prismaClient.ts.ejs +0 -4
|
@@ -3,81 +3,87 @@ import { Request, Response } from 'express';
|
|
|
3
3
|
import bcrypt from 'bcryptjs';
|
|
4
4
|
import jwt from 'jsonwebtoken';
|
|
5
5
|
|
|
6
|
-
<% if (dbType === 'mongoose') {
|
|
6
|
+
<% if (dbType === 'mongoose') { %>
|
|
7
7
|
import User from '../models/User.model';
|
|
8
|
-
<% } else if (dbType === 'prisma') {
|
|
9
|
-
import { prisma } from '../
|
|
10
|
-
<% }
|
|
8
|
+
<% } else if (dbType === 'prisma') { %>
|
|
9
|
+
import { prisma } from '../server';
|
|
10
|
+
<% } %>
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
const secret = process.env.JWT_SECRET;
|
|
14
|
-
if (!secret) {
|
|
15
|
-
return res.status(500).json({ message: 'JWT_SECRET is not configured' });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const payload = { user: { id: userId } };
|
|
19
|
-
|
|
20
|
-
jwt.sign(payload, secret, { expiresIn: '5h' }, (err, token) => {
|
|
21
|
-
if (err || !token) return res.status(500).json({ message: 'Failed to sign token' });
|
|
22
|
-
return res.status(201).json({ token });
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Register
|
|
12
|
+
// @desc Register a new user
|
|
27
13
|
export const registerUser = async (req: Request, res: Response) => {
|
|
28
|
-
const { name, email, password } = req.body
|
|
14
|
+
const { name, email, password } = req.body;
|
|
29
15
|
|
|
30
16
|
try {
|
|
31
|
-
if (
|
|
32
|
-
|
|
17
|
+
<% if (dbType === 'mongoose') { %>
|
|
18
|
+
// Mongoose Logic
|
|
19
|
+
let user = await User.findOne({ email });
|
|
20
|
+
if (user) {
|
|
21
|
+
return res.status(400).json({ message: 'User already exists' });
|
|
33
22
|
}
|
|
34
|
-
|
|
35
|
-
<% if (dbType === 'mongoose') { -%>
|
|
36
|
-
const existing = await User.findOne({ email });
|
|
37
|
-
if (existing) return res.status(400).json({ message: 'User already exists' });
|
|
38
|
-
|
|
39
|
-
const user = new User({ name, email, password }); // password will be hashed by pre-save hook
|
|
23
|
+
user = new User({ name, email, password });
|
|
40
24
|
await user.save();
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
|
|
25
|
+
<% } else if (dbType === 'prisma') { %>
|
|
26
|
+
// Prisma Logic
|
|
27
|
+
const existingUser = await prisma.user.findUnique({ where: { email } });
|
|
28
|
+
if (existingUser) {
|
|
29
|
+
return res.status(400).json({ message: 'User already exists' });
|
|
30
|
+
}
|
|
46
31
|
const hashedPassword = await bcrypt.hash(password, 10);
|
|
47
|
-
const user = await prisma.user.create({
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
32
|
+
const user = await prisma.user.create({
|
|
33
|
+
data: { name, email, password: hashedPassword },
|
|
34
|
+
});
|
|
35
|
+
<% } %>
|
|
36
|
+
|
|
37
|
+
const payload = { user: { id: user.id } };
|
|
38
|
+
jwt.sign(
|
|
39
|
+
payload,
|
|
40
|
+
process.env.JWT_SECRET as string,
|
|
41
|
+
{ expiresIn: '5h' },
|
|
42
|
+
(err, token) => {
|
|
43
|
+
if (err) throw err;
|
|
44
|
+
res.status(201).json({ token });
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error(error);
|
|
49
|
+
res.status(500).send('Server Error');
|
|
52
50
|
}
|
|
53
51
|
};
|
|
54
52
|
|
|
55
|
-
// Login
|
|
53
|
+
// @desc Authenticate user & get token (Login)
|
|
56
54
|
export const loginUser = async (req: Request, res: Response) => {
|
|
57
|
-
const { email, password } = req.body
|
|
55
|
+
const { email, password } = req.body;
|
|
58
56
|
|
|
59
57
|
try {
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
<% if (dbType === 'mongoose') { -%>
|
|
58
|
+
<% if (dbType === 'mongoose') { %>
|
|
59
|
+
// Mongoose Logic
|
|
65
60
|
const user = await User.findOne({ email });
|
|
66
|
-
<% } else if (dbType === 'prisma') {
|
|
61
|
+
<% } else if (dbType === 'prisma') { %>
|
|
62
|
+
// Prisma Logic
|
|
67
63
|
const user = await prisma.user.findUnique({ where: { email } });
|
|
68
|
-
<% }
|
|
64
|
+
<% } %>
|
|
69
65
|
|
|
70
|
-
if (!user)
|
|
66
|
+
if (!user) {
|
|
67
|
+
return res.status(400).json({ message: 'Invalid Credentials' });
|
|
68
|
+
}
|
|
71
69
|
|
|
72
70
|
const isMatch = await bcrypt.compare(password, user.password);
|
|
73
|
-
if (!isMatch)
|
|
71
|
+
if (!isMatch) {
|
|
72
|
+
return res.status(400).json({ message: 'Invalid Credentials' });
|
|
73
|
+
}
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
const payload = { user: { id: user.id } };
|
|
76
|
+
jwt.sign(
|
|
77
|
+
payload,
|
|
78
|
+
process.env.JWT_SECRET as string,
|
|
79
|
+
{ expiresIn: '5h' },
|
|
80
|
+
(err, token) => {
|
|
81
|
+
if (err) throw err;
|
|
82
|
+
res.json({ token });
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error(error);
|
|
87
|
+
res.status(500).send('Server Error');
|
|
82
88
|
}
|
|
83
89
|
};
|
|
@@ -1,38 +1,27 @@
|
|
|
1
|
-
// Auto-generated by create-backlist
|
|
1
|
+
// Auto-generated by create-backlist v3.0 on <%= new Date().toISOString() %>
|
|
2
2
|
import { Request, Response, NextFunction } from 'express';
|
|
3
3
|
import jwt from 'jsonwebtoken';
|
|
4
4
|
|
|
5
|
+
// Extend the default Request interface to include our 'user' property
|
|
5
6
|
interface AuthRequest extends Request {
|
|
6
7
|
user?: any;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export const protect = (req: AuthRequest, res: Response, next: NextFunction) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// Support both:
|
|
14
|
-
// 1) Authorization: Bearer <token>
|
|
15
|
-
// 2) x-auth-token: <token>
|
|
16
|
-
const authHeader = req.header('authorization');
|
|
17
|
-
const xToken = req.header('x-auth-token');
|
|
18
|
-
|
|
19
|
-
let token: string | undefined;
|
|
20
|
-
|
|
21
|
-
if (authHeader && authHeader.toLowerCase().startsWith('bearer ')) {
|
|
22
|
-
token = authHeader.slice(7).trim();
|
|
23
|
-
} else if (xToken) {
|
|
24
|
-
token = xToken.trim();
|
|
25
|
-
}
|
|
11
|
+
// Get token from header
|
|
12
|
+
const token = req.header('x-auth-token');
|
|
26
13
|
|
|
14
|
+
// Check if not token
|
|
27
15
|
if (!token) {
|
|
28
16
|
return res.status(401).json({ message: 'No token, authorization denied' });
|
|
29
17
|
}
|
|
30
18
|
|
|
19
|
+
// Verify token
|
|
31
20
|
try {
|
|
32
|
-
const decoded
|
|
21
|
+
const decoded = jwt.verify(token, process.env.JWT_SECRET as string);
|
|
33
22
|
req.user = decoded.user;
|
|
34
|
-
|
|
35
|
-
} catch {
|
|
36
|
-
|
|
23
|
+
next();
|
|
24
|
+
} catch (err) {
|
|
25
|
+
res.status(401).json({ message: 'Token is not valid' });
|
|
37
26
|
}
|
|
38
27
|
};
|
|
@@ -1,50 +1,50 @@
|
|
|
1
1
|
// Auto-generated by create-backlist on <%= new Date().toISOString() %>
|
|
2
2
|
import { Request, Response } from 'express';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return String(name).replace(/[^a-zA-Z0-9_]/g, '');
|
|
13
|
-
}
|
|
4
|
+
export const create<%= modelName %> = async (req: Request, res: Response) => {
|
|
5
|
+
try {
|
|
6
|
+
// TODO: implement create logic
|
|
7
|
+
res.status(201).json({ message: '<%= modelName %> created', data: req.body });
|
|
8
|
+
} catch (error) {
|
|
9
|
+
res.status(500).json({ message: 'Error creating <%= modelName %>', error });
|
|
10
|
+
}
|
|
11
|
+
};
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
export const getAll<%= modelName %>s = async (_req: Request, res: Response) => {
|
|
14
|
+
try {
|
|
15
|
+
// TODO: implement list logic
|
|
16
|
+
res.status(200).json([]);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
res.status(500).json({ message: 'Error fetching <%= modelName %>s', error });
|
|
19
|
+
}
|
|
20
|
+
};
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
export const get<%= modelName %>ById = async (req: Request, res: Response) => {
|
|
23
|
+
try {
|
|
24
|
+
const { id } = req.params;
|
|
25
|
+
// TODO: implement get by id logic
|
|
26
|
+
res.status(200).json({ id });
|
|
27
|
+
} catch (error) {
|
|
28
|
+
res.status(500).json({ message: 'Error fetching <%= modelName %>', error });
|
|
29
|
+
}
|
|
30
|
+
};
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
const method = String(ep.method || 'GET').toUpperCase();
|
|
29
|
-
const actionName = safeAction(ep.actionName, `handler${i}`);
|
|
30
|
-
const route = ep.route || ep.path || '';
|
|
31
|
-
-%>
|
|
32
|
-
/**
|
|
33
|
-
* <%= method %> <%= route %>
|
|
34
|
-
*/
|
|
35
|
-
export async function <%= actionName %>(req: Request, res: Response) {
|
|
32
|
+
export const update<%= modelName %>ById = async (req: Request, res: Response) => {
|
|
36
33
|
try {
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
const payload = req.body;
|
|
41
|
-
return res.status(<%= method === 'POST' ? 201 : 200 %>).json({ message: 'TODO: implement', payload });
|
|
42
|
-
<% } else { -%>
|
|
43
|
-
return res.status(200).json({ message: 'TODO: implement', params: req.params, query: req.query });
|
|
44
|
-
<% } -%>
|
|
34
|
+
const { id } = req.params;
|
|
35
|
+
// TODO: implement update logic
|
|
36
|
+
res.status(200).json({ id, ...req.body });
|
|
45
37
|
} catch (error) {
|
|
46
|
-
|
|
38
|
+
res.status(500).json({ message: 'Error updating <%= modelName %>', error });
|
|
47
39
|
}
|
|
48
|
-
}
|
|
40
|
+
};
|
|
49
41
|
|
|
50
|
-
|
|
42
|
+
export const delete<%= modelName %>ById = async (req: Request, res: Response) => {
|
|
43
|
+
try {
|
|
44
|
+
const { id } = req.params;
|
|
45
|
+
// TODO: implement delete logic
|
|
46
|
+
res.status(204).send();
|
|
47
|
+
} catch (error) {
|
|
48
|
+
res.status(500).json({ message: 'Error deleting <%= modelName %>', error });
|
|
49
|
+
}
|
|
50
|
+
};
|
|
@@ -8,8 +8,8 @@ namespace <%= projectName %>.Data
|
|
|
8
8
|
{
|
|
9
9
|
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
|
|
10
10
|
|
|
11
|
-
<% modelsToGenerate.forEach(model => {
|
|
12
|
-
public DbSet<<%= model.name %>> <%= model.name %> { get; set; }
|
|
13
|
-
<% });
|
|
11
|
+
<% modelsToGenerate.forEach(model => { %>
|
|
12
|
+
public DbSet<<%= model.name %>> <%= model.name %>s { get; set; }
|
|
13
|
+
<% }); %>
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -1,31 +1,33 @@
|
|
|
1
|
-
# Auto-generated by create-backlist v5.
|
|
1
|
+
# Auto-generated by create-backlist v5.0
|
|
2
2
|
|
|
3
|
+
# ---- Base Stage ----
|
|
3
4
|
FROM node:18-alpine AS base
|
|
4
5
|
WORKDIR /usr/src/app
|
|
5
6
|
COPY package*.json ./
|
|
6
7
|
|
|
8
|
+
# ---- Dependencies Stage ----
|
|
7
9
|
FROM base AS dependencies
|
|
8
|
-
|
|
9
|
-
RUN npm ci
|
|
10
|
+
RUN npm install --frozen-lockfile
|
|
10
11
|
|
|
12
|
+
# ---- Build Stage ----
|
|
11
13
|
FROM base AS build
|
|
12
14
|
COPY --from=dependencies /usr/src/app/node_modules ./node_modules
|
|
13
15
|
COPY . .
|
|
14
|
-
<% if (dbType === 'prisma') {
|
|
16
|
+
<% if (dbType === 'prisma') { %>
|
|
15
17
|
RUN npx prisma generate
|
|
16
|
-
<% }
|
|
18
|
+
<% } %>
|
|
17
19
|
RUN npm run build
|
|
18
20
|
|
|
21
|
+
# ---- Production Stage ----
|
|
19
22
|
FROM node:18-alpine AS production
|
|
20
23
|
WORKDIR /usr/src/app
|
|
21
|
-
ENV NODE_ENV=production
|
|
22
|
-
|
|
23
24
|
COPY --from=build /usr/src/app/dist ./dist
|
|
24
25
|
COPY --from=dependencies /usr/src/app/node_modules ./node_modules
|
|
25
26
|
COPY package*.json ./
|
|
26
|
-
<% if (dbType === 'prisma') {
|
|
27
|
+
<% if (dbType === 'prisma') { %>
|
|
28
|
+
# Copy Prisma schema for runtime
|
|
27
29
|
COPY prisma ./prisma
|
|
28
|
-
<% }
|
|
30
|
+
<% } %>
|
|
29
31
|
|
|
30
32
|
EXPOSE <%= port %>
|
|
31
33
|
CMD ["node", "dist/server.js"]
|
|
@@ -1,34 +1,16 @@
|
|
|
1
1
|
// Auto-generated by create-backlist
|
|
2
|
-
using System;
|
|
3
|
-
|
|
4
2
|
namespace <%= projectName %>.Models
|
|
5
3
|
{
|
|
6
4
|
public class <%= modelName %>
|
|
7
5
|
{
|
|
8
|
-
public Guid Id { get; set; }
|
|
9
|
-
|
|
10
|
-
<%
|
|
11
|
-
function pascal(s){
|
|
12
|
-
return String(s || '')
|
|
13
|
-
.replace(/[-_]+(.)/g, (_,c)=>c.toUpperCase())
|
|
14
|
-
.replace(/^\w/, c => c.toUpperCase())
|
|
15
|
-
.replace(/[^a-zA-Z0-9]/g,'');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function mapType(t){
|
|
19
|
-
if (!t) return "string";
|
|
20
|
-
const x = String(t).toLowerCase();
|
|
21
|
-
if (x === 'number' || x === 'int' || x === 'integer') return "int";
|
|
22
|
-
if (x === 'float' || x === 'double') return "double";
|
|
23
|
-
if (x === 'boolean' || x === 'bool') return "bool";
|
|
24
|
-
if (x === 'date' || x === 'datetime') return "DateTime";
|
|
25
|
-
return "string";
|
|
26
|
-
}
|
|
27
|
-
-%>
|
|
6
|
+
public Guid Id { get; set; }
|
|
28
7
|
|
|
29
|
-
<%
|
|
30
|
-
|
|
31
|
-
<%
|
|
8
|
+
<% model.fields.forEach(field => { %>
|
|
9
|
+
<% let csharpType = 'string'; %>
|
|
10
|
+
<% if (field.type === 'Number') csharpType = 'int'; %>
|
|
11
|
+
<% if (field.type === 'Boolean') csharpType = 'bool'; %>
|
|
12
|
+
public <%= csharpType %> <%= field.name %> { get; set; }
|
|
13
|
+
<% }); %>
|
|
32
14
|
|
|
33
15
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
34
16
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
|
@@ -1,30 +1,22 @@
|
|
|
1
1
|
// Auto-generated by create-backlist on <%= new Date().toISOString() %>
|
|
2
2
|
import mongoose, { Schema, Document } from 'mongoose';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
// Define the interface for the Document
|
|
6
5
|
export interface I<%= modelName %> extends Document {
|
|
7
|
-
<% Object.keys(schema).forEach(key => {
|
|
8
|
-
|
|
9
|
-
const tsType = (t === 'number') ? 'number' : (t === 'boolean') ? 'boolean' : 'string';
|
|
10
|
-
-%>
|
|
11
|
-
<%= key %>: <%= tsType %>;
|
|
6
|
+
<% Object.keys(schema).forEach(key => { %>
|
|
7
|
+
<%= key %>: <%= schema[key].toLowerCase() %>;
|
|
12
8
|
<% }); %>
|
|
13
9
|
}
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<% Object.keys(schema).forEach(key => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<%= key %>: {
|
|
22
|
-
type: <%= mongoType %>,
|
|
23
|
-
required: false,
|
|
24
|
-
},
|
|
25
|
-
<% }); %>
|
|
11
|
+
// Define the Mongoose Schema
|
|
12
|
+
const <%= modelName %>Schema: Schema = new Schema({
|
|
13
|
+
<% Object.keys(schema).forEach(key => { %>
|
|
14
|
+
<%= key %>: {
|
|
15
|
+
type: <%= schema[key] %>,
|
|
16
|
+
// TODO: Add 'required', 'unique', etc. here
|
|
26
17
|
},
|
|
27
|
-
|
|
28
|
-
);
|
|
18
|
+
<% }); %>
|
|
19
|
+
}, { timestamps: true });
|
|
29
20
|
|
|
21
|
+
// Create and export the Model
|
|
30
22
|
export default mongoose.model<I<%= modelName %>>('<%= modelName %>', <%= modelName %>Schema);
|
|
@@ -1,83 +1,66 @@
|
|
|
1
|
-
// Auto-generated by create-backlist v5.
|
|
1
|
+
// Auto-generated by create-backlist v5.0 (Prisma Version)
|
|
2
2
|
import { Request, Response } from 'express';
|
|
3
|
-
import { prisma } from '../
|
|
3
|
+
import { prisma } from '../server'; // Import the Prisma client instance
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const m = String(method || 'GET').toUpperCase();
|
|
17
|
-
return ['POST', 'PUT', 'PATCH'].includes(m);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// prisma client accessor name. Usually lowerCamelCase in prisma client.
|
|
21
|
-
const prismaAccessor = controllerName.charAt(0).toLowerCase() + controllerName.slice(1);
|
|
22
|
-
%>
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Prisma model: <%= controllerName %> (client: prisma.<%= prismaAccessor %>)
|
|
26
|
-
* NOTE: If your prisma model name differs, adjust mapping in generator.
|
|
27
|
-
*/
|
|
5
|
+
// @desc Create a new <%= modelName %>
|
|
6
|
+
export const create<%= modelName %> = async (req: Request, res: Response) => {
|
|
7
|
+
try {
|
|
8
|
+
const newDoc = await prisma.<%= modelName.toLowerCase() %>.create({
|
|
9
|
+
data: req.body,
|
|
10
|
+
});
|
|
11
|
+
res.status(201).json(newDoc);
|
|
12
|
+
} catch (error) {
|
|
13
|
+
res.status(500).json({ message: 'Error creating document', error });
|
|
14
|
+
}
|
|
15
|
+
};
|
|
28
16
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const actionName = safeAction(ep.actionName, `handler${i}`);
|
|
32
|
-
const route = (ep.route || ep.path || '').replace(/^\/api/, '');
|
|
33
|
-
const usesId = hasIdInRoute(route);
|
|
34
|
-
-%>
|
|
35
|
-
/**
|
|
36
|
-
* <%= method %> <%= ep.route || ep.path || '' %>
|
|
37
|
-
*/
|
|
38
|
-
export async function <%= actionName %>(req: Request, res: Response) {
|
|
17
|
+
// @desc Get all <%= modelName %>s
|
|
18
|
+
export const getAll<%= modelName %>s = async (req: Request, res: Response) => {
|
|
39
19
|
try {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<% } else if (method === 'GET' && usesId) { -%>
|
|
47
|
-
const idRaw = req.params.id;
|
|
48
|
-
// Try number first; fallback to string
|
|
49
|
-
const id: any = (idRaw !== undefined && idRaw !== null && String(Number(idRaw)) === idRaw) ? Number(idRaw) : idRaw;
|
|
20
|
+
const docs = await prisma.<%= modelName.toLowerCase() %>.findMany();
|
|
21
|
+
res.status(200).json(docs);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
res.status(500).json({ message: 'Error fetching documents', error });
|
|
24
|
+
}
|
|
25
|
+
};
|
|
50
26
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
27
|
+
// @desc Get a single <%= modelName %> by ID
|
|
28
|
+
export const get<%= modelName %>ById = async (req: Request, res: Response) => {
|
|
29
|
+
try {
|
|
30
|
+
const { id } = req.params;
|
|
31
|
+
const doc = await prisma.<%= modelName.toLowerCase() %>.findUnique({
|
|
32
|
+
where: { id },
|
|
33
|
+
});
|
|
34
|
+
if (!doc) return res.status(404).json({ message: 'Document not found' });
|
|
35
|
+
res.status(200).json(doc);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
res.status(500).json({ message: 'Error fetching document', error });
|
|
38
|
+
}
|
|
39
|
+
};
|
|
57
40
|
|
|
58
|
-
|
|
41
|
+
// @desc Update a <%= modelName %> by ID
|
|
42
|
+
export const update<%= modelName %>ById = async (req: Request, res: Response) => {
|
|
43
|
+
try {
|
|
44
|
+
const { id } = req.params;
|
|
45
|
+
const doc = await prisma.<%= modelName.toLowerCase() %>.update({
|
|
59
46
|
where: { id },
|
|
60
47
|
data: req.body,
|
|
61
48
|
});
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const id: any = (idRaw !== undefined && idRaw !== null && String(Number(idRaw)) === idRaw) ? Number(idRaw) : idRaw;
|
|
66
|
-
|
|
67
|
-
await prisma.<%= prismaAccessor %>.delete({ where: { id } });
|
|
68
|
-
return res.status(200).json({ message: 'Deleted' });
|
|
69
|
-
<% } else { -%>
|
|
70
|
-
// Non-CRUD or route not matching the default patterns
|
|
71
|
-
// TODO: implement custom logic (query params, nested routes, etc.)
|
|
72
|
-
<% if (hasBody(method)) { -%>
|
|
73
|
-
return res.status(200).json({ message: 'TODO: implement', body: req.body, params: req.params, query: req.query });
|
|
74
|
-
<% } else { -%>
|
|
75
|
-
return res.status(200).json({ message: 'TODO: implement', params: req.params, query: req.query });
|
|
76
|
-
<% } -%>
|
|
77
|
-
<% } -%>
|
|
78
|
-
} catch (error: any) {
|
|
79
|
-
return res.status(500).json({ message: 'Internal Server Error', error: error?.message || error });
|
|
49
|
+
res.status(200).json(doc);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
res.status(500).json({ message: 'Error updating document', error });
|
|
80
52
|
}
|
|
81
|
-
}
|
|
53
|
+
};
|
|
82
54
|
|
|
83
|
-
|
|
55
|
+
// @desc Delete a <%= modelName %> by ID
|
|
56
|
+
export const delete<%= modelName %>ById = async (req: Request, res: Response) => {
|
|
57
|
+
try {
|
|
58
|
+
const { id } = req.params;
|
|
59
|
+
await prisma.<%= modelName.toLowerCase() %>.delete({
|
|
60
|
+
where: { id },
|
|
61
|
+
});
|
|
62
|
+
res.status(200).json({ message: 'Document deleted successfully' });
|
|
63
|
+
} catch (error) {
|
|
64
|
+
res.status(500).json({ message: 'Error deleting document', error });
|
|
65
|
+
}
|
|
66
|
+
};
|
|
@@ -1,41 +1,26 @@
|
|
|
1
|
-
// Auto-generated by create-backlist v5.
|
|
1
|
+
// Auto-generated by create-backlist v5.0
|
|
2
2
|
|
|
3
3
|
generator client {
|
|
4
4
|
provider = "prisma-client-js"
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
datasource db {
|
|
8
|
-
provider = "postgresql"
|
|
8
|
+
provider = "postgresql" // User can change to "mysql", "sqlite", "sqlserver", etc.
|
|
9
9
|
url = env("DATABASE_URL")
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
function mapPrismaType(t) {
|
|
14
|
-
const x = String(t || '').toLowerCase();
|
|
15
|
-
if (x === 'number' || x === 'int' || x === 'integer') return 'Int';
|
|
16
|
-
if (x === 'float' || x === 'double') return 'Float';
|
|
17
|
-
if (x === 'boolean' || x === 'bool') return 'Boolean';
|
|
18
|
-
if (x === 'date' || x === 'datetime') return 'DateTime';
|
|
19
|
-
return 'String';
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function safeName(n) {
|
|
23
|
-
return String(n || '').replace(/[^a-zA-Z0-9_]/g, '');
|
|
24
|
-
}
|
|
25
|
-
%>
|
|
26
|
-
|
|
12
|
+
<%# Loop through each model identified by the analyzer %>
|
|
27
13
|
<% modelsToGenerate.forEach(model => { %>
|
|
28
|
-
model <%=
|
|
14
|
+
model <%= model.name %> {
|
|
29
15
|
id String @id @default(cuid())
|
|
30
|
-
|
|
31
|
-
<%
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
<% }); -%>
|
|
16
|
+
<%# Loop through each field in the model %>
|
|
17
|
+
<% model.fields.forEach(field => { %>
|
|
18
|
+
<%# Map JS types to Prisma types. This is a basic mapping. %>
|
|
19
|
+
<% let prismaType = 'String'; %>
|
|
20
|
+
<% if (field.type === 'Number') prismaType = 'Int'; %>
|
|
21
|
+
<% if (field.type === 'Boolean') prismaType = 'Boolean'; %>
|
|
22
|
+
<%= field.name.padEnd(10) %> <%= prismaType %><%- field.isOptional ? '?' : '' %><%- field.isUnique ? ' @unique' : '' %>
|
|
23
|
+
<% }); %>
|
|
39
24
|
|
|
40
25
|
createdAt DateTime @default(now())
|
|
41
26
|
updatedAt DateTime @updatedAt
|
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
This backend was auto-generated by **Backlist**.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
## 🚀 Getting Started
|
|
6
|
+
|
|
7
|
+
1. **Navigate to the directory:**
|
|
8
|
+
```bash
|
|
9
|
+
cd <%= projectName %>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. **Run the development server:**
|
|
13
|
+
```bash
|
|
14
|
+
npm run dev
|
|
15
|
+
```
|
|
16
|
+
The server will start on `http://localhost:8000`.
|