src/menu/menu-api.js

Summary

Maintainability
A
0 mins
Test Coverage
/*
 * Copyright 2019, Momentum Ideas, Co. All rights reserved.
 *
 * Source and object computer code contained herein is the private intellectual
 * property of Bloombox, a California Limited Liability Corporation. Use of this
 * code in source form requires permission in writing before use or the
 * assembly, distribution, or publishing of derivative works, for commercial
 * purposes or any other purpose, from a duly authorized officer of Momentum
 * Ideas Co.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Bloombox: Menu API
 *
 * @fileoverview Provides interface definitions for the Menu API.
 */

/*global goog */

goog.require('bloombox.base.ServiceInterface');
goog.require('bloombox.menu.ObservableMenu');
goog.require('bloombox.rpc.ScopedOptions');
goog.require('proto.opencannabis.products.menu.section.Section');

goog.provide('bloombox.menu.MenuAPI');

goog.provide('bloombox.menu.RetrieveCallback');
goog.provide('bloombox.menu.RetrieveConfig');
goog.provide('bloombox.menu.RetrieveException');
goog.provide('bloombox.menu.RetrieveOptions');
goog.provide('bloombox.menu.Section');


// -- Definitions / Structures -- //
/**
 * Menu sections.
 *
 * @typedef {proto.opencannabis.products.menu.section.Section}
 */
bloombox.menu.Section;


/**
 * Callback function type declaration for menu data retrieval. Once a full menu
 * has been retrieved by the underlying implementation, a callback can be
 * dispatched with this signature, which provides the resulting catalog to
 * invoking code asynchronously.
 *
 * The callback involves two parameters: the resulting menu, if applicable, and
 * the error code, if applicable. Only one value is provided (so, if a menu is
 * provided, there will be no error, and vice-versa).
 *
 * @public
 * @typedef {function(
 *    ?proto.bloombox.services.menu.v1beta1.GetMenu.Response,
 *    *)}
 */
bloombox.menu.RetrieveCallback;


/**
 * Callback function type declaration for individual product data retrieval.
 * Once data or a terminal error state is made available by the underlying RPC
 * implementation, a callback of this signature can be dispatched with one of
 * either the result value (in this case, product data), or the error value.
 *
 * The callback's parameters are either-or in this sense: if a result is passed,
 * the error is passed as `null`, and vice-versa.
 *
 * @public
 * @typedef {function(
 *    ?proto.bloombox.services.menu.v1beta1.GetProduct.Response,
 *    *)}
 */
bloombox.menu.ProductCallback;


/**
 * Callback function type declaration for operations that produce lists of
 * products marked as featured-for-promotion. This flag indicates the item is
 * eligible to be elevated to more prominent displays, which on the web might be
 * featured product areas in the section master UI.
 *
 * The callback's parameters are either-or in this sense: if a result is passed,
 * the error is passed as `null`, and vice-versa.
 *
 * @public
 * @typedef {function(
 *    ?proto.bloombox.services.menu.v1beta1.GetFeatured.Response,
 *    *)}
 */
bloombox.menu.FeaturedCallback;


/**
 * Specifies a simple record type, which is inflatable into a full settings
 * object which specifies options for retrieving menus.
 *
 * @public
 * @typedef {{
 *    full: boolean,
 *    keysOnly: boolean,
 *    fresh: boolean,
 *    snapshot: ?string,
 *    fingerprint: ?string,
 *    scope: ?string,
 *    section: ?proto.opencannabis.products.menu.section.Section}}
 */
bloombox.menu.RetrieveConfig;


/**
 * Represents an exception that occurred while retrieving menu data for a given
 * partner/location pair.
 *
 * @param {string} message Exception error message.
 * @param {number=} err Error code or status code.
 * @constructor
 * @export
 */
bloombox.menu.RetrieveException = function RetrieveException(message, err) {
  /**
   * Exception message.
   *
   * @public
   * @type {string}
   */
  this['message'] = message;

  /**
   * Exception or status code.
   *
   * @public
   * @type {number}
   */
  this['err'] = err || -1;
};


/**
 * Options object, which specifies various parameters or settings when fetching
 * a full catalog from the Menu API. Each parameter is documented herein. A
 * simple object can be specified with the options herein, with defaults
 * applying where properties are unspecified (defaults are merged in, without
 * overwriting, before options are used).
 *
 * @export
 * @extends {bloombox.rpc.ScopedOptions}
 */
bloombox.menu.RetrieveOptions = (
  class RetrieveOptions extends bloombox.rpc.ScopedOptions {
  /**
   * Build a menu retrieval options object from scratch, with the ability to
   * specify the full set of parameters.
   *
   * @param {boolean} full Fetch a 'full' catalog, including out-of-stock items.
   * @param {boolean} keysOnly Fetch keys only, without full product data.
   * @param {?string} snap Snapshot-based filtering, if applicable.
   * @param {?string} fingerprint Bloom filter-based filtering, if applicable.
   * @param {proto.opencannabis.products.menu.section.Section} section Menu
   *        section to retrieve data for. If unset, all sections are fetched.
   * @param {boolean} fresh Request a forced-fresh response, which causes the
   *        server to skip caches when generating a response.
   * @param {?string} scope Value to override partner scope with, if applicable.
   */
  constructor(full, keysOnly, snap, fingerprint, section, fresh, scope) {
    super(scope);

    /**
     * Whether to fetch the 'full' menu catalog, which includes items that are
     * out of stock, or hidden from the menu for other reasons. This property
     * is generally left unset and defaults to `false`.
     *
     * @public
     * @type {boolean}
     **/
    this.full = full;

    /**
     * Specifies whether to fetch product data in addition to product keys. If
     * set to `true`, the RPC layer will operate in "keys-only" mode, returning
     * only the keys of matching objects on read operations. In this mode, the
     * user is responsible for resolving object data via the `products` method.
     *
     * @public
     * @type {boolean}
     */
    this.keysOnly = keysOnly;

    /**
     * Specifies a snapshot of existing menu data, which the server may compare
     * with a given response payload. If the snapshot values match, the response
     * can be omitted with a '304 Not-Modified'-style response. Defaults to an
     * unset value, which skips snapshot-based filtering.
     *
     * @public
     * @type {?string}
     */
    this.snapshot = snap;

    /**
     * Specifies a fingerprint representing an encoded Bloom filter, encoded in
     * Base64. If a given product key matches the Bloom filter, it is withheld
     * by the server to alleviate congestion on the client. Defaults to an unset
     * value, which skips fingerprint-based filtering.
     *
     * @public
     * @type {?string}
     */
    this.fingerprint = fingerprint;

    /**
     * Filters or restricts the response to a given menu section. If specified,
     * the response will only include a stanza for the specified section.
     * Defaults to an unset value, which fetches all menu sections.
     *
     * @public
     * @type {proto.opencannabis.products.menu.section.Section}
     */
    this.section = section;

    /**
     * Request a forced-fresh response from the server, which re-calculates the
     * underlying menu data without speaking to caches. The server is under no
     * obligation to cooperate with this request. Defaults to `false`, allowing
     * intelligent menu caching.
     *
     * @public
     * @type {boolean}
     */
    this.fresh = fresh;
  }

  /**
   * Prepare a `RetrieveOptions` instance with default values for all config
   * options with specified defaults.
   *
   * @export
   * @returns {bloombox.menu.RetrieveOptions} Default set of options.
   */
  static defaults() {
    return new bloombox.menu.RetrieveOptions(
      false,  /* slim menu mode */
      false,  /* full product data */
      null,  /* no default snapshot */
      null,  /* no default fingerprint */
      proto.opencannabis.products.menu.section.Section.UNSPECIFIED,
      false  /* allow caching */,
      null  /* no scope override */);
  }

  /**
   * Generate a `RetrieveOptions` instance from a simple JavaScript record
   * object, which specifies config settings.
   *
   * @export
   * @param {bloombox.menu.RetrieveConfig} record Config settings to inflate
   *        into a full settings object.
   * @returns {bloombox.menu.RetrieveOptions} Full settings object.
   */
  static fromObject(record) {
    return new bloombox.menu.RetrieveOptions(
      record['full'] || false,
      record['keysOnly'] || false,
      record['snapshot'] || null,
      record['fingerprint'] || null,
      record['section'] || (
        proto.opencannabis.products.menu.section.Section.UNSPECIFIED),
      record['fresh'] || false,
      record['scope'] || null);
  }

  /**
   * Returns a serialized object containing the properties specified in this
   * retrieve options payload.
   *
   * @public
   * @returns {bloombox.menu.RetrieveConfig} Object form of this config.
   */
  toObject() {
    return {
      'full': this.full,
      'keysOnly': this.keysOnly,
      'snapshot': this.snapshot,
      'fingerprint': this.fingerprint,
      'section': this.section,
      'fresh': this.fresh,
      'scope': this.scope};
  }
});


// -- API Surface -- //
/**
 * Defines the surface of the Menu API, which provides product/menu catalog data
 * to invoking code, at the level of a full menu, a menu section, or one or more
 * individual product records.
 *
 * @interface
 * @extends bloombox.base.ServiceInterface
 */
bloombox.menu.MenuAPI = (class MenuAPI {
  // -- API: Menu Retrieval -- //
  /**
   * Retrieve a full menu via Bloombox systems, for a given retail location.
   * Before this method is called, the user should setup their partnership
   * information via the `setup` method, including their partner code, location
   * code, and API key.
   *
   * Once `setup` calls back, indicating the library is ready for use, a full
   * menu catalog can be fetched via this method, according to the options
   * specified in the `options` parameter.
   *
   * @param {?bloombox.menu.RetrieveCallback=} callback Function to dispatch
   *        once data is available for the underlying menu catalog.
   * @param {?bloombox.menu.RetrieveOptions=} config Configuration options for
   *        this menu retrieval operation. See type docs for more info.
   * @return {Promise<proto.bloombox.services.menu.v1beta1.GetMenu.Response>}
   *         Promise attached to the underlying RPC call.
   * @throws {bloombox.rpc.RPCException} If an error occurs preparing to send
   *         the underlying RPC, or during transmission.
   */
  retrieve(callback, config) {}

  // -- API: Product Retrieval -- //
  /**
   * Fetch an individual product record, addressed by its unique product key,
   * which is comprised of the product's type, and the product's key ID (which
   * is an opaque string value provisioned when the product is created).
   *
   * Once either product data or a terminal error state are encountered, the
   * given callback, if provided, is dispatched, and the resulting promise is
   * fulfilled. If a result is available, it is passed in as the first parameter
   * of the callback, otherwise, an error is passed in as the second parameter.
   * In no case are two values passed.
   *
   * @param {proto.opencannabis.base.ProductKey} key Product key to fetch.
   * @param {?bloombox.menu.ProductCallback=} callback Callback to dispatch once
   *        either a result or terminal error state are reached. Optional.
   * @param {?bloombox.menu.RetrieveOptions=} config Configuration options to
   *        apply to this request.
   * @return {Promise<proto.bloombox.services.menu.v1beta1.GetProduct.Response>}
   *         Promise attached to the underlying RPC call.
   * @throws {bloombox.rpc.RPCException} If an error occurs preparing to send
   *         the underlying RPC, or during transmission.
   */
  product(key, callback, config) {}

  // -- API: Featured Products -- //
  /**
   * Retrieve featured products for a given menu section. "Featured" products
   * are items with the "FEATURED" flag present in their product flags, as
   * indicated by staff or external systems via the Bloombox Dashboard.
   *
   * @param {?proto.opencannabis.products.menu.section.Section} section Menu
   *        section to fetch. If left unset, fetches across all sections.
   * @param {?bloombox.menu.FeaturedCallback=} callback Callback to dispatch
   *        once a dataset of products is available, or a terminal error is
   *        reached. Optional.
   * @param {?bloombox.menu.RetrieveOptions=} config Options, or configuration,
   *        to apply in the scope of just this RPC operation. In some cases, a
   *        given API method may not apply or use all options. If left unset, a
   *        sensible set of default settings is generated and used.
   * @return {Promise<proto.bloombox.services.menu.v1beta1.GetFeatured.Response>}
   *         Promise attached to the underlying RPC call.
   * @throws {bloombox.rpc.RPCException} If an error occurs preparing to send
   *         the underlying RPC, or during transmission.
   */
  featured(section, callback, config) {}

  // -- API: Menu Stream -- //
  /**
   * Establish a stream over which we can receive menu change updates. Initially
   * a full menu payload is sent, to sync the client with the server's state,
   * and subsequently, delta updates are relayed as they occur in underlying
   * menu catalog storage.
   *
   * Depending on the settings passed in `config`, the delta payload will
   * reference a changed/added/deleted product by key, or enclose the full
   * product payload. Each time, an updated menu fingerprint is sent back.
   *
   * @param {?proto.opencannabis.products.menu.Menu=} localMenu Local-side
   *        menu to compare with the server. Fingerprint config setting is
   *        required if a local menu is provided, for comparison server-side.
   * @param {?bloombox.menu.RetrieveOptions=} config Options, or configuration,
   *        to apply in the scope of just this RPC operation. In some cases, a
   *        given API method may not apply or use all options. If left unset, a
   *        sensible set of default settings is generated and used.
   * @return {bloombox.menu.ObservableMenu} Observable menu object, which wraps
   *        a promise for the initial menu, and provides methods for subscribing
   *        to menu data changes (which are dispatched after being applied to
   *        any active local DB/caching engine).
   */
  stream(localMenu, config) {}
});