Giter Club home page Giter Club logo

herbs's Introduction

Website

This website is built using Docusaurus 2, a modern static website generator.

Installation

yarn install

Local Development

yarn start

This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server.

Build

yarn build

This command generates static content into the build directory and can be served using any static contents hosting service.

Deployment

GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy

If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the gh-pages branch.

herbs's People

Contributors

dalssoft avatar dependabot[bot] avatar jhomarolo avatar jhomarolo-vortx avatar priscilanfs28 avatar semantic-release-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

herbs's Issues

Log glue - herbs2winston

As we are using practically all herbs projects with winston + kinesis, with code repetition in several places, I imagined that we can create a new herb glue that automatically connects herbs with winston (and still remains compatible for winston connectors ), possible a herbs2winston glue;

I would like to know if you think that there would be a real gain in this implementation and how it could work (breaking as little as possible of what we have today)

Add: Imagine just like the buchu that you can put in .env the audit for it to blow the exception, we can put this glue to log the entire use case execution that happens, I don't know, it was just an idea.

Add: I imagine the lib going more towards, for example, automatically auditing all usecases with a predefined (winston) transport. Or log all usecases that return error automatically.

Code owners feature

as a contributor that spends time in all repositories(issues, pull requests), I would like to receive this thing in my issues and pull requests list on GitHub.

We could create a file for code owners that contain the nickname for all owners(herbs team + repository creator), the GitHub make the magic for notification us.

here we have a tutorial about it

What about mutant tests?

From @italojs

What do you think about mutant test?
Some times ago we I had problems with herbs bugs that the unit test don't filtered it, so I was thinking how to mitigate it to happens again, so I would like to propose to use mutant test in herbs libs

The ideia of mutant tests is to test your test, confirm how much your test coverage all situations

example:

// ./src/legalAge.js
module.exports = isLegalAge = age => {
  return age >= 18
}

// ./__tests__/legalAge.spec.js
test('FAIL: must to check if have legal age', () => {
  expect(isLegalAge(17)).toBe(false)
})

the code above have 100% of test coverage, but what happens if some developer change the function code to

module.exports = isLegalAge = age => {
  return age > 18
}

//or 

module.exports = isLegalAge = age => {
  return false
}

my test will pass and I dont will detec the new bug generated by this change because all my testes(100% coverage) is passing.

To solve it, the mutant test modify your code and try to broken your test, if the modified(bugged) code dont broken your tests, you must to improve your scenarios coverage

To fix the code above, the correct tests must to be:

test('FAIL: must to check if 17 is legal age', () => {
  expect(isLegalAge(17)).toBe(false)
})

test('SUCCESS: must to check if 18 is legal age', () => {
  expect(isLegalAge(18)).toBe(true)
})

test('SUCCESS: must to check if gratter then 18 is legal age', () => {
  expect(isLegalAge(19)).toBe(true)
})

some refs:
[pt]

https://github.com/PauloGoncalvesBH/teste-de-mutacao/tree/at-talks
https://www.youtube.com/watch?v=k8Dq8YZgci8&ab_channel=Locaweb
[en]
https://pedrorijo.com/blog/intro-mutation/
http://atodorov.org/blog/2016/12/27/mutation-testing-vs-coverage/
https://medium.com/appsflyer/tests-coverage-is-dead-long-live-mutation-testing-7fd61020330e

CLI - What would the future of a new CLI look like?

The CLI has become a central tool in the Herbs developer experience.

The current CLI has two problems in my opinion: the first is technical, with low test coverage and with many responsibilities, making it difficult to evolve. The second is a DX (developer experience) which is ok, but not amazing.

But the CLI, like the website, is where developers perceive the quality of the project. In addition, differentiated DX can have a real impact on the developer's daily life and performance.

With that in mind, I'd like to bring the teaser to the contributors: the CLI should be AWESOME!

This means:

  • Beautiful, nice and innovative UI
  • UX focused on the developers' job to be done
  • use the best practices
  • stay close to market trends
  • extract as much of the possibilities that the terminal allows

The developer using this CLI should feel like using something completely new, as well as feeling empowered to extract the maximum value from the tool. In short: developers need to love the CLI!

This could also be an opportunity to think about a new architecture that not only supports the evolution of the tool, but also brings concepts such as plugins, templates, etc.

I've been researching and doing some benchmarks and would like to share some here:

UI

When I look at projects like Ink and Textualize, I see that there are still a lot of UI possibilities in the terminal that we are not exploring.

These tools open up a world of possibility from the point of view of usability and new aesthetics.

The possibilities are many!

https://github.com/Textualize/textual
https://github.com/projectwallace/wallace-cli
https://github.com/maticzav/emma-cli
https://github.com/GitGud-org/GitGud
https://github.com/kraanzu/gupshup
https://github.com/aristocratos/btop
https://github.com/jarun/googler
https://github.com/helix-editor/helix
https://github.com/chubin/wttr.in
https://github.com/rastapasta/mapscii
https://betterprogramming.pub/designing-beautiful-command-line-applications-with-python-72bd2f972ea

Let's not forget about images and animations!
https://www.youtube.com/watch?v=ZjN6L_btw0Q
https://asciiart.club/
https://ascii.co.uk/animated
https://www.deviantart.com/zonedev/art/Logotypes-zoNE-ASCII-3D-Animation-GIF-913308765

DX

The aforementioned tools can greatly improve the usability of the CLI. In addition, we can apply best practices from other established CLIs that are loved by developers.

12 Factor CLI Apps
https://medium.com/@jdxcode/12-factor-cli-apps-dd3c227a0e46

10 design principles for delightful CLIs
https://blog.developer.atlassian.com/10-design-principles-for-delightful-clis/

CLI Style Guide
https://devcenter.heroku.com/articles/cli-style-guide

Command Line UX in 2020
https://puppet.com/blog/command-line-ux-in-2020/

New DXs:

For example, what would it be like to bring herbsshelf to the CLI? Or what would a new experience for Aloe on the CLI look like?

Documentation:

The DX for documentation can be raised to the tenth power, be it the doc from the CLI, from Herbs and of course from the project itself using Herbs.

Architecture

A new CLI is the opportunity to rethink the successes and mistakes of the past.

Responsibilities:

Currently there are responsibilities in the CLI that do not necessarily need to be in the CLI. Ex: Aloe test runner, complex and specialized file generation logics, etc.

What would an architecture that could be more modularized look like?

Tests:

By modularizing the CLI, it would be an opportunity to create more specific and decoupled tests, which could run in milliseconds, without file system dependency, for example.

Conclusion

For now I'm just putting everything in my head in terms of possibilities here. I believe that CLI can have a very high impact on the project and therefore deserves our attention and affection.

As next steps, the brainstorm is open to contributors. I intend to bring some ideas based on the content I brought here as well.

Native queue support

Is your feature request related to a problem? Please describe.
A message queue is a form of asynchronous communication between services used in serverless and microservices architectures. Messages are stored in the queue until processed and deleted. Each message is processed only once, by a single consumer. Message queues can be used to decouple heavy processing, to store work in buffers or batches, and to evenly process peak workloads.

In the modern cloud architecture, applications are decoupled into independent core components that are easier to develop, deploy and maintain. Message queues provide communication and coordination capabilities for these distributed applications. Message queues can greatly simplify coding decoupled applications and increase performance, reliability, and scalability.

image

Generally, messages are small and can be items such as requests, responses, error messages, or just information. To send a message, a component called a producer adds a message to the queue. The message is stored in the queue until another component called the consumer retrieves the message and does something with it.

Describe the solution you'd like
Considering the need to solve 2 main problems, I suggest we natively implement queue support in herbs.

problem 1
The unreliability of transmitting http requests between endpoints. That is, using the queue as a retry submission functionality (in a similar way to polly https://netflix.github.io/pollyjs/#/) .

problem 2
The big bottleneck that can be generated in massive data writing on the producer or consumer part. With the queuing system, both parties can process the request the way computational power processes requests.

Additional context
I imagine a solution implemented in some layer of buchu where I would mark that a usecase is consumer or producer.

    usecase('Usecase X', **options**, {

        // Input/Request type validation
        request: {  },

        // Output/Response type
        response: {  },

        // Authorization Audit
        authorize: async (user) => {}

        // Dependency Injection control
        setup: (ctx) => {}

       })

Where options could be a group of sets about producer: true, consumer:true, retrys: X

Enable intellisense in IDE

Is your feature request related to a problem? Please describe.
One problem is that herbsJs doesn't have type declaration files or JsDocs, which means we don't have intellisense in any of the libs or glues.

Describe the solution you'd like
We can insert .d.ts type declaration files to enable intellisense, at the same time these files become documentation.
This makes it easier to know which methods can be called and what they return.

Describe alternatives you've considered
We can also use DefinitelyTyped, where we can leave the type declarations in a separate repository, example: @types/herbs

Or add a JsDocs header to the functions we want to document.

Additional context
Example:
Screenshot_512
Screenshot_514

TS to JsDoc conversion

Hard to identify the reason of an error

Is your feature request related to a problem? Please describe.

Working on a project, I spent a good couple of hours strugling with a mistake I made.

In a scenario where a property of an entity is an array of another entity, like the image below:

image

And that entity is the response of my usecase:

image

If I push an object that isn't an entity (does not implements BaseEntity), it throws an error at runtime:

image

image

Describe the solution you'd like

It would be nice to have a better error message, telling the developer he is pushing the wrong object to that array.
The example I created is very simple, so it's easier to identify the problem. But when I faced this problem, I was on a larger code base, so it took me a lot of time to understand what was going on.

Describe alternatives you've considered

Herbs is written in JS, so it's hard to handle this kind of errors because it only happens at runtime.

Thinking about the problem, may it would be possible to identify this by using Proxies on entity properties, so we can intercept the changes in the object and print a more specific message on the console.

Additional context

I created a minimal herbs project showing how to emulate the same problem.

New Glue - Herbs2Serverless

Is your feature request related to a problem? Please describe.
As a support platform for microservices and with the growing demand for serverless applications, it would be important for herbs to support the framework. Facilitating the configuration of routes and deploys, mainly on AWS.

Additional context
We already have a draft here: herbsjs/todolist-on-herbs#123
And an issue about it here: herbsjs/herbs-cli#75

Aloe - Capturing domain knowledge using test scenarios

Intro

As I have already discussed with some members of the Herbs community, I believe that in addition to the use case and the entities, the test scenarios are also part of the domain. This domain knowledge is usually translated from user stories, requirements, etc. to use cases as well as test cases. However, currently Herbs does not support to absorb this knowledge of test scenarios in a structured way.

When we think about how test scenarios are part of the domain, just think use cases are HOW, test scenarios are WHAT. Ex:

WHAT: Allow creating a client in the repository only if it is valid

HOW: Create Client (use case)

Or

WHAT: Do not allow changing a product in the repository if it is expired

HOW: Update Product (use case)

This knowledge is a fundamental part of the domain and should be discussed in a fluid way between developers, product managers, testers, etc. This knowledge should also have greater representation in the code in a structured way, as we have today with entities and use cases.

Given that, I propose a solution to capture this knowledge and expose it via metadata to other glues, especially Shelf.

Aloe - More than a test runner

Ex:

const { CreateProduct } = require('./usecases/createProduct')

spec(CreateProduct, {

    'Successful create a simple product': scenario({
        description: 'Try to creat a product with just a valid name.',

        happyPath: true,

        request: {
            name: 'A simple product'
        },

        user: () =>
            ({ canCreateProduct: true }),

        injection: () =>
            ({ ProductRepo: { save: () => { id: 1 } } }),

        'Product must be saved in the repository': check((ret) => {
            assert.ok(ret.product.id)
        }),

        'Product must have a new Id': check((ret) => {
            assert.ok(ret.product.id === 1)
        }),

    }),

    'Do not save a product with invalid name': scenario({
        description: 'Reject products with invalid names in the repository',

        request: {
            name: 'A simple product @'
        },

        user: () =>
            ({ canCreateProduct: true }),

        injection: () => { },

        'Product should not be saved in the repository': check((ret) => {
            assert.ok(ret.product === null)
            assert.ok(ret.isInvalidEntityError)
        }),

    })

})

The first thing to note is that the spec is connected to a use case. This is important because current test runners do not have this kind of explicit link with the objects to be tested. Here we want to capture the scenarios of a specific use case and have that as metadata. I see that the natural expansion would be to have spec not only for use cases but also for entities, but I still haven't thought about how it would be.

Another important point, different from solutions like Cucumber, the code is close to the intent description.

Given / When / Then

When I started thinking about this lib, I was trying to emulate the BDD (behavior driven development) in the spec structure, but it became clear that some things are already given in the current structure of Herbs and would not need to be rewritten.

The Given is basically the input and is formed by the set of:

  • injection for dependency injection.
  • user for use case authorization;
  • use case request and its values;

The When is the execution of the use case, going through the authorization first. But this is transparent and happens automatically.

const uc = usecase(injection)
const hasAccess = await uc.authorize(user)
const response = await uc.run(request)

What we're left with is Then. Here the idea is not only to verify the output of the use case, but also to capture domain knowledge, explaining what is valid and what is not valid for each scenario.

One more example:

spec(ChangeItemPosition, {

    'Successful change item position': scenario({
        description: 'Try to change the item position in a list with a valid position.',

        happyPath: true,

        request: {
            itemId: 1,
            position: 10
        },

        user: () =>
            ({ canChangePosition: true }),

        injection: () =>
        ({
            ListRepo: { find: (id) => ({ id, items: [] }) },
            ItemRepo: { save: () => ({ position: 10 }) }
        }),

        'Item position must have been changed and saved in the repository': check((ret) => {
            assert.ok(ret.item.position === 10)
        }),

        'Item position must be in a valid range': check((ret) => {
            assert.ok(ret.item.position >= 0)
            assert.ok(ret.item.position <= 20)
        })

    }),

    'Do not change item position when a position is invalid': scenario({
        description: 'A position for a item is invalid when it is out of range',

        request: {
            itemId: 1,
            position: 100
        },

        user: () =>
            ({ canChangePosition: true }),

        injection: () =>
        ({
            ListRepo: { find: (id) => ({ id, items: [] }) },
            ItemRepo: { save: () => ({ position: 10 }) }
        }),

        'Item position should not be changed in the repository': check((ret) => {
            assert.ok(ret.isInvalidPositionError)
        }),

    })

})

Shelf

Having a structured form of the scenarios is important for the developer to have clarity of the scenarios that that use case is exercised.
But perhaps just as important is that we can extract this knowledge from the code and bring it to the conversation with stakeholders. For that the Shelf would be the ideal tool.

Using the use cases above as an example, it would be possible to build documentation something like:

  • Create Product

    • Successful registration with a simple product
      • Try to register a product with just a valid name
      • Product must be saved in the repository
      • Product must have a new Id
    • Do not save a product with invalid name
      • Reject products with invalid names in the repository
      • Product should not be saved in the repository
  • Change Item Position

    • Successful change item position
      • Try to change the item position in a list with a valid position.
      • Item position must have been changed and saved in the repository
      • Item position must be in a valid range
    • Do not change item position when a position is invalid
      • A position for a item is invalid when it is out of range
      • Item position should not be changed in the repository

Herbarium

Every spec should be informed to Herbarium as a new kind of object.

module.exports =
    herbarium.specs
        .add(CreateProductSpec)
        .spec

It would be possible to find specs related to a use case or entity using Herbarium.

Examples / Samples

One functionality that needs to be discussed is the multiple inputs to validate the same scenario. I think of something like this:

spec(CreateProduct, {

    'Successful create a simple product': scenario({
        ...

        request: [
            { name: 'A simple product' }, 
            { name: 'ProdName' }, 
            { name: 'A simple product' }
        ],

But it needs to be discussed how each check has context about which request item is being executed. Maybe use ctx instead of just ret (check((ctx)) and use ctx.ret and ctx.req, as in the use case, with ctx.req containing info about request of that execution.

Spy

Advanced scenarios with spys should be allowed because in some cases it is the only way to validate the output. However, the use of mocks should be discouraged, as they validate and couple to the behavior of the use case and not to the output.

We need to dig deeper to see how these scenarios would look.

Conclusion

This is the beginning of a discussion. Conceptual and implementation insights are welcome. It would be great if someone can bring examples so that we can exercise this model as well.

Live metrics - audit trail

Is your feature request related to a problem? Please describe.
Buchu's audit trail functionality (https://github.com/herbsjs/buchu#audit) is something really illuminating. However, the tool needs an interface or integration that makes it possible to see in real time (or close to it) what is going on in the audit trail.

Describe the solution you'd like
I would like to see the audit trail logs somewhere.

herbs2swagger

I think would be great if we could to use the herbs2rest metadata to generate a swagger page and a SDK-client for apis.

Following the @expresso router lib from @roziscoding, it receive a openAPIspecification and the swagger lib generates the documentation aaaaand the SDK-client.
thinking in herbsjs, would be great if I give the route matadata for a usecase or routes so it generates a swagger endpoint into my Express app.

const express = require('express')
const { generateSwagger } = require('@herbsjs/herbs2swagger')

const app = express()
const openAPISpecifications =     {
      "title": "Sample Pet Store App",
      "description": "This is a sample server for a pet store.",
      "termsOfService": "http://example.com/terms/",
      "contact": {
        "name": "API Support",
        "url": "http://www.example.com/support",
        "email": "[email protected]"
      },
      "license": {
        "name": "Apache 2.0",
        "url": "https://www.apache.org/licenses/LICENSE-2.0.html"
      },
      "version": "1.0.1",
    "routes":     {
      "get": {
        "description": "Returns pets based on ID",
        "summary": "Find pets by ID",
        "operationId": "getPetsById",
        "responses": {
          "200": {
            "description": "pet response",
            "content": {
              "*/*": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Pet"
                  }
                }
              }
            }
          },
          "default": {
            "description": "error payload",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorModel"
                }
              }
            }
          }
        }
      },
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "description": "ID of pet to use",
          "required": true,
          "schema": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "style": "simple"
        }
      ]
    }
generateSwagger(app, routes)

we could use it together herbs2rest like

const express = require('express')
const { generateRoutes } = require('@herbsjs/herbs2rest')
const { useSwagger } = require('@herbsjs/herbs2swagger')

const app = express()
const routes = new express.Router()

const metadatas = generateRoutes(controllerList, routes, true)
useSwagger(app,metadatas)

app.use(routes)

How can we pass authentication/authorization data more implicitly?

Today, transferring user data (I'll call it token) between usecases and sometimes even between applications always ends up requiring the creation of explicit variables in use cases, middlewares, manipulation classes, etc.

How can we define a convention or sometimes even some new functionality in Herbs for passing user tokens via context?

Implement Performance Measurement APIs from Node.js in AuditTrail for HerbsJS Framework

In this issue I would like to discuss usage ideas before implement it

Feature affected: Audit trail feature

New Performance Measurement APIs introduced in Node.js These APIs provide insights into the performance of applications.

This issue proposes the implementation of the Performance Measurement APIs in the AuditTrail module of HerbsJS, enabling developers to seamlessly monitor and measure the performance of their applications.

Benefits:

  • Enhanced Performance Analysis: Developers gain access to detailed performance data (CPU utilization, memory usage, event loop latency, function execution times), facilitating identification of bottlenecks and code optimization.

  • Real-time Monitoring: Developers can monitor application performance in real-time, enabling timely detection of degradation or anomalies, particularly beneficial for high-performance and responsive applications.

  • Optimization Opportunities: Performance data empowers developers to pinpoint areas for code optimization, resulting in faster and more efficient applications.

Use Scenarios:

  • Identifying Slow Routes: Performance Measurement APIs help identify routes or endpoints with longer processing times, allowing optimization for improved response times.

  • Optimizing CPU-bound Operations: Measure CPU utilization, identify CPU-intensive operations, and optimize algorithms or consider parallelization strategies for improved performance.

  • Monitoring Memory Usage: Track memory consumption, detect memory leaks, and optimize memory allocation and deallocation for efficient memory management.

  • Analyzing Event Loop Performance: Gain insights into event loop latency and execution times of event loop handlers, optimizing event-driven applications and ensuring timely event processing.

In conclusion, implementing the Performance Measurement APIs from Node.js 20v in the AuditTrail module of HerbsJS will empower developers to analyze and optimize the performance of their applications more effectively.

Audit trail example:
json

{
    configuration:{output: {return: false, user: false}}
    description:'A use case'
    elapsedTime:362700n
    request: null
    steps: [ {
          type: 'step', 
          description: 'A step',
           return: {Ok: ''},
           metrics: {...}
    }, 
    metrics: {...} 
    elapsedTime: 76100n
    }],
    transactionId:'cfd88c2b-1d34-4c81-a07c-ac4ea5420d04'
    type:'use case'
}

Inside metrics we could collect everything we need from https://nodejs.org/api/perf_hooks.html

It could be activated by using an env var: APM=true npm run start
all the data could be provided in herbsshelf like this another issue requires #55

New Glue - Herbs2memcached

I'm suggesting a new herbs glue for storing and fetching entities in an in-memory database

Initially, the idea is to build the glue for Memcached and then replicate it for Redis as well.

Here is the first (and not optimized) alpha version: https://github.com/jhomarolo/herbs2memcached/tree/main/testdb

I thought about replicating the methods (set, setmulti, get, getmulti) and still doing some abstractions like getAll and getbyId.

Additionally, I'm trying to resolve a known timeout issue in the Memcached library (3rd-Eden/memcached#199)

Feedbacks are welcome

Herbs DB Migrations - Change your domain and your database will follow

Problem

Changing a working software is hard. Especially when it is connected to a database.

Keeping the database schema in sync with the domain is timing consuming and error prone.

Solution

Herbs mantra is to make developers focus on the domain and let the tools handle the infrastructure code.

Herbs DB Migrations should help developers to keep your database schema in sync with your domain in a simple and easy way.

Ex: on herbs update it should check if the database schema is in sync with the domain and if not, it should update the database schema.

How it should work

The idea is to have a three phase process:

  1. Generate a Virtual Schema from Domain (VSD)
  2. Generate a Virtual Schema from Migrations (VSM)
  3. Diff VSD and VSM and generate the new migrations

Generate a Virtual Schema from Domain (VSD)

The VSD is a representation of the domain in a database schema. It should be generated from the domain entities.

It should handle the one-to-many and many-to-many relationships. It also should be agnostic to the database type.

Ex:

const User = 
    entity('User', {
        id: id(Number),
        name: field(String),
        lastAccess: field(Date),
        accessCount: field(Number),
        hasAccess: field(Boolean),
        plan: field(Plan),
        groups: field([Group])
    })

Should generate something like this:

const VSD = {
    tables: [
        {
            name: 'users',
            fields: [
                { name: 'id', type: 'number', isId: true },
                { name: 'name', type: 'string' },
                { name: 'lastAccess', type: 'date' },
                { name: 'accessCount', type: 'number' },
                { name: 'hasAccess', type: 'boolean' },
                { name: 'plan_id', type: 'number', fk: { table: 'plans', field: 'id' } },
            ]
        },
        {
            name: 'plans',
            fields: [
                { name: 'id', type: 'number', isId: true },
                ...
            ]
        },
        {
            name: 'groups',
            fields: [
                { name: 'id', type: 'number', isId: true },
                ...
            ]
        },
        {
            name: 'users_groups',
            fields: [
                { name: 'user_id', type: 'number', fk: { table: 'users', field: 'id' } },
                { name: 'group_id', type: 'number', fk: { table: 'groups', field: 'id' } },
            ]
        }
    ]
}

Generate a Virtual Schema from Migrations (VSM)

The VSM is a representation of the database schema from the migration files. In the example above, it comes from the Knex migration files.

Example of Knex migration files:

exports.up = function(knex) {
    return knex.schema
        .createTable('users', function (table) {
            table.increments('id')
            table.string('name')
            table.date('lastAccess')
            table.integer('accessCount')
            table.boolean('hasAccess')
            table.integer('plan_id').references('id').inTable('plans')
        })
        .createTable('plans', function (table) {
            table.increments('id')
            ...
        })
        .createTable('groups', function (table) {
            table.increments('id')
            ...
        })
        .createTable('users_groups', function (table) {
            table.integer('user_id').references('id').inTable('users')
            table.integer('group_id').references('id').inTable('groups')
        })
}

Instead of running the migration file using Knex and change the DB schema, we should implement the same functions / API exposed by Knex and generate the VSM.

Should generate something like this:

const VSM = {
    tables: [
        {
            name: 'users',
            fields: [
                { name: 'id', type: 'number', isId: true },
                { name: 'name', type: 'string' },
                { name: 'lastAccess', type: 'date' },
                { name: 'accessCount', type: 'number' },
                { name: 'hasAccess', type: 'boolean' },
                { name: 'plan_id', type: 'number', fk: { table: 'plans', field: 'id' } },
            ]
        },
        {
            name: 'plans',
            fields: [
                { name: 'id', type: 'number', isId: true },
                ...
            ]
        },
        {
            name: 'groups',
            fields: [
                { name: 'id', type: 'number', isId: true },
                ...
            ]
        },
        {
            name: 'users_groups',
            fields: [
                { name: 'user_id', type: 'number', fk: { table: 'users', field: 'id' } },
                { name: 'group_id', type: 'number', fk: { table: 'groups', field: 'id' } },
            ]
        }
    ]
}

As you can see, the structure is the same as the VSD. It means it is agnostic to the database type. So in the future, we could support other libs like Sequelize or TypeORM.

Diff VSD and VSM and generate the new migrations

Since we have the VSD as the desired state and the VSM as the current state, we can diff them and generate the new migrations.

There are some libs that can help us to do this diff. Ex: https://github.com/flitbit/diff

Once the diff format is generated, we can use the Knex API to generate the migration files.

Conclusion

As far as I know, there is no such tool that does anything similar to what I described above. Been able to change your domain and your database will follow is a game changer.

This is no small task and I bet there are lots of corner cases that would make this task harder than I described above. But I think it is feasible and worth the effort.

Extra Info

There are other issues and efforts related to this topic that I think are worth mentioning:

herbsjs/herbs-cli#145

The reason I suggested this is beacuse it is more generic, works not only with new entities but also with existing ones: if you change a existing entity, it should generate the new migrations.

Create a XLSX spreadsheet glue from the output of an USECASE

Is your feature request related to a problem? Please describe.

Its a suggestion: create a glue for Herbs, to generate and make available spreadsheet files in XLSX format from the output data of the USE CASES processing.

Describe the solution you'd like

Create a glue for Herbs that generates from the output data of USE CASE processing, generates and makes available files in XLSX format ("Office Open XML" spreadsheet).

BENEFITS OF THIS GLUE:

  • Standardize, simplify and abstract the work of this generation of XLSX.
  • Faster development speed.
  • Provide solution for this type of requirement in projects.

Describe alternatives you've considered

The alternative is to generate XLSX spreadsheets manually, usually using one of the many libraries available.

Additional context

Some references about XLSX:

Import ES Modules not working for react

Hello everyone!

I'm using react 16 with herbs and when I go to import the herbs module I get the herbs.csj file.

To Reproduce

Steps to reproduce the behavior:

  1. Using react 16
  2. Import ES Module from import herbs from '@herbsjs/herbs'
  3. Create a new entity

Expected behavior

Import ES Module with herbs functions like entity, field...

Screenshots

image

Blog posts suggestions

Theme suggestions:

Metadata:

  • The power of metadata
  • What is metadata in Herbs
  • How to build a simple glue

Domain-first

  • What is domain-first
  • How is the infrastructure?
  • How to customize the infrastructure?

Domain Driven

  • How Herbs addresses DDD

Clean Architecture

  • How Herbs approaches Clean Architecture

Efficiency

  • How Herbs increase the velocity of development

Tools and libs

  • How to start with Herbs with CLI
  • How to change from rest to graphql in minutes with Herbs
  • How to create a serverless application with Herbs

Object Discovery - How to find use cases, entities, etc in a Herbs project

Problem:

In order to use an use case or entity metadata or to know what the repositories of an application are, we first need to know where to find them.

The current solution are index.js files with reference to all objects. Ex: \srs\domain\usecases\index.js, \srs\domain\entities\index.js and \srs\infra\repositories\index.js

These are the problems we are currently facing:

  • There is no standardization of the structure of these files
  • There is no standard on how to find an object or a set (eg. how to find a particular UC in the list or filter by metadata)
  • It is necessary to update the file for each addition or change of objects (UC, entity or repository)
  • You must always know the path for index.js. This is a problem for glues.
  • CLI update has difficulty keeping index.js files up to date

Also, some of these index.js files carry metadata, such as index.js for use cases (ex: { usecase: require('./user/createUser'), tags: { group: 'Users', type: 'create'} },)

Suggestion:

Ideally there would be an automatic discovery mechanism for the objects, using their own metadata. In addition, it would be possible to add other metadata to the objects.

As an initial solution I imagined a solution where each UC or entity could "register" in a centralized list.

Ex:

// src\domain\entities\user.js

const User =
        entity('User', {
        ...

discoveryservice.entities.add('User', User)

module.exports = User


// src\domain\usecases\user\createUser.js

const useCase = ({ userRepository }) => () =>
  usecase('Create User', {
  ...

discoveryservice.usecases.add('CreateUser', useCase).metadata.add({ tags: { group: 'Users', type: 'create', entity: 'User' } })

module.exports = useCase


// src\infra\data\repositories\userRepository.js

const repository = class UserRepository extends Repository {
    constructor(connection) {
        super({
            entity: User,
            table: "users",
            ids: ["id"],
            knex: connection
        })
    }
}

discoveryservice.repositories.add('UserRepository', repository).metadata.add({ entity: 'User' })

module.exports = repository

With that a Herbs glue could easly find all the objects in a project to perform its goal.

Ex:

discoveryservice.findAll() // list of all objects

discoveryservice.usecases.findAll() // list of all usecases

...

If this discovery mechanism works, it could be argued whether module.exports and require should be used for this objects at all. It would be easier to just call discoveryservice.usecases.find('CreateUser') because now it is not necessary to know the file path.

Regarding metadata, it would also be possible to add metadata for a object after its inital registration.

Ex:

discoveryservice.usecases.find('CreateUser').metadata.add({ rest: { httpVerb: 'get' } })

The suggested interface (method names, etc) for this solution needs refinement. But the general idea is here.

Given this, the nice thing would be to discuss all the premises presented here: if the problem is relevant, if this is the solution, etc. Please comment.

Metadata - Different DX

Brainstorm from @dalssoft:

I've been thinking about the developer experience when dealing with glues. Although it is correct to have a folder and files for each glue (ex: graphQL and REST) from the architecture point of view, it doesn't make it clear the idea of metadata to developers.

Thinking about that I created a different way to specify the metadata:

(1) You would have a folder \infra\meta...
https://user-images.githubusercontent.com/209287/122963117-5e735200-d35c-11eb-996a-4e710618f243.png

(2) Meta for Entities
https://user-images.githubusercontent.com/209287/122962983-413e8380-d35c-11eb-99d1-cad70bd9f797.png

(2) Meta for Usecases
https://user-images.githubusercontent.com/209287/122963058-52879000-d35c-11eb-8315-19328a175fd1.png

Different approachs come to my mind but I think this one is the one I like most. What do you think?

Lack of treatment for circular structures

Describe the bug
The Step class uses JSON.stringify without the callback function to handle circular structures. When passing an object with a circular structure it shows the error "TypeError: Converting circular structure to JSON" and interrupts code execution.

To Reproduce
Steps to reproduce the behavior:

  1. Create a usecase and use the step method on it.
  2. Create an object with a circular structure, for example by creating a spreadsheet with exceljs.
  3. Try passing the created spreadsheet from one step to another inside usecase
  4. See the error
    TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Worksheet'
    | property '_rows' -> object with constructor 'Array'
    | index 0 -> object with constructor 'Row'
    --- property '_worksheet' closes the circle

Expected behavior
The Setp class should perform the packaging of objects with circular structures.

Screenshots
Object with circular reference
image

The output error
image

Additional context
n/a

New labels for issues and pull requests

I'm thinking about the labels on issues and pull requests and would like to hear from you before implementing them.

Suggestions for issues and pull requests:

  • bug
  • documentation
  • duplicate
  • enhancement
  • good first issue
  • help wanted
  • question
  • invalid
  • released (used to mark when a feature request is in production)
  • wontfix (used to mark when a issue wont be fixed that way)
  • blocked
  • severity-major
  • severity-minor
  • severity-nice-to-have
  • working

What do you think? Missed something? Overlabeling?

[CI] - Codecov deprecration of v1

On February 1, 2022, this version will be fully sunset and no longer function

Due to the deprecation of the underlying bash uploader, the Codecov GitHub Action has released v2 which will use the new uploader. You can learn more about our deprecation plan and the new uploader on our blog.

We will be restricting any updates to the v1 Action to security updates and hotfixes.

Migration from v1 to v2

The v2 uploader has a few breaking changes for users

Multiple fields have not been transferred from the bash uploader or have been deprecated. Notably many of the functionalities and gcov_ arguments have been removed. Please check the documentation below for the full list.

More info: https://github.com/codecov/codecov-action

Typescript support And class-based Use Case

Hey guys,
I was wondering, does Herbs.js plan to introduce Typescript support?
Additionally, I'm curious if there are any plans to incorporate class-based development with decorators?

I was thinking about changing this:
image

For that:
Like That:
image

New herb, complement a herb or use some market lib to transforms and conversions?

Hello everyone, seen that we need to construct some conversors, like camelcase conversor, or any other conversor like this Anchorme.js, that converts string to an html with an anchor link, for example.

What is your perception about this theme?

Talking with @jhomarolo he do a suggestion to use the suma to realize the conversions, since some conversions like camelcase for example can be validated and used to another purpose and validations.

But in my opinion, we can create a new herb if we need, for me, the suma is something to improve de precision of our entities, and this conversor can be more generalist and do not have an accuracy too big, with the intention of improve versatility of the system.

And we can continue creating generic codes or using any js libs to do this conversions and transformations...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.