bunsane 0.1.0 โ 0.1.2
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/.github/workflows/deploy-docs.yml +57 -0
- package/LICENSE.md +1 -1
- package/README.md +2 -28
- package/TODO.md +8 -1
- package/bun.lock +3 -0
- package/config/upload.config.ts +135 -0
- package/core/App.ts +168 -4
- package/core/ArcheType.ts +122 -0
- package/core/BatchLoader.ts +100 -0
- package/core/ComponentRegistry.ts +4 -3
- package/core/Components.ts +2 -2
- package/core/Decorators.ts +15 -8
- package/core/Entity.ts +193 -14
- package/core/EntityCache.ts +15 -0
- package/core/EntityHookManager.ts +855 -0
- package/core/EntityManager.ts +12 -2
- package/core/ErrorHandler.ts +64 -7
- package/core/FileValidator.ts +284 -0
- package/core/Query.ts +503 -85
- package/core/RequestContext.ts +24 -0
- package/core/RequestLoaders.ts +89 -0
- package/core/SchedulerManager.ts +710 -0
- package/core/UploadManager.ts +261 -0
- package/core/components/UploadComponent.ts +206 -0
- package/core/decorators/EntityHooks.ts +190 -0
- package/core/decorators/ScheduledTask.ts +83 -0
- package/core/events/EntityLifecycleEvents.ts +177 -0
- package/core/processors/ImageProcessor.ts +423 -0
- package/core/storage/LocalStorageProvider.ts +290 -0
- package/core/storage/StorageProvider.ts +112 -0
- package/database/DatabaseHelper.ts +183 -58
- package/database/index.ts +5 -5
- package/database/sqlHelpers.ts +7 -0
- package/docs/README.md +149 -0
- package/docs/_coverpage.md +36 -0
- package/docs/_sidebar.md +23 -0
- package/docs/api/core.md +568 -0
- package/docs/api/hooks.md +554 -0
- package/docs/api/index.md +222 -0
- package/docs/api/query.md +678 -0
- package/docs/api/service.md +744 -0
- package/docs/core-concepts/archetypes.md +512 -0
- package/docs/core-concepts/components.md +498 -0
- package/docs/core-concepts/entity.md +314 -0
- package/docs/core-concepts/hooks.md +683 -0
- package/docs/core-concepts/query.md +588 -0
- package/docs/core-concepts/services.md +647 -0
- package/docs/examples/code-examples.md +425 -0
- package/docs/getting-started.md +337 -0
- package/docs/index.html +97 -0
- package/gql/Generator.ts +58 -35
- package/gql/decorators/Upload.ts +176 -0
- package/gql/helpers.ts +67 -0
- package/gql/index.ts +65 -31
- package/gql/types.ts +1 -1
- package/index.ts +79 -11
- package/package.json +19 -10
- package/rest/Generator.ts +3 -0
- package/rest/index.ts +22 -0
- package/service/Service.ts +1 -1
- package/service/ServiceRegistry.ts +10 -6
- package/service/index.ts +12 -1
- package/tests/bench/insert.bench.ts +59 -0
- package/tests/bench/relations.bench.ts +269 -0
- package/tests/bench/sorting.bench.ts +415 -0
- package/tests/component-hooks.test.ts +1409 -0
- package/tests/component.test.ts +338 -0
- package/tests/errorHandling.test.ts +155 -0
- package/tests/hooks.test.ts +666 -0
- package/tests/query-sorting.test.ts +101 -0
- package/tests/relations.test.ts +169 -0
- package/tests/scheduler.test.ts +724 -0
- package/tsconfig.json +35 -34
- package/types/graphql.types.ts +87 -0
- package/types/hooks.types.ts +141 -0
- package/types/scheduler.types.ts +165 -0
- package/types/upload.types.ts +184 -0
- package/upload/index.ts +140 -0
- package/utils/UploadHelper.ts +305 -0
- package/utils/cronParser.ts +366 -0
- package/utils/errorMessages.ts +151 -0
- package/core/Events.ts +0 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# Code Examples
|
|
2
|
+
|
|
3
|
+
This section contains practical, runnable examples that demonstrate BunSane's capabilities. Each example includes complete code that you can copy and run in your own project.
|
|
4
|
+
|
|
5
|
+
## ๐ Quick Start Example
|
|
6
|
+
|
|
7
|
+
Here's a complete example showing how to create a user management system with BunSane:
|
|
8
|
+
|
|
9
|
+
### Project Setup
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Create a new project
|
|
13
|
+
mkdir bunsane-user-app
|
|
14
|
+
cd bunsane-user-app
|
|
15
|
+
|
|
16
|
+
# Initialize with Bun
|
|
17
|
+
bun init -y
|
|
18
|
+
|
|
19
|
+
# Install BunSane
|
|
20
|
+
bun add bunsane
|
|
21
|
+
|
|
22
|
+
# Create project structure
|
|
23
|
+
mkdir -p src/services
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 1. Define Components
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
// src/services/UserComponents.ts
|
|
30
|
+
import { Component, CompData, BaseComponent } from 'bunsane';
|
|
31
|
+
|
|
32
|
+
@Component
|
|
33
|
+
export class UserProfile extends BaseComponent {
|
|
34
|
+
@CompData()
|
|
35
|
+
name: string = '';
|
|
36
|
+
|
|
37
|
+
@CompData()
|
|
38
|
+
email: string = '';
|
|
39
|
+
|
|
40
|
+
@CompData({ indexed: true })
|
|
41
|
+
username: string = '';
|
|
42
|
+
|
|
43
|
+
@CompData()
|
|
44
|
+
bio: string = '';
|
|
45
|
+
|
|
46
|
+
@CompData()
|
|
47
|
+
avatarUrl: string = '';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@Component
|
|
51
|
+
export class UserPreferences extends BaseComponent {
|
|
52
|
+
@CompData()
|
|
53
|
+
theme: 'light' | 'dark' | 'auto' = 'light';
|
|
54
|
+
|
|
55
|
+
@CompData()
|
|
56
|
+
notifications: boolean = true;
|
|
57
|
+
|
|
58
|
+
@CompData()
|
|
59
|
+
language: string = 'en';
|
|
60
|
+
|
|
61
|
+
@CompData()
|
|
62
|
+
timezone: string = 'UTC';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@Component
|
|
66
|
+
export class UserStats extends BaseComponent {
|
|
67
|
+
@CompData()
|
|
68
|
+
loginCount: number = 0;
|
|
69
|
+
|
|
70
|
+
@CompData()
|
|
71
|
+
lastLogin: Date = new Date();
|
|
72
|
+
|
|
73
|
+
@CompData()
|
|
74
|
+
postsCount: number = 0;
|
|
75
|
+
|
|
76
|
+
@CompData()
|
|
77
|
+
followersCount: number = 0;
|
|
78
|
+
|
|
79
|
+
@CompData()
|
|
80
|
+
followingCount: number = 0;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 2. Create ArcheType
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
// src/services/UserArcheType.ts
|
|
88
|
+
import { ArcheType } from 'bunsane';
|
|
89
|
+
import { UserProfile, UserPreferences, UserStats } from './UserComponents';
|
|
90
|
+
|
|
91
|
+
export const UserArcheType = new ArcheType([
|
|
92
|
+
UserProfile,
|
|
93
|
+
UserPreferences,
|
|
94
|
+
UserStats
|
|
95
|
+
]);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 3. Create Service
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// src/services/UserService.ts
|
|
102
|
+
import { BaseService, GraphQLObjectType, GraphQLOperation, GraphQLField, GraphQLFieldTypes } from 'bunsane';
|
|
103
|
+
import { UserArcheType } from './UserArcheType';
|
|
104
|
+
|
|
105
|
+
const userFields = {
|
|
106
|
+
id: GraphQLFieldTypes.ID_REQUIRED,
|
|
107
|
+
name: GraphQLFieldTypes.STRING_OPTIONAL,
|
|
108
|
+
email: GraphQLFieldTypes.STRING_REQUIRED,
|
|
109
|
+
username: GraphQLFieldTypes.STRING_OPTIONAL,
|
|
110
|
+
bio: GraphQLFieldTypes.STRING_OPTIONAL,
|
|
111
|
+
avatarUrl: GraphQLFieldTypes.STRING_OPTIONAL,
|
|
112
|
+
theme: GraphQLFieldTypes.STRING_OPTIONAL,
|
|
113
|
+
notifications: GraphQLFieldTypes.BOOLEAN_OPTIONAL,
|
|
114
|
+
loginCount: GraphQLFieldTypes.INT_OPTIONAL,
|
|
115
|
+
lastLogin: GraphQLFieldTypes.STRING_OPTIONAL,
|
|
116
|
+
postsCount: GraphQLFieldTypes.INT_OPTIONAL,
|
|
117
|
+
followersCount: GraphQLFieldTypes.INT_OPTIONAL,
|
|
118
|
+
followingCount: GraphQLFieldTypes.INT_OPTIONAL
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const userInputs = {
|
|
122
|
+
createUser: {
|
|
123
|
+
name: GraphQLFieldTypes.STRING_REQUIRED,
|
|
124
|
+
email: GraphQLFieldTypes.STRING_REQUIRED,
|
|
125
|
+
username: GraphQLFieldTypes.STRING_REQUIRED,
|
|
126
|
+
bio: GraphQLFieldTypes.STRING_OPTIONAL,
|
|
127
|
+
avatarUrl: GraphQLFieldTypes.STRING_OPTIONAL
|
|
128
|
+
},
|
|
129
|
+
getUser: {
|
|
130
|
+
id: GraphQLFieldTypes.ID_REQUIRED
|
|
131
|
+
},
|
|
132
|
+
updateUser: {
|
|
133
|
+
id: GraphQLFieldTypes.ID_REQUIRED,
|
|
134
|
+
name: GraphQLFieldTypes.STRING_OPTIONAL,
|
|
135
|
+
email: GraphQLFieldTypes.STRING_OPTIONAL,
|
|
136
|
+
bio: GraphQLFieldTypes.STRING_OPTIONAL,
|
|
137
|
+
avatarUrl: GraphQLFieldTypes.STRING_OPTIONAL
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
@GraphQLObjectType({
|
|
142
|
+
name: "User",
|
|
143
|
+
fields: userFields
|
|
144
|
+
})
|
|
145
|
+
export default class UserService extends BaseService {
|
|
146
|
+
@GraphQLOperation({
|
|
147
|
+
type: "Mutation",
|
|
148
|
+
input: userInputs.createUser,
|
|
149
|
+
output: "User"
|
|
150
|
+
})
|
|
151
|
+
async createUser(args: { name: string; email: string; username: string; bio?: string; avatarUrl?: string }) {
|
|
152
|
+
const userEntity = UserArcheType.fill({
|
|
153
|
+
userProfile: args,
|
|
154
|
+
userPreferences: { theme: 'light', notifications: true },
|
|
155
|
+
userStats: { loginCount: 0, lastLogin: new Date() }
|
|
156
|
+
}).createEntity();
|
|
157
|
+
|
|
158
|
+
await userEntity.save();
|
|
159
|
+
return await UserArcheType.Unwrap(userEntity);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@GraphQLOperation({
|
|
163
|
+
type: "Query",
|
|
164
|
+
input: userInputs.getUser,
|
|
165
|
+
output: "User"
|
|
166
|
+
})
|
|
167
|
+
async getUser(args: { id: string }) {
|
|
168
|
+
const entity = await Entity.FindById(args.id);
|
|
169
|
+
if (!entity) return null;
|
|
170
|
+
return await UserArcheType.Unwrap(entity);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async getUsers(args: { limit?: number; offset?: number }) {
|
|
174
|
+
const query = new Query()
|
|
175
|
+
.with(UserProfile)
|
|
176
|
+
.limit(args.limit || 10)
|
|
177
|
+
.offset(args.offset || 0);
|
|
178
|
+
|
|
179
|
+
const entities = await query.exec();
|
|
180
|
+
return await Promise.all(
|
|
181
|
+
entities.map(entity => UserArcheType.Unwrap(entity))
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@GraphQLOperation({
|
|
186
|
+
type: "Mutation",
|
|
187
|
+
input: userInputs.updateUser,
|
|
188
|
+
output: "User"
|
|
189
|
+
})
|
|
190
|
+
async updateUser(args: { id: string; name?: string; email?: string; bio?: string; avatarUrl?: string }) {
|
|
191
|
+
const entity = await Entity.FindById(args.id);
|
|
192
|
+
if (!entity) throw new Error('User not found');
|
|
193
|
+
|
|
194
|
+
await UserArcheType.updateEntity(entity, {
|
|
195
|
+
userProfile: args
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
await entity.save();
|
|
199
|
+
return await UserArcheType.Unwrap(entity);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async deleteUser(args: { id: string }) {
|
|
203
|
+
const entity = await Entity.FindById(args.id);
|
|
204
|
+
if (!entity) throw new Error('User not found');
|
|
205
|
+
|
|
206
|
+
await entity.delete(true);
|
|
207
|
+
return { success: true, message: 'User deleted successfully' };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@GraphQLField({ type: "User", field: "id" })
|
|
211
|
+
idResolver(parent: Entity) {
|
|
212
|
+
return parent.id;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@GraphQLField({ type: "User", field: "name" })
|
|
216
|
+
async nameResolver(parent: Entity) {
|
|
217
|
+
const profile = await parent.get(UserProfile);
|
|
218
|
+
return profile?.name ?? "";
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@GraphQLField({ type: "User", field: "email" })
|
|
222
|
+
async emailResolver(parent: Entity) {
|
|
223
|
+
const profile = await parent.get(UserProfile);
|
|
224
|
+
return profile?.email ?? "";
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### 4. Set Up Application
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// index.ts
|
|
233
|
+
import { App } from 'bunsane';
|
|
234
|
+
import UserService from './src/services/UserService';
|
|
235
|
+
|
|
236
|
+
async function main() {
|
|
237
|
+
// Services are automatically registered when imported
|
|
238
|
+
// No manual registration needed
|
|
239
|
+
|
|
240
|
+
// Create and start the application
|
|
241
|
+
const app = new App({
|
|
242
|
+
port: 3000,
|
|
243
|
+
databaseUrl: process.env.DATABASE_URL || 'postgresql://user:pass@localhost:5432/bunsane_db'
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
await app.start();
|
|
247
|
+
|
|
248
|
+
console.log('๐ BunSane server running on http://localhost:3000');
|
|
249
|
+
console.log('๐ GraphQL Playground: http://localhost:3000/graphql');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
main().catch(console.error);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### 5. Environment Configuration
|
|
256
|
+
|
|
257
|
+
```env
|
|
258
|
+
# .env
|
|
259
|
+
DATABASE_URL=postgresql://username:password@localhost:5432/bunsane_db
|
|
260
|
+
NODE_ENV=development
|
|
261
|
+
PORT=3000
|
|
262
|
+
LOG_LEVEL=info
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### 6. TypeScript Configuration
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
// tsconfig.json
|
|
269
|
+
{
|
|
270
|
+
"compilerOptions": {
|
|
271
|
+
"target": "ES2022",
|
|
272
|
+
"module": "ESNext",
|
|
273
|
+
"moduleResolution": "bundler",
|
|
274
|
+
"experimentalDecorators": true,
|
|
275
|
+
"emitDecoratorMetadata": true,
|
|
276
|
+
"strict": true,
|
|
277
|
+
"esModuleInterop": true,
|
|
278
|
+
"skipLibCheck": true,
|
|
279
|
+
"forceConsistentCasingInFileNames": true,
|
|
280
|
+
"allowSyntheticDefaultImports": true,
|
|
281
|
+
"resolveJsonModule": true,
|
|
282
|
+
"isolatedModules": true,
|
|
283
|
+
"noEmit": true,
|
|
284
|
+
"types": ["bun-types"]
|
|
285
|
+
},
|
|
286
|
+
"include": ["src/**/*", "index.ts"],
|
|
287
|
+
"exclude": ["node_modules"]
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## ๐งช Testing the Example
|
|
292
|
+
|
|
293
|
+
### Start the Server
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
bun run index.ts
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### GraphQL Queries
|
|
300
|
+
|
|
301
|
+
Visit `http://localhost:3000/graphql` and try these queries:
|
|
302
|
+
|
|
303
|
+
#### Create a User
|
|
304
|
+
|
|
305
|
+
```graphql
|
|
306
|
+
mutation CreateUser($input: CreateUserInput!) {
|
|
307
|
+
createUser(input: $input) {
|
|
308
|
+
id
|
|
309
|
+
name
|
|
310
|
+
email
|
|
311
|
+
username
|
|
312
|
+
theme
|
|
313
|
+
notifications
|
|
314
|
+
loginCount
|
|
315
|
+
lastLogin
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Variables:
|
|
321
|
+
```json
|
|
322
|
+
{
|
|
323
|
+
"input": {
|
|
324
|
+
"name": "John Doe",
|
|
325
|
+
"email": "john.doe@example.com",
|
|
326
|
+
"username": "johndoe",
|
|
327
|
+
"bio": "Software developer passionate about TypeScript",
|
|
328
|
+
"avatarUrl": "https://example.com/avatar.jpg"
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
#### Get Users
|
|
334
|
+
|
|
335
|
+
```graphql
|
|
336
|
+
query GetUsers {
|
|
337
|
+
getUsers(limit: 10, offset: 0) {
|
|
338
|
+
id
|
|
339
|
+
name
|
|
340
|
+
email
|
|
341
|
+
username
|
|
342
|
+
bio
|
|
343
|
+
postsCount
|
|
344
|
+
followersCount
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### Update User
|
|
350
|
+
|
|
351
|
+
```graphql
|
|
352
|
+
mutation UpdateUser($input: UpdateUserInput!) {
|
|
353
|
+
updateUser(input: $input) {
|
|
354
|
+
id
|
|
355
|
+
name
|
|
356
|
+
email
|
|
357
|
+
bio
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Variables:
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"input": {
|
|
366
|
+
"id": "01HXXXXXXXXXXXXXXXXXXXXX",
|
|
367
|
+
"name": "John Smith",
|
|
368
|
+
"bio": "Full-stack developer specializing in modern web technologies"
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## ๐ More Examples
|
|
374
|
+
|
|
375
|
+
- **[Blog Application](blog-tutorial.md)** - Complete blogging platform
|
|
376
|
+
- **[E-commerce System](ecommerce-tutorial.md)** - Online store with products and orders
|
|
377
|
+
- **[Social Media Platform](social-tutorial.md)** - User interactions and content sharing
|
|
378
|
+
|
|
379
|
+
## ๐ง Running Examples
|
|
380
|
+
|
|
381
|
+
Each example includes:
|
|
382
|
+
|
|
383
|
+
1. **Complete code** - Copy and run immediately
|
|
384
|
+
2. **Database setup** - SQL scripts for schema creation
|
|
385
|
+
3. **GraphQL queries** - Ready-to-use API calls
|
|
386
|
+
4. **Testing instructions** - How to verify functionality
|
|
387
|
+
|
|
388
|
+
### Local Development
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
# Clone the example
|
|
392
|
+
git clone https://github.com/yaaruu/bunsane-examples.git
|
|
393
|
+
cd bunsane-examples/user-management
|
|
394
|
+
|
|
395
|
+
# Install dependencies
|
|
396
|
+
bun install
|
|
397
|
+
|
|
398
|
+
# Set up database
|
|
399
|
+
createdb bunsane_examples
|
|
400
|
+
psql bunsane_examples < schema.sql
|
|
401
|
+
|
|
402
|
+
# Start the server
|
|
403
|
+
bun run dev
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Docker Development
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
# Use Docker Compose for full development environment
|
|
410
|
+
docker-compose up -d
|
|
411
|
+
|
|
412
|
+
# Run the example
|
|
413
|
+
bun run index.ts
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## ๐ฏ Learning Path
|
|
417
|
+
|
|
418
|
+
1. **Start Here** - User management system (you're here!)
|
|
419
|
+
2. **Add Features** - Extend with posts, comments, likes
|
|
420
|
+
3. **Go Advanced** - Add real-time updates, file uploads, caching
|
|
421
|
+
4. **Production Ready** - Add authentication, rate limiting, monitoring
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
*Ready to build something amazing? Try the [Blog Application](blog-tutorial.md) next!* ๐
|