Best way to parse a query like string - sql

So I am building a query like search component for a web application I am working on, similar to the search bar seen for Jira's advance issues search:
https://jira.atlassian.com/browse/WBS-167?jql=status%20%3D%20Accepted
The search is basically very similar to the WHERE statement in SQL but only supporting selected set of comparison operators (for instance I don't plan on supporting the between comparison operator). First thing that came to mind is to use regex but I hear that SQL is the 3rd worst thing to parse with regex.
As an example, this would probably be a complex query I would want to be able to parse:
firstName = 'john' OR (lastName = 'doe' AND (status IN (1,3,5) OR type NOT IN (2, 4, 6)) AND username CONTAINS 'd' AND (type = 1 OR status = 2)
and would would want the result of parsing this string to looks something like this:
[{
field: 'firstName',
comparison: '=',
value: 'john'
}, {
connector: 'OR',
items: [{
field: 'lastName',
comparison: '=',
value: 'doe'
}, {
connector: 'AND',
items: [{
field: 'status',
comparison: 'IN',
value: [1,3,5]
}, {
connector: 'OR',
field: 'type',
comparison: 'NOT IN',
value: [2,4,6]
}]
}]
}, {
connector: 'AND',
field: 'username',
comparison: 'CONTAINS',
value: 'd'
}, {
connector: 'AND',
items: [{
field: 'type',
comparison: '=',
value: 1
}, {
connector: 'OR',
field: 'status',
comparison: '=',
value: 2
}]
}]
If regex is a bad choice (and trying to work with regex for a couple of hours did not produce any good results), what is the best why to try to parse this type of string?

It looks like you are developing a small and simple language. As ebyrod said you should use a grammar-based parser instead of regex. Lex and Yacc are great and easy tools for the job. Depending on the language you are using, there are different alternatives.
Take a look at this.
As you can see, you will need to define all the supported operations that can appear on your input. This is done on the Lex file. Then you will need to define your syntax structure (grammar) and the last step is composing your output string.

Related

Object method approach to .setLeftParens .setRightParens & .setOr in SuiteScript 2.X

I'm searching for the equivalent in SS 2.X of this:
new nlobjSearchFilter('postingperiod', 'transaction', 'is', period).setLeftParens(1).setOr(true)
This seems to not work:
searchMod.createFilter({
name: 'postingperiod',
operator: searchMod.Operator.IS,
join: 'transaction',
values: period
}).setLeftParens(1).setOr(true);
You can use filter expressions (Search.filterExpression) to group filters using and or or.
The sample below is from the Help Center:
search.create({
type: search.Type.CUSTOMER,
filters: [
['email', search.Operator.STARTSWITH, 'kwolff'],
'and',
[
['id', search.Operator.EQUALTO, 107], 'or',
['id', search.Operator.EQUALTO, 2508]
]
]
});

How to select specific fields on FaunaDB Query Language?

I can't find anything about how to do this type of query in FaunaDB. I need to select only specifics fields from a document, not all fields. I can select one field using Select function, like below:
serverClient.query(
q.Map(
q.Paginate(q.Documents(q.Collection('products')), {
size: 12,
}),
q.Lambda('X', q.Select(['data', 'title'], q.Get(q.Var('X'))))
)
)
Forget the selectAll function, it's deprecated.
You can also return an object literal like this:
serverClient.query(
q.Map(
q.Paginate(q.Documents(q.Collection('products')), {
size: 12,
}),
q.Lambda(
'X',
{
title: q.Select(['data', 'title'], q.Get(q.Var('X')),
otherField: q.Select(['data', 'other'], q.Get(q.Var('X'))
}
)
)
)
Also you are missing the end and beginning quotation marks in your question at ['data, title']
One way to achieve this would be to create an index that returns the values required. For example, if using the shell:
CreateIndex({
name: "<name of index>",
source: Collection("products"),
values: [
{ field: ["data", "title"] },
{ field: ["data", "<another field name>"] }
]
})
Then querying that index would return you the fields defined in the values of the index.
Map(
Paginate(
Match(Index("<name of index>"))
),
Lambda("product", Var("product"))
)
Although these examples are to be used in the shell, they can easily be used in code by adding a q. in front of each built-in function.

Filter Vue list based on select option value

I try to filter my list with 2 select lists based on the selected value. It seems like my computed filter is not working?
You should be able to filter the list on 'Price from' and 'Price to'
List.vue
My computed filter property:
filteredData() {
const LowerCaseSearch = this.search.toLowerCase();
return this.products.filter(
product =>
(product.name.toLowerCase().includes(LowerCaseSearch) ||
product.category.toLowerCase().includes(LowerCaseSearch)) &&
(!this.checked.length || this.checked.includes(product.category)) &&
(!this.selectedFrom.length || this.selectedFrom.includes(product.price)) &&
(!this.selectedTo.length || this.selectedTo.includes(product.price))
);
},
In my registered component I use v-model to bind to the computed property selectedFrom
<Price v-model="selectedFrom" />
How do I bind to the other property selectedTo in one v-model and what's wrong with my filter?
I also use a prefix 'From' and 'To' to put in front of the options.
data: () => {
return {
selectedFrom: '0,00',
priceFrom: [
{ prefix: 'From', text: '0,00', value: '0,00' },
{ prefix: 'From', text: '200,00', value: '200,00' },
{ prefix: 'From', text: '400,00', value: '400,00' }
],
selectedTo: 'No max',
priceTo: [
{ prefix: 'To', text: '400,00', value: '400,00' },
{ prefix: 'To', text: '600,00', value: '600,00' },
{ prefix: 'To', text: '800,00', value: '800,00' },
{ text: 'No max', value: 'No max' }
]
}
},
Is there a more elegant and D.R.Y way to do this?
Here is a sandbox what I have so far.
You should bind an object to your v-model on the <price> component.
This way you can pass multiple values to and from your component, without having to use multiple props.
I would also suggest you convert your value in your selects to numbers, so it's easier to use them to compare to your prices.
You've also defined data properties and computed properties in the sandbox (<price> component) with the same name, this is not possible. So you should remove the data properties and stick to the computed ones to handle your data.
Fork of your sandbox with my suggested changes.

Dojo DGrid RQL Search

I am working with a dgrid where I want to find a search term in my grid on two columns.
For instance, I want to see if the scientific name and commonName columns contain the string "Aca" (I want my search to be case insensitive)
My Grid definition:
var CustomGrid = declare([Grid, Pagination ]);
var gridStore = new Memory({ idProperty: 'tsn', data: null });
gridStore.queryEngine = rql.query;
grid = new CustomGrid({
store: gridStore,
columns:
[
{ field: "tsn", label: "TSN #"},
{ field: "scientificName", label: "Scientific Name"},
{ field: "commonName", label: "Common Name",},
],
autoHeight: 'true',
firstLastArrows: 'true',
pageSizeOptions: [50, 100],
}, id);
With the built in query language (I think simple query language), I was able to find the term in one column or the other, but I couldn't do a complex search that would return results for both columns.
grid.set("query", { scientificName : new RegExp(speciesKeyword, "i") });
grid.refresh()
I started reading and I think RQL can solve this problem, however, I am struggling with the syntax.
I have been looking at these pages:
http://rql-engine.eu01.aws.af.cm/
https://github.com/kriszyp/rql
And I am able to understand basic queries, however the "contains" syntax eludes me.
For instance if I had this simple data set and wanted to find the entries with scientific and common names that contain the string "Aca" I would think my contains query would look like this:
contains(scientificName,string:aca)
However, this results in no matches.
[
{
"tsn": 1,
"scientificName": "Acalypha ostryifolia",
"commonName": "Rough-pod Copperleaf",
},
{
"tsn": 2,
"scientificName": "Aegalius acadicus",
"commonName": "Northern Saw-whet Owl",
},
{
"tsn": 3,
"scientificName": "Portulaca pilosa",
"commonName": "2012-02-01",
},
{
"tsn": 4,
"scientificName": "Accipiter striatus",
"commonName": "Kiss-me-quick",
},
{
"tsn": 5,
"scientificName": "Acorus americanus",
"commonName": "American Sweetflag",
}
]
Can someone guide me in how to formulate the correct syntax? Thank you.
From what I'm briefly reading, it appears that:
contains was replaced by any and all
these are meant for array comparisons, not string comparisons
I'm not sure offhand whether RegExps can just be handed to other operations e.g. eq.
With dojo/store/Memory, you can also pass a query function which will allow you to do whatever you want, so if you wanted to compare for a match in one field or the other you could do something like this:
grid.set('query', function (item) {
var scientificRx = new RegExp(speciesKeyword, 'i');
var commonRx = new RegExp(...);
return scientificRx.test(item.scientificName) || commonRx.test(item.commonName);
});
Of course, if you want to filter only items that match both, you can do that with simple object syntax:
grid.set('query', {
scientificName: scientificRx,
commonName: commonRx
});

How to filter by sub-object in Rally 2 SDK

I'm trying to query for user stories whose release start date is greater than a particular date. Is it possible to do this using the "filters" config rather than querying all stories and then checking manually?
Is this valid? :
Ext.create('Rally.data.WsapiDataStore', {
model: 'UserStory',
context: {
project: '/project/xxxx'
},
autoLoad: true,
fetch: ['Rank', 'FormattedID', 'Release'],
filters: [
{
property: 'Release.ReleaseStartDate',
operator: '>',
value: '2012-10-10'
}
]
});
It doesn't work, just fetches all records.
The code posted above does work. I was actually using a comboBox value in the "value" property. Turns out I didn't convert it to a proper DateTime format and hence the comparison was failing and returning all records.
In my case I had to use Rally.util.DateTime.toIsoString in order to compare the value in the combobox.