@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 +85 -528
- package/index.d.ts +46 -38
- package/main.js +2544 -0
- package/main.js.map +8 -0
- package/package.json +7 -7
- package/index.js +0 -61796
package/README.md
CHANGED
|
@@ -5,42 +5,18 @@
|
|
|
5
5
|
- [OQL](#oql)
|
|
6
6
|
- [Overview](#overview)
|
|
7
7
|
- [Installation](#installation)
|
|
8
|
-
- [
|
|
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
|
-
|
|
43
|
-
- [
|
|
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
|
-
|
|
27
|
+
       
|
|
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*
|
|
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
|
|
40
|
+
Some features of the OQL language include:
|
|
59
41
|
|
|
60
|
-
-
|
|
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
|
-
###
|
|
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
|
-
|
|
54
|
+
Install using the [npm install](https://docs.npmjs.com/downloading-and-installing-packages-locally) command:
|
|
73
55
|
|
|
74
|
-
|
|
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" % "
|
|
71
|
+
libraryDependencies += "com.vinctus" %%% "-vinctus-oql" % "1.1.33"
|
|
88
72
|
|
|
89
|
-
|
|
90
|
-
"pg"
|
|
91
|
-
"@types/pg"
|
|
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
|
-
|
|
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
|
-
|
|
83
|
+
Generally, using OQL in a project has the following form:
|
|
101
84
|
|
|
102
85
|
```typescript
|
|
103
|
-
import { OQL
|
|
86
|
+
import { OQL } from '@vinctus/oql'
|
|
104
87
|
|
|
105
|
-
const
|
|
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.
|
|
90
|
+
oql.queryMany(<query>).then((<result>: any) => <handle result>)
|
|
109
91
|
```
|
|
110
92
|
|
|
111
|
-
|
|
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
|
-
|
|
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
|
-
|
|
97
|
+
*query* is the OQL query string.
|
|
120
98
|
|
|
121
|
-
|
|
99
|
+
*handle result* is your result array handling code. The *result* object will be predictably structured according to the query.
|
|
122
100
|
|
|
123
|
-
|
|
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
|
-
|
|
104
|
+
You can follow a fully explained tutorial example [here](https://vinctustech.github.io/oql/tutorial.html).
|
|
128
105
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
```
|
|
106
|
+
API
|
|
107
|
+
---
|
|
132
108
|
|
|
133
|
-
|
|
109
|
+
Full API documentation can be found [here](https://vinctustech.github.io/oql/api.html).
|
|
134
110
|
|
|
135
|
-
|
|
111
|
+
Examples
|
|
112
|
+
--------
|
|
136
113
|
|
|
137
|
-
|
|
114
|
+
Several examples are given [here](https://vinctustech.github.io/oql/examples.html).
|
|
138
115
|
|
|
139
|
-
|
|
116
|
+
Tests
|
|
117
|
+
-----
|
|
140
118
|
|
|
141
|
-
|
|
119
|
+
### Requirements
|
|
142
120
|
|
|
143
|
-
|
|
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
|
-
|
|
125
|
+
### Setup PostgreSQL
|
|
146
126
|
|
|
147
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
138
|
+
### Clone the repository
|
|
251
139
|
|
|
252
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
150
|
+
Type
|
|
344
151
|
|
|
345
|
-
|
|
152
|
+
```shell
|
|
153
|
+
cd oql/test
|
|
346
154
|
|
|
347
|
-
|
|
155
|
+
sh start
|
|
348
156
|
|
|
349
|
-
|
|
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
|
-
|
|
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
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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
|
-
|
|
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
|
-
|
|
173
|
+
Type
|
|
481
174
|
|
|
482
175
|
```
|
|
483
|
-
|
|
484
|
-
|
|
176
|
+
cd ..
|
|
177
|
+
sbt test
|
|
485
178
|
```
|
|
486
179
|
|
|
487
|
-
|
|
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://
|
|
189
|
+
OQL uses the commercial friendly open source [ISC](https://raw.githubusercontent.com/vinctustech/oql/stable/LICENSE) license.
|
|
190
|
+
|