Skip to content

Commit 7842716

Browse files
authored
Merge pull request #188 from objectstack-ai/copilot/fix-job-step-error
2 parents 1d9ab59 + dedebf7 commit 7842716

5 files changed

Lines changed: 56 additions & 30 deletions

File tree

examples/showcase/enterprise-erp/__tests__/data-api.test.ts

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ import { ObjectQL } from '@objectql/core';
1616
import { SqlDriver } from '@objectql/driver-sql';
1717
import { ObjectLoader } from '@objectql/platform-node';
1818
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);
2319

2420
describe('Enterprise Data API', () => {
2521
let app: ObjectQL;
@@ -62,7 +58,7 @@ describe('Enterprise Data API', () => {
6258
it('should create a user', async () => {
6359
const ctx = app.createContext({ isSystem: true });
6460
const result = await ctx.object('user').create({
65-
id: generateId(), // Provide ID manually
61+
6662
name: 'John Doe',
6763
email: 'john@example.com',
6864
username: 'johndoe'
@@ -193,7 +189,7 @@ describe('Enterprise Data API', () => {
193189
const ctx = app.createContext({ isSystem: true });
194190
// First create an account (required for contact)
195191
const account = await ctx.object('crm_account').create({
196-
id: generateId(),
192+
197193
name: 'Contact Test Company',
198194
account_number: 'CTC001'
199195
});
@@ -238,7 +234,7 @@ describe('Enterprise Data API', () => {
238234
const ctx = app.createContext({ isSystem: true });
239235
// Create required department and position first
240236
const dept = await ctx.object('hr_department').create({
241-
id: generateId(),
237+
242238
name: 'Engineering Dept',
243239
code: 'ENGD'
244240
});
@@ -249,7 +245,7 @@ describe('Enterprise Data API', () => {
249245
expect(dept.id).not.toBeNull();
250246

251247
const pos = await ctx.object('hr_position').create({
252-
id: generateId(),
248+
253249
title: 'Software Engineer', // Position uses 'title', not 'name'
254250
code: 'SWE'
255251
});
@@ -260,7 +256,7 @@ describe('Enterprise Data API', () => {
260256
expect(pos.id).not.toBeNull();
261257

262258
const result = await ctx.object('hr_employee').create({
263-
id: generateId(),
259+
264260
first_name: 'Alice',
265261
last_name: 'Brown',
266262
employee_number: 'EMP001',
@@ -298,7 +294,7 @@ describe('Enterprise Data API', () => {
298294
it('should create an HR department', async () => {
299295
const ctx = app.createContext({ isSystem: true });
300296
const result = await ctx.object('hr_department').create({
301-
id: generateId(),
297+
302298
name: 'Sales Department',
303299
code: 'SALES' // Use unique code
304300
});
@@ -318,7 +314,7 @@ describe('Enterprise Data API', () => {
318314
const ctx = app.createContext({ isSystem: true });
319315
// Create a user first (required as project owner)
320316
const user = await ctx.object('user').create({
321-
id: generateId(),
317+
322318
name: 'Project Manager',
323319
email: 'pm@example.com',
324320
username: 'pmuser'
@@ -329,7 +325,7 @@ describe('Enterprise Data API', () => {
329325
expect(user.id).toBeDefined();
330326

331327
const result = await ctx.object('project_project').create({
332-
id: generateId(),
328+
333329
name: 'Website Redesign',
334330
code: 'WEB-001',
335331
status: 'planning', // Required field
@@ -363,7 +359,7 @@ describe('Enterprise Data API', () => {
363359
const ctx = app.createContext({ isSystem: true });
364360
// Create a user and project first (required for task)
365361
const user = await ctx.object('user').create({
366-
id: generateId(),
362+
367363
name: 'Task Owner',
368364
email: 'taskowner@example.com',
369365
username: 'taskuser'
@@ -373,7 +369,7 @@ describe('Enterprise Data API', () => {
373369
expect(user.id).toBeDefined();
374370

375371
const project = await ctx.object('project_project').create({
376-
id: generateId(),
372+
377373
name: 'Test Project',
378374
code: 'TEST-001',
379375
status: 'planning',
@@ -385,7 +381,7 @@ describe('Enterprise Data API', () => {
385381
expect(project.id).toBeDefined();
386382

387383
const result = await ctx.object('project_task').create({
388-
id: generateId(),
384+
389385
name: 'Design mockups',
390386
description: 'Create initial design mockups',
391387
project: project.id, // Required field
@@ -405,7 +401,7 @@ describe('Enterprise Data API', () => {
405401
const ctx = app.createContext({ isSystem: true });
406402
// Create an account first (required for invoice)
407403
const account = await ctx.object('crm_account').create({
408-
id: generateId(),
404+
409405
name: 'Invoice Test Company',
410406
account_number: 'ITC001'
411407
});
@@ -414,7 +410,7 @@ describe('Enterprise Data API', () => {
414410
expect(account.id).toBeDefined();
415411

416412
const result = await ctx.object('finance_invoice').create({
417-
id: generateId(),
413+
418414
invoice_number: 'INV-001',
419415
total_amount: 1000,
420416
account: account.id, // Required
@@ -435,7 +431,7 @@ describe('Enterprise Data API', () => {
435431
const ctx = app.createContext({ isSystem: true });
436432
// Create an account first (required for payment)
437433
const account = await ctx.object('crm_account').create({
438-
id: generateId(),
434+
439435
name: 'Payment Test Company',
440436
account_number: 'PTC001'
441437
});
@@ -444,7 +440,7 @@ describe('Enterprise Data API', () => {
444440
expect(account.id).toBeDefined();
445441

446442
const result = await ctx.object('finance_payment').create({
447-
id: generateId(),
443+
448444
payment_number: 'PAY-001', // Required
449445
amount: 500,
450446
payment_method: 'bank_transfer', // Use underscore format
@@ -466,7 +462,7 @@ describe('Enterprise Data API', () => {
466462

467463
// Create records in different modules
468464
const account = await ctx.object('crm_account').create({
469-
id: generateId(),
465+
470466
name: 'Multi-Module Test',
471467
account_number: 'MMT001'
472468
});
@@ -476,7 +472,7 @@ describe('Enterprise Data API', () => {
476472

477473
// Create required department and position first
478474
const dept = await ctx.object('hr_department').create({
479-
id: generateId(),
475+
480476
name: 'Cross Test Dept',
481477
code: 'CTD'
482478
});
@@ -485,7 +481,7 @@ describe('Enterprise Data API', () => {
485481
expect(dept.id).toBeDefined();
486482

487483
const pos = await ctx.object('hr_position').create({
488-
id: generateId(),
484+
489485
title: 'Cross Test Position', // Position uses 'title', not 'name'
490486
code: 'CTP'
491487
});
@@ -494,7 +490,7 @@ describe('Enterprise Data API', () => {
494490
expect(pos.id).toBeDefined();
495491

496492
const employee = await ctx.object('hr_employee').create({
497-
id: generateId(),
493+
498494
first_name: 'Test',
499495
last_name: 'Employee',
500496
employee_number: 'TEST001',
@@ -511,7 +507,7 @@ describe('Enterprise Data API', () => {
511507

512508
// Create a user for project owner
513509
const user = await ctx.object('user').create({
514-
id: generateId(),
510+
515511
name: 'Cross Test User',
516512
email: 'crosstest@example.com',
517513
username: 'crosstestuser'
@@ -521,7 +517,7 @@ describe('Enterprise Data API', () => {
521517
expect(user.id).toBeDefined();
522518

523519
const project = await ctx.object('project_project').create({
524-
id: generateId(),
520+
525521
name: 'Cross-Module Project',
526522
code: 'CROSS-001',
527523
status: 'planning',

packages/drivers/sql/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"dependencies": {
2525
"@objectql/types": "workspace:*",
2626
"@objectstack/spec": "^0.3.1",
27-
"knex": "^3.1.0"
27+
"knex": "^3.1.0",
28+
"nanoid": "^3.3.11"
2829
},
2930
"devDependencies": {
3031
"sqlite3": "^5.1.7"

packages/drivers/sql/src/index.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ type DriverInterface = System.DriverInterface;
1313

1414
import { Driver, IntrospectedSchema, IntrospectedTable, IntrospectedColumn, IntrospectedForeignKey } from '@objectql/types';
1515
import knex, { Knex } from 'knex';
16+
import { nanoid } from 'nanoid';
17+
18+
/**
19+
* Default ID length for auto-generated IDs
20+
*/
21+
const DEFAULT_ID_LENGTH = 16;
1622

1723
/**
1824
* Command interface for executeCommand method
@@ -271,8 +277,9 @@ export class SqlDriver implements Driver {
271277
// If _id exists and id doesn't, map _id to id
272278
if (_id !== undefined && toInsert.id === undefined) {
273279
toInsert.id = _id;
274-
} else if (toInsert.id !== undefined) {
275-
// normal case
280+
} else if (toInsert.id === undefined) {
281+
// Auto-generate ID if not provided
282+
toInsert.id = nanoid(DEFAULT_ID_LENGTH);
276283
}
277284

278285
// Knex insert returns Result array (e.g. ids)
@@ -290,7 +297,10 @@ export class SqlDriver implements Driver {
290297
const builder = this.getBuilder(objectName, options);
291298
const formatted = this.formatInput(objectName, data);
292299
await builder.where('id', id).update(formatted);
293-
return { id, ...data };
300+
301+
// Fetch and return the updated record
302+
const updated = await this.findOne(objectName, id, undefined, options);
303+
return updated;
294304
}
295305

296306
async delete(objectName: string, id: string | number, options?: any) {

packages/foundation/core/src/repository.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,14 +314,30 @@ export class ObjectRepository {
314314
}
315315

316316
async count(filters: any): Promise<number> {
317+
// Normalize filters to UnifiedQuery format
318+
// If filters is an array, wrap it in a query object
319+
// If filters is already a UnifiedQuery (has UnifiedQuery-specific properties), use it as-is
320+
let query: UnifiedQuery;
321+
if (Array.isArray(filters)) {
322+
query = { filters };
323+
} else if (filters && typeof filters === 'object' && (filters.fields || filters.sort || filters.limit !== undefined || filters.skip !== undefined)) {
324+
// It's already a UnifiedQuery object
325+
query = filters;
326+
} else if (filters) {
327+
// It's a raw filter object, wrap it
328+
query = { filters };
329+
} else {
330+
query = {};
331+
}
332+
317333
const hookCtx: RetrievalHookContext = {
318334
...this.context,
319335
objectName: this.objectName,
320336
operation: 'count',
321337
api: this.getHookAPI(),
322338
user: this.getUserFromContext(),
323339
state: {},
324-
query: filters
340+
query
325341
};
326342
await this.app.triggerHook('beforeCount', this.objectName, hookCtx);
327343

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)