Skip to content

Commit 986bf59

Browse files
Copilothotlong
andcommitted
fix: add upsert support to batchData and update kernel services docs
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent ac5972d commit 986bf59

2 files changed

Lines changed: 89 additions & 0 deletions

File tree

content/docs/architecture/core.mdx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,85 @@ await kernel.stop();
693693
const plugins = kernel.getPlugins();
694694
```
695695

696+
## Kernel Services
697+
698+
ObjectQL implements the ObjectStack protocol's **kernel services architecture**. The protocol defines **17 services** with **57 total methods** governed by the `ObjectStackProtocol` interface.
699+
700+
### Architecture
701+
702+
```
703+
┌─────────────────────────────────────────────────────────┐
704+
│ Kernel Layer │
705+
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
706+
│ │ metadata (⚠️) │ │ data + analytics (✅) │ │
707+
│ │ In-memory only │ │ ObjectQL example kernel │ │
708+
│ │ DB persistence │ │ Will be rebuilt as plugins │ │
709+
│ │ pending │ │ │ │
710+
│ └──────────────────┘ └──────────────────────────────┘ │
711+
├─────────────────────────────────────────────────────────┤
712+
│ Plugin Layer │
713+
│ All other services: auth, automation, workflow, ui, │
714+
│ realtime, notification, ai, i18n, graphql, search, │
715+
│ file-storage, cache, queue, job │
716+
│ │
717+
│ Discovery API reports: enabled/unavailable/degraded │
718+
│ per service so clients adapt their UI accordingly │
719+
└─────────────────────────────────────────────────────────┘
720+
```
721+
722+
### Service Status
723+
724+
The `getDiscovery()` method returns a per-service status map so clients know what is available:
725+
726+
```typescript
727+
const protocol = new ObjectStackProtocolImplementation(engine);
728+
const discovery = await protocol.getDiscovery();
729+
730+
// discovery.services.metadata → { enabled: true, status: 'degraded', ... }
731+
// discovery.services.data → { enabled: true, status: 'available', ... }
732+
// discovery.services.auth → { enabled: false, status: 'unavailable', ... }
733+
```
734+
735+
### Implemented Services (Kernel-Provided)
736+
737+
| Service | Methods | Status |
738+
|:--------|:--------|:-------|
739+
| **metadata** | 7 (getDiscovery, getMetaTypes, getMetaItems, getMetaItem, saveMetaItem, getMetaItemCached, getUiView) | ⚠️ Framework (in-memory) |
740+
| **data** | 9 (findData, getData, createData, updateData, deleteData, batchData, createManyData, updateManyData, deleteManyData) | ✅ Implemented |
741+
| **analytics** | 2 (analyticsQuery, getAnalyticsMeta) | ✅ Implemented |
742+
743+
### Plugin-Required Services
744+
745+
| Service | Methods | Criticality |
746+
|:--------|:--------|:------------|
747+
| **auth** | 3 (checkPermission, getObjectPermissions, getEffectivePermissions) | required |
748+
| **ui** | 5 (listViews, getView, createView, updateView, deleteView) | optional |
749+
| **workflow** | 5 (getWorkflowConfig, getWorkflowState, workflowTransition, workflowApprove, workflowReject) | optional |
750+
| **automation** | 1 (triggerAutomation) | optional |
751+
| **realtime** | 6 (connect, disconnect, subscribe, unsubscribe, setPresence, getPresence) | optional |
752+
| **notification** | 7 (registerDevice, unregisterDevice, getNotificationPreferences, updateNotificationPreferences, listNotifications, markNotificationsRead, markAllNotificationsRead) | optional |
753+
| **ai** | 4 (aiNlq, aiChat, aiSuggest, aiInsights) | optional |
754+
| **i18n** | 3 (getLocales, getTranslations, getFieldLabels) | optional |
755+
| **cache** || core |
756+
| **queue** || core |
757+
| **job** || core |
758+
759+
### Plugin Registration
760+
761+
When a plugin registers a service, the discovery endpoint automatically updates:
762+
763+
```typescript
764+
// In a plugin's install() method:
765+
protocol.updateServiceStatus('auth', {
766+
enabled: true,
767+
status: 'available',
768+
route: '/api/v1/auth',
769+
provider: 'plugin-auth',
770+
});
771+
```
772+
773+
For the complete kernel services specification, see: [protocol.objectstack.ai/docs/guides/kernel-services](https://protocol.objectstack.ai/docs/guides/kernel-services)
774+
696775
## Shared Metadata
697776

698777
Share `MetadataRegistry` between multiple ObjectQL instances:

packages/foundation/core/src/protocol.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ export class ObjectStackProtocolImplementation implements ObjectStackProtocol {
284284
async batchData(args: { object: string; request: { operation: 'create' | 'update' | 'delete' | 'upsert'; records: any[] } }): Promise<any> {
285285
const { object, request } = args;
286286
const { operation, records } = request;
287+
// Sequential execution to preserve ordering and avoid connection pool exhaustion
287288
const results: any[] = [];
288289

289290
for (const record of records) {
@@ -297,6 +298,15 @@ export class ObjectStackProtocolImplementation implements ObjectStackProtocol {
297298
case 'delete':
298299
results.push(await this.deleteData({ object, id: record.id || record }));
299300
break;
301+
case 'upsert': {
302+
// Try update first; if entity not found, create
303+
try {
304+
results.push(await this.updateData({ object, id: record.id, data: record }));
305+
} catch {
306+
results.push(await this.createData({ object, data: record }));
307+
}
308+
break;
309+
}
300310
default:
301311
throw new Error(`Unsupported batch operation: ${operation}`);
302312
}

0 commit comments

Comments
 (0)