@objectql/server 1.7.2 → 1.8.0

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.
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Integration Example: Demonstrates the new standardized API response format
3
+ *
4
+ * This file is for documentation purposes and shows how the API responses
5
+ * look with the new standardized format.
6
+ */
7
+
8
+ import { ObjectQL } from '@objectql/core';
9
+ import { createRESTHandler } from '../src/adapters/rest';
10
+ import { Driver } from '@objectql/types';
11
+
12
+ // Example: Setting up ObjectQL with a simple in-memory driver
13
+ class InMemoryDriver implements Driver {
14
+ private data: Record<string, any[]> = {};
15
+
16
+ async init() {}
17
+
18
+ async find(objectName: string, query: any) {
19
+ let items = this.data[objectName] || [];
20
+
21
+ // Apply skip and limit for pagination
22
+ if (query) {
23
+ if (query.skip) {
24
+ items = items.slice(query.skip);
25
+ }
26
+ if (query.limit) {
27
+ items = items.slice(0, query.limit);
28
+ }
29
+ }
30
+
31
+ return items;
32
+ }
33
+
34
+ async findOne(objectName: string, id: string | number) {
35
+ const items = this.data[objectName] || [];
36
+ return items.find(item => item.id === String(id)) || null;
37
+ }
38
+
39
+ async create(objectName: string, data: any) {
40
+ if (!this.data[objectName]) {
41
+ this.data[objectName] = [];
42
+ }
43
+ const newItem = { ...data, id: String(Date.now()) };
44
+ this.data[objectName].push(newItem);
45
+ return newItem;
46
+ }
47
+
48
+ async update(objectName: string, id: string | number, data: any) {
49
+ const items = this.data[objectName] || [];
50
+ const index = items.findIndex(item => item.id === String(id));
51
+ if (index >= 0) {
52
+ this.data[objectName][index] = { ...items[index], ...data };
53
+ return this.data[objectName][index];
54
+ }
55
+ return null;
56
+ }
57
+
58
+ async delete(objectName: string, id: string | number) {
59
+ const items = this.data[objectName] || [];
60
+ const index = items.findIndex(item => item.id === String(id));
61
+ if (index >= 0) {
62
+ this.data[objectName].splice(index, 1);
63
+ return 1;
64
+ }
65
+ return 0;
66
+ }
67
+
68
+ async count(objectName: string) {
69
+ return (this.data[objectName] || []).length;
70
+ }
71
+
72
+ // Seed some sample data
73
+ seed(objectName: string, items: any[]) {
74
+ this.data[objectName] = items;
75
+ }
76
+ }
77
+
78
+ // Initialize ObjectQL
79
+ const driver = new InMemoryDriver();
80
+ const app = new ObjectQL({
81
+ datasources: {
82
+ default: driver
83
+ }
84
+ });
85
+
86
+ // Register a simple object schema
87
+ app.metadata.register('object', {
88
+ type: 'object',
89
+ id: 'contract',
90
+ content: {
91
+ name: 'contract',
92
+ label: 'Contract',
93
+ fields: {
94
+ name: { type: 'text', label: 'Contract Name' },
95
+ amount: { type: 'number', label: 'Amount' },
96
+ status: { type: 'text', label: 'Status' }
97
+ }
98
+ }
99
+ });
100
+
101
+ // Seed sample data
102
+ driver.seed('contract', [
103
+ { id: '1', name: 'Contract A', amount: 5000, status: 'active' },
104
+ { id: '2', name: 'Contract B', amount: 3000, status: 'pending' },
105
+ { id: '3', name: 'Contract C', amount: 7500, status: 'active' },
106
+ { id: '4', name: 'Contract D', amount: 2000, status: 'completed' },
107
+ { id: '5', name: 'Contract E', amount: 9000, status: 'active' },
108
+ ]);
109
+
110
+ /**
111
+ * Example 1: List all contracts (no pagination)
112
+ *
113
+ * Request: GET /api/data/contract
114
+ *
115
+ * Response:
116
+ * {
117
+ * "items": [
118
+ * { "id": "1", "name": "Contract A", "amount": 5000, "status": "active" },
119
+ * { "id": "2", "name": "Contract B", "amount": 3000, "status": "pending" },
120
+ * { "id": "3", "name": "Contract C", "amount": 7500, "status": "active" },
121
+ * { "id": "4", "name": "Contract D", "amount": 2000, "status": "completed" },
122
+ * { "id": "5", "name": "Contract E", "amount": 9000, "status": "active" }
123
+ * ]
124
+ * }
125
+ */
126
+
127
+ /**
128
+ * Example 2: List contracts with pagination (first page)
129
+ *
130
+ * Request: GET /api/data/contract?limit=2&skip=0
131
+ *
132
+ * Response:
133
+ * {
134
+ * "items": [
135
+ * { "id": "1", "name": "Contract A", "amount": 5000, "status": "active" },
136
+ * { "id": "2", "name": "Contract B", "amount": 3000, "status": "pending" }
137
+ * ],
138
+ * "meta": {
139
+ * "total": 5,
140
+ * "page": 1,
141
+ * "size": 2,
142
+ * "pages": 3,
143
+ * "has_next": true
144
+ * }
145
+ * }
146
+ */
147
+
148
+ /**
149
+ * Example 3: List contracts with pagination (second page)
150
+ *
151
+ * Request: GET /api/data/contract?limit=2&skip=2
152
+ *
153
+ * Response:
154
+ * {
155
+ * "items": [
156
+ * { "id": "3", "name": "Contract C", "amount": 7500, "status": "active" },
157
+ * { "id": "4", "name": "Contract D", "amount": 2000, "status": "completed" }
158
+ * ],
159
+ * "meta": {
160
+ * "total": 5,
161
+ * "page": 2,
162
+ * "size": 2,
163
+ * "pages": 3,
164
+ * "has_next": true
165
+ * }
166
+ * }
167
+ */
168
+
169
+ /**
170
+ * Example 4: Get a single contract
171
+ *
172
+ * Request: GET /api/data/contract/1
173
+ *
174
+ * Response:
175
+ * {
176
+ * "data": {
177
+ * "id": "1",
178
+ * "name": "Contract A",
179
+ * "amount": 5000,
180
+ * "status": "active"
181
+ * }
182
+ * }
183
+ */
184
+
185
+ /**
186
+ * Example 5: Create a new contract
187
+ *
188
+ * Request: POST /api/data/contract
189
+ * Body: { "name": "Contract F", "amount": 4500, "status": "pending" }
190
+ *
191
+ * Response:
192
+ * {
193
+ * "data": {
194
+ * "id": "6",
195
+ * "name": "Contract F",
196
+ * "amount": 4500,
197
+ * "status": "pending"
198
+ * }
199
+ * }
200
+ */
201
+
202
+ /**
203
+ * Example 6: Update a contract
204
+ *
205
+ * Request: PUT /api/data/contract/1
206
+ * Body: { "status": "completed" }
207
+ *
208
+ * Response:
209
+ * {
210
+ * "data": {
211
+ * "id": "1",
212
+ * "name": "Contract A",
213
+ * "amount": 5000,
214
+ * "status": "completed"
215
+ * }
216
+ * }
217
+ */
218
+
219
+ /**
220
+ * Example 7: Delete a contract
221
+ *
222
+ * Request: DELETE /api/data/contract/1
223
+ *
224
+ * Response:
225
+ * {
226
+ * "data": {
227
+ * "id": "1",
228
+ * "deleted": true
229
+ * }
230
+ * }
231
+ */
232
+
233
+ /**
234
+ * Example 8: Error response (not found)
235
+ *
236
+ * Request: GET /api/data/contract/999
237
+ *
238
+ * Response:
239
+ * {
240
+ * "error": {
241
+ * "code": "NOT_FOUND",
242
+ * "message": "Record not found"
243
+ * }
244
+ * }
245
+ */
246
+
247
+ export { app, driver };
package/test/node.test.ts CHANGED
@@ -60,7 +60,7 @@ describe('Node Adapter', () => {
60
60
 
61
61
  expect(response.status).toBe(200);
62
62
  expect(response.body).toEqual({
63
- data: [{ id: 1, name: 'Alice' }]
63
+ items: [{ id: 1, name: 'Alice' }]
64
64
  });
65
65
  });
66
66
 
@@ -78,7 +78,9 @@ describe('Node Adapter', () => {
78
78
 
79
79
  expect(response.status).toBe(200);
80
80
  expect(response.body).toEqual({
81
- data: { id: 2, name: 'Bob' }
81
+ id: 2,
82
+ name: 'Bob',
83
+ '@type': 'user'
82
84
  });
83
85
  });
84
86