1 <stránka |
1 <stránka |
2 xmlns="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana" |
2 xmlns="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana" |
3 xmlns:m="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro"> |
3 xmlns:m="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro"> |
4 |
4 |
5 <nadpis>Complex filtering with Guile</nadpis> |
5 <nadpis>Complex filtering with Scheme</nadpis> |
6 <perex>filtering records with AND, OR and functions</perex> |
6 <perex>filtering records with AND, OR and functions</perex> |
7 <m:pořadí-příkladu>01400</m:pořadí-příkladu> |
7 <m:pořadí-příkladu>01400</m:pořadí-příkladu> |
8 |
8 |
9 <text xmlns="http://www.w3.org/1999/xhtml"> |
9 <text xmlns="http://www.w3.org/1999/xhtml"> |
10 |
10 |
11 <p> |
11 <p> |
12 For simple filtering, we can use <code>relpipe-tr-grep</code>. |
12 For simple filtering, we can use <code>relpipe-tr-grep</code>. |
13 But what if we need to write some complex query that contains AND and OR operators? |
13 But what if we need to write some complex query that contains AND and OR operators? |
14 What if we need e.g. compare numbers – not only match texts against regular expressions? |
14 What if we need e.g. compare numbers – not only match texts against regular expressions? |
15 There is a tool capable to do this and much more: <code>relpipe-tr-guile</code>! |
15 There is a tool capable to do this and much more: <code>relpipe-tr-scheme</code>! |
16 </p> |
16 </p> |
17 |
17 |
18 <p> |
18 <p> |
19 <a href="https://www.gnu.org/software/guile/">Guile</a> is the GNU implementation of Scheme language (something like Lisp and also full of parenthesis). |
19 <a href="https://www.gnu.org/software/guile/">Guile</a> is the GNU implementation of Scheme language (something like Lisp and also full of parenthesis). |
20 The <code>relpipe-tr-guile</code> uses GNU Guile as a library, puts data in the Guile context and evaluates Guile expressions and then reads data from the Guile context back and generates relational output from them. |
20 The <code>relpipe-tr-scheme</code> reference implementation uses GNU Guile as a library, puts data in the Scheme context and evaluates Scheme expressions and then reads data from the Scheme context back and generates relational output from them. |
21 Good news are that it is not necessary to know Lisp/Scheme to use this tool. For the first steps, it can be used just as a query language – like SQL, just a bit Polish. |
21 Good news are that it is not necessary to know Lisp/Scheme to use this tool. For the first steps, it can be used just as a query language – like SQL, just a bit Polish. |
22 </p> |
22 </p> |
23 |
23 |
24 <h2>Filtering numbers</h2> |
24 <h2>Filtering numbers</h2> |
25 |
25 |
27 We are looking for „satanistic“ icons in our filesystem – those that have size = 666 bytes. |
27 We are looking for „satanistic“ icons in our filesystem – those that have size = 666 bytes. |
28 </p> |
28 </p> |
29 |
29 |
30 <m:pre jazyk="bash"><![CDATA[find /usr/share/icons/ -type f -print0 \ |
30 <m:pre jazyk="bash"><![CDATA[find /usr/share/icons/ -type f -print0 \ |
31 | relpipe-in-filesystem \ |
31 | relpipe-in-filesystem \ |
32 | relpipe-tr-guile --relation 'files.*' --where '(= $size 666)' \ |
32 | relpipe-tr-scheme --relation 'files.*' --where '(= $size 666)' \ |
33 | relpipe-out-tabular]]></m:pre> |
33 | relpipe-out-tabular]]></m:pre> |
34 |
34 |
35 <p>Well, well… here we are:</p> |
35 <p>Well, well… here we are:</p> |
36 |
36 |
37 <m:pre jazyk="text"><![CDATA[filesystem: |
37 <m:pre jazyk="text"><![CDATA[filesystem: |
52 │ /usr/share/icons/gnome/22x22/status/weather-overcast.png │ f │ 666 │ root │ root │ |
52 │ /usr/share/icons/gnome/22x22/status/weather-overcast.png │ f │ 666 │ root │ root │ |
53 │ /usr/share/icons/gnome/16x16/actions/go-home.png │ f │ 666 │ root │ root │ |
53 │ /usr/share/icons/gnome/16x16/actions/go-home.png │ f │ 666 │ root │ root │ |
54 ╰───────────────────────────────────────────────────────────────────────┴───────────────┴────────────────┴────────────────┴────────────────╯ |
54 ╰───────────────────────────────────────────────────────────────────────┴───────────────┴────────────────┴────────────────┴────────────────╯ |
55 Record count: 13]]></m:pre> |
55 Record count: 13]]></m:pre> |
56 |
56 |
57 <p>The <code>--relation 'files.*'</code> is a regular expression that says which relations should be processed in Guile – others are passed through unchanged.</p> |
57 <p>The <code>--relation 'files.*'</code> is a regular expression that says which relations should be processed in Scheme – others are passed through unchanged.</p> |
58 |
58 |
59 <p> |
59 <p> |
60 The <code>--where '(= $size 666)'</code> is our condition. |
60 The <code>--where '(= $size 666)'</code> is our condition. |
61 The Polish<m:podČarou>see <a href="https://en.wikipedia.org/wiki/Polish_notation">Polish notation</a></m:podČarou> thing means that we write <code>= $size 666</code> instead of <code>$size = 666</code>. |
61 The Polish<m:podČarou>see <a href="https://en.wikipedia.org/wiki/Polish_notation">Polish notation</a></m:podČarou> thing means that we write <code>= $size 666</code> instead of <code>$size = 666</code>. |
62 It seems a bit weird but it makes sense – the <code>=</code> is a function that compares two numbers and returns a boolean value – |
62 It seems a bit weird but it makes sense – the <code>=</code> is a function that compares two numbers and returns a boolean value – |
63 so we just call this function and pass <code>$size</code> and <code>666</code> arguments to it. |
63 so we just call this function and pass <code>$size</code> and <code>666</code> arguments to it. |
64 And because it is a function, there are <code>(</code>parentheses<code>)</code>. |
64 And because it is a function, there are <code>(</code>parentheses<code>)</code>. |
65 </p> |
65 </p> |
66 |
66 |
67 <p> |
67 <p> |
68 Relational attributes are mapped to Guile variables with same name, just prefixed with <code>$</code>. |
68 Relational attributes are mapped to Scheme variables with same name, just prefixed with <code>$</code>. |
69 (we considered <code> |
69 (we considered <code> |
70 <abbr title="Bitcoin">₿</abbr> |
70 <abbr title="Bitcoin">₿</abbr> |
71 </code> symbol, but <code>$</code> seems to be still more common on keyboards in 2019) |
71 </code> symbol, but <code>$</code> seems to be still more common on keyboards in 2019) |
72 While relational attribute name is an arbitrary string, Guile variable names have some limitations, thus not all attributes can be mapped – those with spaces and some special characters are currently unsupported (this will be fixed in later versions by some kind of encoding/escaping). |
72 While relational attribute name is an arbitrary string, Scheme variable names have some limitations, thus not all attributes can be mapped – those with spaces and some special characters are currently unsupported (this will be fixed in later versions by some kind of encoding/escaping). |
73 </p> |
73 </p> |
74 |
74 |
75 <p> |
75 <p> |
76 We can also look for |
76 We can also look for |
77 <code>--where '(> $size 100)'</code> which means „size is greater than 100“ |
77 <code>--where '(> $size 100)'</code> which means „size is greater than 100“ |
86 Scheme is strongly typed language and we have to use proper functions/operators for each type. |
86 Scheme is strongly typed language and we have to use proper functions/operators for each type. |
87 For strings, it is <code>string=</code> instead of <code>=</code> function: |
87 For strings, it is <code>string=</code> instead of <code>=</code> function: |
88 </p> |
88 </p> |
89 |
89 |
90 <m:pre jazyk="bash"><![CDATA[relpipe-in-fstab \ |
90 <m:pre jazyk="bash"><![CDATA[relpipe-in-fstab \ |
91 | relpipe-tr-guile --relation 'fstab' --where '(string= $type "btrfs")' \ |
91 | relpipe-tr-scheme --relation 'fstab' --where '(string= $type "btrfs")' \ |
92 | relpipe-out-tabular]]></m:pre> |
92 | relpipe-out-tabular]]></m:pre> |
93 |
93 |
94 <p>The Btrfs filesystems in our <code>fstab</code>:</p> |
94 <p>The Btrfs filesystems in our <code>fstab</code>:</p> |
95 |
95 |
96 <m:pre jazyk="text"><![CDATA[fstab: |
96 <m:pre jazyk="text"><![CDATA[fstab: |
104 <p> |
104 <p> |
105 There is also <code>string-prefix?</code> which evaluates whether the first string is a prefix of the second string: |
105 There is also <code>string-prefix?</code> which evaluates whether the first string is a prefix of the second string: |
106 </p> |
106 </p> |
107 |
107 |
108 <m:pre jazyk="bash"><![CDATA[relpipe-in-fstab \ |
108 <m:pre jazyk="bash"><![CDATA[relpipe-in-fstab \ |
109 | relpipe-tr-guile --relation 'fstab' --where '(string-prefix? "/mnt" $mount_point)' \ |
109 | relpipe-tr-scheme --relation 'fstab' --where '(string-prefix? "/mnt" $mount_point)' \ |
110 | relpipe-out-tabular]]></m:pre> |
110 | relpipe-out-tabular]]></m:pre> |
111 |
111 |
112 <p>So we can find filesystems mounted somewhere under <code>/mnt</code>:</p> |
112 <p>So we can find filesystems mounted somewhere under <code>/mnt</code>:</p> |
113 |
113 |
114 <m:pre jazyk="bash"><![CDATA[fstab: |
114 <m:pre jazyk="bash"><![CDATA[fstab: |
128 |
128 |
129 <h2>AND and OR</h2> |
129 <h2>AND and OR</h2> |
130 |
130 |
131 <p> |
131 <p> |
132 Like in SQL, we can join multiple conditions together with logical operators AND and OR. |
132 Like in SQL, we can join multiple conditions together with logical operators AND and OR. |
133 In Guile/Scheme these operators are also functions – they are written in the same <code>(</code>fashion<code>)</code>. |
133 In Scheme these operators are also functions – they are written in the same <code>(</code>fashion<code>)</code>. |
134 </p> |
134 </p> |
135 |
135 |
136 <p> |
136 <p> |
137 So we can e.g. look for icons that are „satanistic“ or „Orwellian“: |
137 So we can e.g. look for icons that are „satanistic“ or „Orwellian“: |
138 </p> |
138 </p> |
139 |
139 |
140 <m:pre jazyk="bash"><![CDATA[find /usr/share/icons/ -type f -print0 \ |
140 <m:pre jazyk="bash"><![CDATA[find /usr/share/icons/ -type f -print0 \ |
141 | relpipe-in-filesystem --file path --file size \ |
141 | relpipe-in-filesystem --file path --file size \ |
142 | relpipe-tr-guile --relation 'files.*' --where '(or (= $size 666) (= $size 1984) )' \ |
142 | relpipe-tr-scheme --relation 'files.*' --where '(or (= $size 666) (= $size 1984) )' \ |
143 | relpipe-out-tabular]]></m:pre> |
143 | relpipe-out-tabular]]></m:pre> |
144 |
144 |
145 <p>Files with sizes 666 bytes or 1984 bytes:</p> |
145 <p>Files with sizes 666 bytes or 1984 bytes:</p> |
146 |
146 |
147 <m:pre jazyk="text"><![CDATA[filesystem: |
147 <m:pre jazyk="text"><![CDATA[filesystem: |
170 |
170 |
171 <p>Or we can look for icons that are in SVG format and (at the same time) Orwellian:</p> |
171 <p>Or we can look for icons that are in SVG format and (at the same time) Orwellian:</p> |
172 |
172 |
173 <m:pre jazyk="bash"><![CDATA[find /usr/share/icons/ -type f -print0 \ |
173 <m:pre jazyk="bash"><![CDATA[find /usr/share/icons/ -type f -print0 \ |
174 | relpipe-in-filesystem --file path --file size \ |
174 | relpipe-in-filesystem --file path --file size \ |
175 | relpipe-tr-guile \ |
175 | relpipe-tr-scheme \ |
176 --relation 'files.*' \ |
176 --relation 'files.*' \ |
177 --where '(and (string-suffix? ".svg" $path) (= $size 1984) )' \ |
177 --where '(and (string-suffix? ".svg" $path) (= $size 1984) )' \ |
178 | relpipe-out-tabular]]></m:pre> |
178 | relpipe-out-tabular]]></m:pre> |
179 |
179 |
180 <p>Which is quite rare and we have only two such icons:</p> |
180 <p>Which is quite rare and we have only two such icons:</p> |