Skip to content

Commit f848d5c

Browse files
authored
Merge pull request #877 from objectstack-ai/copilot/unify-id-field-naming
2 parents 5d862a2 + 03a58c1 commit f848d5c

41 files changed

Lines changed: 191 additions & 199 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ROADMAP.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ This strategy ensures rapid iteration while maintaining a clear path to producti
126126
| CI lint rule rejecting new `z.any()` | 🔴 | Planned — eslint or custom lint rule to block `z.any()` additions |
127127
| Dispatcher async `getService` bug fix || All `getService`/`getObjectQLService` calls in `http-dispatcher.ts` now properly `await` async service factories. Covers `handleAnalytics`, `handleAuth`, `handleStorage`, `handleAutomation`, `handleMetadata`, `handleUi`, `handlePackages`. All 7 framework adapters (Express, Fastify, Hono, Next.js, SvelteKit, NestJS, Nuxt) updated to use `getServiceAsync()` for auth service resolution. |
128128
| Analytics `getMetadata``getMeta` naming fix || `handleAnalytics` in `http-dispatcher.ts` called `getMetadata({ request })` which didn't match the `IAnalyticsService` contract (`getMeta(cubeName?: string)`). Renamed to `getMeta()` and aligned call signature. Updated test mocks accordingly. |
129+
| Unified ID/audit/tenant field naming || Eliminated `_id`/`modified_at`/`modified_by`/`space_id` from protocol layer. All protocol code uses `id`, `updated_at`, `updated_by`, `tenant_id` per `SystemFieldName`. Storage-layer (NoSQL driver internals) retains `_id` for MongoDB/Mingo compat. |
129130

130131
---
131132

apps/studio/src/components/ObjectDataForm.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ export function ObjectDataForm({ objectApiName, record, onSuccess, onCancel }: O
5757

5858
try {
5959
const dataToSubmit = { ...formData };
60-
delete dataToSubmit._id;
6160
delete dataToSubmit.id;
6261
delete dataToSubmit.created_at;
6362
delete dataToSubmit.updated_at;
@@ -71,8 +70,8 @@ export function ObjectDataForm({ objectApiName, record, onSuccess, onCancel }: O
7170
});
7271
}
7372

74-
if (record && (record.id || record._id)) {
75-
await client.data.update(objectApiName, record.id || record._id, dataToSubmit);
73+
if (record && record.id) {
74+
await client.data.update(objectApiName, record.id, dataToSubmit);
7675
} else {
7776
await client.data.create(objectApiName, dataToSubmit);
7877
}
@@ -109,10 +108,10 @@ export function ObjectDataForm({ objectApiName, record, onSuccess, onCancel }: O
109108

110109
const fields = def.fields || {};
111110
const fieldKeys = Object.keys(fields).filter(k => {
112-
return !['created_at', 'updated_at', 'created_by', 'modified_by'].includes(k);
111+
return !['created_at', 'updated_at', 'created_by', 'updated_by'].includes(k);
113112
});
114113

115-
const isEdit = !!(record && (record.id || record._id));
114+
const isEdit = !!(record && record.id);
116115

117116
return (
118117
<Dialog open={true} onOpenChange={(open) => !open && onCancel()}>

apps/studio/src/components/ObjectDataTable.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ export function ObjectDataTable({ objectApiName, onEdit }: ObjectDataTableProps)
277277
{loading && records.length === 0 ? (
278278
<TableSkeleton cols={columns.length} />
279279
) : filteredRecords.map(record => (
280-
<TableRow key={record.id || record._id} className="group">
280+
<TableRow key={record.id} className="group">
281281
{columns.map(col => (
282282
<TableCell key={col.name} className="py-2.5">
283283
<CellValue value={record[col.name]} type={col.type} />
@@ -302,7 +302,7 @@ export function ObjectDataTable({ objectApiName, onEdit }: ObjectDataTableProps)
302302
</DropdownMenuItem>
303303
<DropdownMenuSeparator />
304304
<DropdownMenuItem
305-
onClick={() => handleDelete(record.id || record._id)}
305+
onClick={() => handleDelete(record.id)}
306306
className="text-destructive focus:text-destructive"
307307
>
308308
<Trash2 className="mr-2 h-4 w-4" />

apps/studio/src/mocks/createKernel.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export async function createKernel(options: KernelOptions) {
6565
if (method === 'create') {
6666
const res = await ql.insert(params.object, params.data);
6767
const record = { ...params.data, ...res };
68-
return { object: params.object, id: record.id || record._id, record };
68+
return { object: params.object, id: record.id, record };
6969
}
7070
if (method === 'get') {
7171
// Delegate to protocol for proper expand/select support
@@ -74,7 +74,7 @@ export async function createKernel(options: KernelOptions) {
7474
}
7575
let all = await ql.find(params.object);
7676
if (!all) all = [];
77-
const match = all.find((i: any) => i.id === params.id || i._id === params.id);
77+
const match = all.find((i: any) => i.id === params.id);
7878
return match ? { object: params.object, id: params.id, record: match } : null;
7979
}
8080
if (method === 'update') {
@@ -85,7 +85,7 @@ export async function createKernel(options: KernelOptions) {
8585
if (all && (all as any).value) all = (all as any).value;
8686
if (!all) all = [];
8787

88-
const existing = all.find((i: any) => i.id === params.id || i._id === params.id);
88+
const existing = all.find((i: any) => i.id === params.id);
8989

9090
if (!existing) {
9191
console.warn(`[BrokerShim] Update failed: Record ${params.id} not found.`);
@@ -183,7 +183,7 @@ export async function createKernel(options: KernelOptions) {
183183
: String(queryOptions.select).split(',').map((s: string) => s.trim());
184184

185185
all = all.map((item: any) => {
186-
const projected: any = { id: item.id, _id: item._id }; // Always include ID
186+
const projected: any = { id: item.id }; // Always include ID
187187
selectFields.forEach((f: string) => {
188188
if (item[f] !== undefined) projected[f] = item[f];
189189
});

apps/studio/src/types.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
* Task type definition (todo_task)
55
*/
66
export interface Task {
7-
_id: string; // Internal ID
8-
id: string; // External ID usually, but here we might get _id or id depending on driver
7+
id: string;
98
subject: string;
109
priority: number;
1110
is_completed: boolean;

content/docs/guides/standards.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ describe('Account Object', () => {
545545
- [ ] All objects use `ObjectSchema.create()`
546546
- [ ] Field names are `snake_case`
547547
- [ ] Config keys are `camelCase`
548-
- [ ] Lookups don't have `_id` suffix
548+
- [ ] Lookups don't have `_id` suffix (use `id`)
549549
- [ ] All validations have clear messages
550550
- [ ] Documentation is up to date
551551
- [ ] Tests pass

content/docs/protocol/objectql/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ const query: Query = {
147147
-- PostgreSQL (with JOIN)
148148
SELECT c.company_name, c.industry, u.name AS "owner.name"
149149
FROM customer c
150-
LEFT JOIN user u ON c.owner_id = u._id
150+
LEFT JOIN user u ON c.owner_id = u.id
151151
WHERE c.industry = 'tech' AND c.annual_revenue > 1000000
152152
ORDER BY c.created_at DESC
153153
LIMIT 10;

content/docs/protocol/objectql/query-syntax.mdx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ SELECT
407407
o.amount,
408408
a.company_name AS "account.company_name"
409409
FROM opportunity o
410-
LEFT JOIN account a ON o.account_id = a._id
410+
LEFT JOIN account a ON o.account_id = a.id
411411
```
412412

413413
### Multiple Relationships
@@ -594,7 +594,7 @@ const query = {
594594
['exists', {
595595
object: 'opportunity',
596596
filters: [
597-
['account_id', '=', '{{parent._id}}'],
597+
['account_id', '=', '{{parent.id}}'],
598598
['stage', '=', 'Closed Won']
599599
]
600600
}]
@@ -603,7 +603,7 @@ const query = {
603603

604604
// SQL: WHERE EXISTS (
605605
// SELECT 1 FROM opportunity
606-
// WHERE opportunity.account_id = account._id
606+
// WHERE opportunity.account_id = account.id
607607
// AND opportunity.stage = 'Closed Won'
608608
// )
609609
```
@@ -617,7 +617,7 @@ const query = {
617617
['not_exists', {
618618
object: 'opportunity',
619619
filters: [
620-
['account_id', '=', '{{parent._id}}']
620+
['account_id', '=', '{{parent.id}}']
621621
]
622622
}]
623623
]
@@ -778,17 +778,17 @@ const page2 = await ObjectQL.query({
778778
const result = await ObjectQL.query({
779779
object: 'customer',
780780
limit: 10,
781-
sort: [{ field: '_id', order: 'asc' }]
781+
sort: [{ field: 'id', order: 'asc' }]
782782
});
783783

784-
// Next page (use last _id as cursor)
784+
// Next page (use last id as cursor)
785785
const nextResult = await ObjectQL.query({
786786
object: 'customer',
787787
filters: [
788-
['_id', '>', result[result.length - 1]._id]
788+
['id', '>', result[result.length - 1].id]
789789
],
790790
limit: 10,
791-
sort: [{ field: '_id', order: 'asc' }]
791+
sort: [{ field: 'id', order: 'asc' }]
792792
});
793793
```
794794

@@ -808,7 +808,7 @@ const customer = await ObjectQL.findOne('customer', '123');
808808
// Equivalent to:
809809
await ObjectQL.query({
810810
object: 'customer',
811-
filters: [['_id', '=', '123']],
811+
filters: [['id', '=', '123']],
812812
limit: 1
813813
});
814814
```

content/docs/protocol/objectql/schema.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ label: Project
7575
```
7676
7777
This 2-line definition creates:
78-
- Database table `project` with system fields (`_id`, `created_at`, `updated_at`)
78+
- Database table `project` with system fields (`id`, `created_at`, `updated_at`)
7979
- REST API: `GET/POST/PUT/DELETE /api/project`
8080
- Admin UI: List view + Form
8181
- TypeScript types
@@ -303,7 +303,7 @@ Every object automatically includes system fields:
303303

304304
```yaml
305305
# Auto-generated (not defined in .object.yml)
306-
_id:
306+
id:
307307
type: id
308308
label: Record ID
309309
read_only: true
@@ -637,7 +637,7 @@ parent_id:
637637
Query polymorphic fields:
638638
```typescript
639639
const activity = await ObjectQL.findOne('activity', id);
640-
// activity.parent_id = { _id: '123', _type: 'account' }
640+
// activity.parent_id = { id: '123', _type: 'account' }
641641
```
642642

643643
### Computed Fields (Virtual)

content/docs/protocol/objectql/security.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ const user = await ObjectQL.findOne('user', '123');
256256

257257
// Result (salary/ssn stripped):
258258
// {
259-
// _id: '123',
259+
// id: '123',
260260
// name: 'John Doe',
261261
// email: 'john@example.com'
262262
// // salary: REMOVED
@@ -268,7 +268,7 @@ const user = await ObjectQL.findOne('user', '123');
268268

269269
// Result (salary visible):
270270
// {
271-
// _id: '123',
271+
// id: '123',
272272
// name: 'John Doe',
273273
// email: 'john@example.com',
274274
// salary: { amount: 120000, currency: 'USD' }

0 commit comments

Comments
 (0)