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

[@loopback/sequelize] Entity with JSON data is not parsed to an object when using MySQL / MariaDB #9598

Closed
KalleV opened this issue Jun 1, 2023 · 3 comments · Fixed by #10285

Comments

@KalleV
Copy link
Contributor

KalleV commented Jun 1, 2023

Describe the bug

While testing “@loopback/sequelize” I encountered some errors retrieving entity properties stored as JSON using MySQL as the data source.

Saving JSON object data is working without modification but repositories are returning a stringified object.

As a workaround, I tried adding a getter (https://sequelize.org/docs/v6/core-concepts/getters-setters-virtuals/#getters) to all entity JSON properties that checks for a string and then calls JSON.parse.

Logs

No response

Additional information

The root cause for this seems to be on the Sequelize side based on this issue:
sequelize/sequelize#10946

Sequelize v7 added more support to the MariaDB “dialect” to accommodate some of the issues:
https://github.com/sequelize/sequelize/blob/a9fd5010809366eb50fa9d6fc4bf0612a9d1d751/src/dialects/mariadb/query.js#L179

References:

Reproduction

N/A

@KalleV KalleV added the bug label Jun 1, 2023
@shubhamp-sf
Copy link
Contributor

shubhamp-sf commented Jun 6, 2023

Thanks for reporting this @KalleV, It seems sequelize relies on the actual db column type for the parsing. As I tried it with postgres and as long as the datatype in db is set to character varying the json in raw format is what I get otherwise it's is stringified.
It's not respecting the JSON defined in the model definition.

As a solution for data type disparity puting this parsing logic into this extension to match the behaviour of different loopback-connectors sounds cumbersome but will what best I can do to match it.

@shubhamp-sf
Copy link
Contributor

Also when you say:

I tried adding a getter to all entity JSON properties...

Where did you add that in your LoopBack app?

@KalleV
Copy link
Contributor Author

KalleV commented Jun 7, 2023

I defined the custom getter using the "sequelizeOptions" hooks. Something like this:

sequelizeOptions: {
  hooks: {
    beforeDefine: (attributes, options) => {
      // ...

      Object.keys(attributes).forEach((key) => {
        const attribute = attributes[key];
        if (
          typeof attribute !== 'string' &&
          'type' in attribute &&
          attribute.type === DataTypes.JSON
        ) {
          Object.assign(attribute, {
            get() {
              const value = this.getDataValue(key);

              if (typeof value === 'string') {
                try {
                  return JSON.parse(value);
                } catch (error) {
                  /* log error */
                  return null;
                }
              }
              return value;
            }
          });
        }
      });
    }
  },
  // ...

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

Successfully merging a pull request may close this issue.

3 participants