Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate DBML from JS object #514

Open
loicknuchel opened this issue Feb 11, 2024 · 4 comments
Open

Generate DBML from JS object #514

loicknuchel opened this issue Feb 11, 2024 · 4 comments

Comments

@loicknuchel
Copy link

Hi,
First, thank you for this project and the libraries <3

I have an object representing my db and I'm looking to generate DBML from it.
Looking at https://dbml.dbdiagram.io/js-module/#class-modelexporter I see I can generate DBML using:

ModelExporter.export(database, 'postgres', false)

My issue is, I don't know how to generate a database value with Database type 😞

In the example it's build using the parser but I don't have DBML as input.

I saw the Database class is exported here: dbml-core/src/model_structure/database.js, and I tried to import it using:

import Database from "@dbml/core/types/model_structure/database";

But it gives me the error: Cannot find module '@dbml/core/types/model_structure/database' from 'src/dbml.ts'

And when I try:

import Database from "@dbml/core/model_structure/database";

I got the error: Cannot find module '@dbml/core/model_structure/database' or its corresponding type declarations.

Do you have any idea how I can configure TypeScript to match modules and type definitions or how I can create a Database class?
I think it would be nice to export the models in model_structure in the index.js, what do you think?
Also, I don't know the difference between a Database and a NormalizedDatabase, is there any explanation somewhere?

Thanks!

@loicknuchel
Copy link
Author

loicknuchel commented Feb 11, 2024

Looking a bit more at the API I found I could use the JSON parser to generate a Database:

const db: Database = (new Parser(undefined)).parse(JSON.stringify({...}), 'json')

It seems the JSON parser takes a RawDatabase type, which is better but comes back to the same issue with the Table model for example (can't build it, at least for now).

So I tried to export to JSON and then import:

const dbmb = `...`
const db: Database = (new Parser(undefined)).parse(dbml, 'dbmlv2')
const json: string = ModelExporter.export(db, 'json', false)
const db2: Database = (new Parser(undefined)).parse(json, 'json')
const generated = ModelExporter.export(db2, 'dbml', false)

But this fails when parsing the JSON, on the 4th line, with Can't find table "null"."posts".
Looks like the JSON output is not a valid JSON input 😞
Seems that the relations don't work well on JSON, they fail both with and without schema.
Is there somewhere a documentation with the expected JSON structure for the Parser?

In the RawDatabase I see there is both schemas (with tables inside) and tables directly at the root. How does it work? Should I duplicate tables in both?

Edit: In investigated more and succedeed to make it work when the relation is not in the same schema as tables (maybe linked to looking for tables before adding them?).
This DBML is working:

Table s1.users {
  id integer [primary key]
  name varchar
}

Table s2.posts {
  id int [pk]
  author integer
}

Ref: s1.users.id < s2.posts.author

It works because the relation is cross schema and then put inside the public one.
If both tables are in the same schema, the relation will be inside as well and it fails.

@NQPhuc
Copy link
Contributor

NQPhuc commented Feb 12, 2024

Hi @loicknuchel

Can you help provide the JSON that failed initially (the one that give error Can't find table "null"."posts"). We'll take a look into this.

@loicknuchel
Copy link
Author

I used the example from your documentation: https://dbml.dbdiagram.io/docs/#take-a-look-at-an-example-below
Here is my full code:

test('https://github.com/holistics/dbml/issues/514',  () => {
    const content = `Table users {
    id integer
    username varchar
    role varchar
    created_at timestamp
}

Table posts {
    id integer [primary key]
    title varchar
    body text [note: 'Content of the post']
    user_id integer
    created_at timestamp
}

Ref: posts.user_id > users.id // many-to-one`
    const dbFromDbml = (new Parser(undefined)).parse(content, 'dbmlv2')
    const json: string = ModelExporter.export(dbFromDbml, 'json', false)
    console.log('json', json)
    const dbFromJson = (new Parser(undefined)).parse(json, 'json')
    console.log('json parsed!')
    const generated = ModelExporter.export(dbFromJson, 'dbml', false)
    console.log('dbml generated', generated)
})

It fails when trying to parse the json: (new Parser(undefined)).parse(json, 'json') with the error:

Can't find table "null"."posts"

Here is the printed JSON:

{
  "schemas": [{
    "name": "public",
    "note": "Default Public Schema",
    "tables": [{
      "name": "users",
      "alias": null,
      "note": null,
      "fields": [
        {"name": "id", "type": {"schemaName": null, "type_name": "integer", "args": null}, "unique": false, "pk": false, "note": null},
        {"name": "username", "type": {"schemaName": null, "type_name": "varchar", "args": null}, "unique": false, "pk": false, "note": null},
        {"name": "role", "type": {"schemaName": null, "type_name": "varchar", "args": null}, "unique": false, "pk": false, "note": null},
        {"name": "created_at", "type": {"schemaName": null, "type_name": "timestamp", "args": null}, "unique": false, "pk": false, "note": null}
      ],
      "indexes": []
    }, {
      "name": "posts",
      "alias": null,
      "note": null,
      "fields": [
        {"name": "id", "type": {"schemaName": null, "type_name": "integer", "args": null}, "unique": false, "pk": true, "not_null": false, "note": null, "increment": false},
        {"name": "title", "type": {"schemaName": null, "type_name": "varchar", "args": null}, "unique": false, "pk": false, "note": null},
        {"name": "body", "type": {"schemaName": null, "type_name": "text", "args": null}, "unique": false, "pk": false, "not_null": false, "note": "Content of the post", "increment": false},
        {"name": "user_id", "type": {"schemaName": null, "type_name": "integer", "args": null}, "unique": false, "pk": false, "note": null},
        {"name": "created_at", "type": {"schemaName": null, "type_name": "timestamp", "args": null}, "unique": false, "pk": false, "note": null}
      ],
      "indexes": []
    }],
    "enums": [],
    "tableGroups": [],
    "refs": [{
      "name": null,
      "endpoints": [
        {"schemaName": null, "tableName": "posts", "fieldNames": ["user_id"], "relation": "*"},
        {"schemaName": null, "tableName": "users", "fieldNames": ["id"], "relation": "1"}
      ]
    }]
  }]
}

If the relation is not in the same schema as tables, it works.
BTW, it also fails with any TableGroup ^^

But I'm only using the JSON parser to build a Database class from my own structure as I couldn't create it directly 😞
Is it an intended usage to generate DBML from JavaScript? (coming with my own data)

@klerick
Copy link

klerick commented May 7, 2024

The problem is here
try to find schema, but it is not exist in database object, because here the object is creating yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants