@objectql/create 4.0.0 → 4.0.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.
Files changed (46) hide show
  1. package/package.json +1 -1
  2. package/templates/enterprise/CHANGELOG.md +20 -0
  3. package/templates/enterprise/README.md +2 -2
  4. package/templates/enterprise/package.json +2 -2
  5. package/templates/enterprise/src/core/attachment.object.yml +10 -1
  6. package/templates/enterprise/src/core/organization.object.yml +41 -6
  7. package/templates/enterprise/src/core/user.object.yml +37 -12
  8. package/templates/enterprise/src/extensions/README.md +4 -4
  9. package/templates/enterprise/src/extensions/user_extension.object.yml +65 -0
  10. package/templates/enterprise/src/modules/crm/crm_account.object.yml +57 -13
  11. package/templates/enterprise/src/modules/crm/crm_contact.object.yml +42 -8
  12. package/templates/enterprise/src/modules/crm/crm_lead.object.yml +82 -21
  13. package/templates/enterprise/src/modules/crm/crm_opportunity.object.yml +65 -15
  14. package/templates/enterprise/src/modules/finance/finance_budget.object.yml +67 -16
  15. package/templates/enterprise/src/modules/finance/finance_expense.object.yml +75 -19
  16. package/templates/enterprise/src/modules/finance/finance_invoice.object.yml +61 -16
  17. package/templates/enterprise/src/modules/finance/finance_payment.object.yml +65 -16
  18. package/templates/enterprise/src/modules/hr/hr_department.object.yml +29 -2
  19. package/templates/enterprise/src/modules/hr/hr_employee.object.yml +50 -8
  20. package/templates/enterprise/src/modules/hr/hr_position.object.yml +46 -10
  21. package/templates/enterprise/src/modules/hr/hr_timesheet.object.yml +44 -8
  22. package/templates/enterprise/src/modules/project/project_milestone.object.yml +36 -4
  23. package/templates/enterprise/src/modules/project/project_project.object.yml +64 -13
  24. package/templates/enterprise/src/modules/project/project_task.object.yml +70 -9
  25. package/templates/enterprise/src/modules/project/project_timesheet_entry.object.yml +39 -4
  26. package/templates/enterprise/src/plugins/audit/audit.plugin.ts +1 -1
  27. package/templates/enterprise/src/plugins/audit/note.object.yml +17 -0
  28. package/templates/enterprise/tsconfig.tsbuildinfo +1 -1
  29. package/templates/hello-world/CHANGELOG.md +16 -0
  30. package/templates/hello-world/README.md +73 -10
  31. package/templates/hello-world/package.json +1 -1
  32. package/templates/hello-world/src/index.ts +17 -5
  33. package/templates/starter/CHANGELOG.md +20 -0
  34. package/templates/starter/package.json +1 -1
  35. package/templates/starter/src/modules/projects/projects.action.ts +195 -346
  36. package/templates/starter/src/modules/projects/projects.hook.ts +98 -263
  37. package/templates/starter/src/modules/projects/projects.object.yml +65 -6
  38. package/templates/starter/src/modules/projects/projects.validation.yml +13 -4
  39. package/templates/starter/src/seed.ts +1 -1
  40. package/templates/starter/tsconfig.tsbuildinfo +1 -1
  41. package/templates/enterprise/__tests__/data-api.test.ts +0 -554
  42. package/templates/enterprise/__tests__/data-api.test.ts.backup +0 -526
  43. package/templates/enterprise/__tests__/metadata-api.test.ts +0 -315
  44. package/templates/enterprise/__tests__/metadata-loading.test.ts +0 -258
  45. package/templates/enterprise/src/extensions/user.extension.object.yml +0 -42
  46. package/templates/starter/__tests__/projects-hooks-actions.test.ts +0 -498
@@ -1,554 +0,0 @@
1
- /**
2
- * ObjectQL
3
- * Copyright (c) 2026-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- /**
10
- * Data API Tests for Enterprise Starter
11
- *
12
- * Tests CRUD operations for enterprise objects
13
- */
14
-
15
- import { ObjectQL } from '@objectql/core';
16
- import { SqlDriver } from '@objectql/driver-sql';
17
- import { ObjectLoader } from '@objectql/platform-node';
18
- import * as path from 'path';
19
- import { nanoid } from 'nanoid';
20
-
21
- // Helper to generate IDs since SQL driver doesn't auto-generate them
22
- const generateId = () => nanoid(16);
23
-
24
- describe('Enterprise Data API', () => {
25
- let app: ObjectQL;
26
-
27
- beforeAll(async () => {
28
- // Initialize ObjectQL
29
- app = new ObjectQL({
30
- datasources: {
31
- default: new SqlDriver({
32
- client: 'sqlite3',
33
- connection: {
34
- filename: ':memory:'
35
- },
36
- useNullAsDefault: true
37
- })
38
- }
39
- });
40
-
41
- // Load metadata
42
- const srcDir = path.resolve(__dirname, '../src');
43
- const loader = new ObjectLoader(app.metadata);
44
- loader.load(srcDir);
45
-
46
- await app.init();
47
- });
48
-
49
- afterAll(async () => {
50
- if (app && (app as any).datasources?.default) {
51
- const driver = (app as any).datasources.default;
52
- if (driver.knex) {
53
- await driver.knex.destroy();
54
- }
55
- }
56
- });
57
-
58
- describe('Core Object Operations', () => {
59
- describe('User CRUD', () => {
60
- let userId: string;
61
-
62
- it('should create a user', async () => {
63
- const ctx = app.createContext({ isSystem: true });
64
- const result = await ctx.object('user').create({
65
- id: generateId(), // Provide ID manually
66
- name: 'John Doe',
67
- email: 'john@example.com',
68
- username: 'johndoe'
69
- });
70
-
71
-
72
- expect(result).toBeDefined();
73
- expect(result.id).toBeDefined();
74
- expect(result.id).not.toBeNull();
75
- expect(result.name).toBe('John Doe');
76
-
77
- userId = result.id;
78
- });
79
-
80
- it('should find users', async () => {
81
- const ctx = app.createContext({ isSystem: true });
82
- const results = await ctx.object('user').find({});
83
-
84
- expect(results).toBeDefined();
85
- expect(Array.isArray(results)).toBe(true);
86
- expect(results.length).toBeGreaterThanOrEqual(1);
87
- });
88
-
89
- it('should find user by id', async () => {
90
- const ctx = app.createContext({ isSystem: true });
91
- const result = await ctx.object('user').findOne(userId);
92
-
93
- expect(result).toBeDefined();
94
- expect(result.id).toBe(userId);
95
- expect(result.name).toBe('John Doe');
96
- });
97
-
98
- it('should update user', async () => {
99
- const ctx = app.createContext({ isSystem: true });
100
- await ctx.object('user').update(userId, {
101
- email: 'john.doe@example.com'
102
- });
103
-
104
- const updated = await ctx.object('user').findOne(userId);
105
- expect(updated.email).toBe('john.doe@example.com');
106
- });
107
-
108
- it('should delete user', async () => {
109
- const ctx = app.createContext({ isSystem: true });
110
- await ctx.object('user').delete(userId);
111
-
112
- const deleted = await ctx.object('user').findOne(userId);
113
- expect(deleted).toBeFalsy();
114
- });
115
- });
116
-
117
- describe('Organization CRUD', () => {
118
- let orgId: string;
119
-
120
- it('should create an organization', async () => {
121
- const ctx = app.createContext({ isSystem: true });
122
- const result = await ctx.object('organization').create({
123
- name: 'Acme Corp',
124
- code: 'ACME'
125
- });
126
-
127
- expect(result).toBeDefined();
128
- expect(result.id).toBeDefined();
129
- expect(result.name).toBe('Acme Corp');
130
-
131
- orgId = result.id;
132
- });
133
-
134
- it('should find organizations', async () => {
135
- const ctx = app.createContext({ isSystem: true });
136
- const results = await ctx.object('organization').find({});
137
-
138
- expect(results).toBeDefined();
139
- expect(results.length).toBeGreaterThanOrEqual(1);
140
- });
141
-
142
- it('should delete organization', async () => {
143
- const ctx = app.createContext({ isSystem: true });
144
- await ctx.object('organization').delete(orgId);
145
- });
146
- });
147
- });
148
-
149
- describe('CRM Module Operations', () => {
150
- describe('Account CRUD', () => {
151
- let accountId: string;
152
-
153
- it('should create a CRM account', async () => {
154
- const ctx = app.createContext({ isSystem: true });
155
- const result = await ctx.object('crm_account').create({
156
- name: 'Global Solutions Inc',
157
- industry: 'Technology'
158
- });
159
-
160
- expect(result).toBeDefined();
161
- expect(result.id).toBeDefined();
162
- expect(result.name).toBe('Global Solutions Inc');
163
-
164
- accountId = result.id;
165
- });
166
-
167
- it('should find CRM accounts', async () => {
168
- const ctx = app.createContext({ isSystem: true });
169
- const results = await ctx.object('crm_account').find({});
170
-
171
- expect(results).toBeDefined();
172
- expect(results.length).toBeGreaterThanOrEqual(1);
173
- });
174
-
175
- it('should update CRM account', async () => {
176
- const ctx = app.createContext({ isSystem: true });
177
- await ctx.object('crm_account').update(accountId, {
178
- industry: 'IT Services'
179
- });
180
-
181
- const updated = await ctx.object('crm_account').findOne(accountId);
182
- expect(updated.industry).toBe('IT Services');
183
- });
184
-
185
- it('should delete CRM account', async () => {
186
- const ctx = app.createContext({ isSystem: true });
187
- await ctx.object('crm_account').delete(accountId);
188
- });
189
- });
190
-
191
- describe('Contact and Lead CRUD', () => {
192
- it('should create a CRM contact', async () => {
193
- const ctx = app.createContext({ isSystem: true });
194
- // First create an account (required for contact)
195
- const account = await ctx.object('crm_account').create({
196
- id: generateId(),
197
- name: 'Contact Test Company',
198
- account_number: 'CTC001'
199
- });
200
-
201
- console.log('CRM Account:', account); // Debugging
202
- expect(account).toBeDefined();
203
- expect(account.id).toBeDefined();
204
-
205
- const result = await ctx.object('crm_contact').create({
206
- first_name: 'Jane',
207
- last_name: 'Smith',
208
- email: 'jane.smith@example.com',
209
- account: account.id // Required field
210
- });
211
-
212
- expect(result).toBeDefined();
213
- expect(result.id).toBeDefined();
214
- expect(result.first_name).toBe('Jane');
215
- });
216
-
217
- it('should create a CRM lead', async () => {
218
- const ctx = app.createContext({ isSystem: true });
219
- const result = await ctx.object('crm_lead').create({
220
- first_name: 'Bob',
221
- last_name: 'Johnson',
222
- company: 'Tech Startup',
223
- status: 'new' // Required field
224
- });
225
-
226
- expect(result).toBeDefined();
227
- expect(result.id).toBeDefined();
228
- expect(result.company).toBe('Tech Startup');
229
- });
230
- });
231
- });
232
-
233
- describe('HR Module Operations', () => {
234
- describe('Employee CRUD', () => {
235
- let employeeId: string;
236
-
237
- it('should create an HR employee', async () => {
238
- const ctx = app.createContext({ isSystem: true });
239
- // Create required department and position first
240
- const dept = await ctx.object('hr_department').create({
241
- id: generateId(),
242
- name: 'Engineering Dept',
243
- code: 'ENGD'
244
- });
245
-
246
-
247
- expect(dept).toBeDefined();
248
- expect(dept.id).toBeDefined();
249
- expect(dept.id).not.toBeNull();
250
-
251
- const pos = await ctx.object('hr_position').create({
252
- id: generateId(),
253
- title: 'Software Engineer', // Position uses 'title', not 'name'
254
- code: 'SWE'
255
- });
256
-
257
-
258
- expect(pos).toBeDefined();
259
- expect(pos.id).toBeDefined();
260
- expect(pos.id).not.toBeNull();
261
-
262
- const result = await ctx.object('hr_employee').create({
263
- id: generateId(),
264
- first_name: 'Alice',
265
- last_name: 'Brown',
266
- employee_number: 'EMP001',
267
- email: 'alice.brown@example.com', // Required
268
- department: dept.id, // Required
269
- position: pos.id, // Required
270
- hire_date: '2024-01-01', // Required
271
- status: 'active',
272
- employment_type: 'full_time'
273
- });
274
-
275
- expect(result).toBeDefined();
276
- expect(result.id).toBeDefined();
277
- expect(result.id).not.toBeNull();
278
- expect(result.first_name).toBe('Alice');
279
-
280
- employeeId = result.id;
281
- });
282
-
283
- it('should find HR employees', async () => {
284
- const ctx = app.createContext({ isSystem: true });
285
- const results = await ctx.object('hr_employee').find({});
286
-
287
- expect(results).toBeDefined();
288
- expect(results.length).toBeGreaterThanOrEqual(1);
289
- });
290
-
291
- it('should delete HR employee', async () => {
292
- const ctx = app.createContext({ isSystem: true });
293
- await ctx.object('hr_employee').delete(employeeId);
294
- });
295
- });
296
-
297
- describe('Department CRUD', () => {
298
- it('should create an HR department', async () => {
299
- const ctx = app.createContext({ isSystem: true });
300
- const result = await ctx.object('hr_department').create({
301
- id: generateId(),
302
- name: 'Sales Department',
303
- code: 'SALES' // Use unique code
304
- });
305
-
306
- expect(result).toBeDefined();
307
- expect(result.id).toBeDefined();
308
- expect(result.name).toBe('Sales Department');
309
- });
310
- });
311
- });
312
-
313
- describe('Project Module Operations', () => {
314
- describe('Project CRUD', () => {
315
- let projectId: string;
316
-
317
- it('should create a project', async () => {
318
- const ctx = app.createContext({ isSystem: true });
319
- // Create a user first (required as project owner)
320
- const user = await ctx.object('user').create({
321
- id: generateId(),
322
- name: 'Project Manager',
323
- email: 'pm@example.com',
324
- username: 'pmuser'
325
- });
326
-
327
- console.log('Project User:', user); // Debugging
328
- expect(user).toBeDefined();
329
- expect(user.id).toBeDefined();
330
-
331
- const result = await ctx.object('project_project').create({
332
- id: generateId(),
333
- name: 'Website Redesign',
334
- code: 'WEB-001',
335
- status: 'planning', // Required field
336
- owner: user.id, // Required field
337
- start_date: '2024-01-01' // Required field
338
- });
339
-
340
- expect(result).toBeDefined();
341
- expect(result.id).toBeDefined();
342
- expect(result.name).toBe('Website Redesign');
343
-
344
- projectId = result.id;
345
- });
346
-
347
- it('should find projects', async () => {
348
- const ctx = app.createContext({ isSystem: true });
349
- const results = await ctx.object('project_project').find({});
350
-
351
- expect(results).toBeDefined();
352
- expect(results.length).toBeGreaterThanOrEqual(1);
353
- });
354
-
355
- it('should delete project', async () => {
356
- const ctx = app.createContext({ isSystem: true });
357
- await ctx.object('project_project').delete(projectId);
358
- });
359
- });
360
-
361
- describe('Task CRUD', () => {
362
- it('should create a project task', async () => {
363
- const ctx = app.createContext({ isSystem: true });
364
- // Create a user and project first (required for task)
365
- const user = await ctx.object('user').create({
366
- id: generateId(),
367
- name: 'Task Owner',
368
- email: 'taskowner@example.com',
369
- username: 'taskuser'
370
- });
371
-
372
- expect(user).toBeDefined();
373
- expect(user.id).toBeDefined();
374
-
375
- const project = await ctx.object('project_project').create({
376
- id: generateId(),
377
- name: 'Test Project',
378
- code: 'TEST-001',
379
- status: 'planning',
380
- owner: user.id, // Required
381
- start_date: '2024-01-01' // Required
382
- });
383
-
384
- expect(project).toBeDefined();
385
- expect(project.id).toBeDefined();
386
-
387
- const result = await ctx.object('project_task').create({
388
- id: generateId(),
389
- name: 'Design mockups',
390
- description: 'Create initial design mockups',
391
- project: project.id, // Required field
392
- status: 'pending' // Required field
393
- });
394
-
395
- expect(result).toBeDefined();
396
- expect(result.id).toBeDefined();
397
- expect(result.name).toBe('Design mockups');
398
- });
399
- });
400
- });
401
-
402
- describe('Finance Module Operations', () => {
403
- describe('Invoice CRUD', () => {
404
- it('should create a finance invoice', async () => {
405
- const ctx = app.createContext({ isSystem: true });
406
- // Create an account first (required for invoice)
407
- const account = await ctx.object('crm_account').create({
408
- id: generateId(),
409
- name: 'Invoice Test Company',
410
- account_number: 'ITC001'
411
- });
412
-
413
- expect(account).toBeDefined();
414
- expect(account.id).toBeDefined();
415
-
416
- const result = await ctx.object('finance_invoice').create({
417
- id: generateId(),
418
- invoice_number: 'INV-001',
419
- total_amount: 1000,
420
- account: account.id, // Required
421
- invoice_date: '2024-01-01', // Required
422
- due_date: '2024-01-31', // Required
423
- subtotal: 1000, // Required
424
- status: 'draft'
425
- });
426
-
427
- expect(result).toBeDefined();
428
- expect(result.id).toBeDefined();
429
- expect(result.invoice_number).toBe('INV-001');
430
- });
431
- });
432
-
433
- describe('Payment CRUD', () => {
434
- it('should create a finance payment', async () => {
435
- const ctx = app.createContext({ isSystem: true });
436
- // Create an account first (required for payment)
437
- const account = await ctx.object('crm_account').create({
438
- id: generateId(),
439
- name: 'Payment Test Company',
440
- account_number: 'PTC001'
441
- });
442
-
443
- expect(account).toBeDefined();
444
- expect(account.id).toBeDefined();
445
-
446
- const result = await ctx.object('finance_payment').create({
447
- id: generateId(),
448
- payment_number: 'PAY-001', // Required
449
- amount: 500,
450
- payment_method: 'bank_transfer', // Use underscore format
451
- account: account.id, // Required
452
- payment_date: '2024-01-01', // Required
453
- status: 'completed'
454
- });
455
-
456
- expect(result).toBeDefined();
457
- expect(result.id).toBeDefined();
458
- expect(result.amount).toBe(500);
459
- });
460
- });
461
- });
462
-
463
- describe('Cross-Module Operations', () => {
464
- it('should handle operations across multiple modules', async () => {
465
- const ctx = app.createContext({ isSystem: true });
466
-
467
- // Create records in different modules
468
- const account = await ctx.object('crm_account').create({
469
- id: generateId(),
470
- name: 'Multi-Module Test',
471
- account_number: 'MMT001'
472
- });
473
-
474
- expect(account).toBeDefined();
475
- expect(account.id).toBeDefined();
476
-
477
- // Create required department and position first
478
- const dept = await ctx.object('hr_department').create({
479
- id: generateId(),
480
- name: 'Cross Test Dept',
481
- code: 'CTD'
482
- });
483
-
484
- expect(dept).toBeDefined();
485
- expect(dept.id).toBeDefined();
486
-
487
- const pos = await ctx.object('hr_position').create({
488
- id: generateId(),
489
- title: 'Cross Test Position', // Position uses 'title', not 'name'
490
- code: 'CTP'
491
- });
492
-
493
- expect(pos).toBeDefined();
494
- expect(pos.id).toBeDefined();
495
-
496
- const employee = await ctx.object('hr_employee').create({
497
- id: generateId(),
498
- first_name: 'Test',
499
- last_name: 'Employee',
500
- employee_number: 'TEST001',
501
- email: 'test.employee@example.com', // Required
502
- department: dept.id, // Required
503
- position: pos.id, // Required
504
- hire_date: '2024-01-01', // Required
505
- employment_type: 'full_time',
506
- status: 'active'
507
- });
508
-
509
- expect(employee).toBeDefined();
510
- expect(employee.id).toBeDefined();
511
-
512
- // Create a user for project owner
513
- const user = await ctx.object('user').create({
514
- id: generateId(),
515
- name: 'Cross Test User',
516
- email: 'crosstest@example.com',
517
- username: 'crosstestuser'
518
- });
519
-
520
- expect(user).toBeDefined();
521
- expect(user.id).toBeDefined();
522
-
523
- const project = await ctx.object('project_project').create({
524
- id: generateId(),
525
- name: 'Cross-Module Project',
526
- code: 'CROSS-001',
527
- status: 'planning',
528
- owner: user.id, // Required
529
- start_date: '2024-01-01' // Required
530
- });
531
-
532
- expect(account.id).toBeDefined();
533
- expect(employee.id).toBeDefined();
534
- expect(project.id).toBeDefined();
535
-
536
- // Cleanup
537
- await ctx.object('crm_account').delete(account.id);
538
- await ctx.object('hr_employee').delete(employee.id);
539
- await ctx.object('project_project').delete(project.id);
540
- });
541
-
542
- it('should count records across modules', async () => {
543
- const ctx = app.createContext({ isSystem: true });
544
-
545
- const accountCount = await ctx.object('crm_account').count([]);
546
- const employeeCount = await ctx.object('hr_employee').count([]);
547
- const projectCount = await ctx.object('project_project').count([]);
548
-
549
- expect(typeof accountCount).toBe('number');
550
- expect(typeof employeeCount).toBe('number');
551
- expect(typeof projectCount).toBe('number');
552
- });
553
- });
554
- });