@resin/pinejs
Version:
Pine.js is a sophisticated rules-driven API engine that enables you to define rules in a structured subset of English. Those rules are used in order for Pine.js to generate a database schema and the associated [OData](http://www.odata.org/) API. This make
138 lines (135 loc) • 5.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateODataMetadata = void 0;
const sbvrTypes = require("@resin/sbvr-types");
const { version } = require('../../package.json');
const getResourceName = (resourceName) => resourceName
.split('-')
.map((namePart) => namePart.split(' ').join('_'))
.join('__');
const forEachUniqueTable = (model, callback) => {
const usedTableNames = {};
const result = [];
for (const key in model) {
if (model.hasOwnProperty(key)) {
const table = model[key];
if (typeof table !== 'string' &&
!table.primitive &&
!usedTableNames[table.name]) {
usedTableNames[table.name] = true;
result.push(callback(key, table));
}
}
}
return result;
};
exports.generateODataMetadata = (vocabulary, abstractSqlModel) => {
const complexTypes = {};
const resolveDataType = (fieldType) => {
if (sbvrTypes[fieldType] == null) {
console.error('Could not resolve type', fieldType);
throw new Error('Could not resolve type' + fieldType);
}
const { complexType } = sbvrTypes[fieldType].types.odata;
if (complexType != null) {
complexTypes[fieldType] = complexType;
}
return sbvrTypes[fieldType].types.odata.name;
};
const model = abstractSqlModel.tables;
const associations = [];
forEachUniqueTable(model, (_key, { name: resourceName, fields }) => {
resourceName = getResourceName(resourceName);
for (const { dataType, required, references } of fields) {
if (dataType === 'ForeignKey' && references != null) {
const { resourceName: referencedResource } = references;
associations.push({
name: resourceName + referencedResource,
ends: [
{ resourceName, cardinality: required ? '1' : '0..1' },
{ resourceName: referencedResource, cardinality: '*' },
],
});
}
}
});
return (`
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="2.0">
<Schema Namespace="${vocabulary}"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
` +
forEachUniqueTable(model, (_key, { idField, name: resourceName, fields }) => {
resourceName = getResourceName(resourceName);
return (`
<EntityType Name="${resourceName}">
<Key>
<PropertyRef Name="${idField}" />
</Key>
` +
fields
.filter(({ dataType }) => dataType !== 'ForeignKey')
.map(({ dataType, fieldName, required }) => {
dataType = resolveDataType(dataType);
fieldName = getResourceName(fieldName);
return `<Property Name="${fieldName}" Type="${dataType}" Nullable="${!required}" />`;
})
.join('\n') +
'\n' +
fields
.filter(({ dataType, references }) => dataType === 'ForeignKey' && references != null)
.map(({ fieldName, references }) => {
const { resourceName: referencedResource } = references;
fieldName = getResourceName(fieldName);
return `<NavigationProperty Name="${fieldName}" Relationship="${vocabulary}.${resourceName + referencedResource}" FromRole="${resourceName}" ToRole="${referencedResource}" />`;
})
.join('\n') +
'\n' +
`
</EntityType>`);
}).join('\n\n') +
associations
.map(({ name, ends }) => {
name = getResourceName(name);
return (`<Association Name="${name}">` +
'\n\t' +
ends
.map(({ resourceName, cardinality }) => `<End Role="${resourceName}" Type="${vocabulary}.${resourceName}" Multiplicity="${cardinality}" />`)
.join('\n\t') +
'\n' +
`</Association>`);
})
.join('\n') +
`
<EntityContainer Name="${vocabulary}Service" m:IsDefaultEntityContainer="true">
` +
forEachUniqueTable(model, (_key, { name: resourceName }) => {
resourceName = getResourceName(resourceName);
return `<EntitySet Name="${resourceName}" EntityType="${vocabulary}.${resourceName}" />`;
}).join('\n') +
'\n' +
associations
.map(({ name, ends }) => {
name = getResourceName(name);
return (`<AssociationSet Name="${name}" Association="${vocabulary}.${name}">` +
'\n\t' +
ends
.map(({ resourceName }) => `<End Role="${resourceName}" EntitySet="${vocabulary}.${resourceName}" />`)
.join('\n\t') +
`
</AssociationSet>`);
})
.join('\n') +
`
</EntityContainer>` +
Object.values(complexTypes).join('\n') +
`
</Schema>
</edmx:DataServices>
</edmx:Edmx>`);
};
exports.generateODataMetadata.version = version;
//# sourceMappingURL=odata-metadata-generator.js.map