simple-graph-query 1.0.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.
- package/README.md +73 -0
- package/dist/bundle.js +1 -0
- package/package.json +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# simple-graph-query
|
|
2
|
+
|
|
3
|
+
**simple-graph-query** is a lightweight query engine for navigating and extracting tuples from finite graphs using a relational logic inspired by Alloy. It runs entirely client-side and supports a small, composable query language based on set comprehension and relational navigation.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
This tool lets you run queries like:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
{ x, y : Person | y in x.friend* }
|
|
11
|
+
{ x, y : Person | x.friend = y }
|
|
12
|
+
{ x : Person | x in x.friend* }
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
over JSON-encoded graphs like:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"nodes": [
|
|
20
|
+
{ "id": "a", "type": "Person" },
|
|
21
|
+
{ "id": "b", "type": "Person" },
|
|
22
|
+
{ "id": "c", "type": "Person" }
|
|
23
|
+
],
|
|
24
|
+
"edges": [
|
|
25
|
+
{ "from": "a", "to": "b", "label": "friend" },
|
|
26
|
+
{ "from": "b", "to": "c", "label": "friend" }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
And returns results like:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
[
|
|
35
|
+
["a", "b"],
|
|
36
|
+
["a", "c"],
|
|
37
|
+
["b", "c"]
|
|
38
|
+
]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## What Logic Does It Support
|
|
42
|
+
|
|
43
|
+
`simple-graph-query` evaluates first-order relational queries over finite graph structures. Specifically:
|
|
44
|
+
|
|
45
|
+
- Typed variables: `{ x, y : Person | ... }`
|
|
46
|
+
- Set comprehension: `{ tuple | condition }`
|
|
47
|
+
- Relational navigation: `x.friend`, `x.friend.friend`
|
|
48
|
+
- Equality: `x.friend = y`
|
|
49
|
+
- Membership: `y in x.friend`
|
|
50
|
+
- Transitive closure: `x.friend*`
|
|
51
|
+
|
|
52
|
+
This is a subset of Alloy-style relational logic, evaluated over a fixed graph structure, with results returned as sets of tuples.
|
|
53
|
+
|
|
54
|
+
## Getting Started
|
|
55
|
+
|
|
56
|
+
1. Clone or unzip the repository.
|
|
57
|
+
2. Open `public/index.html` in your browser.
|
|
58
|
+
3. Paste a query like `{ x, y : Person | y in x.friend* }`.
|
|
59
|
+
4. Click Run and view the results.
|
|
60
|
+
|
|
61
|
+
## Project Structure
|
|
62
|
+
|
|
63
|
+
- `src/` – parser, evaluator, and AST
|
|
64
|
+
- `examples/graph.json` – sample graph data
|
|
65
|
+
- `public/index.html` – minimal UI to run queries
|
|
66
|
+
- `runQuery(graph, query)` – main API
|
|
67
|
+
|
|
68
|
+
## TODO
|
|
69
|
+
|
|
70
|
+
- Support for `and`, `!=`, `no`, `some`
|
|
71
|
+
- Regex-style navigation (`friend|coworker`)
|
|
72
|
+
- Type checking and improved error handling
|
|
73
|
+
|
package/dist/bundle.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(t,r){"object"==typeof exports&&"object"==typeof module?module.exports=r():"function"==typeof define&&define.amd?define([],r):"object"==typeof exports?exports.SimpleGraphQuery=r():t.SimpleGraphQuery=r()}(this,()=>(()=>{"use strict";var t={d:(r,e)=>{for(var n in e)t.o(e,n)&&!t.o(r,n)&&Object.defineProperty(r,n,{enumerable:!0,get:e[n]})},o:(t,r)=>Object.prototype.hasOwnProperty.call(t,r),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},r={};t.r(r),t.d(r,{default:()=>u,runQuery:()=>n});var e=function(){function t(t,r){this.result=t,this.expression=r}return t.prototype.prettyPrint=function(){return JSON.stringify(this.result,null,2)},t.prototype.noResult=function(){return Array.isArray(this.result)?0===this.result.length:"object"==typeof this.result&&"error"in this.result},t.prototype.singleResult=function(){if(Array.isArray(this.result)&&1===this.result.length&&1===this.result[0].length)return this.result[0][0];throw new Error("Result is not a singleton")},t.prototype.selectedAtoms=function(){return Array.isArray(this.result)?this.result.filter(function(t){return 1===t.length}).map(function(t){return String(t[0])}):[]},t.prototype.selectedTwoples=function(){return Array.isArray(this.result)?this.result.filter(function(t){return 2===t.length}).map(function(t){return[String(t[0]),String(t[1])]}):[]},t.prototype.selectedTuplesAll=function(){return Array.isArray(this.result)?this.result.map(function(t){return t.map(String)}):[]},t.prototype.isError=function(){return"object"==typeof this.result&&"error"in this.result},t.prototype.isSingleton=function(){return!!Array.isArray(this.result)&&1===this.result.length&&1===this.result[0].length},t.prototype.getExpression=function(){return this.expression},t.prototype.getRawResult=function(){return this.result},t}();function n(t,r){for(var e,n=function(t){var r=t.match(/\{\s*(.*?)\s*:\s*(\w+)\s*\|\s*(.*?)\s*\}/);if(!r)throw new Error("Parse error");r[0];var e=r[1],n=r[2],i=r[3];return{vars:e.split(",").map(function(t){return t.trim()}),type:n,condition:i}}(r),o=n.vars,s=n.type,u=n.condition,l=t.nodes.filter(function(t){return t.type===s}).map(function(t){return t.id}),a=[],p=0,f=l;p<f.length;p++)for(var c=f[p],h=0,y=l;h<y.length;h++){var g=y[h];i(u,((e={})[o[0]]=c,e[o[1]]=g,e),t)&&a.push([c,g])}return a}function i(t,r,e){return t.includes("=")?function(t,r,e){var n=t.split("=").map(function(t){return t.trim()}),i=n[0],s=n[1],u=o(i,r,e),l=o(s,r,e).values().next().value;return"string"==typeof l&&u.has(l)}(t,r,e):!!t.includes("in")&&function(t,r,e){var n=t.split("in").map(function(t){return t.trim()}),i=n[0],o=n[1],u=r[i],l=o.split("."),a=l[l.length-1].endsWith("*"),p=l[l.length-1].replace("*",""),f=a?s(u,p,e):function(t,r,e){return new Set(e.edges.filter(function(e){return e.from===t&&e.label===r}).map(function(t){return t.to}))}(u,p,e);return f.has(r[l[0]])}(t,r,e)}function o(t,r,e){if(t.includes(".")){var n=t.replace("*","").split("."),i=n[0],o=n[1],u=r[i];return"string"==typeof u?s(u,o,e):new Set}var l=r[t];return"string"==typeof l?new Set([l]):new Set}function s(t,r,e){for(var n=new Set,i=[t];i.length;){var o=i.pop();if(!n.has(o)){n.add(o);for(var s=0,u=e.edges;s<u.length;s++){var l=u[s];l.from!==o||l.label!==r||n.has(l.to)||i.push(l.to)}}}return n}const u=function(){function t(){this.context=null,this.graph=null}return t.prototype.initialize=function(t){this.context=t,t.processedData&&Array.isArray(t.processedData.nodes)&&Array.isArray(t.processedData.edges)?this.graph=t.processedData:this.graph=null},t.prototype.isReady=function(){return!!this.graph},t.prototype.evaluate=function(t,r){if(!this.graph)throw new Error("Evaluator not initialized");try{var i=n(this.graph,t);return new e(i,t)}catch(r){return new e({error:{message:r.message}},t)}},t}();return r})());
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "simple-graph-query",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A simple graph query library bundled for CDN use.",
|
|
5
|
+
"main": "dist/bundle.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist/"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "webpack --mode production",
|
|
11
|
+
"dev": "webpack --mode development --watch"
|
|
12
|
+
},
|
|
13
|
+
"author": "Siddhartha Prasad",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.0.0",
|
|
17
|
+
"webpack": "^5.0.0",
|
|
18
|
+
"webpack-cli": "^5.0.0",
|
|
19
|
+
"ts-loader": "^9.0.0"
|
|
20
|
+
}
|
|
21
|
+
}
|