create-backlist 6.0.7 → 6.0.9
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 +104 -315
- package/src/generators/dotnet.js +94 -120
- package/src/generators/java.js +109 -157
- package/src/generators/node.js +157 -261
- 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 +5 -17
- package/bin/backlist.js +0 -228
- 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
|
@@ -1,61 +1,38 @@
|
|
|
1
|
-
// Auto-generated by create-backlist v5.
|
|
1
|
+
// Auto-generated by create-backlist v5.0
|
|
2
2
|
import request from 'supertest';
|
|
3
3
|
import express from 'express';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import authRoutes from '../routes/Auth.routes';
|
|
9
|
-
<% } -%>
|
|
4
|
+
// Import your main app configuration. This might need path adjustment.
|
|
5
|
+
// For simplicity, we create a test server here.
|
|
6
|
+
import apiRoutes from '../routes'; // Assuming main routes
|
|
7
|
+
import authRoutes from '../routes/Auth.routes'; // Assuming auth routes
|
|
10
8
|
|
|
11
9
|
const app = express();
|
|
12
10
|
app.use(express.json());
|
|
13
|
-
|
|
14
|
-
<% if (addAuth) { -%>
|
|
11
|
+
app.use('/api', apiRoutes);
|
|
15
12
|
app.use('/api/auth', authRoutes);
|
|
16
|
-
<% } -%>
|
|
17
13
|
|
|
18
|
-
app.use('/api', apiRoutes);
|
|
19
14
|
|
|
20
|
-
describe('API Endpoints
|
|
21
|
-
|
|
15
|
+
describe('API Endpoints', () => {
|
|
16
|
+
|
|
17
|
+
it('should respond to the root GET endpoint', async () => {
|
|
18
|
+
// This test assumes a GET /api/ endpoint exists or a similar public one.
|
|
19
|
+
// You might need to adjust this to a real endpoint from your app.
|
|
20
|
+
// Example for GET /api/users
|
|
21
|
+
// const res = await request(app).get('/api/users');
|
|
22
|
+
// expect(res.statusCode).toEqual(200);
|
|
23
|
+
|
|
24
|
+
// For now, a placeholder test:
|
|
22
25
|
expect(1 + 1).toBe(2);
|
|
23
26
|
});
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// replace ":id" style params with dummy value
|
|
36
|
-
.replace(/:\w+/g, '1');
|
|
37
|
-
-%>
|
|
38
|
-
it('<%= ep.method %> <%= url %> should respond', async () => {
|
|
39
|
-
const req = request(app).<%= method %>('<%= '/api' + url %>');
|
|
40
|
-
|
|
41
|
-
<% if (['post','put','patch'].includes(method) && ep.schemaFields) { -%>
|
|
42
|
-
req.send(
|
|
43
|
-
<%- JSON.stringify(
|
|
44
|
-
Object.fromEntries(
|
|
45
|
-
Object.entries(ep.schemaFields).map(([k, t]) => [
|
|
46
|
-
k,
|
|
47
|
-
t === 'Number' ? 1 : (t === 'Boolean' ? true : 'test')
|
|
48
|
-
])
|
|
49
|
-
)
|
|
50
|
-
) %>
|
|
51
|
-
);
|
|
52
|
-
<% } -%>
|
|
53
|
-
|
|
54
|
-
const res = await req;
|
|
55
|
-
|
|
56
|
-
// We only assert "not 404" because generated handlers may be TODO stubs,
|
|
57
|
-
// and auth/validation may affect exact status codes.
|
|
58
|
-
expect(res.statusCode).not.toBe(404);
|
|
59
|
-
});
|
|
60
|
-
<% }) -%>
|
|
28
|
+
// TODO: Add more specific tests for your generated endpoints
|
|
29
|
+
// describe('POST /api/users', () => {
|
|
30
|
+
// it('should create a new user', async () => {
|
|
31
|
+
// const res = await request(app)
|
|
32
|
+
// .post('/api/users')
|
|
33
|
+
// .send({ name: 'Test User', email: 'test@example.com', password: 'password123' });
|
|
34
|
+
// expect(res.statusCode).toEqual(201);
|
|
35
|
+
// expect(res.body).toHaveProperty('name', 'Test User');
|
|
36
|
+
// });
|
|
37
|
+
// });
|
|
61
38
|
});
|
|
@@ -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
|
+
};
|