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;
});