RSQL
A parser of RSQL expressions, with no dependencies.
$ npm i @toa.io/rsql
import { parse } from '@toa.io/rsql'
parse('rank>5;name==*tea*')
{
type: 'LOGIC',
left: {
type: 'COMPARISON',
left: { type: 'SELECTOR', selector: 'rank' },
operator: '>',
right: { type: 'VALUE', value: '5' }
},
operator: ';',
right: {
type: 'COMPARISON',
left: { type: 'SELECTOR', selector: 'name' },
operator: '==',
right: { type: 'VALUE', value: '*tea*' }
}
}
Expression
== != | as written | one value |
< <= > >= | as written | one value |
=lt= =le= =gt= =ge= | < <= > >= | one value |
=in= =out= | as written | a list |
; or and | ; | two expressions |
, or or | , | two expressions |
; binds tighter than ,, and parentheses group: a==1,b==2;c==3 is a==1,(b==2;c==3).
=in= and =out= hold a list whether they are given one in parentheses or a single value:
state=in=(hot,cold), state=in=hot. No other operator takes a list.
A selector is unquoted. A value is unquoted, or quoted with " or ' when it has whitespace or any
of "'();,=!~<> in it; inside the quotes a backslash stands for the character after it:
name=="hot \"tea\"".
Whitespace between the parts of an expression means nothing. and and or are ordinary words
where a selector or a value is expected: and==or and or==and.
Values
A value is a string, unless parse is given a function that reads it as something else:
import { parse, type Literal } from '@toa.io/rsql'
function read({ text, quoted, selector, operator }: Literal): string | number | null {
if (quoted) return text
if (text === 'null') return null
return selector === 'rank' ? Number(text) : text
}
const tree = parse('rank>5;state=in=(hot,"null",null)', read)
It is called once for each value, a list's values one by one, in the order they are written. What
it throws, parse throws, so it is also where a selector or a value an application does not accept
is refused.
Errors
An expression that cannot be parsed throws a SyntaxError. Positions count from one.
Unexpected '~' at position 6 | something is where it may not be |
Unexpected end | the expression ends where it may not |
Unknown operator '=like=' at position 5 | an operator of the =name= form is none of the above |
Unclosed quote at position 4 | a quote opened there is never closed |
Unclosed parenthesis at position 1 | a parenthesis opened there is never closed |
Expression is empty | there is nothing but whitespace |
Coming from @rsql/parser
The tree has the shape @rsql/parser gives it, as plain objects. What differs:
- Operators are in one spelling:
=gt= arrives as >, and as ;, or as ,.
=in= and =out= always hold a list, and a list given to any other operator is refused.
- An operator the table above does not name is refused, where any
=name= was accepted.
and and or need no space after them: (a==1)and(b==2).
- Messages do not repeat the expression, a parenthesis left open is named by its position in the
expression, and of several things wrong the first is reported.