Search code examples
mysqlangularjsnode.jsbreeze

Exception using a naming convention w/ Breeze Angular mySql Node Express stack


I'm able to successfully connect and query data from a mySql db via a Breeze/Angular client, following the todo-angular example. I switched out the db table and the GUI and was still ok. The problem starts when I try to use a naming convention. (I don't have control over the db that I have to connect to & I really don't want to use Uppercase_Underscored_Words in my client!)

I'm getting the following exception:

/Users/Sherri/Sites/awdb-web/node_modules/breeze-sequelize/node_modules/breeze-client/breeze.debug.js:1852
    throw new Error("Unable to locate a registered object by the name: " + k
        ^
Error: Unable to locate a registered object by the name:     NamingConvention.underscoreCamelCase
    at Object.__config._fetchObject (/Users/Sherri/Sites/awdb-web/node_modules/breeze-sequelize/node_modules/breeze-client/breeze.debug.js:1852:13)
    at MetadataStore.proto.importMetadata (/Users/Sherri/Sites/awdb-web/node_modules/breeze-sequelize/node_modules/breeze-client/breeze.debug.js:6517:40)
    at new module.exports.MetadataMapper (/Users/Sherri/Sites/awdb-web/node_modules/breeze-sequelize/MetadataMapper.js:19:8)
    at SequelizeManager.importMetadata (/Users/Sherri/Sites/awdb-web/node_modules/breeze-sequelize/SequelizeManager.js:46:24)
    at createSequelizeManager (/Users/Sherri/Sites/awdb-web/server/routes.js:114:8)
    at /Users/Sherri/Sites/awdb-web/server/routes.js:23:27

When I take the "namingConvention": "camelCase" line out of the metadata.json file, the error goes away, but of course, the database property is not able to be correctly converted.

Here is the relevant code I use to set up the Entity Manager: (EDIT: I'm pretty sure my problem is server side and has nothing to do with this code, though)

var namingConvention = new UnderscoreCamelCaseConvention();
namingConvention.setAsDefault();

breeze.core.config.initializeAdapterInstance("uriBuilder", "json");

var serviceName = 'breeze/awdb';
var manager = new breeze.EntityManager(serviceName);


// Take any server property name and make it camelCase for the client to use.
// also, save it so that we can convert from the client back to the server's name
function UnderscoreCamelCaseConvention() {
  var serverNames = {
    netPoints: 'netPoints',
    netPointsSpent: 'netPointsSpent'
  }; // every translated server name

  return new breeze.NamingConvention({
    name: 'underscoreCamelCase',
    clientPropertyNameToServer: clientPropertyNameToServer,
    serverPropertyNameToClient: serverPropertyNameToClient
  });

  function clientPropertyNameToServer(clientPropertyName) {
    return serverNames[clientPropertyName];
  }

  function serverPropertyNameToClient(serverPropertyName) {
    var clientName = _.camelCase(serverPropertyName);
    serverNames[clientName] = serverPropertyName;
    return clientName;
  }
}

And here is a snippet of my metadata.json file:

{
  "metadataVersion": "1.0.5",
  "namingConvention": "underscoreCamelCase",
  "localQueryComparisonOptions": "caseInsensitiveSQL",
  "dataServices": [
    {
      "serviceName": "breeze/awdb/",
      "hasServerMetadata": true,
      "jsonResultsAdapter": "webApi_default",
      "useJsonp": false
    }
  ],
  "structuralTypes": [
    {
      "shortName": "person",
      "namespace": "AWdb.Models",
      "autoGeneratedKeyType": "Identity",
      "defaultResourceName": "people",
      "dataProperties": [
        {
          "name": "Person_ID",
          "dataType": "Int32",
          "isNullable": false,
          "defaultValue": 0,
          "isPartOfKey": true,
          "validators": [
            {
              "name": "required"
            },
            {
              "min": -2147483648,
              "max": 2147483647,
              "name": "int32"
            }
          ]
        },
        {
          "name": "Household_ID",
          "dataType": "Int32",
          "validators": [
            {
              "min": -2147483648,
              "max": 2147483647,
              "name": "int32"
            }
          ]
        },
....
      ]
    }
  ],
  "resourceEntityTypeMap": {"people": "person:#AWdb.Models"}
}

EDIT: Here is code from my routes.js file that gets the metadata.

  var fs = require('fs');
  var breezeSequelize = require('breeze-sequelize');

  var SequelizeManager = breezeSequelize.SequelizeManager;
  var SequelizeQuery = breezeSequelize.SequelizeQuery;
  var SequelizeSaveHandler = breezeSequelize.SequelizeSaveHandler;

  var breeze = breezeSequelize.breeze;
  var EntityQuery = breeze.EntityQuery;

  var dbConfig = {
    host: 'localhost',
    user: 'xx',
    password: 'xx',
    dbName: 'xx'
  };

  var _sequelizeManager = createSequelizeManager();

  // _sequelizeManager.sync(true).then(seed).then(function(){
  //     console.log('db init successful');
  // });

  exports.init = init;

  function init(app) {
    app.get('/breeze/awdb/Metadata', function (req, res, next) {
      try {
        var metadata = readMetadata();
        res.send(metadata);
      } catch(e){
        next(e);
      }
    });

  function createSequelizeManager() {
    var metadata = readMetadata();
    var sm = new SequelizeManager(dbConfig);
    sm.importMetadata(metadata);

    return sm;
  }

  function readMetadata() {
    var filename = "server/AWdbMetadata.json";
    if (!fs.existsSync(filename)) {
      filename = "AWdbMetadata.json";

      if (!fs.existsSync(filename)) {
        throw new Error("Unable to locate file: " + filename);
      }
    }
    var metadata = fs.readFileSync(filename, 'utf8');
    return JSON.parse(metadata);
  }

Any ideas? Should I be able to use a custom naming convention when I'm on a node.js server, using a metadata.json file instead of a .net entity framework?


Solution

  • If I'm looking at this correctly, then I think your issue is the metadata on the server. If I understand correctly, your table and column names follow the Uppercase_Underscored_Word pattern. The Breeze/Sequelize stack on the server currently doesn't have the ability to convert names, so you must use the names of entities and properties exactly as they are in the DB schema. Otherwise, the Breeze to Sequelize translation will fail. You can still use a naming convention on the client to turn the underscored server names into whatever you want them to be on the client.

    So, you need two metadata files. One for the server that is used by the Breeze/Sequelize stack and that uses names exactly as they are in the DB and then a separate metadata file for the client, where you can do the translation.