@fjell/client-api 4.4.6 → 4.4.9

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,467 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ /**
3
+ * Multi-Level Keys Fjell-Client-API Example - Hierarchical Data Operations
4
+ *
5
+ * This example demonstrates advanced usage of fjell-client-api with multi-level
6
+ * hierarchical data structures. It shows how to work with contained items across
7
+ * multiple organizational levels.
8
+ *
9
+ * This example covers:
10
+ * - Multi-level location hierarchies (Organization → Department → Employee)
11
+ * - Nested contained item APIs with location arrays
12
+ * - Cross-hierarchy queries and operations
13
+ * - Location-based data management
14
+ * - Complex API routing with multiple path segments
15
+ *
16
+ * Run this example with: npx tsx examples/multi-level-keys.ts
17
+ *
18
+ * Note: This is a conceptual example showing hierarchical API patterns.
19
+ * In production, use actual fjell-client-api with proper types.
20
+ */
21
+
22
+ /**
23
+ * Organizational Hierarchy:
24
+ * Organization (Primary) → Department (Contained) → Employee (Contained)
25
+ *
26
+ * API Structure:
27
+ * - /organizations/{orgId}
28
+ * - /organizations/{orgId}/departments/{deptId}
29
+ * - /organizations/{orgId}/departments/{deptId}/employees/{empId}
30
+ */
31
+
32
+ // ===== Mock Hierarchical API Implementations =====
33
+
34
+ interface MockHierarchicalApi {
35
+ all(query: any, locations?: any[]): Promise<any[]>;
36
+ create(item: any, locations?: any[]): Promise<any>;
37
+ get(key: any): Promise<any>;
38
+ update(key: any, updates: any): Promise<any>;
39
+ remove(key: any): Promise<boolean>;
40
+ action(key: any, action: string, body?: any): Promise<any>;
41
+ find(finder: string, params?: any, locations?: any[]): Promise<any[]>;
42
+ facet(key: any, facet: string, params?: any): Promise<any>;
43
+ allAction(action: string, body?: any, locations?: any[]): Promise<any[]>;
44
+ allFacet(facet: string, params?: any, locations?: any[]): Promise<any>;
45
+ }
46
+
47
+ const createMockHierarchicalApi = (itemType: string, levelDepth: number): MockHierarchicalApi => ({
48
+ async all(query: any, locations?: any[]) {
49
+ const locationPath = locations ? `/${locations.join('/')}` : '';
50
+ console.log(`📊 HierarchicalApi.all(${itemType}) at level ${levelDepth} - path:${locationPath}, query:`, query);
51
+
52
+ const items = Array.from({ length: 3 }, (_, i) => ({
53
+ id: `${itemType}-${i + 1}`,
54
+ name: `${itemType} ${i + 1}`,
55
+ keyType: itemType,
56
+ ...(locations && { parentPath: locations })
57
+ }));
58
+
59
+ return items;
60
+ },
61
+
62
+ async create(item: any, locations?: any[]) {
63
+ const locationPath = locations ? `/${locations.join('/')}` : '';
64
+ const created = {
65
+ ...item,
66
+ id: `${itemType}-${Date.now()}`,
67
+ parentPath: locations
68
+ };
69
+ console.log(`➕ HierarchicalApi.create(${itemType}) at level ${levelDepth} - path:${locationPath}, created:`, created.id);
70
+ return created;
71
+ },
72
+
73
+ async get(key: any) {
74
+ console.log(`🔍 HierarchicalApi.get(${itemType}) at level ${levelDepth} - key:`, key);
75
+ return {
76
+ id: key.id,
77
+ name: `${itemType} ${key.id}`,
78
+ keyType: itemType,
79
+ level: levelDepth
80
+ };
81
+ },
82
+
83
+ async update(key: any, updates: any) {
84
+ console.log(`✏️ HierarchicalApi.update(${itemType}) at level ${levelDepth} - key:`, key, 'updates:', updates);
85
+ return { id: key.id, ...updates, keyType: itemType, level: levelDepth };
86
+ },
87
+
88
+ async remove(key: any) {
89
+ console.log(`🗑️ HierarchicalApi.remove(${itemType}) at level ${levelDepth} - key:`, key);
90
+ return true;
91
+ },
92
+
93
+ async action(key: any, action: string, body?: any) {
94
+ console.log(`⚡ HierarchicalApi.action(${itemType}) at level ${levelDepth} - action:`, action, 'on:', key.id);
95
+ return { success: true, action, result: body, level: levelDepth };
96
+ },
97
+
98
+ async find(finder: string, params?: any, locations?: any[]) {
99
+ const locationPath = locations ? `/${locations.join('/')}` : '';
100
+ console.log(`🔍 HierarchicalApi.find(${itemType}) at level ${levelDepth} - finder:`, finder, 'path:', locationPath);
101
+ return [{
102
+ id: '1',
103
+ name: `Found ${itemType}`,
104
+ keyType: itemType,
105
+ level: levelDepth,
106
+ parentPath: locations
107
+ }];
108
+ },
109
+
110
+ async facet(key: any, facet: string, params?: any) {
111
+ console.log(`📈 HierarchicalApi.facet(${itemType}) at level ${levelDepth} - facet:`, facet, 'on:', key.id);
112
+ return {
113
+ facet,
114
+ level: levelDepth,
115
+ data: { count: 10 + levelDepth, hierarchy: `Level ${levelDepth}` }
116
+ };
117
+ },
118
+
119
+ async allAction(action: string, body?: any, locations?: any[]) {
120
+ const locationPath = locations ? `/${locations.join('/')}` : '';
121
+ console.log(`📦 HierarchicalApi.allAction(${itemType}) at level ${levelDepth} - action:`, action, 'path:', locationPath);
122
+ return [
123
+ { id: '1', result: 'updated', level: levelDepth },
124
+ { id: '2', result: 'updated', level: levelDepth }
125
+ ];
126
+ },
127
+
128
+ async allFacet(facet: string, params?: any, locations?: any[]) {
129
+ const locationPath = locations ? `/${locations.join('/')}` : '';
130
+ console.log(`📊 HierarchicalApi.allFacet(${itemType}) at level ${levelDepth} - facet:`, facet, 'path:', locationPath);
131
+ return {
132
+ facet,
133
+ level: levelDepth,
134
+ totalCount: 50 + (levelDepth * 10),
135
+ data: `Level ${levelDepth} aggregated results`,
136
+ locationPath
137
+ };
138
+ }
139
+ });
140
+
141
+ /**
142
+ * Demonstrates Organization operations (Primary Items - Level 0)
143
+ */
144
+ async function demonstrateOrganizationOperations() {
145
+ console.log('\n🚀 === Organization Operations (Primary Items - Level 0) ===');
146
+
147
+ // Conceptual: const orgApi = createPItemApi<Organization, 'organization'>('organization', ['organizations'], config);
148
+ const orgApi = createMockHierarchicalApi('organization', 0);
149
+
150
+ try {
151
+ // 1. Get all organizations
152
+ console.log('\n📊 Getting all organizations...');
153
+ const organizations = await orgApi.all({});
154
+ console.log(`Found ${organizations.length} organizations`);
155
+
156
+ // 2. Create a new organization
157
+ console.log('\n➕ Creating a new organization...');
158
+ const newOrg = {
159
+ name: 'TechCorp International',
160
+ type: 'Technology',
161
+ founded: '2020',
162
+ keyType: 'organization'
163
+ };
164
+ const createdOrg = await orgApi.create(newOrg);
165
+ console.log(`Created organization: ${createdOrg.name} (${createdOrg.id})`);
166
+
167
+ // 3. Get organization analytics
168
+ console.log('\n📈 Getting organization analytics...');
169
+ const orgKey = { keyType: 'organization', id: createdOrg.id };
170
+ const analytics = await orgApi.facet(orgKey, 'analytics', {
171
+ metrics: ['employees', 'departments', 'revenue']
172
+ });
173
+ console.log(`Organization analytics:`, analytics);
174
+
175
+ return createdOrg.id;
176
+
177
+ } catch (error) {
178
+ console.error('❌ Error in organization operations:', error);
179
+ return null;
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Demonstrates Department operations (Contained Items - Level 1)
185
+ */
186
+ async function demonstrateDepartmentOperations(organizationId: string) {
187
+ console.log('\n🚀 === Department Operations (Contained Items - Level 1) ===');
188
+
189
+ // Conceptual: const deptApi = createCItemApi<Department, 'department', 'organization'>('department', ['organizations', 'departments'], config);
190
+ const deptApi = createMockHierarchicalApi('department', 1);
191
+
192
+ try {
193
+ // Organization location for departments
194
+ const orgLocation = [organizationId];
195
+
196
+ // 1. Get all departments in organization
197
+ console.log('\n📊 Getting all departments in organization...');
198
+ const departments = await deptApi.all({ active: true }, orgLocation);
199
+ console.log(`Found ${departments.length} departments in organization`);
200
+
201
+ // 2. Create multiple departments
202
+ console.log('\n➕ Creating departments...');
203
+ const departmentData = [
204
+ { name: 'Engineering', type: 'Development', budget: 1000000 },
205
+ { name: 'Marketing', type: 'Business', budget: 500000 },
206
+ { name: 'Sales', type: 'Revenue', budget: 750000 }
207
+ ];
208
+
209
+ const createdDepartments = [];
210
+ for (const deptData of departmentData) {
211
+ const newDept = { ...deptData, keyType: 'department' };
212
+ const created = await deptApi.create(newDept, orgLocation);
213
+ createdDepartments.push(created);
214
+ console.log(`Created department: ${created.name} (${created.id})`);
215
+ }
216
+
217
+ // 3. Execute batch operations on departments
218
+ console.log('\n📦 Executing batch budget update...');
219
+ await deptApi.allAction('updateBudgets', {
220
+ adjustment: 0.10, // 10% increase
221
+ reason: 'Annual review'
222
+ }, orgLocation);
223
+ console.log('Batch budget update completed');
224
+
225
+ // 4. Get department analytics
226
+ console.log('\n📊 Getting department analytics...');
227
+ const deptAnalytics = await deptApi.allFacet('budgetAnalysis', {
228
+ period: 'quarterly',
229
+ includeProjections: true
230
+ }, orgLocation);
231
+ console.log(`Department analytics:`, deptAnalytics);
232
+
233
+ // 5. Find departments by criteria
234
+ console.log('\n🔍 Finding high-budget departments...');
235
+ const highBudgetDepts = await deptApi.find('byBudgetRange', {
236
+ minBudget: 600000,
237
+ maxBudget: 2000000
238
+ }, orgLocation);
239
+ console.log(`Found ${highBudgetDepts.length} high-budget departments`);
240
+
241
+ return createdDepartments.map(d => d.id);
242
+
243
+ } catch (error) {
244
+ console.error('❌ Error in department operations:', error);
245
+ return [];
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Demonstrates Employee operations (Contained Items - Level 2)
251
+ */
252
+ async function demonstrateEmployeeOperations(organizationId: string, departmentIds: string[]) {
253
+ console.log('\n🚀 === Employee Operations (Contained Items - Level 2) ===');
254
+
255
+ // Conceptual: const empApi = createCItemApi<Employee, 'employee', 'organization', 'department'>('employee', ['organizations', 'departments', 'employees'], config);
256
+ const empApi = createMockHierarchicalApi('employee', 2);
257
+
258
+ try {
259
+ const engineeringDeptId = departmentIds[0]; // Engineering department
260
+ const marketingDeptId = departmentIds[1]; // Marketing department
261
+
262
+ // Multi-level location paths
263
+ const engineeringLocation = [organizationId, engineeringDeptId];
264
+ const marketingLocation = [organizationId, marketingDeptId];
265
+
266
+ // 1. Add employees to Engineering department
267
+ console.log('\n👨‍💻 Adding employees to Engineering department...');
268
+ const engineeringEmployees = [
269
+ { name: 'Alice Johnson', role: 'Senior Developer', salary: 120000, skills: ['React', 'Node.js'] },
270
+ { name: 'Bob Smith', role: 'DevOps Engineer', salary: 110000, skills: ['AWS', 'Docker'] },
271
+ { name: 'Carol Chen', role: 'Tech Lead', salary: 140000, skills: ['Architecture', 'Mentoring'] }
272
+ ];
273
+
274
+ for (const empData of engineeringEmployees) {
275
+ const newEmp = { ...empData, keyType: 'employee' };
276
+ const created = await empApi.create(newEmp, engineeringLocation);
277
+ console.log(`Added to Engineering: ${created.name} - ${created.role}`);
278
+ }
279
+
280
+ // 2. Add employees to Marketing department
281
+ console.log('\n📢 Adding employees to Marketing department...');
282
+ const marketingEmployees = [
283
+ { name: 'David Wilson', role: 'Marketing Manager', salary: 95000, skills: ['Strategy', 'Analytics'] },
284
+ { name: 'Emma Davis', role: 'Content Creator', salary: 70000, skills: ['Writing', 'Design'] }
285
+ ];
286
+
287
+ for (const empData of marketingEmployees) {
288
+ const newEmp = { ...empData, keyType: 'employee' };
289
+ const created = await empApi.create(newEmp, marketingLocation);
290
+ console.log(`Added to Marketing: ${created.name} - ${created.role}`);
291
+ }
292
+
293
+ // 3. Get all employees in Engineering
294
+ console.log('\n📊 Getting all Engineering employees...');
295
+ const engineeringTeam = await empApi.all({ active: true }, engineeringLocation);
296
+ console.log(`Engineering team has ${engineeringTeam.length} employees`);
297
+
298
+ // 4. Cross-department analytics
299
+ console.log('\n📈 Getting cross-department employee analytics...');
300
+
301
+ // Analytics for Engineering department
302
+ const engAnalytics = await empApi.allFacet('teamMetrics', {
303
+ metrics: ['performance', 'skills', 'satisfaction']
304
+ }, engineeringLocation);
305
+ console.log(`Engineering metrics:`, engAnalytics);
306
+
307
+ // Analytics for Marketing department
308
+ const mktAnalytics = await empApi.allFacet('teamMetrics', {
309
+ metrics: ['campaigns', 'creativity', 'results']
310
+ }, marketingLocation);
311
+ console.log(`Marketing metrics:`, mktAnalytics);
312
+
313
+ // 5. Find employees by skills across departments
314
+ console.log('\n🔍 Finding employees with specific skills...');
315
+
316
+ // Find React developers in Engineering
317
+ const reactDevs = await empApi.find('bySkill', { skill: 'React' }, engineeringLocation);
318
+ console.log(`Found ${reactDevs.length} React developers in Engineering`);
319
+
320
+ // Find creative talent in Marketing
321
+ const creatives = await empApi.find('bySkill', { skill: 'Design' }, marketingLocation);
322
+ console.log(`Found ${creatives.length} creative employees in Marketing`);
323
+
324
+ // 6. Execute department-specific actions
325
+ console.log('\n⚡ Executing department-specific actions...');
326
+
327
+ // Performance review for Engineering
328
+ await empApi.allAction('startPerformanceReview', {
329
+ type: 'technical',
330
+ reviewCycle: 'quarterly'
331
+ }, engineeringLocation);
332
+ console.log('Started technical performance reviews for Engineering');
333
+
334
+ // Campaign planning for Marketing
335
+ await empApi.allAction('planCampaign', {
336
+ type: 'product-launch',
337
+ budget: 50000
338
+ }, marketingLocation);
339
+ console.log('Started campaign planning for Marketing');
340
+
341
+ // 7. Individual employee operations
342
+ console.log('\n👤 Individual employee operations...');
343
+ const empKey = { keyType: 'employee', id: 'employee-1' };
344
+
345
+ // Update employee
346
+ const updatedEmp = await empApi.update(empKey, {
347
+ salary: 125000,
348
+ role: 'Principal Developer'
349
+ });
350
+ console.log(`Updated employee: ${updatedEmp.name}`);
351
+
352
+ // Employee-specific action
353
+ await empApi.action(empKey, 'assignProject', {
354
+ projectId: 'proj-123',
355
+ role: 'Technical Lead'
356
+ });
357
+ console.log('Assigned employee to project');
358
+
359
+ } catch (error) {
360
+ console.error('❌ Error in employee operations:', error);
361
+ }
362
+ }
363
+
364
+ /**
365
+ * Demonstrates cross-hierarchy operations and complex queries
366
+ */
367
+ async function demonstrateCrossHierarchyOperations(organizationId: string) {
368
+ console.log('\n🚀 === Cross-Hierarchy Operations ===');
369
+
370
+ const orgApi = createMockHierarchicalApi('organization', 0);
371
+ const deptApi = createMockHierarchicalApi('department', 1);
372
+ const empApi = createMockHierarchicalApi('employee', 2);
373
+
374
+ try {
375
+ // 1. Organization-wide analytics
376
+ console.log('\n📊 Organization-wide analytics...');
377
+ const orgKey = { keyType: 'organization', id: organizationId };
378
+ const orgAnalytics = await orgApi.facet(orgKey, 'hierarchicalAnalytics', {
379
+ includeSublevels: true,
380
+ metrics: ['totalEmployees', 'departmentCount', 'averageSalary', 'skillsDistribution']
381
+ });
382
+ console.log(`Organization analytics:`, orgAnalytics);
383
+
384
+ // 2. Department-level aggregations
385
+ console.log('\n📈 Department-level aggregations...');
386
+ const orgLocation = [organizationId];
387
+ const deptAggregations = await deptApi.allFacet('aggregatedMetrics', {
388
+ groupBy: ['type', 'budget'],
389
+ calculations: ['sum', 'average', 'count']
390
+ }, orgLocation);
391
+ console.log(`Department aggregations:`, deptAggregations);
392
+
393
+ // 3. Cross-department employee search
394
+ console.log('\n🔍 Cross-department employee search...');
395
+ // Note: In a real implementation, this might be a special endpoint or query
396
+ console.log('Searching for employees across all departments...');
397
+ console.log('(In production, this would use a cross-hierarchy search endpoint)');
398
+
399
+ // 4. Organizational restructuring simulation
400
+ console.log('\n🔄 Organizational restructuring simulation...');
401
+ await orgApi.action(orgKey, 'simulateRestructure', {
402
+ changes: [
403
+ { type: 'mergeDepartments', source: 'dept-1', target: 'dept-2' },
404
+ { type: 'createDepartment', name: 'Innovation' }
405
+ ]
406
+ });
407
+ console.log('Restructuring simulation completed');
408
+
409
+ } catch (error) {
410
+ console.error('❌ Error in cross-hierarchy operations:', error);
411
+ }
412
+ }
413
+
414
+ /**
415
+ * Main function to run the multi-level keys example
416
+ */
417
+ export async function runMultiLevelKeysExample() {
418
+ console.log('🎯 Fjell-Client-API Multi-Level Keys Example');
419
+ console.log('============================================');
420
+ console.log('Demonstrating hierarchical data operations with multi-level location keys\n');
421
+
422
+ try {
423
+ // Level 0: Create and manage organizations
424
+ const organizationId = await demonstrateOrganizationOperations();
425
+
426
+ if (!organizationId) {
427
+ throw new Error('Failed to create organization');
428
+ }
429
+
430
+ // Level 1: Create and manage departments within organization
431
+ const departmentIds = await demonstrateDepartmentOperations(organizationId);
432
+
433
+ if (departmentIds.length === 0) {
434
+ throw new Error('Failed to create departments');
435
+ }
436
+
437
+ // Level 2: Create and manage employees within departments
438
+ await demonstrateEmployeeOperations(organizationId, departmentIds);
439
+
440
+ // Cross-hierarchy operations
441
+ await demonstrateCrossHierarchyOperations(organizationId);
442
+
443
+ console.log('\n✅ Multi-level keys example completed successfully!');
444
+ console.log('\nKey Concepts Demonstrated:');
445
+ console.log('• Hierarchical data organization (Organization → Department → Employee)');
446
+ console.log('• Multi-level location keys for contained items');
447
+ console.log('• Complex API routing with nested path segments');
448
+ console.log('• Cross-hierarchy queries and analytics');
449
+ console.log('• Department and employee-specific operations');
450
+ console.log('• Organizational data management patterns');
451
+ console.log('\nLocation Key Patterns:');
452
+ console.log('• Level 0 (Primary): /organizations/{orgId}');
453
+ console.log('• Level 1 (Contained): /organizations/{orgId}/departments/{deptId}');
454
+ console.log('• Level 2 (Contained): /organizations/{orgId}/departments/{deptId}/employees/{empId}');
455
+ console.log('\nNote: This is a conceptual example showing hierarchical API patterns.');
456
+ console.log('In production, use actual fjell-client-api with proper types.');
457
+
458
+ } catch (error) {
459
+ console.error('❌ Multi-level keys example failed:', error);
460
+ throw error;
461
+ }
462
+ }
463
+
464
+ // Run the example if this file is executed directly
465
+ if (import.meta.url === `file://${process.argv[1]}`) {
466
+ runMultiLevelKeysExample().catch(console.error);
467
+ }