@objectstack/objectql 0.6.1 → 0.7.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/CHANGELOG.md +20 -0
- package/dist/engine.d.ts +137 -47
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +238 -155
- package/dist/plugin.js +5 -10
- package/dist/protocol.d.ts +103 -33
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +224 -46
- package/package.json +5 -5
- package/src/engine.ts +256 -176
- package/src/plugin.ts +5 -5
- package/src/protocol.ts +255 -49
package/dist/protocol.d.ts
CHANGED
|
@@ -1,43 +1,113 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ObjectStackProtocol } from '@objectstack/spec/api';
|
|
2
2
|
import { IDataEngine } from '@objectstack/core';
|
|
3
|
-
|
|
3
|
+
import type { BatchUpdateRequest, BatchUpdateResponse, UpdateManyDataRequest, DeleteManyDataRequest } from '@objectstack/spec/api';
|
|
4
|
+
import type { MetadataCacheRequest, MetadataCacheResponse } from '@objectstack/spec/api';
|
|
5
|
+
import type { CreateViewRequest, UpdateViewRequest, ListViewsRequest, ViewResponse, ListViewsResponse } from '@objectstack/spec/api';
|
|
6
|
+
export declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
|
|
4
7
|
private engine;
|
|
8
|
+
private viewStorage;
|
|
5
9
|
constructor(engine: IDataEngine);
|
|
6
|
-
getDiscovery(): {
|
|
7
|
-
name: string;
|
|
10
|
+
getDiscovery(_request: {}): Promise<{
|
|
8
11
|
version: string;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
getMetaItems(
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
apiName: string;
|
|
13
|
+
capabilities: string[];
|
|
14
|
+
endpoints: {};
|
|
15
|
+
}>;
|
|
16
|
+
getMetaTypes(_request: {}): Promise<{
|
|
17
|
+
types: string[];
|
|
18
|
+
}>;
|
|
19
|
+
getMetaItems(request: {
|
|
20
|
+
type: string;
|
|
21
|
+
}): Promise<{
|
|
22
|
+
type: string;
|
|
23
|
+
items: unknown[];
|
|
24
|
+
}>;
|
|
25
|
+
getMetaItem(request: {
|
|
26
|
+
type: string;
|
|
27
|
+
name: string;
|
|
28
|
+
}): Promise<{
|
|
19
29
|
type: string;
|
|
30
|
+
name: string;
|
|
31
|
+
item: unknown;
|
|
32
|
+
}>;
|
|
33
|
+
getUiView(request: {
|
|
34
|
+
object: string;
|
|
35
|
+
type: 'list' | 'form';
|
|
36
|
+
}): Promise<{
|
|
37
|
+
object: string;
|
|
38
|
+
type: "list" | "form";
|
|
39
|
+
view: any;
|
|
40
|
+
}>;
|
|
41
|
+
findData(request: {
|
|
42
|
+
object: string;
|
|
43
|
+
query?: any;
|
|
44
|
+
}): Promise<{
|
|
45
|
+
object: string;
|
|
46
|
+
value: any[];
|
|
47
|
+
records: any[];
|
|
48
|
+
total: number;
|
|
49
|
+
hasMore: boolean;
|
|
50
|
+
}>;
|
|
51
|
+
getData(request: {
|
|
20
52
|
object: string;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
53
|
+
id: string;
|
|
54
|
+
}): Promise<{
|
|
55
|
+
object: string;
|
|
56
|
+
id: string;
|
|
57
|
+
record: any;
|
|
58
|
+
}>;
|
|
59
|
+
createData(request: {
|
|
60
|
+
object: string;
|
|
61
|
+
data: any;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
object: string;
|
|
64
|
+
id: any;
|
|
65
|
+
record: any;
|
|
66
|
+
}>;
|
|
67
|
+
updateData(request: {
|
|
68
|
+
object: string;
|
|
69
|
+
id: string;
|
|
70
|
+
data: any;
|
|
71
|
+
}): Promise<{
|
|
72
|
+
object: string;
|
|
73
|
+
id: string;
|
|
74
|
+
record: any;
|
|
75
|
+
}>;
|
|
76
|
+
deleteData(request: {
|
|
77
|
+
object: string;
|
|
78
|
+
id: string;
|
|
79
|
+
}): Promise<{
|
|
80
|
+
object: string;
|
|
81
|
+
id: string;
|
|
82
|
+
success: boolean;
|
|
83
|
+
}>;
|
|
84
|
+
getMetaItemCached(request: {
|
|
27
85
|
type: string;
|
|
86
|
+
name: string;
|
|
87
|
+
cacheRequest?: MetadataCacheRequest;
|
|
88
|
+
}): Promise<MetadataCacheResponse>;
|
|
89
|
+
batchData(_request: {
|
|
90
|
+
object: string;
|
|
91
|
+
request: BatchUpdateRequest;
|
|
92
|
+
}): Promise<BatchUpdateResponse>;
|
|
93
|
+
createManyData(request: {
|
|
94
|
+
object: string;
|
|
95
|
+
records: any[];
|
|
96
|
+
}): Promise<any>;
|
|
97
|
+
updateManyData(_request: UpdateManyDataRequest): Promise<any>;
|
|
98
|
+
deleteManyData(request: DeleteManyDataRequest): Promise<any>;
|
|
99
|
+
createView(request: CreateViewRequest): Promise<ViewResponse>;
|
|
100
|
+
getView(request: {
|
|
101
|
+
id: string;
|
|
102
|
+
}): Promise<ViewResponse>;
|
|
103
|
+
listViews(request: ListViewsRequest): Promise<ListViewsResponse>;
|
|
104
|
+
updateView(request: UpdateViewRequest): Promise<ViewResponse>;
|
|
105
|
+
deleteView(request: {
|
|
106
|
+
id: string;
|
|
107
|
+
}): Promise<{
|
|
108
|
+
success: boolean;
|
|
28
109
|
object: string;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
fields: {
|
|
32
|
-
field: string;
|
|
33
|
-
}[];
|
|
34
|
-
}[];
|
|
35
|
-
columns?: undefined;
|
|
36
|
-
};
|
|
37
|
-
findData(object: string, query: any): Promise<any[]>;
|
|
38
|
-
getData(object: string, id: string): Promise<any>;
|
|
39
|
-
createData(object: string, data: any): Promise<any>;
|
|
40
|
-
updateData(object: string, id: string, data: any): Promise<any>;
|
|
41
|
-
deleteData(object: string, id: string): Promise<boolean>;
|
|
110
|
+
id: string;
|
|
111
|
+
}>;
|
|
42
112
|
}
|
|
43
113
|
//# sourceMappingURL=protocol.d.ts.map
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.js
CHANGED
|
@@ -1,37 +1,58 @@
|
|
|
1
1
|
// We import SchemaRegistry directly since this class lives in the same package
|
|
2
2
|
import { SchemaRegistry } from './registry';
|
|
3
|
+
/**
|
|
4
|
+
* Simple hash function for ETag generation (browser-compatible)
|
|
5
|
+
* Uses a basic hash algorithm instead of crypto.createHash
|
|
6
|
+
*/
|
|
7
|
+
function simpleHash(str) {
|
|
8
|
+
let hash = 0;
|
|
9
|
+
for (let i = 0; i < str.length; i++) {
|
|
10
|
+
const char = str.charCodeAt(i);
|
|
11
|
+
hash = ((hash << 5) - hash) + char;
|
|
12
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
13
|
+
}
|
|
14
|
+
return Math.abs(hash).toString(16);
|
|
15
|
+
}
|
|
3
16
|
export class ObjectStackProtocolImplementation {
|
|
4
17
|
constructor(engine) {
|
|
18
|
+
this.viewStorage = new Map();
|
|
5
19
|
this.engine = engine;
|
|
6
20
|
}
|
|
7
|
-
getDiscovery() {
|
|
21
|
+
async getDiscovery(_request) {
|
|
8
22
|
return {
|
|
9
|
-
name: 'ObjectStack API',
|
|
10
23
|
version: '1.0',
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
ui: true
|
|
15
|
-
}
|
|
24
|
+
apiName: 'ObjectStack API',
|
|
25
|
+
capabilities: ['metadata', 'data', 'ui'],
|
|
26
|
+
endpoints: {}
|
|
16
27
|
};
|
|
17
28
|
}
|
|
18
|
-
getMetaTypes() {
|
|
19
|
-
return
|
|
29
|
+
async getMetaTypes(_request) {
|
|
30
|
+
return {
|
|
31
|
+
types: SchemaRegistry.getRegisteredTypes()
|
|
32
|
+
};
|
|
20
33
|
}
|
|
21
|
-
getMetaItems(
|
|
22
|
-
return
|
|
34
|
+
async getMetaItems(request) {
|
|
35
|
+
return {
|
|
36
|
+
type: request.type,
|
|
37
|
+
items: SchemaRegistry.listItems(request.type)
|
|
38
|
+
};
|
|
23
39
|
}
|
|
24
|
-
getMetaItem(
|
|
25
|
-
return
|
|
40
|
+
async getMetaItem(request) {
|
|
41
|
+
return {
|
|
42
|
+
type: request.type,
|
|
43
|
+
name: request.name,
|
|
44
|
+
item: SchemaRegistry.getItem(request.type, request.name)
|
|
45
|
+
};
|
|
26
46
|
}
|
|
27
|
-
getUiView(
|
|
28
|
-
const schema = SchemaRegistry.getObject(object);
|
|
47
|
+
async getUiView(request) {
|
|
48
|
+
const schema = SchemaRegistry.getObject(request.object);
|
|
29
49
|
if (!schema)
|
|
30
|
-
throw new Error(`Object ${object} not found`);
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
throw new Error(`Object ${request.object} not found`);
|
|
51
|
+
let view;
|
|
52
|
+
if (request.type === 'list') {
|
|
53
|
+
view = {
|
|
33
54
|
type: 'list',
|
|
34
|
-
object: object,
|
|
55
|
+
object: request.object,
|
|
35
56
|
columns: Object.keys(schema.fields || {}).slice(0, 5).map(f => ({
|
|
36
57
|
field: f,
|
|
37
58
|
label: schema.fields[f].label || f
|
|
@@ -39,9 +60,9 @@ export class ObjectStackProtocolImplementation {
|
|
|
39
60
|
};
|
|
40
61
|
}
|
|
41
62
|
else {
|
|
42
|
-
|
|
63
|
+
view = {
|
|
43
64
|
type: 'form',
|
|
44
|
-
object: object,
|
|
65
|
+
object: request.object,
|
|
45
66
|
sections: [
|
|
46
67
|
{
|
|
47
68
|
label: 'General',
|
|
@@ -52,36 +73,193 @@ export class ObjectStackProtocolImplementation {
|
|
|
52
73
|
]
|
|
53
74
|
};
|
|
54
75
|
}
|
|
76
|
+
return {
|
|
77
|
+
object: request.object,
|
|
78
|
+
type: request.type,
|
|
79
|
+
view
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async findData(request) {
|
|
83
|
+
// TODO: Normalize query from HTTP Query params (string values) to DataEngineQueryOptions (typed)
|
|
84
|
+
// For now, we assume query is partially compatible or simple enough.
|
|
85
|
+
// We should parse 'top', 'skip', 'limit' to numbers if they are strings.
|
|
86
|
+
const options = { ...request.query };
|
|
87
|
+
if (options.top)
|
|
88
|
+
options.top = Number(options.top);
|
|
89
|
+
if (options.skip)
|
|
90
|
+
options.skip = Number(options.skip);
|
|
91
|
+
if (options.limit)
|
|
92
|
+
options.limit = Number(options.limit);
|
|
93
|
+
// Handle OData style $filter if present, or flat filters
|
|
94
|
+
// This is a naive implementation, a real OData parser is needed for complex scenarios.
|
|
95
|
+
const records = await this.engine.find(request.object, options);
|
|
96
|
+
return {
|
|
97
|
+
object: request.object,
|
|
98
|
+
value: records, // OData compaibility
|
|
99
|
+
records, // Legacy
|
|
100
|
+
total: records.length,
|
|
101
|
+
hasMore: false
|
|
102
|
+
};
|
|
55
103
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
async getData(object, id) {
|
|
60
|
-
// IDataEngine doesn't have findOne, so we simulate it with find and limit 1
|
|
61
|
-
// Assuming the ID field is named '_id' or 'id'.
|
|
62
|
-
// For broad compatibility, we might need to know the ID field name.
|
|
63
|
-
// But traditionally it is _id in ObjectStack/mongo or id in others.
|
|
64
|
-
// Let's rely on finding by ID if the engine supports it via find?
|
|
65
|
-
// Actually, ObjectQL (the implementation) DOES have findOne.
|
|
66
|
-
// But we are programming against IDataEngine interface here.
|
|
67
|
-
// If the engine IS ObjectQL (which it practically is), we could cast it.
|
|
68
|
-
// But let's try to stick to interface.
|
|
69
|
-
const results = await this.engine.find(object, {
|
|
70
|
-
filter: { _id: id }, // Default Assumption: _id
|
|
71
|
-
limit: 1
|
|
104
|
+
async getData(request) {
|
|
105
|
+
const result = await this.engine.findOne(request.object, {
|
|
106
|
+
filter: { _id: request.id }
|
|
72
107
|
});
|
|
73
|
-
if (
|
|
74
|
-
return
|
|
108
|
+
if (result) {
|
|
109
|
+
return {
|
|
110
|
+
object: request.object,
|
|
111
|
+
id: request.id,
|
|
112
|
+
record: result
|
|
113
|
+
};
|
|
75
114
|
}
|
|
76
|
-
throw new Error(`Record ${id} not found in ${object}`);
|
|
115
|
+
throw new Error(`Record ${request.id} not found in ${request.object}`);
|
|
116
|
+
}
|
|
117
|
+
async createData(request) {
|
|
118
|
+
const result = await this.engine.insert(request.object, request.data);
|
|
119
|
+
return {
|
|
120
|
+
object: request.object,
|
|
121
|
+
id: result._id || result.id,
|
|
122
|
+
record: result
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
async updateData(request) {
|
|
126
|
+
// Adapt: update(obj, id, data) -> update(obj, data, options)
|
|
127
|
+
const result = await this.engine.update(request.object, request.data, { filter: { _id: request.id } });
|
|
128
|
+
return {
|
|
129
|
+
object: request.object,
|
|
130
|
+
id: request.id,
|
|
131
|
+
record: result
|
|
132
|
+
};
|
|
77
133
|
}
|
|
78
|
-
|
|
79
|
-
|
|
134
|
+
async deleteData(request) {
|
|
135
|
+
// Adapt: delete(obj, id) -> delete(obj, options)
|
|
136
|
+
await this.engine.delete(request.object, { filter: { _id: request.id } });
|
|
137
|
+
return {
|
|
138
|
+
object: request.object,
|
|
139
|
+
id: request.id,
|
|
140
|
+
success: true
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
// ==========================================
|
|
144
|
+
// Metadata Caching
|
|
145
|
+
// ==========================================
|
|
146
|
+
async getMetaItemCached(request) {
|
|
147
|
+
try {
|
|
148
|
+
const item = SchemaRegistry.getItem(request.type, request.name);
|
|
149
|
+
if (!item) {
|
|
150
|
+
throw new Error(`Metadata item ${request.type}/${request.name} not found`);
|
|
151
|
+
}
|
|
152
|
+
// Calculate ETag (simple hash of the stringified metadata)
|
|
153
|
+
const content = JSON.stringify(item);
|
|
154
|
+
const hash = simpleHash(content);
|
|
155
|
+
const etag = { value: hash, weak: false };
|
|
156
|
+
// Check If-None-Match header
|
|
157
|
+
if (request.cacheRequest?.ifNoneMatch) {
|
|
158
|
+
const clientEtag = request.cacheRequest.ifNoneMatch.replace(/^"(.*)"$/, '$1').replace(/^W\/"(.*)"$/, '$1');
|
|
159
|
+
if (clientEtag === hash) {
|
|
160
|
+
// Return 304 Not Modified
|
|
161
|
+
return {
|
|
162
|
+
notModified: true,
|
|
163
|
+
etag,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Return full metadata with cache headers
|
|
168
|
+
return {
|
|
169
|
+
data: item,
|
|
170
|
+
etag,
|
|
171
|
+
lastModified: new Date().toISOString(),
|
|
172
|
+
cacheControl: {
|
|
173
|
+
directives: ['public', 'max-age'],
|
|
174
|
+
maxAge: 3600, // 1 hour
|
|
175
|
+
},
|
|
176
|
+
notModified: false,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// ==========================================
|
|
184
|
+
// Batch Operations
|
|
185
|
+
// ==========================================
|
|
186
|
+
async batchData(_request) {
|
|
187
|
+
// Map high-level batch request to DataEngine batch if available
|
|
188
|
+
// Or implement loop here.
|
|
189
|
+
// For now, let's just fail or implement basic loop to satisfying interface
|
|
190
|
+
// since full batch mapping requires careful type handling.
|
|
191
|
+
throw new Error('Batch operations not yet fully implemented in protocol adapter');
|
|
192
|
+
}
|
|
193
|
+
async createManyData(request) {
|
|
194
|
+
const records = await this.engine.insert(request.object, request.records);
|
|
195
|
+
return {
|
|
196
|
+
object: request.object,
|
|
197
|
+
records,
|
|
198
|
+
count: records.length
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
async updateManyData(_request) {
|
|
202
|
+
// TODO: Implement proper updateMany in DataEngine
|
|
203
|
+
throw new Error('updateManyData not implemented');
|
|
204
|
+
}
|
|
205
|
+
async deleteManyData(request) {
|
|
206
|
+
// This expects deleting by IDs.
|
|
207
|
+
return this.engine.delete(request.object, {
|
|
208
|
+
filter: { _id: { $in: request.ids } },
|
|
209
|
+
...request.options
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// ==========================================
|
|
213
|
+
// View Storage (Mock Implementation for now)
|
|
214
|
+
// ==========================================
|
|
215
|
+
async createView(request) {
|
|
216
|
+
const id = Math.random().toString(36).substring(7);
|
|
217
|
+
// Cast to unknown then SavedView to bypass strict type checks for the mock
|
|
218
|
+
const view = {
|
|
219
|
+
id,
|
|
220
|
+
...request,
|
|
221
|
+
createdAt: new Date().toISOString(),
|
|
222
|
+
updatedAt: new Date().toISOString(),
|
|
223
|
+
createdBy: 'system',
|
|
224
|
+
updatedBy: 'system'
|
|
225
|
+
};
|
|
226
|
+
this.viewStorage.set(id, view);
|
|
227
|
+
return { success: true, data: view };
|
|
228
|
+
}
|
|
229
|
+
async getView(request) {
|
|
230
|
+
const view = this.viewStorage.get(request.id);
|
|
231
|
+
if (!view)
|
|
232
|
+
throw new Error(`View ${request.id} not found`);
|
|
233
|
+
return { success: true, data: view };
|
|
234
|
+
}
|
|
235
|
+
async listViews(request) {
|
|
236
|
+
const views = Array.from(this.viewStorage.values())
|
|
237
|
+
.filter(v => !request?.object || v.object === request.object);
|
|
238
|
+
return {
|
|
239
|
+
success: true,
|
|
240
|
+
data: views,
|
|
241
|
+
pagination: {
|
|
242
|
+
total: views.length,
|
|
243
|
+
limit: request.limit || 50,
|
|
244
|
+
offset: request.offset || 0,
|
|
245
|
+
hasMore: false
|
|
246
|
+
}
|
|
247
|
+
};
|
|
80
248
|
}
|
|
81
|
-
|
|
82
|
-
|
|
249
|
+
async updateView(request) {
|
|
250
|
+
const view = this.viewStorage.get(request.id);
|
|
251
|
+
if (!view)
|
|
252
|
+
throw new Error(`View ${request.id} not found`);
|
|
253
|
+
const { id, ...updates } = request;
|
|
254
|
+
// Cast to unknown then SavedView to bypass strict type checks for the mock
|
|
255
|
+
const updated = { ...view, ...updates, updatedAt: new Date().toISOString() };
|
|
256
|
+
this.viewStorage.set(request.id, updated);
|
|
257
|
+
return { success: true, data: updated };
|
|
83
258
|
}
|
|
84
|
-
|
|
85
|
-
|
|
259
|
+
async deleteView(request) {
|
|
260
|
+
const deleted = this.viewStorage.delete(request.id);
|
|
261
|
+
if (!deleted)
|
|
262
|
+
throw new Error(`View ${request.id} not found`);
|
|
263
|
+
return { success: true, object: 'view', id: request.id };
|
|
86
264
|
}
|
|
87
265
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/objectql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Isomorphic ObjectQL Engine for ObjectStack",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@objectstack/core": "0.
|
|
9
|
-
"@objectstack/spec": "0.
|
|
10
|
-
"@objectstack/types": "0.
|
|
8
|
+
"@objectstack/core": "0.7.2",
|
|
9
|
+
"@objectstack/spec": "0.7.2",
|
|
10
|
+
"@objectstack/types": "0.7.2"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"typescript": "^5.0.0",
|
|
@@ -15,6 +15,6 @@
|
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsc",
|
|
18
|
-
"test": "
|
|
18
|
+
"test": "echo no tests"
|
|
19
19
|
}
|
|
20
20
|
}
|