@vinctus/oql 0.1.65 → 0.2.0-alpha.1

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/README.md CHANGED
@@ -5,42 +5,18 @@
5
5
  - [OQL](#oql)
6
6
  - [Overview](#overview)
7
7
  - [Installation](#installation)
8
- - [Node.js](#nodejs)
8
+ - [TypeScript/JavaScript](#typescriptjavascript)
9
9
  - [Scala.js](#scalajs)
10
+ - [Usage](#usage)
11
+ - [Tutorial](#tutorial)
10
12
  - [API](#api)
11
- - [The `OQL` Class](#the-oql-class)
12
- - [count(query, [parameters])](#countquery-parameters)
13
- - [entity(name)](#entityname)
14
- - [queryBuilder()](#querybuilder)
15
- - [queryOne(query, [parameters])](#queryonequery-parameters)
16
- - [queryMany(query, [parameters])](#querymanyquery-parameters)
17
- - [raw(sql, [values])](#rawsql-values)
18
- - [The `QueryBuilder` Class](#the-querybuilder-class)
19
- - [cond(exp)](#condexp)
20
- - [getCount()](#getcount)
21
- - [getMany()](#getmany)
22
- - [getOne()](#getone)
23
- - [limit(a)](#limita)
24
- - [offset(a)](#offseta)
25
- - [order(attribute, sorting)](#orderattribute-sorting)
26
- - [project(entity, attributes)](#projectentity-attributes)
27
- - [query(base_query, [parameters])](#querybase_query-parameters)
28
- - [select(selection, [parameters])](#selectselection-parameters)
29
- - [The `Resource` Class](#the-resource-class)
30
- - [delete(id)](#deleteid)
31
- - [getMany()](#getmany-1)
32
- - [insert(obj)](#insertobj)
33
- - [link(e1, attribute, e2)](#linke1-attribute-e2)
34
- - [unlink(e1, resource, e2)](#unlinke1-resource-e2)
35
- - [update(e, updates)](#updatee-updates)
36
- - [Syntax](#syntax)
37
- - [Data Modeling Language](#data-modeling-language)
38
- - [Production Rules](#production-rules)
39
- - [Query Language](#query-language)
40
- - [Production Rules](#production-rules-1)
41
13
  - [Examples](#examples)
42
- - [Example (many-to-one)](#example-many-to-one)
43
- - [Example (many-to-many)](#example-many-to-many)
14
+ - [Tests](#tests)
15
+ - [Requirements](#requirements)
16
+ - [Setup PostgreSQL](#setup-postgresql)
17
+ - [Clone the repository](#clone-the-repository)
18
+ - [Build the test database](#build-the-test-database)
19
+ - [Run tests](#run-tests)
44
20
  - [License](#license)
45
21
 
46
22
  <!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -48,30 +24,38 @@
48
24
  OQL
49
25
  ===
50
26
 
51
- *Object Query Language* inspired by [GraphQL](https://graphql.org/)
27
+ ![npm (scoped)](https://img.shields.io/npm/v/@vinctus/oql) ![GitHub Release Date](https://img.shields.io/github/release-date/vinctustech/oql) ![GitHub](https://img.shields.io/github/license/vinctustech/oql) ![GitHub last commit](https://img.shields.io/github/last-commit/vinctustech/oql) ![GitHub issues](https://img.shields.io/github/issues/vinctustech/oql) ![Snyk Vulnerabilities for npm scoped package](https://img.shields.io/snyk/vulnerabilities/npm/@vinctus/oql) ![npm bundle size (scoped)](https://img.shields.io/bundlephobia/minzip/@vinctus/oql) ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/vinctustech/oql/unit-tests)
28
+
29
+ Object Query Language (OQL) is a simple relational database query language inspired by GraphQL and SQL, but designed to be translated query-for-query into database engine specific SQL, with identical behaviour across supported engines.
30
+
31
+ Full library documentation can be found [here](https://vinctustech.github.io/oql).
52
32
 
53
33
  Overview
54
34
  --------
55
35
 
56
- *OQL* (Object Query Language) is a language for querying a relational database. The syntax is inspired by GraphQL and is similar, but not identical. Some capabilities missing from GraphQL have been added, and some capabilities found in GraphQL are implemented differently. *OQL* only provides support for data retrieval, however there are class methods for performing mutations. Furthermore, mutation operations all abide by the supplied Entity-Relationship database description, i.e. aliases.
36
+ *OQL* is a language for querying a relational database. The query syntax draws inspiration from GraphQL and is similar, but with many differences. Some capabilities missing from GraphQL have been added, and some capabilities found in GraphQL have a different syntax. We believe that much of conventional SQL syntax is still preferable to creating a completely new syntax for every single feature of the query language. However, whereas SQL can be seen as a "low level" relational query language, OQL takes a higher level Entity-Relationship (ER) Model view of the database.
37
+
38
+ The name "OQL" refers to both a software library, and a query language implemented within that library. The OQL library provides support for data retrieval (via the OQL query language), and a query builder for constructing queries step by step in your code. There are also class methods for performing all kinds of mutations, including mutations that support the ER model view of the database. Furthermore, query and mutation operations all abide by the supplied ER data model.
57
39
 
58
- Some features of *OQL* include:
40
+ Some features of the OQL language include:
59
41
 
60
- - very similar to [GraphQL](https://graphql.org/) (for querying)
61
- - uses a very simple [Entity-Relationship model](https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model) description of the database
42
+ - similar to [GraphQL](https://graphql.org/) in that query results have exactly the structure requested in the query (i.e., you get what you ask for).
43
+ - uses a very simple [Entity-Relationship model](https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model) description of the database
62
44
  - works with the [PostgreSQL database system](https://www.postgresql.org/)
63
45
  - designed to work with existing databases without having to change the database at all
64
46
 
65
47
  Installation
66
48
  ------------
67
49
 
68
- ### Node.js
50
+ ### TypeScript/JavaScript
69
51
 
70
52
  There is a [Node.js](https://nodejs.org/en/) module available through the [npm registry](https://www.npmjs.com/).
71
53
 
72
- Installation is done using the [npm install command](https://docs.npmjs.com/downloading-and-installing-packages-locally):
54
+ Install using the [npm install](https://docs.npmjs.com/downloading-and-installing-packages-locally) command:
73
55
 
74
- `$ npm install @vinctus/oql`
56
+ ```bash
57
+ npm install @vinctus/oql
58
+ ```
75
59
 
76
60
  TypeScript declarations are included in the package.
77
61
 
@@ -84,550 +68,123 @@ Add the following lines to your `build.sbt`:
84
68
  ```sbt
85
69
  externalResolvers += "OQL" at "https://maven.pkg.github.com/vinctustech/oql"
86
70
 
87
- libraryDependencies += "com.vinctus" %%% "-vinctus-oql" % "0.1.47",
71
+ libraryDependencies += "com.vinctus" %%% "-vinctus-oql" % "1.1.33"
88
72
 
89
- npmDependencies in Compile ++= Seq(
90
- "pg" -> "8.5.1",
91
- "@types/pg" -> "7.14.7"
73
+ Compile / npmDependencies ++= Seq(
74
+ "pg" -> "8.13.1",
75
+ "@types/pg" -> "8.11.11",
76
+ "source-map-support" -> "0.5.21",
92
77
  )
93
78
  ```
94
79
 
95
- API
96
- ---
97
-
98
- The TypeScript API is documented first here followed by a few notes on the Scala.js API which is very similar.
80
+ Usage
81
+ -----
99
82
 
100
- The following TypeScript snippet provides an overview of the API.
83
+ Generally, using OQL in a project has the following form:
101
84
 
102
85
  ```typescript
103
- import { OQL, PostgresConnection } from '@vinctus/oql'
86
+ import { OQL } from '@vinctus/oql'
104
87
 
105
- const conn = new PostgresConnection( <host>, <port>, <database>, <user>, <password>, <max>)
106
- const oql = new OQL( conn, <data model> )
88
+ const oql = new OQL(<data model>, <host>, <port>, <database>, <user>, <password>, <ssl>, <idleTimeoutMillis>, <max>)
107
89
 
108
- oql.query(<query>).then((result: any) => <handle result> )
90
+ oql.queryMany(<query>).then((<result>: any) => <handle result>)
109
91
  ```
110
92
 
111
- `<host>`, `<port>`, `<database>`, `<user>`, `<password>`, and `<max>` are the connection pool (`PoolConfig`) parameters for the Postgres database you are querying.
112
-
113
- `<data model>` describes the parts of the database being queried. It's not necessary to describe every field of every table in the database, only what is being retrieved with *OQL*. However, primary keys of tables that are being queried should always be included, even if you're not interested in retrieving the primary keys themselves.
114
-
115
- `<query>` is the OQL query string.
93
+ where *host*, *port*, *database*, *user*, *password*, *ssl*, *idleTimeoutMillis*, and *max* are the [connection pool](https://node-postgres.com/api/pool) (`PoolConfig`) parameters for the Postgres database you are querying.
116
94
 
117
- `<handle result>` is your result array handling code. The `result` object will be predictably structured according to the query.
95
+ *data model* describes the parts of the database available for querying. It's not necessary to describe every field of every table in the database, only what is being retrieved with OQL. However, primary keys of tables that are being queried should always be included, even if you're not interested in retrieving the primary keys themselves.
118
96
 
119
- ### The `OQL` Class
97
+ *query* is the OQL query string.
120
98
 
121
- These are the methods of the `OQL` class, which are the main methods that you will be using. Brackets are a parameter signifies an optional parameter.
99
+ *handle result* is your result array handling code. The *result* object will be predictably structured according to the query.
122
100
 
123
- #### count(query, [parameters])
124
-
125
- Returns a promise for the number of objects where `query` is the query string written in the [OQL query language](#query-language). If `parameters` is given, each parameter is referenced in the query as `:name` where `name` is the name of the parameter.
101
+ Tutorial
102
+ --------
126
103
 
127
- For example
104
+ You can follow a fully explained tutorial example [here](https://vinctustech.github.io/oql/tutorial.html).
128
105
 
129
- ```typescript
130
- oql.count('product [price < :max]', {max: 100.00})
131
- ```
106
+ API
107
+ ---
132
108
 
133
- gets the number of products that are less than $100.
109
+ Full API documentation can be found [here](https://vinctustech.github.io/oql/api.html).
134
110
 
135
- #### entity(name)
111
+ Examples
112
+ --------
136
113
 
137
- Returns a `Resource` instance for OQL class instance that it was called on. See [The `Resource` Class](#the-resource-class) for a method reference.
114
+ Several examples are given [here](https://vinctustech.github.io/oql/examples.html).
138
115
 
139
- #### queryBuilder()
116
+ Tests
117
+ -----
140
118
 
141
- Returns a `QueryBuilder` instance for OQL class instance that it was called on. See [The `QueryBuilder` Class](#the-querybuilder-class) for a method reference.
119
+ ### Requirements
142
120
 
143
- #### queryOne(query, [parameters])
121
+ - Git (for cloning)
122
+ - Java 11+
123
+ - [sbt](https://www.scala-sbt.org/1.x/docs/Setup.html) (for building and running tests)
144
124
 
145
- Returns a promise for zero or one object where `query` is the query string written in the [OQL query language](#query-language). If `parameters` is given, each parameter is referenced in the query as `:name` where `name` is the name of the parameter.
125
+ ### Setup PostgreSQL
146
126
 
147
- For example
127
+ To run the unit test, you will need to get [PostgreSQL](https://hub.docker.com/_/postgres) running in a [docker container](https://www.docker.com/resources/what-container):
148
128
 
149
- ```typescript
150
- oql.queryOne('user {id name email} [id < :id]', {id: 12345})
151
129
  ```
152
-
153
- gets the `id`, `name`, and `email` for user with id 12345.
154
-
155
- #### queryMany(query, [parameters])
156
-
157
- Returns a promise for an array of objects where `query` is the query string written in the [OQL query language](#query-language). If `parameters` is given, each parameter is referenced in the query as `:name` where `name` is the name of the parameter.
158
-
159
- For example
160
-
161
- ```typescript
162
- oql.queryMany('product {id name price supplier.name} [price < :max]', {max: 100.00})
130
+ docker pull postgres
131
+ docker run --rm --name pg-docker -e POSTGRES_PASSWORD=docker -d -p 5432:5432 postgres
163
132
  ```
164
133
 
165
- gets the `id`, `name`, `price` and `supplier.name` for products that are less than $100.
166
-
167
- #### raw(sql, [values])
168
-
169
- Perform the raw SQL query and return a promise for the results where `sql` is the query string and `values` are query parameter values.
170
-
171
- ### The `QueryBuilder` Class
172
-
173
- `QueryBuilder` is used to build up a query step by step. `QueryBuilder` instances are immutable so each method that returns a `QueryBuilder` object is returning a new instance.
174
-
175
- #### cond(exp)
176
-
177
- Blocks the next method call in a chain of `QueryBuilder` calls if the condition expression `exp` is falsy.
178
-
179
- #### getCount()
180
-
181
- Returns a promise for the number of objects that could be retrieved with `this` query builder.
182
-
183
- #### getMany()
184
-
185
- Returns a promise for an array of object specified by `this` query builder.
186
-
187
- #### getOne()
188
-
189
- Returns a promise for zero or one object specified by `this` query builder.
190
-
191
- #### limit(a)
192
-
193
- Returns a new query builder with a query limit of `a`.
194
-
195
- #### offset(a)
196
-
197
- Returns a new query builder with a query offset of `a`.
198
-
199
- #### order(attribute, sorting)
200
-
201
- Returns a new query builder with a query ordering on `attribute` with `sorting` direction.
202
-
203
- #### project(entity, attributes)
204
-
205
- Returns a new query builder to query `entiry` retrieving `attributes`. This method is a bit more efficient than using `query` because it avoids parsing the query.
206
-
207
- #### query(base_query, [parameters])
208
-
209
- Returns a new query builder with the given `base_query`, which must be a well-formed OQL query.
210
-
211
- #### select(selection, [parameters])
212
-
213
- Returns a new query builder with the given `selection`. If a selection has been given, either using `query` (with the selection within brackets) or using `select`, then this selection will be logically AND'ed with the previous one. There or no need to add parentheses to ensure correct order of operations if the selection contains a logical OR, this is done internally.
134
+ The [PostgreSQL client](https://www.postgresql.org/docs/13.3/app-psql.html) (`psql`) should be installed. If necessary, it can be installed with the command
214
135
 
215
- ### The `Resource` Class
216
-
217
- These are methods that can be called on a resource object.
218
-
219
- #### delete(id)
220
-
221
- Returns a promise to delete object with primary key `id`.
222
-
223
- #### getMany()
224
-
225
- Returns a promise for all objects of `this` resource.
226
-
227
- #### insert(obj)
228
-
229
- Returns a promise to insert `obj` into `this` resource. The promise resolves to an object with the primary key of the inserted object.
230
-
231
- #### link(e1, attribute, e2)
232
-
233
- Returns a promise to link object `e1` of `this` resource to object `e2` of the type given for `attribute`.
234
-
235
- #### unlink(e1, resource, e2)
236
-
237
- Returns a promise to unlink object `e1` of `this` resource to object `e2` of the type given for `attribute`.
238
-
239
- #### update(e, updates)
240
-
241
- Returns a promise to unlink object `e` of `this` resource according to `updates`.
242
-
243
- Syntax
244
- ------
245
-
246
- The syntax of both the data modeling language and the query language is given using a kind of enhanced [Wirth Syntax Notation](https://en.wikipedia.org/wiki/Wirth_syntax_notation). The enhancement is just the use of a postfix "+" to mean one-or-more repetition of the preceding pattern. The definition for `json` ([JSON syntax](https://www.json.org/json-en.html)) has been omitted.
247
-
248
- ### Data Modeling Language
136
+ `sudo apt-get install postgresql-client`
249
137
 
250
- An "Entity-Relationship" style language is used to describe the database. Only the portions of the database for which OQL is being used need to be described.
138
+ ### Clone the repository
251
139
 
252
- #### Production Rules
140
+ At the shell terminal go to the folder where the sources will be downloaded, referred to as `dev-path/`, and type
253
141
 
254
142
  ```
255
- model = entity+ .
256
- entity = "entity" identifier [ "(" alias ")" ] "{" attribute+ "}" .
257
- digit = "0" | "1" | … | "8" | "9" .
258
- upperCase = "A" | "B" | … | "Y" | "Z" .
259
- lowerCase = "a" | "b" | … | "y" | "z" .
260
- identChar = upperCase | lowerCase | "_" | "$" .
261
- identifier = identChar { identChar | digit } .
262
- alias = identifier .
263
- attribute = [ "*" ] attributeName [ "(" alias ")" ] ":" type [ "!" ]
264
- | identifier "=" json .
265
- type = primitiveType
266
- | entityType
267
- | "[" entityType [ "." attributeName ] "]"
268
- | "<" entityType [ "." attributeName ] ">"
269
- | "[" entityType [ "." attributeName ] "]" "(" entityType ")" .
270
- primitiveType = "text"
271
- | "integer" | "int" | "int4"
272
- | "bool" | "boolean"
273
- | "bigint"
274
- | "decimal"
275
- | "date"
276
- | "float" | "float8"
277
- | "uuid"
278
- | "timestamp" .
279
- entityType = identifier .
280
- attributeName = identifier .
143
+ git git@github.com:vinctustech/oql.git
281
144
  ```
282
145
 
283
- Regarding the `primitiveType` syntax rule, all alternatives on the same line are synonymous. So, `bool` and `boolean` are synonymous and denote the same type.
284
-
285
- ### Query Language
286
-
287
- The query language is inspired by GraphQL. In the following grammar, all keywords (double-quoted string literals) are case-insensitive.
146
+ This will create folder `dev-path/oql`.
288
147
 
289
- #### Production Rules
290
-
291
- ```
292
- query = identifier [ project ] [ select ] [ group ] [ order ] [ restrict ] .
293
- project = "{" (attributeProject | "-" identifier | "&" identifier | "*")+ "}"
294
- | "." attributeProject .
295
- attributeProject = identifier "(" [ "*" | identifier ] ")"
296
- | "^" query
297
- | query .
298
- select = "[" logicalExpression "]" .
299
- variable = ident { "." ident } .
300
- expression = additiveExpression .
301
- logicalExpression = orExpression .
302
- orExpression = andExpression { "OR" andExpression } .
303
- andExpression = notExpression { "AND" notExpression } .
304
- notExpression = "NOT" comparisonExpression
305
- | comparisonExpression .
306
- comparisonExpression = applyExpression ("<=" | ">=" | "<" | ">" | "=" | "!="
307
- | [ "NOT" ] ("LIKE" | "ILIKE")) applyExpression
308
- | applyExpression [ "NOT" ] "BETWEEN" applyExpression "AND" applyExpression
309
- | applyExpression ("IS" "NULL" | "IS" "NOT" "NULL")
310
- | applyExpression [ "NOT" ] "IN" expressions
311
- | applyExpression [ "NOT" ] "IN" "(" query ")"
312
- | "EXISTS" "(" query ")"
313
- | applyExpression .
314
- additiveExpression = multiplicativeExpression { ("+" | "-") multiplicativeExpression } .
315
- multiplicativeExpression = applyExpression { ("*" | "/") applyExpression } .
316
- expressions = "(" expression { "," expression } ")" .
317
- applyExpression = identifier expressions
318
- | primaryExpression .
319
- primaryExpression = number
320
- | string
321
- | "TRUE" | "FALSE"
322
- | "&" identifier { "." identifier }
323
- | "INTERVAL" singleQuoteString
324
- | variable
325
- | caseExpression
326
- | "(" query ")"
327
- | "(" logicalExpression ")" .
328
- caseExpression = "CASE" when+ [ "ELSE" expression ] "END" .
329
- when = "WHEN" logicalExpression "THEN" expression .
330
- expression = applyExpression .
331
- order = "<" orderExpressions ">" .
332
- orderExpressions = orderExpression { "," orderExpression } .
333
- orderExpression = expression [ "ASC" | "DESC" ] [ "NULLS" ("FIRST" | "LAST") ] .
334
- group = "(" variables ")" .
335
- variables = variable { "," variable } .
336
- restrict = "|" integer [ "," integer ] "|"
337
- | "|" "," integer "|" .
338
- ```
339
-
340
- Examples
341
- --------
148
+ ### Build the test database
342
149
 
343
- Several examples are presented, each one creating a different database. Each example presents a different use case.
150
+ Type
344
151
 
345
- ### Example (many-to-one)
152
+ ```shell
153
+ cd oql/test
346
154
 
347
- This example presents a very simple "employee" database where employees have a manager and a department (among other things), so that the employees and their managers are in a *many-to-one* relationship, which also requires that the employee table to joined to itself. Employees and departments are also in a *many-to-one* relationship.
155
+ sh start
348
156
 
349
- Get [PostgreSQL](https://hub.docker.com/_/postgres) running in a [docker container](https://www.docker.com/resources/what-container):
157
+ sh tests
350
158
 
159
+ sh build
351
160
  ```
352
- sudo docker pull postgres
353
- sudo docker run --rm --name pg-docker -e POSTGRES_PASSWORD=docker -d -p 5432:5432 postgres
354
- ```
355
-
356
- Run the [PostgreSQL terminal](https://www.postgresql.org/docs/9.3/app-psql.html) to create a database:
357
-
358
- `psql -h localhost -U postgres -d postgres`
359
-
360
- which can be installed if necessary with the command
361
-
362
- `sudo apt-get install postgresql-client`
363
161
 
364
- Create a simple database by copy-pasting the following (yes, all in one shot) at the `psql` prompt:
365
-
366
- ```sql
367
- CREATE DATABASE employees;
368
-
369
- CREATE TABLE department (
370
- dep_id SERIAL PRIMARY KEY,
371
- dep_name TEXT
372
- );
373
-
374
- CREATE TABLE employee (
375
- emp_id SERIAL PRIMARY KEY,
376
- emp_name TEXT,
377
- job_title TEXT,
378
- manager_id INTEGER REFERENCES employee,
379
- dep_id INTEGER REFERENCES department
380
- );
381
-
382
- INSERT INTO department (dep_id, dep_name) VALUES
383
- (1001, 'FINANCE'),
384
- (2001, 'AUDIT'),
385
- (3001, 'MARKETING');
386
-
387
- INSERT INTO employee (emp_id, emp_name, job_title, manager_id, dep_id) VALUES
388
- (68319, 'KAYLING', 'PRESIDENT', null, 1001),
389
- (66928, 'BLAZE', 'MANAGER', 68319, 3001),
390
- (67832, 'CLARE', 'MANAGER', 68319, 1001),
391
- (65646, 'JONAS', 'MANAGER', 68319, 2001),
392
- (67858, 'SCARLET', 'ANALYST', 65646, 2001),
393
- (69062, 'FRANK', 'ANALYST', 65646, 2001),
394
- (63679, 'SANDRINE', 'CLERK', 69062, 2001),
395
- (64989, 'ADELYN', 'SALESREP', 66928, 3001),
396
- (65271, 'WADE', 'SALESREP', 66928, 3001),
397
- (66564, 'MADDEN', 'SALESREP', 66928, 3001),
398
- (68454, 'TUCKER', 'SALESREP', 66928, 3001),
399
- (68736, 'ADNRES', 'CLERK', 67858, 2001),
400
- (69000, 'JULIUS', 'CLERK', 66928, 3001),
401
- (69324, 'MARKER', 'CLERK', 67832, 1001);
402
- ```
403
-
404
- Run the following TypeScript program:
162
+ The last few lines of output should be
405
163
 
406
- ```typescript
407
- import { OQL, PostgresConnection } from '@vinctus/oql'
408
-
409
- const conn = new PostgresConnection("localhost", 5432, "postgres", 'postgres', 'docker', false)
410
- const oql =
411
- new OQL(`
412
- entity employee {
413
- *emp_id: integer
414
- name (emp_name): text
415
- job_title: text
416
- manager (manager_id): employee
417
- department (dep_id): department
418
- }
419
-
420
- entity department {
421
- *dep_id: integer
422
- name (dep_name): text
423
- }
424
- `)
425
-
426
- oql
427
- .query("employee { name manager.name department.name } [job_title = 'CLERK']", conn)
428
- .then((res: any) => console.log(JSON.stringify(res, null, 2)))
429
164
  ```
430
-
431
- Output:
432
-
433
- ```json
434
- [
435
- {
436
- "name": "SANDRINE",
437
- "manager": {
438
- "name": "FRANK"
439
- },
440
- "department": {
441
- "name": "AUDIT"
442
- }
443
- },
444
- {
445
- "name": "ADNRES",
446
- "manager": {
447
- "name": "SCARLET"
448
- },
449
- "department": {
450
- "name": "AUDIT"
451
- }
452
- },
453
- {
454
- "name": "JULIUS",
455
- "manager": {
456
- "name": "BLAZE"
457
- },
458
- "department": {
459
- "name": "MARKETING"
460
- }
461
- },
462
- {
463
- "name": "MARKER",
464
- "manager": {
465
- "name": "CLARE"
466
- },
467
- "department": {
468
- "name": "FINANCE"
469
- }
470
- }
471
- ]
165
+ CREATE TABLE
166
+ ALTER TABLE
167
+ INSERT 0 4
168
+ INSERT 0 4
472
169
  ```
473
170
 
474
- The query `employee { name manager.name department.name } [job_title = 'CLERK']` in the above example program is asking for the names of employees with job title "CLERK" as well as the names of their manager and department. In standard GraphQL, the query would have been `{ employee(job_title: 'CLERK') { name manager { name } department { name } } }`, which we feel is more verbose than it needs to be. The use of dot notation as in `manager.name` is semantically equivalent to `manager { name }`.
475
-
476
- ### Example (many-to-many)
477
-
478
- This example presents a very simple "student" database where students are enrolled in classes, so that the students and classes are in a *many-to-many* relationship. The example has tables and fields that are intentionally poorly named so as to demonstrate the aliasing features of the database modeling language.
171
+ ### Run tests
479
172
 
480
- Get [PostgreSQL](https://hub.docker.com/_/postgres) running in a [docker container](https://www.docker.com/resources/what-container):
173
+ Type
481
174
 
482
175
  ```
483
- sudo docker pull postgres
484
- sudo docker run --rm --name pg-docker -e POSTGRES_PASSWORD=docker -d -p 5432:5432 postgres
176
+ cd ..
177
+ sbt test
485
178
  ```
486
179
 
487
- Run the [PostgreSQL terminal](https://www.postgresql.org/docs/9.3/app-psql.html) to create a database:
180
+ You should see
488
181
 
489
- `psql -h localhost -U postgres -d postgres`
490
-
491
- which can be installed if necessary with the command
492
-
493
- `sudo apt-get install postgresql-client`
494
-
495
- Create a simple database by copy-pasting the following (yes, all in one shot) at the `psql` prompt:
496
-
497
- ```sql
498
- CREATE DATABASE student;
499
-
500
- CREATE TABLE students (
501
- id SERIAL PRIMARY KEY,
502
- stu_name TEXT
503
- );
504
-
505
- CREATE TABLE class (
506
- id SERIAL PRIMARY KEY,
507
- name TEXT
508
- );
509
-
510
- CREATE TABLE student_class (
511
- studentid INTEGER REFERENCES students (id),
512
- classid INTEGER REFERENCES class (id),
513
- year INTEGER,
514
- semester TEXT,
515
- grade TEXT
516
- );
517
-
518
- INSERT INTO students (id, stu_name) VALUES
519
- (1, 'John'),
520
- (2, 'Debbie');
521
-
522
- INSERT INTO class (id, name) VALUES
523
- (1, 'English'),
524
- (2, 'Maths'),
525
- (3, 'Spanish'),
526
- (4, 'Biology'),
527
- (5, 'Science'),
528
- (6, 'Programming'),
529
- (7, 'Law'),
530
- (8, 'Commerce'),
531
- (9, 'Physical Education');
532
-
533
- INSERT INTO student_class (studentid, classid, year, semester, grade) VALUES
534
- (1, 3, 2019, 'fall', 'B+'),
535
- (1, 5, 2018, 'winter', 'A'),
536
- (1, 9, 2019, 'summer', 'F'),
537
- (2, 1, 2018, 'fall', 'A+'),
538
- (2, 4, 2019, 'winter', 'B-'),
539
- (2, 5, 2018, 'summer', 'A-'),
540
- (2, 9, 2019, 'fall', 'B+');
541
182
  ```
542
-
543
- Run the following TypeScript program:
544
-
545
- ```typescript
546
- import { OQL, PostgresConnection } from '@vinctus/oql'
547
-
548
- const conn = new PostgresConnection("localhost", 5432, "postgres", 'postgres', 'docker', false)
549
- const oql =
550
- new OQL(`
551
- entity class {
552
- *id: integer
553
- name: text
554
- students: [student] (enrollment)
555
- }
556
-
557
- entity student (students) {
558
- *id: integer
559
- name (stu_name): text
560
- classes: [class] (enrollment)
561
- }
562
-
563
- entity enrollment (student_class) {
564
- student (studentid): student
565
- class (classid): class
566
- year: integer
567
- semester: text
568
- grade: text
569
- }
570
- `)
571
-
572
- oql
573
- .query("student { * classes { * students <name> } <name> } [name = 'John']", conn)
574
- .then((res: any) => console.log(JSON.stringify(res, null, 2)))
575
- ```
576
-
577
- Output:
578
-
579
- ```json
580
- [
581
- {
582
- "id": 1,
583
- "name": "John",
584
- "classes": [
585
- {
586
- "id": 9,
587
- "name": "Physical Education",
588
- "students": [
589
- {
590
- "id": 2,
591
- "name": "Debbie"
592
- },
593
- {
594
- "id": 1,
595
- "name": "John"
596
- }
597
- ]
598
- },
599
- {
600
- "id": 5,
601
- "name": "Science",
602
- "students": [
603
- {
604
- "id": 2,
605
- "name": "Debbie"
606
- },
607
- {
608
- "id": 1,
609
- "name": "John"
610
- }
611
- ]
612
- },
613
- {
614
- "id": 3,
615
- "name": "Spanish",
616
- "students": [
617
- {
618
- "id": 1,
619
- "name": "John"
620
- }
621
- ]
622
- }
623
- ]
624
- }
625
- ]
183
+ [info] All tests passed.
626
184
  ```
627
185
 
628
- The query `student { * classes { * students <name> } <name> } [name = 'John']` in the above example program is asking for the names of the students enrolled only in the classes in which John is enrolled. Also, the query is asking for the classes and the students in each class to be ordered by class name and student name, respectively. The `*` operator is a wildcard that stands for all attributes that do not result in an array value.
629
-
630
186
  License
631
187
  -------
632
188
 
633
- [ISC](https://opensource.org/licenses/ISC)
189
+ OQL uses the commercial friendly open source [ISC](https://raw.githubusercontent.com/vinctustech/oql/stable/LICENSE) license.
190
+