Skip to content

Commit 96ead1c

Browse files
committed
update(feat): query in codeblocks
1 parent 5d6f8ee commit 96ead1c

File tree

5 files changed

+156
-3
lines changed

5 files changed

+156
-3
lines changed

Diff for: README.md

+34
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,18 @@ Furthermore, QJSON extends its functionality to external JSON files. For example
7272
@data.json>store.books.0.author;
7373
```
7474

75+
It's also posible to query the file directly using the `#qj-query` flag:
76+
77+
~~~markdown
78+
```qjson
79+
#qj-id: 24
80+
#qj-file: data.json
81+
#qj-show-json
82+
#qj-hide-id
83+
#qj-query: pageProps.heroData[win_rate >= 55 && role == Mage]
84+
```
85+
~~~
86+
7587
## 🏳️ Flags
7688

7789
Query JSON supports various flags to enhance customization and functionality:
@@ -96,6 +108,28 @@ This flag allows you to display the JSON within the rendered output. By default
96108

97109
If provided, this flag specifies the file path containing the JSON data. In its absence, the plugin scans for JSON data within the code block.
98110

111+
#### `#qj-query` (optional)
112+
113+
This flag allows you to query the JSON file directly from your codeblock. The query syntax must be inside brackets `[]`. The supported operators are:
114+
115+
- Logical operators: `&&`, `||`
116+
- Comparison operators: `==`, `!=`, `>`, `>=`, `<`, `<=`
117+
118+
**Example**:
119+
120+
~~~markdown
121+
```qjson
122+
#qj-id: 24
123+
#qj-file: data.json
124+
#qj-show-json
125+
#qj-hide-id
126+
#qj-query: pageProps.heroData[win_rate >= 55 && role == Mage]
127+
```
128+
~~~
129+
130+
> [!NOTE]
131+
> The `#qj-show-json` flag is mandatory when using the `#qj-query` flag.
132+
99133
## 🛠️ Contribution
100134

101135
If you encounter any issues or have suggestions for improvement, please feel free to contribute to the project. Your feedback is invaluable in enhancing the plugin's functionality and user experience.

Diff for: manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "query-json",
33
"name": "Query JSON",
4-
"version": "0.0.6",
4+
"version": "0.0.7",
55
"minAppVersion": "0.15.0",
66
"description": "Read, query and work with JSON.",
77
"author": "rooyca",

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "query-json",
3-
"version": "0.0.6",
3+
"version": "0.0.7",
44
"description": "Read, query and work with JSON.",
55
"main": "main.js",
66
"scripts": {

Diff for: src/functions.ts

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
export function parseQuery(query) {
2+
const parts = query.split('.');
3+
return parts.map(part => {
4+
const match = part.match(/(\w+)\[(.*)\]/);
5+
if (match) {
6+
return {
7+
type: 'filter',
8+
field: match[1],
9+
condition: match[2]
10+
};
11+
}
12+
return {
13+
type: 'field',
14+
name: part
15+
};
16+
});
17+
}
18+
19+
function parseCondition(condition) {
20+
const logicalOperators = ['&&', '||'];
21+
let conditions = [];
22+
let operators = [];
23+
24+
let remainingCondition = condition;
25+
logicalOperators.forEach(operator => {
26+
if (remainingCondition.includes(operator)) {
27+
const parts = remainingCondition.split(operator).map(s => s.trim());
28+
conditions.push(parseSingleCondition(parts[0]));
29+
operators.push(operator);
30+
remainingCondition = parts[1];
31+
}
32+
});
33+
34+
if (conditions.length === 0) {
35+
conditions.push(parseSingleCondition(remainingCondition));
36+
} else {
37+
conditions.push(parseSingleCondition(remainingCondition));
38+
}
39+
40+
return { conditions, operators };
41+
}
42+
43+
function parseSingleCondition(condition) {
44+
const comparisonOperators = ['>=', '<=', '==', '>', '<', '!='];
45+
for (let operator of comparisonOperators) {
46+
if (condition.includes(operator)) {
47+
const [key, value] = condition.split(operator).map(s => s.trim());
48+
return { key, operator, value };
49+
}
50+
}
51+
throw new Error(`Invalid condition: ${condition}`);
52+
}
53+
54+
export function executeQuery(json, parsedQuery) {
55+
let result = json;
56+
let finalResult = result; // Initialize finalResult to the full dataset initially
57+
58+
parsedQuery.forEach(part => {
59+
if (part.type === 'field') {
60+
result = result[part.name];
61+
} else if (part.type === 'filter') {
62+
const { conditions, operators } = parseCondition(part.condition);
63+
result = result[part.field];
64+
finalResult = result.filter(item => {
65+
return evaluateConditions(item, conditions, operators);
66+
});
67+
}
68+
});
69+
70+
if (parsedQuery.length > 0 && parsedQuery[parsedQuery.length - 1].type === 'field') {
71+
finalResult = finalResult.map(item => item[parsedQuery[parsedQuery.length - 1].name]);
72+
}
73+
74+
return finalResult;
75+
}
76+
77+
function evaluateConditions(item, conditions, operators) {
78+
let result = evaluateCondition(item, conditions[0]);
79+
80+
for (let i = 0; i < operators.length; i++) {
81+
const operator = operators[i];
82+
const nextConditionResult = evaluateCondition(item, conditions[i + 1]);
83+
84+
if (operator === '&&') {
85+
result = result && nextConditionResult;
86+
} else if (operator === '||') {
87+
result = result || nextConditionResult;
88+
}
89+
}
90+
91+
return result;
92+
}
93+
94+
function evaluateCondition(item, condition) {
95+
const { key, operator, value } = condition;
96+
switch (operator) {
97+
case '>=': return item[key] >= Number(value);
98+
case '<=': return item[key] <= Number(value);
99+
case '==': return item[key] == value;
100+
case '>': return item[key] > Number(value);
101+
case '<': return item[key] < Number(value);
102+
case '!=': return item[key] != value;
103+
default: return false;
104+
}
105+
}

Diff for: src/main.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { App, Notice, Plugin } from 'obsidian';
2+
import { parseQuery, executeQuery} from './functions';
23

34
export default class QJSON extends Plugin {
45

@@ -23,6 +24,13 @@ export default class QJSON extends Plugin {
2324
return;
2425
}
2526

27+
let query;
28+
29+
if (source.includes('#qj-query:')) {
30+
query = source.match(/#qj-query: (.+)/)[1];
31+
query = parseQuery(query);
32+
}
33+
2634
let desc;
2735

2836
if (!source.includes('#qj-hide-id')) {
@@ -48,7 +56,13 @@ export default class QJSON extends Plugin {
4856
}
4957

5058
const json = JSON.parse(source);
51-
el.createEl('pre', {text: JSON.stringify(json, null, 2), cls: 'QJSON-'+id+' cdQjson '+showJson});
59+
60+
if (query) {
61+
const result = executeQuery(json, query);
62+
el.createEl('pre', {text: JSON.stringify(result, null, 2), cls: 'QJSON-'+id+' cdQjson '+showJson});
63+
} else {
64+
el.createEl('pre', {text: JSON.stringify(json, null, 2), cls: 'QJSON-'+id+' cdQjson '+showJson});
65+
}
5266

5367
qjCount = document.querySelectorAll('.cdQjson').length;
5468
statusBarItemEl.setText('QJSON: ' + qjCount);

0 commit comments

Comments
 (0)