.. -*- coding: utf-8 -*-

Let's learn RQL by practice...

.. contents::

Introduction
------------

RQL has a syntax and principle inspirated from the SQL query language, though
it's at a higher level in order to be more intuitive and suitable to easily make
advanced queries on a schema based database.

* the main idea in RQL is that we'are following relations between entities
* attributes are a special case of relations
* RQL has been inspirated from SQL but is at a higher level
* a knowledge of the application'schema is necessary to build rql queries

To use RQL, you'll have to know the basis of the language as well as a good
knowledge of the application'schema. You can always view it using the "schema"
link in user's dropdown menu (on the top-right of the screen) or by clicking here_.

.. _here: ../schema


Some bits of theory
-------------------

Variables et types
~~~~~~~~~~~~~~~~~~
Entities and attributes'value to follow and / or select are represented by the
query by *variables* which must be written upper-case.

Possible types for each variable are deducted from the schema according to
constraints in the query.

You can explicitly constrain a variable's type using the special relation "is".

Base types
~~~~~~~~~~
* `String` (literal: between double or simple quotes)
* `Int`, `Float` (using '.' as separator)
* `Date`, `Datetime`, `Time` (literal: string YYYY/MM/DD[ hh:mm] or
  `TODAY` and `NOW` keywords)
* `Boolean` (keywords `TRUE` et `FALSE`)
* keyword `NULL`

Opérateurs
~~~~~~~~~~
* Logical operators : `AND`, `OR`, `,`
* Mathematical operators: `+`, `-`, `*`, `/`
* Comparisons operators: `=`, `<`, `<=`, `>=`, `>`, `~=`, `LIKE`, `IN`

  * `=` is the default comparison operator

  * `LIKE` / `~=` permits use of the special character `%` in a string to tell
    the string must begin or end with a prefix or suffix (as SQL LIKE operator) ::
    
      Any X WHERE X name ~= 'Th%'
      Any X WHERE X name LIKE '%lt'

  * `IN` permits to give a list of possible values ::

      Any X WHERE X name IN ('chauvat', 'fayolle', 'di mascio', 'thenault')

Grammaire des requêtes de recherche
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::

  [DISTINCT] <entity type> V1(, V2)*
  [GROUPBY V1(, V2)*]  [ORDERBY <orderterms>]
  [WHERE <restriction>] 
  [LIMIT <value>] [OFFSET <value>]

:entity type:
  Type of the selected variable(s). You'll usually use `Any` type to not specify
  any type.
:restriction:
  List of relations to follow, in the form
    `V1 relation V2|<constant value>`
:orderterms:
  Define a selection order : variable or column number, followed by the sort method
  (`ASC`, `DESC`), with ASC as default when not specified

notice about grouped query (e.g using a `GROUPBY` clause): every selected
variable should be either grouped or used in an aggregat function.


Example schema
--------------

In this document, we will suppose the application's schema is the one described
here. Available entity types are :

:Person:
  ::

	name      (String, required) 
	birthday (Date)


:Company:
  ::

	name   (String)


:Note:
  ::

	diem (Date)
	type (String)


And relations between those entities: ::

	Person  works_for    Company
	Person  evaluated_by Note
	Company evaluated_by Note


Meta-data
~~~~~~~~~
Every entities'type have the following meta-data:

* `eid (Int)`, a unique identifier
* `creation_date (Datetime)`, date on which the entity has been created
* `modification_date (Datetime)`, lastest date on which the entity has been modified

* `created_by (CWUser)`, relation to the user which has created this entity

* `owned_by (CWUser)`, relation to the user()s considered as owner of this
  entity, the entity's creator by default

* `is (Eetype)`, special relation to specify a variable type.

A user's entity has the following schema:

:CWUser:
  ::

	login  	  (String) not null
	password  (Password)
	firstname (String)
	surname   (String)


Basis queries
-------------
0. *Every persons* ::
   
      Person X

   or ::

      Any X WHERE X is Person


1. *The company named Logilab* ::

      Company S WHERE S name 'Logilab'


2. *Every entities with a "name" attribute whose value starts with 'Log'* ::

      Any S WHERE S name LIKE 'Log%'

   or ::

      Any S WHERE S name ~= 'Log%'

   This query may return Person or Company entities.


3. *Every persons working for the Logilab company* ::

      Person P WHERE P works_for S, S name "Logilab"

   or ::

      Person P WHERE P works_for S AND S name "Logilab"


4. *Company named Caesium ou Logilab* ::

      Company S WHERE S name IN ('Logilab','Caesium')

   or ::

      Company S WHERE S name 'Logilab' OR S name 'Caesium'


5. *Every company but ones named Caesium ou Logilab* ::

      Company S WHERE NOT S name IN ('Logilab','Caesium')

   or ::

      Company S WHERE NOT S name 'Logilab' AND NOT S name 'Caesium'


6. *Entities evaluated by the note with eid 43* ::

      Any X WHERE X evaluated_by N, N eid 43


7. *Every persons order by birthday from the youngest to the oldest* ::
   
      Person X ORDERBY D DESC WHERE X birthday D

   Notice you've to define a variable using the birthday relation to use it in the
   sort term. 


8. *Number of persons working for each known company* ::
   
      Any S, COUNT(X) GROUPBY S WHERE X works_for S

   Notice you've that since you're writing a grouped query on S, X have to be
   either grouped as well or used in an aggregat function (as in this example).


   
Advanced
--------
0. *Person with no name specified (i.e NULL)* ::

      Person P WHERE P name NULL


1. *Person which are not working for any company* ::

      Person P WHERE NOT p works_for S


2. *Every company where person named toto isn't working* ::

      Company S WHERE NOT P works_for S , P name 'toto'


3. *Every entity which have been modified between today and yesterday* ::

      Any X WHERE X modification_date <= TODAY, X modification_date >= TODAY - 1


4. *Every note without type, to be done in the next 7 days, ordered by date* ::

      Any N, D where N is Note, N type NULL, N diem D, N diem >= TODAY,
      N diem < today + 7 ORDERBY D


5. *Person with an homonym (without duplicate)* ::

      DISTINCT Person X,Y where X name NX, Y name NX

   or even better (e.g. without both (Xeid, Yeid) and (Yeid, Xeid) in the results) ::

      Person X,Y where X name NX, Y name NX, X eid XE, Y eid > XE
