rust-kgdb 0.6.4 → 0.6.5

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.
@@ -2,61 +2,68 @@
2
2
  * Datalog Example for rust-kgdb TypeScript SDK
3
3
  *
4
4
  * Demonstrates Datalog reasoning capabilities including:
5
- * - Adding facts and rules
5
+ * - Adding facts and rules using JSON format
6
6
  * - Semi-naive evaluation
7
- * - Recursive rule evaluation
8
- * - Stratified negation
9
- * - Query evaluation
10
- * - Integration with RDF graphs
7
+ * - Recursive rule evaluation (transitive closure)
8
+ * - Querying derived facts
9
+ *
10
+ * IMPORTANT: The DatalogProgram API uses JSON strings for facts and rules.
11
+ * This enables a flexible, language-agnostic interface.
11
12
  */
12
13
 
13
- import { DatalogEngine, GraphDb } from 'rust-kgdb';
14
+ import { DatalogProgram, evaluateDatalog, queryDatalog, GraphDB } from 'rust-kgdb';
14
15
 
15
16
  // =============================================================================
16
17
  // Example 1: Basic Facts and Rules
17
18
  // =============================================================================
18
19
 
19
- async function basicDatalogExample() {
20
+ function basicDatalogExample() {
20
21
  console.log('=== Basic Datalog Facts and Rules ===\n');
21
22
 
22
- const engine = new DatalogEngine();
23
+ const program = new DatalogProgram();
23
24
 
24
25
  // Add facts: parent(X, Y) means X is parent of Y
25
- engine.addFact('parent', ['alice', 'bob']);
26
- engine.addFact('parent', ['alice', 'carol']);
27
- engine.addFact('parent', ['bob', 'david']);
28
- engine.addFact('parent', ['bob', 'eve']);
29
- engine.addFact('parent', ['carol', 'frank']);
26
+ // Facts use JSON format: {"predicate": "name", "terms": ["arg1", "arg2"]}
27
+ program.addFact(JSON.stringify({ predicate: 'parent', terms: ['alice', 'bob'] }));
28
+ program.addFact(JSON.stringify({ predicate: 'parent', terms: ['alice', 'carol'] }));
29
+ program.addFact(JSON.stringify({ predicate: 'parent', terms: ['bob', 'david'] }));
30
+ program.addFact(JSON.stringify({ predicate: 'parent', terms: ['bob', 'eve'] }));
31
+ program.addFact(JSON.stringify({ predicate: 'parent', terms: ['carol', 'frank'] }));
30
32
 
31
33
  console.log('Facts added:');
32
34
  console.log(' parent(alice, bob)');
33
35
  console.log(' parent(alice, carol)');
34
36
  console.log(' parent(bob, david)');
35
37
  console.log(' parent(bob, eve)');
36
- console.log(' parent(carol, frank)\n');
38
+ console.log(' parent(carol, frank)');
39
+ console.log(` Total facts: ${program.factCount()}\n`);
37
40
 
38
41
  // Add rule: grandparent(X, Z) :- parent(X, Y), parent(Y, Z)
39
- engine.addRule(
40
- 'grandparent', // head predicate
41
- ['X', 'Z'], // head variables
42
- [
43
- { predicate: 'parent', args: ['X', 'Y'] },
44
- { predicate: 'parent', args: ['Y', 'Z'] }
42
+ // Rules use JSON format: {"head": {...}, "body": [...]}
43
+ program.addRule(JSON.stringify({
44
+ head: { predicate: 'grandparent', terms: ['X', 'Z'] },
45
+ body: [
46
+ { predicate: 'parent', terms: ['X', 'Y'] },
47
+ { predicate: 'parent', terms: ['Y', 'Z'] }
45
48
  ]
46
- );
49
+ }));
47
50
 
48
51
  console.log('Rule added:');
49
- console.log(' grandparent(X, Z) :- parent(X, Y), parent(Y, Z)\n');
52
+ console.log(' grandparent(X, Z) :- parent(X, Y), parent(Y, Z)');
53
+ console.log(` Total rules: ${program.ruleCount()}\n`);
50
54
 
51
- // Evaluate to derive all facts
52
- engine.evaluate();
55
+ // Evaluate to derive all facts using semi-naive evaluation
56
+ const evalResult = evaluateDatalog(program);
57
+ console.log('Evaluation completed.');
58
+ console.log(` Result: ${evalResult}\n`);
53
59
 
54
60
  // Query grandparents
55
- const grandparents = engine.query('grandparent', ['?who', '?grandchild']);
61
+ const grandparents = queryDatalog(program, 'grandparent');
62
+ const results = JSON.parse(grandparents);
56
63
  console.log('Query: grandparent(?who, ?grandchild)');
57
64
  console.log('Results:');
58
- for (const result of grandparents) {
59
- console.log(` ${result.who} is grandparent of ${result.grandchild}`);
65
+ for (const result of results) {
66
+ console.log(` ${result.terms[0]} is grandparent of ${result.terms[1]}`);
60
67
  }
61
68
  console.log();
62
69
  }
@@ -65,173 +72,214 @@ async function basicDatalogExample() {
65
72
  // Example 2: Recursive Rules (Transitive Closure)
66
73
  // =============================================================================
67
74
 
68
- async function recursiveDatalogExample() {
75
+ function recursiveDatalogExample() {
69
76
  console.log('=== Recursive Rules (Transitive Closure) ===\n');
70
77
 
71
- const engine = new DatalogEngine();
78
+ const program = new DatalogProgram();
72
79
 
73
80
  // Add edge facts for a graph
74
- engine.addFact('edge', ['a', 'b']);
75
- engine.addFact('edge', ['b', 'c']);
76
- engine.addFact('edge', ['c', 'd']);
77
- engine.addFact('edge', ['d', 'e']);
78
- engine.addFact('edge', ['a', 'c']); // shortcut
81
+ program.addFact(JSON.stringify({ predicate: 'edge', terms: ['a', 'b'] }));
82
+ program.addFact(JSON.stringify({ predicate: 'edge', terms: ['b', 'c'] }));
83
+ program.addFact(JSON.stringify({ predicate: 'edge', terms: ['c', 'd'] }));
84
+ program.addFact(JSON.stringify({ predicate: 'edge', terms: ['d', 'e'] }));
85
+ program.addFact(JSON.stringify({ predicate: 'edge', terms: ['a', 'c'] })); // shortcut
79
86
 
80
87
  console.log('Graph edges: a->b, b->c, c->d, d->e, a->c\n');
81
88
 
82
89
  // Base case: path(X, Y) :- edge(X, Y)
83
- engine.addRule(
84
- 'path',
85
- ['X', 'Y'],
86
- [{ predicate: 'edge', args: ['X', 'Y'] }]
87
- );
90
+ program.addRule(JSON.stringify({
91
+ head: { predicate: 'path', terms: ['X', 'Y'] },
92
+ body: [{ predicate: 'edge', terms: ['X', 'Y'] }]
93
+ }));
88
94
 
89
95
  // Recursive case: path(X, Z) :- edge(X, Y), path(Y, Z)
90
- engine.addRule(
91
- 'path',
92
- ['X', 'Z'],
93
- [
94
- { predicate: 'edge', args: ['X', 'Y'] },
95
- { predicate: 'path', args: ['Y', 'Z'] }
96
+ program.addRule(JSON.stringify({
97
+ head: { predicate: 'path', terms: ['X', 'Z'] },
98
+ body: [
99
+ { predicate: 'edge', terms: ['X', 'Y'] },
100
+ { predicate: 'path', terms: ['Y', 'Z'] }
96
101
  ]
97
- );
102
+ }));
98
103
 
99
104
  console.log('Rules added:');
100
105
  console.log(' path(X, Y) :- edge(X, Y) % base case');
101
106
  console.log(' path(X, Z) :- edge(X, Y), path(Y, Z) % recursive case\n');
102
107
 
103
108
  // Evaluate using semi-naive algorithm
104
- const iterations = engine.evaluateSemiNaive();
105
- console.log(`Semi-naive evaluation completed in ${iterations} iterations\n`);
109
+ const evalResult = evaluateDatalog(program);
110
+ console.log(`Semi-naive evaluation completed: ${evalResult}\n`);
106
111
 
107
112
  // Query all paths from 'a'
108
- const paths = engine.query('path', ['a', '?end']);
109
- console.log('Query: path(a, ?end)');
110
- console.log('Results (nodes reachable from a):');
111
- for (const result of paths) {
112
- console.log(` a can reach ${result.end}`);
113
+ const paths = queryDatalog(program, 'path');
114
+ const results = JSON.parse(paths);
115
+
116
+ console.log('Query: All paths');
117
+ console.log('Results (nodes reachable from each source):');
118
+ for (const result of results) {
119
+ console.log(` ${result.terms[0]} can reach ${result.terms[1]}`);
113
120
  }
114
121
  console.log();
115
122
  }
116
123
 
117
124
  // =============================================================================
118
- // Example 3: Stratified Negation
125
+ // Example 3: Fraud Detection Rules
119
126
  // =============================================================================
120
127
 
121
- async function negationDatalogExample() {
122
- console.log('=== Stratified Negation ===\n');
123
-
124
- const engine = new DatalogEngine();
128
+ function fraudDetectionExample() {
129
+ console.log('=== Fraud Detection Rules ===\n');
130
+
131
+ const program = new DatalogProgram();
132
+
133
+ // Add transaction facts: transaction(id, sender, receiver, amount)
134
+ program.addFact(JSON.stringify({
135
+ predicate: 'transaction',
136
+ terms: ['tx001', 'account_a', 'account_b', '50000']
137
+ }));
138
+ program.addFact(JSON.stringify({
139
+ predicate: 'transaction',
140
+ terms: ['tx002', 'account_b', 'account_c', '48000']
141
+ }));
142
+ program.addFact(JSON.stringify({
143
+ predicate: 'transaction',
144
+ terms: ['tx003', 'account_c', 'account_a', '45000']
145
+ }));
146
+
147
+ // Add account facts: account(id, jurisdiction)
148
+ program.addFact(JSON.stringify({ predicate: 'account', terms: ['account_a', 'Panama'] }));
149
+ program.addFact(JSON.stringify({ predicate: 'account', terms: ['account_b', 'BVI'] }));
150
+ program.addFact(JSON.stringify({ predicate: 'account', terms: ['account_c', 'Cayman'] }));
151
+
152
+ // Add high-risk jurisdiction facts
153
+ program.addFact(JSON.stringify({ predicate: 'high_risk_jurisdiction', terms: ['Panama'] }));
154
+ program.addFact(JSON.stringify({ predicate: 'high_risk_jurisdiction', terms: ['BVI'] }));
155
+ program.addFact(JSON.stringify({ predicate: 'high_risk_jurisdiction', terms: ['Cayman'] }));
156
+
157
+ console.log('Facts loaded:');
158
+ console.log(' 3 transactions forming circular pattern');
159
+ console.log(' 3 accounts in offshore jurisdictions\n');
160
+
161
+ // Rule: sends_to(A, B) :- transaction(_, A, B, _)
162
+ program.addRule(JSON.stringify({
163
+ head: { predicate: 'sends_to', terms: ['A', 'B'] },
164
+ body: [{ predicate: 'transaction', terms: ['_', 'A', 'B', '_'] }]
165
+ }));
166
+
167
+ // Rule: circular_flow(A, B, C) :- sends_to(A, B), sends_to(B, C), sends_to(C, A)
168
+ program.addRule(JSON.stringify({
169
+ head: { predicate: 'circular_flow', terms: ['A', 'B', 'C'] },
170
+ body: [
171
+ { predicate: 'sends_to', terms: ['A', 'B'] },
172
+ { predicate: 'sends_to', terms: ['B', 'C'] },
173
+ { predicate: 'sends_to', terms: ['C', 'A'] }
174
+ ]
175
+ }));
176
+
177
+ // Rule: offshore_account(A) :- account(A, J), high_risk_jurisdiction(J)
178
+ program.addRule(JSON.stringify({
179
+ head: { predicate: 'offshore_account', terms: ['A'] },
180
+ body: [
181
+ { predicate: 'account', terms: ['A', 'J'] },
182
+ { predicate: 'high_risk_jurisdiction', terms: ['J'] }
183
+ ]
184
+ }));
185
+
186
+ console.log('Fraud detection rules:');
187
+ console.log(' sends_to(A, B) :- transaction(_, A, B, _)');
188
+ console.log(' circular_flow(A, B, C) :- sends_to(A, B), sends_to(B, C), sends_to(C, A)');
189
+ console.log(' offshore_account(A) :- account(A, J), high_risk_jurisdiction(J)\n');
190
+
191
+ // Evaluate
192
+ evaluateDatalog(program);
193
+
194
+ // Query circular flows
195
+ const circularFlows = queryDatalog(program, 'circular_flow');
196
+ const circularResults = JSON.parse(circularFlows);
197
+ console.log('Circular payment patterns detected:');
198
+ for (const result of circularResults) {
199
+ console.log(` ${result.terms[0]} -> ${result.terms[1]} -> ${result.terms[2]} -> ${result.terms[0]}`);
200
+ }
125
201
 
126
- // Add employee facts
127
- engine.addFact('employee', ['alice', 'engineering']);
128
- engine.addFact('employee', ['bob', 'engineering']);
129
- engine.addFact('employee', ['carol', 'sales']);
130
- engine.addFact('employee', ['david', 'hr']);
202
+ // Query offshore accounts
203
+ const offshoreAccounts = queryDatalog(program, 'offshore_account');
204
+ const offshoreResults = JSON.parse(offshoreAccounts);
205
+ console.log('\nOffshore accounts flagged:');
206
+ for (const result of offshoreResults) {
207
+ console.log(` ${result.terms[0]}`);
208
+ }
209
+ console.log();
210
+ }
131
211
 
132
- // Add manager facts
133
- engine.addFact('manager', ['alice']);
134
- engine.addFact('manager', ['carol']);
212
+ // =============================================================================
213
+ // Example 4: Access Control Rules
214
+ // =============================================================================
135
215
 
136
- console.log('Facts:');
137
- console.log(' employee(alice, engineering), employee(bob, engineering)');
138
- console.log(' employee(carol, sales), employee(david, hr)');
139
- console.log(' manager(alice), manager(carol)\n');
216
+ function accessControlExample() {
217
+ console.log('=== Access Control Rules ===\n');
140
218
 
141
- // Rule: non_manager(X) :- employee(X, _), NOT manager(X)
142
- engine.addRuleWithNegation(
143
- 'non_manager',
144
- ['X'],
145
- [{ predicate: 'employee', args: ['X', '_'] }],
146
- [{ predicate: 'manager', args: ['X'] }] // negated atoms
147
- );
219
+ const program = new DatalogProgram();
148
220
 
149
- console.log('Rule with negation:');
150
- console.log(' non_manager(X) :- employee(X, _), NOT manager(X)\n');
221
+ // User roles
222
+ program.addFact(JSON.stringify({ predicate: 'role', terms: ['alice', 'admin'] }));
223
+ program.addFact(JSON.stringify({ predicate: 'role', terms: ['bob', 'developer'] }));
224
+ program.addFact(JSON.stringify({ predicate: 'role', terms: ['carol', 'developer'] }));
225
+ program.addFact(JSON.stringify({ predicate: 'role', terms: ['david', 'viewer'] }));
151
226
 
152
- // Stratified evaluation (handles negation correctly)
153
- engine.evaluateStratified();
227
+ // Resource permissions by role
228
+ program.addFact(JSON.stringify({ predicate: 'permission', terms: ['admin', 'read'] }));
229
+ program.addFact(JSON.stringify({ predicate: 'permission', terms: ['admin', 'write'] }));
230
+ program.addFact(JSON.stringify({ predicate: 'permission', terms: ['admin', 'delete'] }));
231
+ program.addFact(JSON.stringify({ predicate: 'permission', terms: ['developer', 'read'] }));
232
+ program.addFact(JSON.stringify({ predicate: 'permission', terms: ['developer', 'write'] }));
233
+ program.addFact(JSON.stringify({ predicate: 'permission', terms: ['viewer', 'read'] }));
154
234
 
155
- // Query non-managers
156
- const nonManagers = engine.query('non_manager', ['?person']);
157
- console.log('Query: non_manager(?person)');
158
- console.log('Results:');
159
- for (const result of nonManagers) {
160
- console.log(` ${result.person} is not a manager`);
161
- }
162
- console.log();
163
- }
235
+ console.log('Access control facts loaded\n');
164
236
 
165
- // =============================================================================
166
- // Example 4: Aggregate Functions
167
- // =============================================================================
237
+ // Rule: can_do(User, Action) :- role(User, Role), permission(Role, Action)
238
+ program.addRule(JSON.stringify({
239
+ head: { predicate: 'can_do', terms: ['User', 'Action'] },
240
+ body: [
241
+ { predicate: 'role', terms: ['User', 'Role'] },
242
+ { predicate: 'permission', terms: ['Role', 'Action'] }
243
+ ]
244
+ }));
168
245
 
169
- async function aggregateDatalogExample() {
170
- console.log('=== Aggregate Functions ===\n');
171
-
172
- const engine = new DatalogEngine();
173
-
174
- // Add sales facts: sale(product, amount, region)
175
- engine.addFact('sale', ['laptop', '1200', 'west']);
176
- engine.addFact('sale', ['laptop', '1100', 'east']);
177
- engine.addFact('sale', ['phone', '800', 'west']);
178
- engine.addFact('sale', ['phone', '850', 'east']);
179
- engine.addFact('sale', ['tablet', '500', 'west']);
180
- engine.addFact('sale', ['tablet', '450', 'east']);
181
-
182
- console.log('Sales facts added\n');
183
-
184
- // Rule with aggregation: total_by_product(P, sum(A)) :- sale(P, A, _)
185
- engine.addAggregateRule(
186
- 'total_by_product',
187
- ['Product', 'Total'],
188
- { predicate: 'sale', args: ['Product', 'Amount', '_'] },
189
- { function: 'sum', variable: 'Amount', output: 'Total' },
190
- ['Product'] // group by
191
- );
192
-
193
- // Rule: avg_by_region(R, avg(A)) :- sale(_, A, R)
194
- engine.addAggregateRule(
195
- 'avg_by_region',
196
- ['Region', 'Average'],
197
- { predicate: 'sale', args: ['_', 'Amount', 'Region'] },
198
- { function: 'avg', variable: 'Amount', output: 'Average' },
199
- ['Region']
200
- );
201
-
202
- console.log('Aggregate rules added:');
203
- console.log(' total_by_product(P, sum(A)) :- sale(P, A, _)');
204
- console.log(' avg_by_region(R, avg(A)) :- sale(_, A, R)\n');
205
-
206
- engine.evaluate();
207
-
208
- // Query totals by product
209
- const totals = engine.query('total_by_product', ['?product', '?total']);
210
- console.log('Total sales by product:');
211
- for (const result of totals) {
212
- console.log(` ${result.product}: $${result.total}`);
246
+ console.log('Access control rules:');
247
+ console.log(' can_do(User, Action) :- role(User, Role), permission(Role, Action)\n');
248
+
249
+ evaluateDatalog(program);
250
+
251
+ // Query all permissions
252
+ const permissions = queryDatalog(program, 'can_do');
253
+ const results = JSON.parse(permissions);
254
+
255
+ console.log('Derived permissions:');
256
+ const permissionsByUser: { [key: string]: string[] } = {};
257
+ for (const result of results) {
258
+ const user = result.terms[0];
259
+ const action = result.terms[1];
260
+ if (!permissionsByUser[user]) {
261
+ permissionsByUser[user] = [];
262
+ }
263
+ permissionsByUser[user].push(action);
213
264
  }
214
265
 
215
- // Query averages by region
216
- const avgs = engine.query('avg_by_region', ['?region', '?avg']);
217
- console.log('\nAverage sale by region:');
218
- for (const result of avgs) {
219
- console.log(` ${result.region}: $${result.avg}`);
266
+ for (const [user, actions] of Object.entries(permissionsByUser)) {
267
+ console.log(` ${user} can: ${actions.join(', ')}`);
220
268
  }
221
269
  console.log();
222
270
  }
223
271
 
224
272
  // =============================================================================
225
- // Example 5: RDF Graph Integration
273
+ // Example 5: Integration with RDF Graph
226
274
  // =============================================================================
227
275
 
228
- async function rdfIntegrationExample() {
229
- console.log('=== RDF Graph Integration ===\n');
276
+ function rdfIntegrationExample() {
277
+ console.log('=== RDF Graph + Datalog Integration ===\n');
230
278
 
231
279
  // Create RDF graph
232
- const db = new GraphDb('http://example.org/company');
280
+ const db = new GraphDB('http://example.org/company');
233
281
 
234
- // Load company data
282
+ // Load company data in Turtle format
235
283
  const ttl = `
236
284
  @prefix ex: <http://example.org/> .
237
285
  @prefix foaf: <http://xmlns.com/foaf/0.1/> .
@@ -258,193 +306,52 @@ async function rdfIntegrationExample() {
258
306
  `;
259
307
 
260
308
  db.loadTtl(ttl, null);
261
- console.log('RDF graph loaded with company data\n');
262
-
263
- // Create Datalog engine from RDF
264
- const engine = db.toDatalog();
265
-
266
- // The RDF triples become facts:
267
- // triple(subject, predicate, object)
268
- console.log('RDF triples converted to Datalog facts\n');
269
-
270
- // Add reasoning rules
271
- // colleague(X, Y) :- memberOf(X, Dept), memberOf(Y, Dept), X != Y
272
- engine.addRule(
273
- 'colleague',
274
- ['X', 'Y'],
275
- [
276
- { predicate: 'triple', args: ['X', 'http://www.w3.org/ns/org#memberOf', 'Dept'] },
277
- { predicate: 'triple', args: ['Y', 'http://www.w3.org/ns/org#memberOf', 'Dept'] }
278
- ],
279
- { filter: 'X != Y' }
280
- );
281
-
282
- // manager(X, Y) :- reportsTo(Y, X)
283
- engine.addRule(
284
- 'manager',
285
- ['Manager', 'Employee'],
286
- [
287
- { predicate: 'triple', args: ['Employee', 'http://www.w3.org/ns/org#reportsTo', 'Manager'] }
288
- ]
289
- );
290
-
291
- console.log('Reasoning rules added:');
292
- console.log(' colleague(X, Y) :- memberOf(X, Dept), memberOf(Y, Dept), X != Y');
293
- console.log(' manager(M, E) :- reportsTo(E, M)\n');
309
+ console.log(`RDF graph loaded with ${db.countTriples()} triples\n`);
310
+
311
+ // Query to extract facts for Datalog
312
+ const membershipQuery = `
313
+ PREFIX org: <http://www.w3.org/ns/org#>
314
+ SELECT ?person ?dept WHERE {
315
+ ?person org:memberOf ?dept .
316
+ }
317
+ `;
294
318
 
295
- engine.evaluate();
319
+ const memberships = db.querySelect(membershipQuery);
296
320
 
297
- // Query colleagues
298
- const colleagues = engine.query('colleague', ['?person1', '?person2']);
299
- console.log('Colleagues (same department):');
300
- for (const result of colleagues) {
301
- console.log(` ${result.person1.split('/').pop()} and ${result.person2.split('/').pop()}`);
302
- }
321
+ // Create Datalog program from SPARQL results
322
+ const program = new DatalogProgram();
303
323
 
304
- // Query managers
305
- const managers = engine.query('manager', ['?manager', '?employee']);
306
- console.log('\nManagement relationships:');
307
- for (const result of managers) {
308
- console.log(` ${result.manager.split('/').pop()} manages ${result.employee.split('/').pop()}`);
324
+ console.log('Converting RDF to Datalog facts:');
325
+ for (const row of memberships) {
326
+ const person = row.bindings.person.split('/').pop() || '';
327
+ const dept = row.bindings.dept.split('/').pop() || '';
328
+ program.addFact(JSON.stringify({ predicate: 'member_of', terms: [person, dept] }));
329
+ console.log(` member_of(${person}, ${dept})`);
309
330
  }
310
331
  console.log();
311
- }
312
-
313
- // =============================================================================
314
- // Example 6: Access Control Rules (Practical Application)
315
- // =============================================================================
316
-
317
- async function accessControlExample() {
318
- console.log('=== Access Control Rules ===\n');
319
-
320
- const engine = new DatalogEngine();
321
-
322
- // User roles
323
- engine.addFact('role', ['alice', 'admin']);
324
- engine.addFact('role', ['bob', 'developer']);
325
- engine.addFact('role', ['carol', 'developer']);
326
- engine.addFact('role', ['david', 'viewer']);
327
-
328
- // Resource permissions by role
329
- engine.addFact('permission', ['admin', 'read']);
330
- engine.addFact('permission', ['admin', 'write']);
331
- engine.addFact('permission', ['admin', 'delete']);
332
- engine.addFact('permission', ['developer', 'read']);
333
- engine.addFact('permission', ['developer', 'write']);
334
- engine.addFact('permission', ['viewer', 'read']);
335
-
336
- // Resource ownership
337
- engine.addFact('owns', ['alice', 'resource1']);
338
- engine.addFact('owns', ['bob', 'resource2']);
339
332
 
340
- console.log('Access control facts loaded\n');
341
-
342
- // Rule: can_access(User, Resource, Action) :- role(User, Role), permission(Role, Action)
343
- engine.addRule(
344
- 'can_access',
345
- ['User', 'Resource', 'Action'],
346
- [
347
- { predicate: 'role', args: ['User', 'Role'] },
348
- { predicate: 'permission', args: ['Role', 'Action'] }
333
+ // Add rule: colleague(X, Y) :- member_of(X, Dept), member_of(Y, Dept)
334
+ program.addRule(JSON.stringify({
335
+ head: { predicate: 'colleague', terms: ['X', 'Y'] },
336
+ body: [
337
+ { predicate: 'member_of', terms: ['X', 'Dept'] },
338
+ { predicate: 'member_of', terms: ['Y', 'Dept'] }
349
339
  ]
350
- );
351
-
352
- // Rule: owner_override(User, Resource, delete) :- owns(User, Resource)
353
- engine.addRule(
354
- 'can_access',
355
- ['User', 'Resource', 'delete'],
356
- [
357
- { predicate: 'owns', args: ['User', 'Resource'] }
358
- ]
359
- );
340
+ }));
360
341
 
361
- console.log('Access control rules:');
362
- console.log(' can_access(U, R, A) :- role(U, Role), permission(Role, A)');
363
- console.log(' can_access(U, R, delete) :- owns(U, R) % owner override\n');
364
-
365
- engine.evaluate();
366
-
367
- // Check specific access
368
- const checkAccess = (user: string, action: string) => {
369
- const results = engine.query('can_access', [user, '?resource', action]);
370
- return results.length > 0;
371
- };
372
-
373
- const checks = [
374
- ['alice', 'delete'],
375
- ['bob', 'write'],
376
- ['bob', 'delete'],
377
- ['david', 'read'],
378
- ['david', 'write']
379
- ];
380
-
381
- console.log('Access checks:');
382
- for (const [user, action] of checks) {
383
- const allowed = checkAccess(user, action);
384
- const icon = allowed ? '✓' : '✗';
385
- console.log(` ${icon} ${user} can ${action}: ${allowed}`);
386
- }
342
+ console.log('Reasoning rule: colleague(X, Y) :- member_of(X, Dept), member_of(Y, Dept)\n');
387
343
 
388
- // Bob can delete resource2 because he owns it
389
- const bobCanDelete = engine.query('can_access', ['bob', 'resource2', 'delete']);
390
- console.log(`\n Bob can delete resource2 (owner): ${bobCanDelete.length > 0}`);
391
- console.log();
392
- }
344
+ evaluateDatalog(program);
393
345
 
394
- // =============================================================================
395
- // Example 7: Incremental Updates
396
- // =============================================================================
397
-
398
- async function incrementalExample() {
399
- console.log('=== Incremental Updates ===\n');
400
-
401
- const engine = new DatalogEngine();
402
-
403
- // Initial facts
404
- engine.addFact('friend', ['alice', 'bob']);
405
- engine.addFact('friend', ['bob', 'carol']);
406
-
407
- // Bidirectional friendship rule
408
- engine.addRule(
409
- 'friends_with',
410
- ['X', 'Y'],
411
- [{ predicate: 'friend', args: ['X', 'Y'] }]
412
- );
413
- engine.addRule(
414
- 'friends_with',
415
- ['X', 'Y'],
416
- [{ predicate: 'friend', args: ['Y', 'X'] }]
417
- );
418
-
419
- // Transitive friends-of-friends
420
- engine.addRule(
421
- 'fof',
422
- ['X', 'Z'],
423
- [
424
- { predicate: 'friends_with', args: ['X', 'Y'] },
425
- { predicate: 'friends_with', args: ['Y', 'Z'] }
426
- ],
427
- { filter: 'X != Z' }
428
- );
429
-
430
- engine.evaluate();
431
-
432
- console.log('Initial state:');
433
- let fofs = engine.query('fof', ['alice', '?friend']);
434
- console.log(` Alice's friends-of-friends: ${fofs.map(r => r.friend).join(', ')}\n`);
435
-
436
- // Incremental update: add new friendship
437
- console.log('Adding new fact: friend(carol, david)');
438
- engine.addFact('friend', ['carol', 'david']);
439
-
440
- // Incremental evaluation (only processes new facts)
441
- engine.evaluateIncremental();
442
-
443
- console.log('\nAfter incremental update:');
444
- fofs = engine.query('fof', ['alice', '?friend']);
445
- console.log(` Alice's friends-of-friends: ${fofs.map(r => r.friend).join(', ')}`);
446
-
447
- console.log('\nIncremental evaluation is much faster for dynamic graphs!');
346
+ // Query colleagues
347
+ const colleagues = queryDatalog(program, 'colleague');
348
+ const results = JSON.parse(colleagues);
349
+ console.log('Colleagues (same department):');
350
+ for (const result of results) {
351
+ if (result.terms[0] !== result.terms[1]) { // Exclude self-pairs
352
+ console.log(` ${result.terms[0]} and ${result.terms[1]}`);
353
+ }
354
+ }
448
355
  console.log();
449
356
  }
450
357
 
@@ -452,23 +359,23 @@ async function incrementalExample() {
452
359
  // Run All Examples
453
360
  // =============================================================================
454
361
 
455
- async function main() {
456
- console.log('========================================');
457
- console.log(' Datalog Reasoning Examples');
458
- console.log('========================================\n');
362
+ function main() {
363
+ console.log('╔════════════════════════════════════════════════════════════════════╗');
364
+ console.log('Datalog Reasoning Examples - rust-kgdb SDK ║');
365
+ console.log('╠════════════════════════════════════════════════════════════════════╣');
366
+ console.log('║ Using DatalogProgram with JSON-based fact/rule API ║');
367
+ console.log('╚════════════════════════════════════════════════════════════════════╝\n');
459
368
 
460
369
  try {
461
- await basicDatalogExample();
462
- await recursiveDatalogExample();
463
- await negationDatalogExample();
464
- await aggregateDatalogExample();
465
- await rdfIntegrationExample();
466
- await accessControlExample();
467
- await incrementalExample();
468
-
469
- console.log('========================================');
470
- console.log(' All examples completed successfully!');
471
- console.log('========================================');
370
+ basicDatalogExample();
371
+ recursiveDatalogExample();
372
+ fraudDetectionExample();
373
+ accessControlExample();
374
+ rdfIntegrationExample();
375
+
376
+ console.log('════════════════════════════════════════════════════════════════════');
377
+ console.log(' All Datalog examples completed successfully!');
378
+ console.log('════════════════════════════════════════════════════════════════════');
472
379
  } catch (error) {
473
380
  console.error('Error running examples:', error);
474
381
  process.exit(1);