Skip to content

Commit

Permalink
Merge 578bef7 into 2976ce2
Browse files Browse the repository at this point in the history
  • Loading branch information
bajtos committed Nov 19, 2019
2 parents 2976ce2 + 578bef7 commit 70fbbd9
Show file tree
Hide file tree
Showing 10 changed files with 452 additions and 32 deletions.
70 changes: 70 additions & 0 deletions packages/cli/generators/discover/import-discovered-model.js
@@ -0,0 +1,70 @@
// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: @loopback/cli
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

'use strict';

const {pascalCase, stringifyModelSettings} = require('../../lib/utils');
const {sanitizeProperty} = require('../../lib/model-discoverer');
const {
createPropertyTemplateData,
findBuiltinType,
} = require('../model/property-definition');

module.exports = {
importDiscoveredModel,
};

/**
* Convert model definition created by loopback-datasource-juggler discovery
* into template data used by LB4 model generator.
*
* @param {object} discoveredDefinition Model definition as discovered from DB
* @returns {object} Template data for model source file template
*/
function importDiscoveredModel(discoveredDefinition) {
const modelName = discoveredDefinition.name;
const templateData = {
name: modelName,
className: pascalCase(modelName),
modelBaseClass: 'Entity',
isModelBaseBuiltin: true,
settings: importModelSettings(discoveredDefinition.settings),
properties: importModelProperties(discoveredDefinition.properties),
allowAdditionalProperties: true,
};

templateData.modelSettings = stringifyModelSettings(templateData.settings);

return templateData;
}

function importModelSettings(discoveredSettings = {}) {
// Currently a no-op, we may want to apply transformation in the future
// See migrateModelSettings in ../import-lb3-models/migrate-model.js
return {
// Shallow-clone to avoid accidental modification of input data
...discoveredSettings,
};
}

function importModelProperties(discoveredProps) {
const templateData = {};
for (const prop in discoveredProps) {
templateData[prop] = importPropertyDefinition(discoveredProps[prop]);
}
return templateData;
}

function importPropertyDefinition(discoveredDefinition) {
const propDef = {
...discoveredDefinition,
};

const builtinType = findBuiltinType(propDef.type);
if (builtinType) propDef.type = builtinType;

sanitizeProperty(propDef);
return createPropertyTemplateData(propDef);
}
22 changes: 9 additions & 13 deletions packages/cli/generators/discover/index.js
Expand Up @@ -4,6 +4,8 @@ const modelMaker = require('../../lib/model-discoverer');
const debug = require('../../lib/debug')('discover-generator');
const utils = require('../../lib/utils');
const modelDiscoverer = require('../../lib/model-discoverer');
const {importDiscoveredModel} = require('./import-discovered-model');

const rootDir = 'src';

module.exports = class DiscoveryGenerator extends ArtifactGenerator {
Expand Down Expand Up @@ -216,19 +218,13 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
// eslint-disable-next-line @typescript-eslint/prefer-for-of
for (let i = 0; i < this.artifactInfo.modelDefinitions.length; i++) {
const modelDefinition = this.artifactInfo.modelDefinitions[i];
Object.entries(modelDefinition.properties).forEach(([k, v]) =>
modelDiscoverer.sanitizeProperty(v),
);
modelDefinition.isModelBaseBuiltin = true;
modelDefinition.modelBaseClass = 'Entity';
modelDefinition.className = utils.pascalCase(modelDefinition.name);
// These last two are so that the template doesn't error out if they aren't there
modelDefinition.allowAdditionalProperties = true;
// modelDefinition.modelSettings = modelDefinition.settings || {};
modelDefinition.modelSettings = utils.stringifyModelSettings(
modelDefinition.settings || {},
const templateData = importDiscoveredModel(modelDefinition);

debug(
'Generating model %s from template data',
modelDefinition.name,
templateData,
);
debug(`Generating: ${modelDefinition.name}`);

const fullPath = path.resolve(
this.options.outDir || this.artifactInfo.outDir,
Expand All @@ -239,7 +235,7 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
this.copyTemplatedFiles(
modelDiscoverer.MODEL_TEMPLATE_PATH,
fullPath,
modelDefinition,
templateData,
);

this.artifactInfo.indexesToBeUpdated.push({
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/generators/import-lb3-models/migrate-model.js
Expand Up @@ -14,7 +14,7 @@ const {
const {sanitizeProperty} = require('../../lib/model-discoverer');
const {
createPropertyTemplateData,
BUILTIN_TYPES,
findBuiltinType,
} = require('../model/property-definition');
const chalk = require('chalk');

Expand Down Expand Up @@ -109,7 +109,7 @@ function migratePropertyType(typeDef) {
typeDef = typeDef.name.toString();
}

const builtin = BUILTIN_TYPES.find(t => t === typeDef.toLowerCase());
const builtin = findBuiltinType(typeDef);
if (builtin) typeDef = builtin;

// TODO: handle anonymous object types (nested properties)
Expand Down
14 changes: 10 additions & 4 deletions packages/cli/generators/model/index.js
Expand Up @@ -14,7 +14,10 @@ const utils = require('../../lib/utils');
const chalk = require('chalk');
const path = require('path');

const {createPropertyTemplateData} = require('./property-definition');
const {
createPropertyTemplateData,
findBuiltinType,
} = require('./property-definition');

const PROMPT_BASE_MODEL_CLASS = 'Please select the model base class';
const ERROR_NO_MODELS_FOUND = 'Model was not found in';
Expand Down Expand Up @@ -161,6 +164,7 @@ module.exports = class ModelGenerator extends ArtifactGenerator {
views: true,
},
);
await this.artifactInfo.dataSource.disconnect();

if (!schemaDef) {
this.exit(
Expand Down Expand Up @@ -465,9 +469,11 @@ module.exports = class ModelGenerator extends ArtifactGenerator {

debug('scaffolding');

Object.entries(this.artifactInfo.properties).forEach(([k, v]) =>
modelDiscoverer.sanitizeProperty(v),
);
Object.entries(this.artifactInfo.properties).forEach(([k, v]) => {
const builtinType = findBuiltinType(v.type);
if (builtinType) v.type = builtinType;
modelDiscoverer.sanitizeProperty(v);
});

// Data for templates
this.artifactInfo.outFile = utils.getModelFileName(this.artifactInfo.name);
Expand Down
12 changes: 12 additions & 0 deletions packages/cli/generators/model/property-definition.js
Expand Up @@ -11,6 +11,7 @@ const BUILTIN_TYPES = [...TS_TYPES, ...NON_TS_TYPES];

module.exports = {
createPropertyTemplateData,
findBuiltinType,
BUILTIN_TYPES,
};

Expand Down Expand Up @@ -71,3 +72,14 @@ function createPropertyTemplateData(val) {

return val;
}

/**
* Check if the type is a built-in type, return the canonical type name in
* such case (e.g. convert 'String' to 'string').
*
* @param {string} typeName Property type name, e.g. 'String' or 'Address'
* @returns {string|undefined} Built-in type name (e.g. 'string') or undefined
*/
function findBuiltinType(typeName) {
return BUILTIN_TYPES.find(t => t === typeName.toLowerCase());
}
@@ -0,0 +1,110 @@
// IMPORTANT
// This snapshot file is auto-generated, but designed for humans.
// It should be checked into source control and tracked carefully.
// Re-generate by setting UPDATE_SNAPSHOTS=1 and running tests.
// Make sure to inspect the changes in the snapshots below.
// Do not ignore changes!

'use strict';

exports[`lb4 discover integration model discovery generates all models without prompts using --all --dataSource 1`] = `
import {Entity, model, property} from '@loopback/repository';
@model()
export class Schema extends Entity {
// Define well-known properties here
// Indexer property to allow additional data
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[prop: string]: any;
constructor(data?: Partial<Schema>) {
super(data);
}
}
export interface SchemaRelations {
// describe navigational properties here
}
export type SchemaWithRelations = Schema & SchemaRelations;
`;


exports[`lb4 discover integration model discovery generates all models without prompts using --all --dataSource 2`] = `
import {Entity, model, property} from '@loopback/repository';
@model()
export class View extends Entity {
// Define well-known properties here
// Indexer property to allow additional data
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[prop: string]: any;
constructor(data?: Partial<View>) {
super(data);
}
}
export interface ViewRelations {
// describe navigational properties here
}
export type ViewWithRelations = View & ViewRelations;
`;


exports[`lb4 discover integration model discovery uses a different --outDir if provided 1`] = `
import {Entity, model, property} from '@loopback/repository';
@model()
export class Test extends Entity {
@property({
type: 'date',
})
dateTest?: string;
@property({
type: 'number',
})
numberTest?: number;
@property({
type: 'string',
})
stringTest?: string;
@property({
type: 'boolean',
})
booleanText?: boolean;
@property({
type: 'number',
required: true,
scale: 0,
id: 1,
})
id: number;
// Define well-known properties here
// Indexer property to allow additional data
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[prop: string]: any;
constructor(data?: Partial<Test>) {
super(data);
}
}
export interface TestRelations {
// describe navigational properties here
}
export type TestWithRelations = Test & TestRelations;
`;
@@ -0,0 +1,55 @@
// IMPORTANT
// This snapshot file is auto-generated, but designed for humans.
// It should be checked into source control and tracked carefully.
// Re-generate by setting UPDATE_SNAPSHOTS=1 and running tests.
// Make sure to inspect the changes in the snapshots below.
// Do not ignore changes!

'use strict';

exports[`lb4 model integration discovers a model from a datasource 1`] = `
import {Entity, model, property} from '@loopback/repository';
@model()
export class Test extends Entity {
@property({
type: 'date',
})
dateTest?: string;
@property({
type: 'number',
})
numberTest?: number;
@property({
type: 'string',
})
stringTest?: string;
@property({
type: 'boolean',
})
booleanText?: boolean;
@property({
type: 'number',
required: true,
scale: 0,
id: 1,
})
id: number;
constructor(data?: Partial<Test>) {
super(data);
}
}
export interface TestRelations {
// describe navigational properties here
}
export type TestWithRelations = Test & TestRelations;
`;

0 comments on commit 70fbbd9

Please sign in to comment.