Skip to content

Commit

Permalink
feat: Data management feature (#82)
Browse files Browse the repository at this point in the history
* feat: add find feature

* feat: uodate

* fix: Better structure

* fix: Better

* todos

* feat: Operator list

* fix: $gt description

* Fixing some typos and reformulate some sentences

---------

Co-authored-by: Thomas DA ROCHA <thomas.darocha@lenra.io>
Co-authored-by: jonas-martinez <cbobbxta.fr@gmail.com>
Co-authored-by: Thomas DA ROCHA <8969556+taorepoara@users.noreply.github.com>
  • Loading branch information
4 people committed Oct 25, 2023
1 parent f263fcd commit 31a0028
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 68 deletions.
2 changes: 1 addition & 1 deletion doc-deps.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
components:
- name: components-api
url: https://github.com/lenra-io/components-api
version: v1.0.0-beta.79
version: v1.0.0-beta.81
filePrefix: lenra-api-docs
40 changes: 24 additions & 16 deletions lesta.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import fm from 'front-matter';

const languageFileRegex = /^(.+)[.]([a-z]{2})([.](md|html))$/
const attributesMatchingRegex = /#\S+|\.\S+|([a-zA-Z0-9_-]+)(=("(\\"|[^"])*"|'(\\'|[^'])*'|\S*))?/g;
const converter = new Showdown.Converter();
const converter = new Showdown.Converter({tables: true});

const customClassExt = {
type: 'output',
Expand Down Expand Up @@ -95,7 +95,7 @@ async function pageLister(configuration) {
});
const markdownPages = await markdownPageLister(configuration);
const apiPages = await apiPageLister(configuration);
const pages = pugPages.slice();
let pages = pugPages.slice();
addPages(pages, markdownPages);
addPages(pages, apiPages);
pages.forEach(page => {
Expand All @@ -113,7 +113,7 @@ async function pageLister(configuration) {
}
});
setPagesParent(pages);
sortPages(pages);
pages = sortPages(pages);
setPagesChildrenAndNav(pages);
return pages;
}
Expand Down Expand Up @@ -243,31 +243,39 @@ function setPagesChildrenAndNav(pages) {
}

/**
* Set the children pages for each dir page and sort the page list
* Sort the page list
* @param {Page[]} pages
*/
function sortPages(pages) {
// Sort the pages without parent in a resulting array
const ret = sortPageLevel(pages.filter(page => !page.properties.parent));
// for each page in the resulting array, add the sorted sub pages
let i = 0;
while (i < ret.length) {
const page = ret[i];
ret.splice(++i, 0, ...sortPageLevel(pages.filter(p => p.properties.parent == page.href)));
}
return ret;
}

/**
* Sort the page list of a specific level
* @param {Page[]} pages
*/
function sortPageLevel(pages) {
pages.sort((p1, p2) => p1.href.localeCompare(p2.href));
const positionnables = pages.filter(p => "position" in p.properties)
.sort((p1, p2) => {
if (p1.properties.parent == p2.properties.parent)
return p1.properties.position - p2.properties.position
return p1.href.localeCompare(p2.href);
});
.sort((p1, p2) => p1.properties.position - p2.properties.position);
positionnables.forEach(page => {
const children = pages.filter(p => p.properties.parent == page.properties.parent);
const firstChildPos = pages.indexOf(children[0]);
const currentPos = pages.indexOf(page);
let targetPos = firstChildPos + Math.max(
Math.min(page.properties.position, children.length - 1),
let targetPos = Math.max(
Math.min(page.properties.position, pages.length - 1),
0
);
if (currentPos != targetPos) {
pages.splice(currentPos, 1);
if (currentPos < targetPos) {
++targetPos;
}
pages.splice(targetPos, 0, page);
}
});
return pages;
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@
"from": "^/todo-list-guide.html$",
"to": "/guides/todo-list-app.html",
"type": "permanent"
}
}
]
}
}
}
}
136 changes: 136 additions & 0 deletions src/markdown/features/data-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
Lenra Data system is based on Mongo.
Using our API, you can access and manage this data and utilize the [View component](/references/components-api/components/view.html) to adapt your application interface.

## API

To manage the data in your application, you can utilize our REST API.
To make a basic API call within Listeners, you can use the "api" object that is passed as the third parameter. This object provides you with the server URL and your authentication token.

### CRUD

Create a document, give the content in the body

```js
- POST `${api.url}/app/colls/${coll}/docs`
```

Read a specific document
```js
- GET `${api.url}/app/colls/${coll}/docs/${id}`
```

Update a document, give the changes in the body
```js
- PUT `${api.url}/app/colls/${coll}/docs/${doc._id}`
```

Delete a document
```js
- DELETE `${api.url}/app/colls/${coll}/docs/${doc._id}`
```

### Advanced Mongo functions


#### find

The [MongoDB find function](https://www.mongodb.com/docs/manual/reference/method/db.collection.find/) can find many documents in a collection filtered by the query filter.

Run find request, give find params in body like:
- query: the query filter
- projection: the projection map more details [here](#apiProjection)

```js
- POST `${api.url}/app/colls/${coll}/docs/find`
```

The projection allows you to filter the keys in the return object, by giving a projection map, all keys set to *true* will be returned, the default values are *false*, example:

We have in the *users* collection

```json
{
"_id": "123456",
"name": "John",
"age": 20
}
```

## View

Lenra also allows the use of Mongo find to customize the view's results according to the requested data.
Additionally, this behavior automatically updates the interface when a data point corresponding to the view query is changed.
### Examples

The next example will call the `filteredUsers` view with the user called `Thomas` as input data:

```json
{
"type": "view",
"name": "filteredUsers",
"find": {
"coll": "users",
"query": {
"name": "Thomas"
}
}
}
```

You can get only the names of the users by using this projection:

```json
{
"type": "view",
"name": "userList",
"find": {
"coll": "users",
"projection": {"name": true}
}
}
```

### Limitations

In order to manage realtime refresh of the view we had to implement the Mongo operators in our [query-parser project](https://github.com/lenra-io/query-parser).
Since it takes time to implement all the operators (and that we also have lot of work on Lenra) we only have implemented a short list of them.
We will implement the rest of them soon, but if you want to help you can look at [the list of operator task](https://github.com/lenra-io/query-parser/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22+operator).

### Managed operators

<!-- Get the groups and description from Mongo doc: https://www.mongodb.com/docs/manual/reference/operator/query/ -->

#### Comparison

| Operator | Description |
|==========|=============|
| [{:target="_blank" rel="noopener"}$eq](https://www.mongodb.com/docs/manual/reference/operator/query/eq/) | Matches values that are equal to a specified value. |
| [{:target="_blank" rel="noopener"}$ne](https://www.mongodb.com/docs/manual/reference/operator/query/ne/) | Matches all values that are not equal to a specified value. |
| [{:target="_blank" rel="noopener"}$gt](https://www.mongodb.com/docs/manual/reference/operator/query/gt/) | Matches all values that are not equal to a specified value. |
|
| [{:target="_blank" rel="noopener"}$gte](https://www.mongodb.com/docs/manual/reference/operator/query/gte/) | Matches values that are greater than or equal to a specified value. |
| [{:target="_blank" rel="noopener"}$lt](https://www.mongodb.com/docs/manual/reference/operator/query/lt/) | Matches values that are less than a specified value. |
| [{:target="_blank" rel="noopener"}$lte](https://www.mongodb.com/docs/manual/reference/operator/query/lte/) | Matches values that are less than or equal to a specified value. |
| [{:target="_blank" rel="noopener"}$in](https://www.mongodb.com/docs/manual/reference/operator/query/in/) | Matches any of the values specified in an array. |
| [{:target="_blank" rel="noopener"}$nin](https://www.mongodb.com/docs/manual/reference/operator/query/nin/) | Matches none of the values specified in an array. |

#### Logical

| Operator | Description |
|==========|=============|
| [{:target="_blank" rel="noopener"}$and](https://www.mongodb.com/docs/manual/reference/operator/query/and/) | Joins query clauses with a logical `AND` returns all documents that match the conditions of both clauses. |
| [{:target="_blank" rel="noopener"}$or](https://www.mongodb.com/docs/manual/reference/operator/query/or/) | Inverts the effect of a query expression and returns documents that do *not* match the query expression. |
| [{:target="_blank" rel="noopener"}$not](https://www.mongodb.com/docs/manual/reference/operator/query/not/) | Joins query clauses with a logical `NOR` returns all documents that fail to match both clauses. |
| [{:target="_blank" rel="noopener"}$nor](https://www.mongodb.com/docs/manual/reference/operator/query/nor/) | Joins query clauses with a logical `OR` returns all documents that match the conditions of either clause. |

#### Element

| Operator | Description |
|==========|=============|
| [{:target="_blank" rel="noopener"}$exists](https://www.mongodb.com/docs/manual/reference/operator/query/exists/) | Matches documents that have the specified field. |

#### Array

| Operator | Description |
|==========|=============|
| [{:target="_blank" rel="noopener"}$all](https://www.mongodb.com/docs/manual/reference/operator/query/all/) | Matches arrays that contain all elements specified in the query. |
4 changes: 0 additions & 4 deletions src/markdown/references/index.md

This file was deleted.

3 changes: 2 additions & 1 deletion src/static/css/.components.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
@import 'components/.list.css';
@import 'components/.code.css';
@import 'components/.colored-block.css';
@import 'components/.table.css';
@import 'components/.properties-table.css';
@import 'components/.tab.css';
@import 'components/.tab-filter.css';
@import 'components/.tab-filter.css';
55 changes: 11 additions & 44 deletions src/static/css/components/.properties-table.css
Original file line number Diff line number Diff line change
@@ -1,48 +1,15 @@
main>table {
--text-opacity: var(--greyscale-90-opacity);
text-align: left;
border-spacing: 0;
width: 100%;
}

main>table tr>td {
border-bottom: 0.0625rem solid rgba(var(--text-color-data), var(--greyscale-40-opacity));
}

main>table tr:nth-of-type(2n+1) {
background-color: rgba(var(--text-color-data), var(--greyscale-0-opacity));
}

main>table th,
main>table td {
padding: 0.5rem;
}

main>table th {
color: rgb(var(--background-color-data));
background-color: rgb(var(--text-color-data));
}

main>table th:first-of-type {
border-top-left-radius: 0.25rem;
}

main>table th:last-of-type {
border-top-right-radius: 0.25rem;
}

main>table tr:not(.required)>td:first-of-type::after {
content: " (optional)";
main>table.properties tr:not(.required)>td:first-of-type::after {
content: " (optionnal)";
font-size: 0.75rem;
font-style: italic;
color:rgba(var(--text-color-data), calc(var(--text-opacity) * var(--greyscale-80-opacity)))
}

main>table tr.deprecated {
main>table.properties tr.deprecated {
--text-opacity: 0.4;
}

main>table tr.deprecated>td:first-of-type::before {
main>table.properties tr.deprecated>td:first-of-type::before {
--text-opacity: 1;
content: "depreciated";
display: inline-block;
Expand All @@ -55,30 +22,30 @@ main>table tr.deprecated>td:first-of-type::before {
margin-right: 0.5rem;
}

main>table ul.values {
main>table.properties ul.values {
display: inline-block;
}

main>table ul.values::before {
main>table.properties ul.values::before {
content: "(";
}

main>table ul.values::after {
main>table.properties ul.values::after {
content: ")";
}

main>table ul.values>li {
main>table.properties ul.values>li {
display: inline-block;
}

main>table ul.values>li.default {
main>table.properties ul.values>li.default {
text-decoration: underline;
}

main>table ul.values>li:not(:first-of-type) {
main>table.properties ul.values>li:not(:first-of-type) {
margin-left: 0.25rem;
}

main>table ul.values>li:not(:last-of-type)::after {
main>table.properties ul.values>li:not(:last-of-type)::after {
content: ",";
}
32 changes: 32 additions & 0 deletions src/static/css/components/.table.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
main>table {
--text-opacity: var(--greyscale-90-opacity);
text-align: left;
border-spacing: 0;
width: 100%;
}

main>table tr>td {
border-bottom: 0.0625rem solid rgba(var(--text-color-data), var(--greyscale-40-opacity));
}

main>table tr:nth-of-type(2n) {
background-color: rgba(var(--text-color-data), var(--greyscale-0-opacity));
}

main>table th,
main>table td {
padding: 0.5rem;
}

main>table th {
color: rgb(var(--background-color-data));
background-color: rgb(var(--text-color-data));
}

main>table th:first-of-type {
border-top-left-radius: 0.25rem;
}

main>table th:last-of-type {
border-top-right-radius: 0.25rem;
}
4 changes: 4 additions & 0 deletions src/static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ main>:not(h2)+h3::before {
margin: 2rem 0;
}

main>:not(h3)+h4 {
margin-top: 1.5rem;
}


@media (min-width: 35rem) {
h1 {
Expand Down
9 changes: 9 additions & 0 deletions src/views/references/index.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
description: The Lenra project references.
icon: book-open
---

extends ../.layout.pug

append content
include ../.children-pages-list.pug

0 comments on commit 31a0028

Please sign in to comment.