elysia-crud-plugin 0.1.0
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/README.md +204 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +136 -0
- package/dist/index.js.map +10 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Elysia CRUD Plugin
|
|
2
|
+
|
|
3
|
+
Generate REST endpoints for your Drizzle tables without writing boilerplate. Inspired by Django Rest Framework's simplicity, this plugin creates full CRUD operations from your table definitions.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
Pass a Drizzle table to the `crud` function, and you get five REST endpoints:
|
|
8
|
+
|
|
9
|
+
- `GET /{tableName}` - List all records
|
|
10
|
+
- `GET /{tableName}/:id` - Get one record
|
|
11
|
+
- `POST /{tableName}` - Create a record
|
|
12
|
+
- `PUT /{tableName}/:id` - Update a record
|
|
13
|
+
- `DELETE /{tableName}/:id` - Delete a record
|
|
14
|
+
|
|
15
|
+
The plugin automatically detects your primary key, handles errors, and returns appropriate HTTP status codes.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bun add elysia-crud-plugin
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
You also need Elysia and Drizzle ORM:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun add elysia drizzle-orm
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { Elysia } from "elysia";
|
|
33
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
34
|
+
import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core";
|
|
35
|
+
import { Database } from "bun:sqlite";
|
|
36
|
+
import { crud } from "elysia-crud-plugin";
|
|
37
|
+
|
|
38
|
+
// Define your table
|
|
39
|
+
const users = sqliteTable("users", {
|
|
40
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
41
|
+
name: text("name").notNull(),
|
|
42
|
+
email: text("email").notNull(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Set up database
|
|
46
|
+
const sqlite = new Database("example.db");
|
|
47
|
+
const db = drizzle(sqlite);
|
|
48
|
+
|
|
49
|
+
// Create your app
|
|
50
|
+
const app = new Elysia().decorate("db", db).use(crud(users)).listen(3000);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
That's it. You now have working CRUD endpoints for users.
|
|
54
|
+
|
|
55
|
+
## How it works
|
|
56
|
+
|
|
57
|
+
The plugin reads your Drizzle table definition to:
|
|
58
|
+
|
|
59
|
+
1. Extract the table name for route generation
|
|
60
|
+
2. Find the primary key column automatically
|
|
61
|
+
3. Generate type-safe endpoints based on your table schema
|
|
62
|
+
|
|
63
|
+
You don't write route handlers, validation logic, or error handling. The plugin handles it.
|
|
64
|
+
|
|
65
|
+
## Field selection
|
|
66
|
+
|
|
67
|
+
Control which fields appear in responses using the `fields` option:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
app.use(crud(users, { fields: ["id", "name", "email"] }));
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This returns only the specified fields in all responses. Useful for hiding sensitive data like passwords or internal fields.
|
|
74
|
+
|
|
75
|
+
Field selection affects responses only. All fields are still validated on create and update operations.
|
|
76
|
+
|
|
77
|
+
## Database setup
|
|
78
|
+
|
|
79
|
+
The plugin expects a database instance decorated on your Elysia app. Use Elysia's `decorate` method:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const app = new Elysia().decorate("db", db).use(crud(users));
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The plugin works with any database Drizzle supports: SQLite, PostgreSQL, MySQL, and others.
|
|
86
|
+
|
|
87
|
+
## Error handling
|
|
88
|
+
|
|
89
|
+
The plugin handles common errors:
|
|
90
|
+
|
|
91
|
+
- `404 Not Found` - Record doesn't exist (GET, PUT, DELETE by ID)
|
|
92
|
+
- `500 Internal Server Error` - Database not configured or other server errors
|
|
93
|
+
|
|
94
|
+
Error responses include a JSON body with an `error` field:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"error": "Resource not found"
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Limitations
|
|
103
|
+
|
|
104
|
+
The current version focuses on core CRUD operations. It doesn't include:
|
|
105
|
+
|
|
106
|
+
- Pagination for list endpoints
|
|
107
|
+
- Filtering or sorting
|
|
108
|
+
- Query parameter field selection
|
|
109
|
+
- Lifecycle hooks
|
|
110
|
+
- Custom validation beyond Drizzle schema
|
|
111
|
+
|
|
112
|
+
These may be added in future versions. For now, the plugin keeps things simple and focused.
|
|
113
|
+
|
|
114
|
+
## Publishing to npm
|
|
115
|
+
|
|
116
|
+
Para publicar este pacote no npm, siga estes passos:
|
|
117
|
+
|
|
118
|
+
### 1. Preparação
|
|
119
|
+
|
|
120
|
+
Certifique-se de que o `package.json` está configurado corretamente:
|
|
121
|
+
|
|
122
|
+
- Verifique o nome do pacote (deve ser único no npm)
|
|
123
|
+
- Atualize a versão seguindo [Semantic Versioning](https://semver.org/)
|
|
124
|
+
- Preencha os campos `repository`, `bugs` e `homepage` com a URL do seu repositório
|
|
125
|
+
- Adicione informações do autor
|
|
126
|
+
|
|
127
|
+
### 2. Build
|
|
128
|
+
|
|
129
|
+
Compile o código TypeScript:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
bun run build
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Isso irá:
|
|
136
|
+
|
|
137
|
+
- Compilar o código para `dist/index.js`
|
|
138
|
+
- Gerar os arquivos de tipos TypeScript em `dist/index.d.ts`
|
|
139
|
+
|
|
140
|
+
### 3. Teste local (opcional)
|
|
141
|
+
|
|
142
|
+
Antes de publicar, você pode testar o pacote localmente:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
npm pack
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Isso cria um arquivo `.tgz` que você pode instalar em outro projeto para testar.
|
|
149
|
+
|
|
150
|
+
### 4. Login no npm
|
|
151
|
+
|
|
152
|
+
Se ainda não estiver logado:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm login
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Você precisará de:
|
|
159
|
+
|
|
160
|
+
- Nome de usuário do npm
|
|
161
|
+
- Senha
|
|
162
|
+
- Email (para verificação de dois fatores, se habilitado)
|
|
163
|
+
|
|
164
|
+
### 5. Publicar
|
|
165
|
+
|
|
166
|
+
Para publicar o pacote:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
npm publish
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Se o nome do pacote for scoped (começa com `@`), você precisará torná-lo público:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npm publish --access public
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 6. Verificar publicação
|
|
179
|
+
|
|
180
|
+
Após publicar, verifique se o pacote está disponível:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
npm view elysia-crud-plugin
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Ou visite: `https://www.npmjs.com/package/elysia-crud-plugin`
|
|
187
|
+
|
|
188
|
+
### Atualizando versões
|
|
189
|
+
|
|
190
|
+
Para atualizar o pacote:
|
|
191
|
+
|
|
192
|
+
1. Atualize a versão no `package.json` (ex: `0.1.0` → `0.1.1`)
|
|
193
|
+
2. Execute `bun run build`
|
|
194
|
+
3. Execute `npm publish`
|
|
195
|
+
|
|
196
|
+
Você também pode usar `npm version` para atualizar a versão automaticamente:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
npm version patch # 0.1.0 → 0.1.1
|
|
200
|
+
npm version minor # 0.1.0 → 0.2.0
|
|
201
|
+
npm version major # 0.1.0 → 1.0.0
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Isso atualiza o `package.json` e cria uma tag git automaticamente.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import { Table } from 'drizzle-orm';
|
|
3
|
+
type ColumnNames<TTable extends Table> = keyof TTable['_']['columns'] & string;
|
|
4
|
+
interface CrudOptions<TTable extends Table> {
|
|
5
|
+
fields?: ColumnNames<TTable>[];
|
|
6
|
+
}
|
|
7
|
+
export declare function crud<TTable extends Table>(table: TTable, options?: CrudOptions<TTable>): Elysia<"", {
|
|
8
|
+
decorator: {};
|
|
9
|
+
store: {};
|
|
10
|
+
derive: {};
|
|
11
|
+
resolve: {};
|
|
12
|
+
}, {
|
|
13
|
+
typebox: {};
|
|
14
|
+
error: {};
|
|
15
|
+
}, {
|
|
16
|
+
schema: {};
|
|
17
|
+
standaloneSchema: {};
|
|
18
|
+
macro: {};
|
|
19
|
+
macroFn: {};
|
|
20
|
+
parser: {};
|
|
21
|
+
response: {};
|
|
22
|
+
}, {}, {
|
|
23
|
+
derive: {};
|
|
24
|
+
resolve: {};
|
|
25
|
+
schema: {};
|
|
26
|
+
standaloneSchema: {};
|
|
27
|
+
response: {};
|
|
28
|
+
}, {
|
|
29
|
+
derive: {};
|
|
30
|
+
resolve: {};
|
|
31
|
+
schema: {};
|
|
32
|
+
standaloneSchema: {};
|
|
33
|
+
response: {
|
|
34
|
+
[x: number]: number;
|
|
35
|
+
200: Readonly<Error> | {
|
|
36
|
+
error: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
}>;
|
|
40
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/index.ts
|
|
3
|
+
import { Elysia, NotFoundError, InternalServerError } from "elysia";
|
|
4
|
+
import { getTableColumns, getTableName } from "drizzle-orm";
|
|
5
|
+
import { eq } from "drizzle-orm";
|
|
6
|
+
function getPrimaryKeyColumn(table) {
|
|
7
|
+
const columns = getTableColumns(table);
|
|
8
|
+
for (const [name, column] of Object.entries(columns)) {
|
|
9
|
+
if (column.primary) {
|
|
10
|
+
return { name, column };
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
throw new Error(`Table "${getTableName(table)}" must have a primary key column. ` + `Use .primaryKey() on a column or define a composite primary key.`);
|
|
14
|
+
}
|
|
15
|
+
function crud(table, options) {
|
|
16
|
+
const tableName = getTableName(table);
|
|
17
|
+
const { name: primaryKeyField, column: primaryKeyColumn } = getPrimaryKeyColumn(table);
|
|
18
|
+
const columns = getTableColumns(table);
|
|
19
|
+
const app = new Elysia().onError(({ code, error, set }) => {
|
|
20
|
+
if (code === "NOT_FOUND") {
|
|
21
|
+
set.status = 404;
|
|
22
|
+
return { error: error.message };
|
|
23
|
+
}
|
|
24
|
+
if (code === "INTERNAL_SERVER_ERROR") {
|
|
25
|
+
set.status = 500;
|
|
26
|
+
return { error: error.message };
|
|
27
|
+
}
|
|
28
|
+
return error;
|
|
29
|
+
});
|
|
30
|
+
app.get(`/${tableName}`, async ({ db }) => {
|
|
31
|
+
if (!db) {
|
|
32
|
+
throw new InternalServerError("Database not configured");
|
|
33
|
+
}
|
|
34
|
+
if (options?.fields) {
|
|
35
|
+
const selectedColumns = {};
|
|
36
|
+
for (const fieldName of options.fields) {
|
|
37
|
+
selectedColumns[fieldName] = columns[fieldName];
|
|
38
|
+
}
|
|
39
|
+
return await db.select(selectedColumns).from(table);
|
|
40
|
+
}
|
|
41
|
+
return await db.select().from(table);
|
|
42
|
+
});
|
|
43
|
+
app.get(`/${tableName}/:id`, async ({ db, params }) => {
|
|
44
|
+
if (!db) {
|
|
45
|
+
throw new InternalServerError("Database not configured");
|
|
46
|
+
}
|
|
47
|
+
let resources;
|
|
48
|
+
if (options?.fields) {
|
|
49
|
+
const selectedColumns = {};
|
|
50
|
+
for (const fieldName of options.fields) {
|
|
51
|
+
selectedColumns[fieldName] = columns[fieldName];
|
|
52
|
+
}
|
|
53
|
+
resources = await db.select(selectedColumns).from(table).where(eq(primaryKeyColumn, params.id)).limit(1);
|
|
54
|
+
} else {
|
|
55
|
+
resources = await db.select().from(table).where(eq(primaryKeyColumn, params.id)).limit(1);
|
|
56
|
+
}
|
|
57
|
+
if (resources.length === 0) {
|
|
58
|
+
throw new NotFoundError("Resource not found");
|
|
59
|
+
}
|
|
60
|
+
return resources[0];
|
|
61
|
+
});
|
|
62
|
+
app.post(`/${tableName}`, async ({ db, body, set }) => {
|
|
63
|
+
if (!db) {
|
|
64
|
+
throw new InternalServerError("Database not configured");
|
|
65
|
+
}
|
|
66
|
+
const { [primaryKeyField]: _ignoredId, ...dataWithoutId } = body;
|
|
67
|
+
let dataToInsert = dataWithoutId;
|
|
68
|
+
if (options?.fields) {
|
|
69
|
+
dataToInsert = {};
|
|
70
|
+
for (const fieldName of options.fields) {
|
|
71
|
+
if (fieldName !== primaryKeyField && fieldName in dataWithoutId) {
|
|
72
|
+
dataToInsert[fieldName] = dataWithoutId[fieldName];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const result = await db.insert(table).values(dataToInsert).returning();
|
|
77
|
+
set.status = 201;
|
|
78
|
+
return result[0];
|
|
79
|
+
});
|
|
80
|
+
app.put(`/${tableName}/:id`, async ({ db, params, body }) => {
|
|
81
|
+
if (!db) {
|
|
82
|
+
throw new InternalServerError("Database not configured");
|
|
83
|
+
}
|
|
84
|
+
let existing;
|
|
85
|
+
if (options?.fields) {
|
|
86
|
+
const selectedColumns = {};
|
|
87
|
+
for (const fieldName of options.fields) {
|
|
88
|
+
selectedColumns[fieldName] = columns[fieldName];
|
|
89
|
+
}
|
|
90
|
+
existing = await db.select(selectedColumns).from(table).where(eq(primaryKeyColumn, params.id)).limit(1);
|
|
91
|
+
} else {
|
|
92
|
+
existing = await db.select().from(table).where(eq(primaryKeyColumn, params.id)).limit(1);
|
|
93
|
+
}
|
|
94
|
+
if (existing.length === 0) {
|
|
95
|
+
throw new NotFoundError("Resource not found");
|
|
96
|
+
}
|
|
97
|
+
const { [primaryKeyField]: _ignoredId, ...dataWithoutId } = body;
|
|
98
|
+
let dataToUpdate = dataWithoutId;
|
|
99
|
+
if (options?.fields) {
|
|
100
|
+
dataToUpdate = {};
|
|
101
|
+
for (const fieldName of options.fields) {
|
|
102
|
+
if (fieldName !== primaryKeyField && fieldName in dataWithoutId) {
|
|
103
|
+
dataToUpdate[fieldName] = dataWithoutId[fieldName];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const result = await db.update(table).set(dataToUpdate).where(eq(primaryKeyColumn, params.id)).returning();
|
|
108
|
+
return result[0];
|
|
109
|
+
});
|
|
110
|
+
app.delete(`/${tableName}/:id`, async ({ db, params, set }) => {
|
|
111
|
+
if (!db) {
|
|
112
|
+
throw new InternalServerError("Database not configured");
|
|
113
|
+
}
|
|
114
|
+
let existing;
|
|
115
|
+
if (options?.fields) {
|
|
116
|
+
const selectedColumns = {};
|
|
117
|
+
for (const fieldName of options.fields) {
|
|
118
|
+
selectedColumns[fieldName] = columns[fieldName];
|
|
119
|
+
}
|
|
120
|
+
existing = await db.select(selectedColumns).from(table).where(eq(primaryKeyColumn, params.id)).limit(1);
|
|
121
|
+
} else {
|
|
122
|
+
existing = await db.select().from(table).where(eq(primaryKeyColumn, params.id)).limit(1);
|
|
123
|
+
}
|
|
124
|
+
if (existing.length === 0) {
|
|
125
|
+
throw new NotFoundError("Resource not found");
|
|
126
|
+
}
|
|
127
|
+
await db.delete(table).where(eq(primaryKeyColumn, params.id));
|
|
128
|
+
set.status = 204;
|
|
129
|
+
});
|
|
130
|
+
return app;
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
crud
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
//# debugId=92D49CB7EB779F4A64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["..\\src\\index.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { Elysia, NotFoundError, InternalServerError } from 'elysia'\nimport { getTableColumns, getTableName, Table } from 'drizzle-orm'\nimport { eq } from 'drizzle-orm'\n\ntype ColumnNames<TTable extends Table> = keyof TTable['_']['columns'] & string\n\ninterface CrudOptions<TTable extends Table> {\n fields?: ColumnNames<TTable>[]\n}\n\nfunction getPrimaryKeyColumn(table: Table) {\n const columns = getTableColumns(table)\n\n for (const [name, column] of Object.entries(columns)) {\n if (column.primary) {\n return { name, column }\n }\n }\n\n throw new Error(\n `Table \"${getTableName(table)}\" must have a primary key column. ` +\n `Use .primaryKey() on a column or define a composite primary key.`\n )\n}\n\nexport function crud<TTable extends Table>(\n table: TTable,\n options?: CrudOptions<TTable>\n) {\n const tableName = getTableName(table)\n const { name: primaryKeyField, column: primaryKeyColumn } = getPrimaryKeyColumn(table)\n const columns = getTableColumns(table)\n\n const app = new Elysia()\n .onError(({ code, error, set }) => {\n if (code === 'NOT_FOUND') {\n set.status = 404\n return { error: error.message }\n }\n\n if (code === 'INTERNAL_SERVER_ERROR') {\n set.status = 500\n return { error: error.message }\n }\n\n return error\n })\n\n app.get(`/${tableName}`, async ({ db }: any) => {\n if (!db) {\n throw new InternalServerError('Database not configured')\n }\n\n if (options?.fields) {\n const selectedColumns: Record<string, any> = {}\n for (const fieldName of options.fields) {\n selectedColumns[fieldName] = columns[fieldName]\n }\n return await db.select(selectedColumns).from(table)\n }\n\n return await db.select().from(table)\n })\n\n app.get(`/${tableName}/:id`, async ({ db, params }: any) => {\n if (!db) {\n throw new InternalServerError('Database not configured')\n }\n\n let resources\n if (options?.fields) {\n const selectedColumns: Record<string, any> = {}\n for (const fieldName of options.fields) {\n selectedColumns[fieldName] = columns[fieldName]\n }\n resources = await db\n .select(selectedColumns)\n .from(table)\n .where(eq(primaryKeyColumn, params.id))\n .limit(1)\n } else {\n resources = await db\n .select()\n .from(table)\n .where(eq(primaryKeyColumn, params.id))\n .limit(1)\n }\n\n if (resources.length === 0) {\n throw new NotFoundError('Resource not found')\n }\n\n return resources[0]\n })\n\n app.post(`/${tableName}`, async ({ db, body, set }: any) => {\n if (!db) {\n throw new InternalServerError('Database not configured')\n }\n\n const { [primaryKeyField]: _ignoredId, ...dataWithoutId } = body\n\n let dataToInsert = dataWithoutId\n if (options?.fields) {\n dataToInsert = {}\n for (const fieldName of options.fields) {\n if (fieldName !== primaryKeyField && fieldName in dataWithoutId) {\n dataToInsert[fieldName] = dataWithoutId[fieldName]\n }\n }\n }\n\n const result = await db.insert(table).values(dataToInsert).returning()\n\n set.status = 201\n return result[0]\n })\n\n app.put(`/${tableName}/:id`, async ({ db, params, body }: any) => {\n if (!db) {\n throw new InternalServerError('Database not configured')\n }\n\n let existing\n if (options?.fields) {\n const selectedColumns: Record<string, any> = {}\n for (const fieldName of options.fields) {\n selectedColumns[fieldName] = columns[fieldName]\n }\n existing = await db\n .select(selectedColumns)\n .from(table)\n .where(eq(primaryKeyColumn, params.id))\n .limit(1)\n } else {\n existing = await db\n .select()\n .from(table)\n .where(eq(primaryKeyColumn, params.id))\n .limit(1)\n }\n\n if (existing.length === 0) {\n throw new NotFoundError('Resource not found')\n }\n\n const { [primaryKeyField]: _ignoredId, ...dataWithoutId } = body\n\n let dataToUpdate = dataWithoutId\n if (options?.fields) {\n dataToUpdate = {}\n for (const fieldName of options.fields) {\n if (fieldName !== primaryKeyField && fieldName in dataWithoutId) {\n dataToUpdate[fieldName] = dataWithoutId[fieldName]\n }\n }\n }\n\n const result = await db\n .update(table)\n .set(dataToUpdate)\n .where(eq(primaryKeyColumn, params.id))\n .returning()\n\n return result[0]\n })\n\n app.delete(`/${tableName}/:id`, async ({ db, params, set }: any) => {\n if (!db) {\n throw new InternalServerError('Database not configured')\n }\n\n let existing\n if (options?.fields) {\n const selectedColumns: Record<string, any> = {}\n for (const fieldName of options.fields) {\n selectedColumns[fieldName] = columns[fieldName]\n }\n existing = await db\n .select(selectedColumns)\n .from(table)\n .where(eq(primaryKeyColumn, params.id))\n .limit(1)\n } else {\n existing = await db\n .select()\n .from(table)\n .where(eq(primaryKeyColumn, params.id))\n .limit(1)\n }\n\n if (existing.length === 0) {\n throw new NotFoundError('Resource not found')\n }\n\n await db.delete(table).where(eq(primaryKeyColumn, params.id))\n\n set.status = 204\n })\n\n return app\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "92D49CB7EB779F4A64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "elysia-crud-plugin",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Generate REST endpoints for your Drizzle tables without writing boilerplate. Inspired by Django Rest Framework's simplicity.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "bun run build.ts",
|
|
22
|
+
"prepublishOnly": "bun run build",
|
|
23
|
+
"test": "bun test"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"elysia",
|
|
27
|
+
"drizzle",
|
|
28
|
+
"drizzle-orm",
|
|
29
|
+
"crud",
|
|
30
|
+
"rest",
|
|
31
|
+
"api",
|
|
32
|
+
"plugin",
|
|
33
|
+
"typescript",
|
|
34
|
+
"bun"
|
|
35
|
+
],
|
|
36
|
+
"author": "Ruan Gustavo",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/ruangustavo/elysia-crud-plugin.git"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/ruangustavo/elysia-crud-plugin/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/ruangustavo/elysia-crud-plugin#readme",
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/bun": "latest",
|
|
48
|
+
"postgres": "^3.4.8",
|
|
49
|
+
"typescript": "^5.0.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"typescript": "^5"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"drizzle-orm": "^0.45.1",
|
|
56
|
+
"elysia": "^1.4.21"
|
|
57
|
+
}
|
|
58
|
+
}
|