Skip to content

Commit

Permalink
prep work
Browse files Browse the repository at this point in the history
  • Loading branch information
andyslack committed Sep 1, 2024
1 parent bb3874d commit 2428796
Show file tree
Hide file tree
Showing 23 changed files with 372 additions and 166 deletions.
52 changes: 52 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#
# GitHub Actions workflow.
#
# Perfoms the following actions on a pull request:
# * Checkout the code
# * Install Node.js
# * Prepare the environment
# * Install dependencies
# * Lint the code
# * Run the tests
# * Confirm the build runs
#

name: 'PR Checks: Llana'

on:
pull_request:
branches:
- main
workflow_dispatch:
workflow_call:

jobs:
pr_checks:
name: 'Pull Request Package: Llana'
runs-on: ubuntu-latest
steps:

- name: 'Checkout'
uses: actions/checkout@v4
with:
token: ${{ secrets.GH_CI_CD_RELEASE }}

- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 18.18.2

- name: Prepare
run: echo -e "shamefully-hoist=true\\n@fortawesome:registry=https://npm.fontawesome.com/\n//npm.fontawesome.com/:_authToken=${{ secrets.FONTAWESOME_AUTH_TOKEN }}" > .npmrc

- name: Install dependencies
run: npm install

- name: Lint
run: npm run lint

- name: Build Docker Image
run: npm run start:docker

- name: Test
run: npm run test
4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
# GitHub Actions workflow.
#
# Releases the package to npm when a push into main is detected.
# * Checkout the code
# * Install Node.js
# * Install dependencies
# * Pull the latest changes
# * Bump version number
# * Release to NPM
#
Expand Down
21 changes: 21 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Start Docker",
"type": "shell",
"command": "npm run start:docker",
"windows": {
"command": "npm run start:docker"
},
"group": "none",
"presentation": {
"reveal": "always",
"panel": "new"
},
// "runOptions": {
// "runOn": "folderOpen",
// }
},
]
}
59 changes: 42 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<div align="center">

<a href="https://juicyllama.com/" target="_blank">
<img src="https://juicyllama.com/assets/images/icon.png" width="100" alt="JuicyLlama Logo" />
</a>

Visit [JuicyLlama > Tools > Llana](https://juicyllama.com/tools/llana) for full installation instructions, documentation and community.

## Database Support
## Databases

We currently support the following databases:
We are working to support all major databases, if you would like to contribute to the open source project and help integrate your faviourt database, checkout our [contribiution guidelines](https://juicyllama.com/developers/contributing).

- [ ] [ORACLE](https://expressjs.com/en/guide/database-integration.html#oracle) (Help Wanted)
- [ ] [MYSQL](https://expressjs.com/en/guide/database-integration.html#mysql) (In Progress)
- [x] [MYSQL](https://expressjs.com/en/guide/database-integration.html#mysql) (In Progress)
- [ ] MSSQL (Help Wanted)
- [ ] [POSTGRES](https://expressjs.com/en/guide/database-integration.html#postgresql) (Help Wanted)
- [ ] [MONGODB](https://expressjs.com/en/guide/database-integration.html#mongodb) (Help Wanted)
Expand All @@ -21,14 +21,14 @@ We currently support the following databases:
- [ ] [CASSANDRA](https://expressjs.com/en/guide/database-integration.html#cassandra) (Help Wanted)
- [ ] MARIADB (Help Wanted)

## TODO:
[See the complete breakdown of which databases are integrated with which endpoints](#database-support)

- [ ] Auto detect relation {relation}.{col} in fields
## TODO:

- [ ] Authentication
- [ ] Support hosts?[] to restrict access by url
- [ ] Support identity column (in role/permissions)
- [ ] Get key table relation working `users_api_keys`

- [ ] Auth testing files (hosts, apikey)

- [ ] Role based default permissions, e.g.

```
Expand All @@ -39,7 +39,11 @@ We currently support the following databases:
}]
```

- [ ] integrate JWT token support
- [ ] Auth testing (role based access)

- [ ] integrate JWT token support + /login endpoint

- [ ] Auth testing (user/pass, login)

- [ ] Add Demo Database data to Docker setup file

Expand All @@ -50,15 +54,18 @@ We currently support the following databases:
role: {role_string},
own_records: READ | WRITE | DELETE,
other_records: READ | WRITE | DELETE,
identifier_restrictions: [{
identifer_route: 'user_id', // also supports clients.user_clients.user_id

//replaced by identifer_route if possible?
<!-- identifier_restrictions: [{
table: clients,
column: client_id,
relation: [{
type: FK | JOIN
table: string
column: string,
}]
}]
}] -->
}]
}]

Expand All @@ -70,23 +77,31 @@ We currently support the following databases:

- [ ] add full testing

- [ ] move docs to JL Website
- [ ] Move these docs to juicyllama.com/llana, landing page + docs

- [ ] Add redis support for faster performance (e.g. schema caching)

- [ ] containerize and publish to docker

- [ ] use on first external client project

- [ ] move remaining items to github issues

- [ ] Adding more database integrations (postgres, etc)

- [ ] Build integrations with workflow automation tooling (n8n, zapier, make, etc)
- [ ] Scope Llana cloud option for non-technical users

- [ ] Scope out Setup / Install service (pay to deploy on your database)

#### Marketing

- [ ] Build integrations with workflow automation tooling (n8n, zapier, make, etc) and promote on their platforms where possible

- [ ] Publish on Daily.dev, ProductHunt, etc

- [ ] Scope Llana cloud option for non-technical users
- [ ] Commend on Medium posts like: https://javascript.plainenglish.io/my-tech-stack-for-building-web-apps-today-43398556bb4d introducing the plugin

- [ ] Setup / Install service (pay to deploy on your database)
- [ ] Basic PPC campaign


## Installation
Expand Down Expand Up @@ -281,4 +296,14 @@ Example Response:

Out of the box you can use our docker demo data to play with the system. Here is some helpful information:

Test user, email: `[email protected]` password: `test`
Test user, email: `[email protected]` password: `test` with API key: `Ex@mp1eS$Cu7eAp!K3y`



## Database Support

| Endpoint | ORACLE | MYSQL | MSSQL | POSTGRES | MONGODB | REDIS | SNOWFLAKE | ELASTICSEARCH | SQLITE | CASSANDRA | MARIADB |
|---|-|-|-|-|-|-|-|-|-|-|-|
|GET */:id` |[ ]|[x]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|
|POST */` |[ ]|[x]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|
|POST */list` |[ ]|[x]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|[ ]|
1 change: 0 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
version: "3.9"
services:
llana-mysql:
image: mysql:8.0
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:docker": "docker compose --project-name llana up --build --detach",
"test": "jest"
},
"dependencies": {
Expand Down
62 changes: 44 additions & 18 deletions src/app.controller.get.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Controller, Get, Param, Req, Res } from '@nestjs/common';
import { FindService } from './app.service.find';
import { Logger, context } from './helpers/Logger';
import { Logger } from './helpers/Logger';
import { UrlToTable } from './helpers/Database';
import { Schema } from './helpers/Schema';
import { GetResponseObject, ListResponseObject } from './types/response.types';
Expand All @@ -17,9 +17,7 @@ export class GetController {
private readonly schema: Schema,
private readonly sort: Sort,
private readonly authentication: Authentication
) {
logger.setContext(context)
}
) {}

@Get('')
getDocs(@Res() res): string {
Expand Down Expand Up @@ -50,7 +48,7 @@ export class GetController {

const auth = await this.authentication.auth(req)
if (!auth.valid) {
return res.status(403).send(auth.message)
return res.status(401).send(auth.message)
}

const { limit, offset } = this.pagination.get(req.query)
Expand All @@ -63,19 +61,24 @@ export class GetController {
}
}

const relations = combineRelations(req.query.relations, validateFields?.relations)

const validateWhere = this.schema.validateWhereParams(schema, req.query)
if (!validateWhere.valid) {
return res.status(400).send(validateWhere.message)
}

let validateRelations
if (req.query.relations) {
validateRelations = await this.schema.validateRelations(schema, req.query.relations)
if (relations) {
validateRelations = await this.schema.validateRelations(schema, relations)

if (!validateRelations.valid) {
return res.status(400).send(validateRelations.message)
}

for (const relation of validateRelations.params) {
schema = validateRelations.schema

for (const relation of relations) {
const relation_schema = await this.schema.getSchema(relation)
if (!relation_schema) {
return res.status(400).send(`Relation ${relation} not found`)
Expand Down Expand Up @@ -133,7 +136,7 @@ export class GetController {
return res.status(200).send(await this.service.findMany({
schema,
fields: req.query.fields,
relations: req.query.relations,
relations,
where: validateWhere.where,
limit,
offset,
Expand All @@ -156,7 +159,7 @@ export class GetController {

const auth = await this.authentication.auth(req)
if (!auth.valid) {
return res.status(403).send(auth.message)
return res.status(401).send(auth.message)
}

//validate :id field
Expand All @@ -179,19 +182,23 @@ export class GetController {
}
}

const relations = combineRelations(req.query.relations, validateFields?.relations)

let validateRelations
if (req.query.relations) {
validateRelations = await this.schema.validateRelations(schema, req.query.relations)
if (relations) {
validateRelations = await this.schema.validateRelations(schema, relations)
if (!validateRelations.valid) {
return res.status(400).send(validateRelations.message)
}

schema = validateRelations.schema
}

return res.status(200).send(await this.service.findById({
schema,
id: req.params.id,
fields: req.query.fields,
relations: req.query.relations
relations
}))

}
Expand All @@ -211,7 +218,7 @@ export class GetController {

const auth = await this.authentication.auth(req)
if (!auth.valid) {
return res.status(403).send(auth.message)
return res.status(401).send(auth.message)
}

let validateFields
Expand All @@ -222,19 +229,23 @@ export class GetController {
}
}

const relations = combineRelations(req.query.relations, validateFields?.relations)

const validateWhere = this.schema.validateWhereParams(schema, req.query)
if (!validateWhere.valid) {
return res.status(400).send(validateWhere.message)
}

let validateRelations
if (req.query.relations) {
validateRelations = await this.schema.validateRelations(schema, req.query.relations)
if (relations) {
validateRelations = await this.schema.validateRelations(schema, relations)
if (!validateRelations.valid) {
return res.status(400).send(validateRelations.message)
}

for (const relation of validateRelations.params) {
schema = validateRelations.schema

for (const relation of relations) {
const relation_schema = await this.schema.getSchema(relation)
if (!relation_schema) {
return res.status(400).send(`Relation ${relation} not found`)
Expand Down Expand Up @@ -276,10 +287,25 @@ export class GetController {
return res.status(200).send(await this.service.findOne({
schema,
fields: req.query.fields,
relations: req.query.relations,
relations,
where: validateWhere.where
}))

}

}

function combineRelations(query: string, validatedFieldRelations: string[]): string[] {
const relations = query ? query.split(',') : []

if (validatedFieldRelations) {
validatedFieldRelations.forEach(relation => {
if (!relations.includes(relation)) {
relations.push(relation)
}
})
}

return relations

}
Loading

0 comments on commit 2428796

Please sign in to comment.