JavaScript Extension Development API for Oracle Visual Builder Cloud Service - Classic Applications

Source: bop/js/spi/BOP.js

define([], function() {

    'use strict';

    /**
     * SPI object representing a single Business Object Provider (shortly known as BOP).
     *
     * <p>
     * Contains of two main parts:
     * <ul>
     *  <li>
     *      {@link bop/js/spi/entity/EntityProvider EntityProvider} which is an abstract representation of the data structure used by the REST service calls.
     *  </li>
     *  <li>
     *      {@link bop/js/spi/operation/OperationProvider OperationProvider} which is an abstract representation of all REST service calls available on that particular set of {@link entity/js/api/Entity Entities}.
     *  </li>
     * </ul>
     * </p>
     *
     * <p>
     * For example, if you have REST service like this:
     *
     * <ul>
     *  <li>
     *      GET /employeeAll<br/>
     *      --> Which gets all employees. Lets assume only Fistname and Lastname fields are returned.
     *  </li>
     *  <li>
     *      GET /employee/{id}<br/>
     *      --> Which gets single employee defined using the given ID. Lets assume all fields (Firstname, Lastname, Age and Salary) are returned.
     *  </li>
     *  <li>
     *      CREATE /employee<br/>
     *      --> Which creates new employee.
     *  </li>
     *  <li>
     *      DELETE /employee/{id}<br/>
     *      --> Which delete employee using the given ID.
     *  </li>
     *  <li>
     *      UPDATE /employee/{id}<br/>
     *      --> Which updates data for employee with the given ID.
     *  </li>
     * </ul>
     *
     * Your custom {@link bop/js/spi/BOP BOP} need to contains:
     * <ul>
     *  <li>
     *      One {@link bop/js/spi/entity/EntityProvider EntityProvider} with a single {@link entity/js/api/Entity Entity} named "Employee" which will consists of {@link entity/js/api/Property Property} for each field/column these REST calls are
     *      working with. So in the case described above you will have four {@link entity/js/api/Property Properties}: "Firstname", "Lastname", "Age" and "Salary" inside your Employee {@link entity/js/api/Entity Entity}.
     *  </li>
     *  <li>
     *      One {@link bop/js/spi/operation/OperationProvider OperationProvider} with a single {@link operation/js/api/Operation Operation} created for each of these REST calls. Those {@link operation/js/api/Operation Operation}s needs to be described
     *      precisely using {@link bop/js/api/operation/OperationBuilder OperationBuilder}, {@link bop/js/api/operation/OperationInput OperationInput} and {@link bop/js/api/operation/OperationOutput OperationOutput} objects so that Application
     *      Builder allow Business User to use only UI features that are supported by these REST call itself. For example {@link operation/js/api/Operation Operation} that correspond to the GET/employeeAll REST call, need to define and use
     *      different {@link bop/js/api/operation/OperationOutput OperationOutput} because the REST call returns only two fields instead of the full set of them. Based to that information, Application Builder UI addapt automatically.
     *  </li>
     * </ul>
     * </p>
     *
     * <p>
     * This object is pure, fully-customizable BOP with no restrictions. If you don't need any special treatment and rather looking for some simplification where you don't
     * need to take care about parsing dependencies, generating static RT code and other parts of the {@link extensions.dt/js/spi/ExtensionManager Extension} lifecycle, you
     * can alternatively use {@link bop/js/spi/SimpleBOP SimpleBOP} which is build on top the plain {@link bop/js/spi/BOP BOP} and takes care of those stuff for you.
     * </p>
     *
     * @AbcsExtension stable
     * @version 17.1.1
     * @exports bop/js/spi/BOP
     *
     * @constructor
     * @private
     *
     * @see {@link bop/js/api/BOPRegistry BOPRegistry}
     * @see {@link bop/js/spi/SimpleBOP SimpleBOP}
     * @see {@link bop/js/spi/entity/EntityProvider EntityProvider}
     * @see {@link bop/js/spi/operation/OperationProvider OperationProvider}
     *
     * @example
     * <caption>
     *  Example of typical implementation of custom {@link bop/js/spi/BOP BOP}.
     * </caption>
     *
     * define([
     *     '{{package}}/js/CustomEntityProvider',
     *     '{{package}}/js/CustomOperationProvider'
     * ], function (
     *     CustomEntityProvider,
     *     CustomOperationProvider
     * ) {
     *
     *     var CustomBOP = function () {
     *     };
     *
     *     CustomBOP.prototype.getEntityProvider = function () {
     *         return new CustomEntityProvider();
     *     };
     *
     *     CustomBOP.prototype.getOperationProvider = function () {
     *         return new CustomOperationProvider();
     *     };
     *
     *     CustomBOP.prototype.getId = function () {
     *         return 'my.custom.bop';
     *     };
     *
     *     return new CustomBOP();
     * });
     */
    var BOP = function() {
        AbcsLib.checkThis(this);
    };

    /**
     * Returns an instance of {@link bop/js/spi/entity/EntityProvider EntityProvider} associated with this {@link bop/js/spi/BOP BOP}.
     *
     * @AbcsExtension stable
     * @version 17.1.1
     *
     * @returns {bop/js/spi/entity/EntityProvider}
     *
     * @example
     * <caption>
     *  Typical implementation returning an instance of your hand-written {@link bop/js/spi/entity/EntityProvider EntityProvider}.
     * </caption>
     *
     * CustomBOP.prototype.getEntityProvider = function () {
     *     return new CustomEntityProvider();
     * };
     *
     * @example
     * <caption>
     *  Example of typical implementation of custom {@link bop/js/spi/entity/EntityProvider EntityProvider} which is used inside {@link bop/js/spi/BOP BOP}.
     * </caption>
     *
     * define([
     *     'bop/js/api/entity/DataModelFactory',
     *     'entity/js/api/PropertyType'
     * ], function (
     *     DataModelFactory,
     *     PropertyType
     * ) {
     *
     *     var CustomEntityProvider = function () {
     *         var firstname = DataModelFactory.createProperty({
     *             id: 'my.custom.bop.Employee.Firstname',
     *             name: 'Firstname',
     *             type: PropertyType.TEXT
     *         });
     *         var lastname = DataModelFactory.createProperty({
     *             id: 'my.custom.bop.Employee.Lastname',
     *             name: 'Lastname',
     *             type: PropertyType.TEXT
     *         });
     *         var age = DataModelFactory.createProperty({
     *             id: 'my.custom.bop.Employee.Age',
     *             name: 'Age',
     *             type: PropertyType.NUMBER
     *         });
     *         var employee = DataModelFactory.createEntity({
     *             id: 'my.custom.bop.Employee',
     *             singularName: 'Employee',
     *             pluralName: 'Employees',
     *             properties: [firstname, lastname, age]
     *         });
     *
     *         this._entities = [employee];
     *     };
     *
     *     CustomEntityProvider.prototype.getEntities = function() {
     *         return this._entities;
     *     };
     *
     *     return CustomEntityProvider;
     * });
     */
    BOP.prototype.getEntityProvider = function() {
        AbcsLib.throwMustBeOverriddenError();
    };

    /**
     * Returns an instance of {@link bop/js/spi/operation/OperationProvider OperationProvider} associated with this {@link bop/js/spi/BOP BOP}.
     *
     * @AbcsExtension stable
     * @version 17.1.1
     *
     * @returns {bop/js/spi/operation/OperationProvider}
     *
     * @example
     * <caption>
     *  Typical implementation returning an instance of your hand-written {@link bop/js/spi/operation/OperationProvider OperationProvider}.
     * </caption>
     *
     * CustomBOP.prototype.getOperationProvider = function () {
     *     return new CustomOperationProvider();
     * };
     *
     * @example
     * <caption>
     *  Example of typical implementation of custom {@link bop/js/spi/operation/OperationProvider OperationProvider} used inside of the custom {@link bop/js/spi/BOP BOP}.
     * </caption>
     *
     * define([
     *     'bop/js/api/operation/OperationBuilder',
     *     'bop/js/api/operation/OperationInput',
     *     'bop/js/api/operation/OperationOutput',
     *     'operation/js/api/Operation',
     *     'operation/js/api/Operator',
     *     '{{package}}/js/Employee'
     * ], function (
     *     OperationBuilder,
     *     OperationInput,
     *     OperationOutput,
     *     Operation,
     *     Operator,
     *     Employee
     * ) {
     *
     *     var CustomOperationProvider = function () {
     *         this._operations = [];
     *
     *         var employee = Abcs.Entities().findById('my.custom.bop.Employee');
     *         var id = employee.getProperty('my.custom.bop.Employee.ID');
     *         var firstname = employee.getProperty('my.custom.bop.Employee.Firstname');
     *         var lastname = employee.getProperty('my.custom.bop.Employee.Lastname');
     *         var age = employee.getProperty('my.custom.bop.Employee.Age');
     *
     *         var partialOutput = new OperationOutput({
     *             entity: employee
     *         }).property(firstname).
     *             property(lastname);
     *
     *         var idInput = new OperationInput({
     *             entity: employee
     *         }).parameter({
     *             property: id,
     *             required: true
     *         });
     *
     *         var firstnameLastnameInput = new OperationInput({
     *             entity: employee
     *         }).parameter(firstname).
     *             parameter(lastname).
     *             operators([
     *                 Operator.EQUALS,
     *                 Operator.NOT_EQUALS,
     *                 Operator.STARTS_WITH,
     *                 Operator.ENDS_WITH,
     *                 Operator.CONTAINS,
     *                 Operator.NOT_CONTAINS
     *             ]);
     *
     *         var getAllEmployees = new OperationBuilder({
     *             name: 'Find all Employees',
     *             type: Operation.Type.READ_MANY,
     *             performs: function() {
     *                 // Assume there is an Employee object as part of our BOP extension implementation which builds the URL based
     *                 // on the "operationInputData" values, makes the real REST call and returns relevant OperationResult instance
     *                 return Promise.resolve(Employee.getAll());
     *             }
     *         }).description('Longer description of what this Operation does').
     *             returns(partialOutput).
     *             takes(firstnameLastnameInput).
     *             build();
     *
     *         var getEmployeeByID = new OperationBuilder({
     *             name: 'Find Employee by ID',
     *             type: Operation.Type.READ_ONE,
     *             performs: function(operationInputData) {
     *                 // Lets assume there is an Employee object as part of our BOP extension implementation which builds the URL based
     *                 // on the "operationInputData" values, makes the real REST call and returns relevant OperationResult instance
     *                 return Promise.resolve(Employee.findByID(operationInputData));
     *             }
     *         }).specialType(Operation.SpecialType.QUERY_BY_ID).
     *             takes(idInput).
     *             returns(employee).
     *             build();
     *
     *         // Register all relevant operations
     *         this._operations.push(getAllEmployees);
     *         this._operations.push(getEmployeeByID);
     *
     *         // ..include the same for all other REST calls
     *     };
     *
     *     CustomOperationProvider.prototype.getOperations = function() {
     *         return this._operations;
     *     };
     *
     *     return CustomOperationProvider;
     * });
     */
    BOP.prototype.getOperationProvider = function() {
        AbcsLib.throwMustBeOverriddenError();
    };

    /**
     * Gets an unique identifier of this {@link bop/js/spi/BOP BOP}.
     *
     * @AbcsExtension stable
     * @version 17.1.1
     *
     * @returns {String}
     */
    BOP.prototype.getId = function() {
        AbcsLib.throwMustBeOverriddenError();
    };

    return BOP;
});