@wener/common 1.0.1 → 1.0.2
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/lib/search/AdvanceSearch.js +10 -0
- package/lib/search/AdvanceSearch.js.map +1 -0
- package/lib/search/formatAdvanceSearch.js +64 -0
- package/lib/search/formatAdvanceSearch.js.map +1 -0
- package/lib/search/index.js +2 -0
- package/lib/search/index.js.map +1 -0
- package/lib/search/optimizeAdvanceSearch.js +89 -0
- package/lib/search/optimizeAdvanceSearch.js.map +1 -0
- package/lib/search/parseAdvanceSearch.js +20 -0
- package/lib/search/parseAdvanceSearch.js.map +1 -0
- package/lib/search/parser.d.js +3 -0
- package/lib/search/parser.d.js.map +1 -0
- package/lib/search/parser.js +2761 -0
- package/lib/search/parser.js.map +1 -0
- package/lib/search/types.d.js +3 -0
- package/lib/search/types.d.js.map +1 -0
- package/package.json +5 -1
- package/src/parseSort.test.ts +1 -0
- package/src/search/AdvanceSearch.test.ts +156 -0
- package/src/search/AdvanceSearch.ts +14 -0
- package/src/search/Makefile +2 -0
- package/src/search/__snapshots__/AdvanceSearch.test.ts.snap +675 -0
- package/src/search/formatAdvanceSearch.ts +61 -0
- package/src/search/index.ts +1 -0
- package/src/search/optimizeAdvanceSearch.ts +90 -0
- package/src/search/parseAdvanceSearch.ts +26 -0
- package/src/search/parser.d.ts +8 -0
- package/src/search/parser.js +2542 -0
- package/src/search/parser.peggy +204 -0
- package/src/search/types.d.ts +71 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Grammar for advance search query
|
|
3
|
+
|
|
4
|
+
source: https://github.com/wenerme/wener/tree/master/tricks/languages/parser/peg/advance-search.peggy
|
|
5
|
+
================================
|
|
6
|
+
|
|
7
|
+
ok OR yes AND NO AND NO
|
|
8
|
+
QUALIFIER.a:@me is:yes AND yes HELLO WORLD
|
|
9
|
+
start:>2019-09-12T12:20:30.123+08:00
|
|
10
|
+
a:[2, 1 ) -owner:@me AND YES
|
|
11
|
+
-a a yes OR KEY
|
|
12
|
+
NOT NOT AND AND OR OR
|
|
13
|
+
NOT -a
|
|
14
|
+
(NOT hello)
|
|
15
|
+
@AI:"Where is my car"
|
|
16
|
+
owner:@me
|
|
17
|
+
owner:!=@me
|
|
18
|
+
(a OR B)
|
|
19
|
+
( a OR "B )" )
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
{
|
|
23
|
+
const OPERATORS = {
|
|
24
|
+
":": "has",
|
|
25
|
+
":=": "eq",
|
|
26
|
+
":!=": "ne",
|
|
27
|
+
":>": "gt",
|
|
28
|
+
":>=": "gte",
|
|
29
|
+
":<": "lt",
|
|
30
|
+
":<=": "lte",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// todo make /**/b works
|
|
35
|
+
Main = @Exprs EOF
|
|
36
|
+
|
|
37
|
+
Exprs = _ @Expr|1.., __| _
|
|
38
|
+
|
|
39
|
+
Expr
|
|
40
|
+
= Comment
|
|
41
|
+
/ OrExpr
|
|
42
|
+
|
|
43
|
+
Comment
|
|
44
|
+
= "/*" value:$[^*]* "*/" { return { type: "comment", value: value.trim() }; }
|
|
45
|
+
|
|
46
|
+
OrExpr
|
|
47
|
+
= head:AndExpr tail:(__ KW_OR __ @AndExpr)* {
|
|
48
|
+
return !tail.length
|
|
49
|
+
? head
|
|
50
|
+
: { type: "logical", operator: "or", value: [head].concat(tail) };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
AndExpr
|
|
54
|
+
= head:NotExpr tail:(__ KW_AND __ @NotExpr)* {
|
|
55
|
+
return !tail.length
|
|
56
|
+
? head
|
|
57
|
+
: { type: "logical", operator: "and", value: [head].concat(tail) };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
NotExpr
|
|
61
|
+
= KW_NOT __ value:NotExpr { return { type: "not", value }; }
|
|
62
|
+
/ @ParenthesesExpr
|
|
63
|
+
|
|
64
|
+
ParenthesesExpr
|
|
65
|
+
= "(" _ value:Exprs _ ")" { return { type: "parentheses", value }; }
|
|
66
|
+
/ @ComparisonExpr
|
|
67
|
+
|
|
68
|
+
ComparisonExpr
|
|
69
|
+
= modifier:(negative:"-" { return { negative: true }; } / "+" { return {}; })?
|
|
70
|
+
expr:(
|
|
71
|
+
field:field operator:":" value:range {
|
|
72
|
+
return { type: "compare", field, operator: "range", value };
|
|
73
|
+
}
|
|
74
|
+
/ field:field operator:(":=" / ":!=" / ":") value:mention {
|
|
75
|
+
return {
|
|
76
|
+
type: "compare",
|
|
77
|
+
field,
|
|
78
|
+
operator: operator === ":!=" ? "ne" : "eq",
|
|
79
|
+
value,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/ field:field
|
|
83
|
+
operator:(":=" / ":>" / ":<" / ":>=" / ":<=" / ":!=" / ":")
|
|
84
|
+
value:value {
|
|
85
|
+
return {
|
|
86
|
+
type: "compare",
|
|
87
|
+
field,
|
|
88
|
+
operator: OPERATORS[operator],
|
|
89
|
+
value,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
) { return { ...expr, ...modifier }; }
|
|
93
|
+
/ "@" field:field ":" value:string {
|
|
94
|
+
return {
|
|
95
|
+
type: "compare",
|
|
96
|
+
field,
|
|
97
|
+
operator: "has",
|
|
98
|
+
value: { value },
|
|
99
|
+
mention: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/ KeywordExpr
|
|
103
|
+
|
|
104
|
+
KeywordExpr
|
|
105
|
+
= negative:"-"? value:string {
|
|
106
|
+
return {
|
|
107
|
+
type: "keyword",
|
|
108
|
+
negative: Boolean(negative),
|
|
109
|
+
value,
|
|
110
|
+
exact: true,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/ negative:"-"? value:keyword {
|
|
114
|
+
return { type: "keyword", negative: Boolean(negative), value };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
keyword = [^-+,'" \r\n\t()] [^ \r\n\t)]* { return text(); }
|
|
118
|
+
|
|
119
|
+
// support field,
|
|
120
|
+
// support field.key
|
|
121
|
+
// MAYBE field.*, field.0
|
|
122
|
+
// MAYBE date(field)
|
|
123
|
+
field = $ident|1.., "."|
|
|
124
|
+
|
|
125
|
+
range
|
|
126
|
+
= minimum:(value / "*") ".." maximum:(value / "*") {
|
|
127
|
+
return {
|
|
128
|
+
type: "range",
|
|
129
|
+
minimum: minimum === "*" ? undefined : minimum,
|
|
130
|
+
maximum: maximum === "*" ? undefined : maximum,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/ minimumBoundary:[\[(]
|
|
134
|
+
_
|
|
135
|
+
minimum:value?
|
|
136
|
+
_
|
|
137
|
+
","
|
|
138
|
+
_
|
|
139
|
+
maximum:value?
|
|
140
|
+
_
|
|
141
|
+
maximumBoundary:[)\]] {
|
|
142
|
+
return {
|
|
143
|
+
type: "range",
|
|
144
|
+
minimum,
|
|
145
|
+
maximum,
|
|
146
|
+
minimumExclusive: minimumBoundary === "(",
|
|
147
|
+
maximumExclusive: maximumBoundary === ")",
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
mention = "@" value:ident { return { format: "mention", value }; }
|
|
152
|
+
|
|
153
|
+
value
|
|
154
|
+
= @date
|
|
155
|
+
/ value:(ident / literal) { return { type: "literal", value }; }
|
|
156
|
+
|
|
157
|
+
// date-fns yyyy-MM-dd'T'HH:mm:ss.SSSXXX
|
|
158
|
+
// dayjs YYYY-MM-DDTHH:mm:ss.SSSZ
|
|
159
|
+
date
|
|
160
|
+
= ([1-9] [0-9]|3| "-" [0-9]|1..2| "-" [0-9]|1..2|) // date
|
|
161
|
+
time:(
|
|
162
|
+
"T"
|
|
163
|
+
([0-9]|1..2| ":" [0-9]|1..2| ":" [0-9]|1..2|) // time
|
|
164
|
+
("." [0-9]|1..3|)? // mills
|
|
165
|
+
("Z" / "+" [0-9]|1..2| ":" [0-9]|1..2|)? // zone
|
|
166
|
+
)? { return { format: time ? "date-time" : "date", value: text() }; }
|
|
167
|
+
|
|
168
|
+
ident = ([a-zA-Z] [_a-zA-Z0-9]*) { return text(); }
|
|
169
|
+
|
|
170
|
+
literal
|
|
171
|
+
= string
|
|
172
|
+
/ float
|
|
173
|
+
/ int
|
|
174
|
+
/ bool
|
|
175
|
+
/ null
|
|
176
|
+
|
|
177
|
+
number = ([0-9]+ ("." [0-9]+)? / "." [0-9]+) { return parseFloat(text()); }
|
|
178
|
+
|
|
179
|
+
// todo escape
|
|
180
|
+
string = "\"" v:[^"]* "\"" { return v.join(""); }
|
|
181
|
+
|
|
182
|
+
bool = ("true" / "false") { return text().toLowerCase() === "true"; }
|
|
183
|
+
|
|
184
|
+
int = [0-9]+ { return parseInt(text()); }
|
|
185
|
+
|
|
186
|
+
float = [0-9]+ "." [0-9]+ { return parseFloat(text()); }
|
|
187
|
+
|
|
188
|
+
null = "null" { return null; }
|
|
189
|
+
|
|
190
|
+
ident_start = [A-Za-z_]
|
|
191
|
+
|
|
192
|
+
KW_OR = "OR" !ident_start
|
|
193
|
+
|
|
194
|
+
KW_AND = "AND" !ident_start
|
|
195
|
+
|
|
196
|
+
KW_NOT = "NOT" !ident_start
|
|
197
|
+
|
|
198
|
+
_ "whitespace" = white* { return ""; }
|
|
199
|
+
|
|
200
|
+
__ "whitespace" = white+ { return " "; }
|
|
201
|
+
|
|
202
|
+
white = [ \t\n\r]
|
|
203
|
+
|
|
204
|
+
EOF = !.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export type Exprs = Expr[];
|
|
2
|
+
export type Expr =
|
|
3
|
+
| CommentExpr
|
|
4
|
+
| ParenthesesExpr
|
|
5
|
+
| KeywordCondition
|
|
6
|
+
| LogicalCondition
|
|
7
|
+
| NotCondition
|
|
8
|
+
| CompareCondition;
|
|
9
|
+
|
|
10
|
+
export type CommentExpr = {
|
|
11
|
+
type: 'comment';
|
|
12
|
+
value: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type ParenthesesExpr = {
|
|
16
|
+
type: 'parentheses';
|
|
17
|
+
value: Expr[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type KeywordCondition = {
|
|
21
|
+
type: 'keyword';
|
|
22
|
+
value: string;
|
|
23
|
+
negative?: boolean;
|
|
24
|
+
exact?: boolean;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type LogicalCondition = {
|
|
28
|
+
type: 'logical';
|
|
29
|
+
operator: 'and' | 'or';
|
|
30
|
+
value: Expr[];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type NotCondition = {
|
|
34
|
+
type: 'not';
|
|
35
|
+
value: Expr;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type CompareCondition = {
|
|
39
|
+
type: 'compare';
|
|
40
|
+
field: string;
|
|
41
|
+
/**
|
|
42
|
+
* mention value for eq, ne only
|
|
43
|
+
* range require range value
|
|
44
|
+
*/
|
|
45
|
+
operator: 'eq' | 'ne' | 'gt' | 'lt' | 'gte' | 'lte' | 'range' | 'has';
|
|
46
|
+
negative?: boolean;
|
|
47
|
+
mention?: boolean;
|
|
48
|
+
value: Value;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type Value = LiteralValue | RangeValue | MentionValue;
|
|
52
|
+
|
|
53
|
+
export type LiteralValue = {
|
|
54
|
+
type?: 'literal';
|
|
55
|
+
format?: 'date' | 'date-time';
|
|
56
|
+
value: string | number | null;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type MentionValue = {
|
|
60
|
+
type?: 'literal';
|
|
61
|
+
format: 'mention';
|
|
62
|
+
value: string;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type RangeValue = {
|
|
66
|
+
type: 'range';
|
|
67
|
+
minimum: LiteralValue | undefined;
|
|
68
|
+
maximum: LiteralValue | undefined;
|
|
69
|
+
minimumExclusive: boolean;
|
|
70
|
+
maximumExclusive: boolean;
|
|
71
|
+
};
|