Skip to main content

DSL intended to express requests for b3j0f.crudity.

Project description

Summary

Description

Expression is a Domain Specific Language (DSL) designed to express CRUD queries for b3j0f.crudity (https://github.com/b3j0f/requester/).

In other words, you can write Crudity Expressions.

Crudity expressions, cool ! But… what is it ?

This package has been designed to work in strong coupling with b3j0f.requester, so you should know what it is before continuing.

In b3j0f.requester, everything is an Expression (E) or a Function (F). If you want to compare a and b you need to write :

>>> F('>', params=[E.a, E.b])

A programmer can manipulate those nested function calls with no problem, but people with less technical background will find difficulties doing it. j1bz.expression aims to make b3j0f.requester calls more accessible. The syntax is highly inspired from SQL, because any IT guy should have seen at least a few SQL queries and should not be lost :

>>> interpret("SELECT ALL WHERE (a > b);")

The syntax is more restrictive than what native b3j0f.requester allows you to do (main needs are covered). Thus, users are incentived to write things that make sense.

j1bz.expression.intepreter.interpret return a b3j0f.requester.request.crud.{create.Create,read.Read,update.Update,delete.Delete} serialized object (depending on the query). The object can then be processed by any driver.

Installation

aptitude install git virtualenv

virtualenv venv
source venv/bin/activate

git clone https://github.com/b3j0f/requester

cd requester
python setup.py install

pip install j1bz.expression

expression-cli

How-to

Quickstart

>>> from j1bz.expression.interpreter import interpret
>>> res = interpret("SELECT a;")
>>> print(repr(res))
SELECT a

Note: j1bz.expression.exceptions.ParseError should be the only exception you have to catch when invoking interpret function as is.

Examples of expressions

CREATE

INSERT VALUES k:v;
INSERT VALUES k1:v1, k2:v2;
INSERT INTO i VALUES k:v;
INSERT VALUES k:v; AS i

Note: CREATE is a synonym of INSERT. It means every time you can use INSERT you could have used CREATE instead (for semantics in some cases).

CREATE VALUES k:v;

READ

SELECT ALL;
SELECT s;
SELECT s WHERE w;
SELECT s GROUP BY g;
SELECT s ORDER BY o;
SELECT s LIMIT 10;
SELECT s; AS mys

SELECT s WHERE wh GROUP BY g ORDER BY o LIMIT 10; AS mys

SELECT a, b, c;
SELECT f();
SELECT f(a, b, c);

SELECT s WHERE (a);
SELECT s WHERE (a = b);
SELECT s WHERE (a != b);
SELECT s WHERE (a > b);
SELECT s WHERE (a >= b);
SELECT s WHERE (a < b);
SELECT s WHERE (a <= b);
SELECT s WHERE (a IN b);
SELECT s WHERE (a NIN b);
SELECT s WHERE (a LIKE b);

SELECT s WHERE (a AND b);
SELECT s WHERE (a OR b);
SELECT s WHERE (a OR (b AND c));

SELECT s ORDER BY o1, o2;
SELECT s ORDER BY o1 DESC, o2, o3 ASC;

Note: READ is a synonym of SELECT.

READ ALL;

UPDATE

UPDATE VALUES k:v;
UPDATE VALUES k:v WHERE w;
UPDATE VALUES k:v; AS myu

UPDATE INTO u VALUES k:v;
UPDATE INTO u VALUES k:v WHERE w;
UPDATE INTO u VALUES k1:v1, k2:v2;

DELETE

DELETE d;
DELETE d1, d2, d3;
DELETE d WHERE w;
DELETE d1, d2, d3 WHERE w;
DELETE d; AS myd

Note: Expression uses Grako (https://pypi.python.org/pypi/grako) to generate a parser from a grammar defined in {{ PACKAGE }}/etc/j1bz/expression/grammar.bnf. You can read this bnf description to check for all available possibilities.

Advanced how-to

If you want to integrate j1bz.expression in your code to do more than just interpret() calls, this part is for you.

Using a custom grammar

The engine powering j1bz.expression is grako. Grako (for Grammar Kompiler) take a bnf-derivated grammar file in input and generates a parser in python code.

This package embeds a grammar file and a pre-compiled parser generated from this grammar ({{ PACKAGE }}/etc/j1bz/expression/grammar.bnf).

It is possible to change this grammar and use a parser generated at runtime for your interpret() calls :

>>> interpret("SELECT a;", "/PATH/TO/grammar.bnf")

Note: Once you’ve called interpret() for the first time (with or without grammar file), the same parser used for the first time will be used later (due to a singleton mechanic).

Interpreter vs interpret

interpret() uses a singleton mechanic to provide a shortcut.

If you want to do more complex things, you can use the j1bz.expression.interpreter.Interpreter class.

Examples :

>>> i1 = Interpreter(parser=mygrakoparser, walker=mycustomwalker)
>>> i1.interpret("SELECT a;")

>>> i2 = Interpreter(pkwargs={'rule_name': 'condition'})
>>> i2.interpret("(a > b)")

>>> i3 = Interpreter(grammar_file='/PATH/TO/grammar.bnf')
>>> i3.interpret("SELECT_ALIAS a;")

Note: grammar_file argument will be used only if you did not provide a custom parser via parser argument.

Exception handling

j1bz.expression.exceptions currently defines 2 exceptions :

  • ParserGenerationError : Raised when you provide a custom grammar in order to generate a parser, but generation failed (your grammar is not correct !).

  • ParseError : Raised when an expression given to interpret() is not parsable.

Some other exceptions (IOError, OSError, FileNotFoundError) can also be raised when trying to compile a custom parser if the grammar file is not readable, does not exist, etc.

If you’re only using interpret() shortcut, you should handle all named exceptions above.

If you’re using Interpreter class, you need to handle ParserGenerationError (and file related exceptions) when you instantiate it and ParseError when you make interpret() calls.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

j1bz.expression-0.0.4.tar.gz (13.1 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page