Git Product home page Git Product logo

cqrs_dx's Introduction

Salesforce CQRS

Command-Query Responsibility Segregation, or CSRQ, provides the ability to separate Query from Commands responsibilities using SOLID Principles. Queries retrieve information from a sink (data store) for the user. A command performs a task, such as update a sink (data store). Commands mutate state, while a Query does not. Technically, a Command does not return a value; however, the example which follows will return status. Each provides a single responsibility (Single Responsibility principle in Solid).

Documentation can be found in the docs directory and CQRS

Caveat-Preemptor

The sample code is just that. There is room for much improvement and robustness. The Unit Tests are enough to provide at least 75% code coverage. If one decides to use the code, it is AS-IS. Finally, the code was prefixed with either cqrs_ or util_ to avoid name collision. The packaging does not use a namespace but was tested and can be packaged as a 2GP unlocked package.

Samples

Command

The simplest thing to do is start with a sample command. This example is found in the source tree (./scripts/apex/exampleCommand.apex). Please note this is a raw form and can be used in a service supporting specific functionality (i.e., Customer Management, Lead Management, etc.). Above, is a collection of commands, creates a Command Dispatcher, passes in the command collection, and the dispatcher finds the appropriate handlers and executes.

// list of commands to run (default behavior is to exits on bad status on any command)
final List<cqrs_ICommand> commands = new List<cqrs_ICommand> {
    new cqrs_AuthenticationCommand('test-uid','test-password'),
    new cqrs_WriteResultCommand('test-id')
};
cqrs_ICommandResult result= new cqrs_CommandDispatcher().dispatch(commands);
System.debug('++++++++++++++++RESULTs++++++++++++++++++++++++++++');
System.debug('Command(s) Result Successful?:' + result.success());
System.debug('Command(s) Result:' + result);

Query

Like the sample command there is a sample query. This example is found in the source tree (./scripts/apex/exampleQuery.apex). Please note, this too is a raw form and can be used in a service supporting specific functionality (i.e., Customer Management, Lead Management, etc.)

// set up / arrange
final List<cqrs_IQuery> queries = new List<cqrs_IQuery> {
   // get account by type ()
   new cqrs_GetAccountByTypeQuery('Enterprise')
};
Integer inx=1;
// act -- dispatcher looks up a handler and executes
final cqrs_IQueryResult result= new cqrs_QueryDispatcher().dispatch(queries);
//
// results
//
System.debug('++++++++++++++++RESULTs++++++++++++++++++++++++++++');
System.debug('Query(s) Result Successful ?:' + result.success());
System.debug('Query(s) Result Count Found :' + result.results().size());
System.debug('Query(s) Result Searched for: "' + ((cqrs_GetAccountByTypeQuery)queries[0]).theUserAccountType() + '"' );
System.debug('++++++++++++++++RECORDs++++++++++++++++++++++++++++');
//
// iterate over the results
for ( cqrs_AccountTypeRecordsDTO dto: (List<cqrs_AccountTypeRecordsDTO>)result.results() ) {
   System.debug('Query Result (' + inx++ + ') Name=' + dto.name);
}

Following the same flow as a command, the above is a collection of (one) query, where we create a Query Dispatcher, pass in the query collection, and the dispatcher finds the appropriate handlers and executes.

Service ( which wraps commands and queries)

The Commands and Queries can be used to form a Service. The service could be Customer Search, Customer Management, Order Management, etc. In this example, we create a Customer Service. The Customer Service just contains a query method; it could contain a sundry of services relevant to Customer Service.

//
// Call a Service directly -- service wraps Command and Query Behavior
//
Integer inx=1;
// The Service Name -- Note, it looks for the service based on name and running environment
// If run from anonymous window ( that is considered "Debug" mode
//
final String serviceName='Customer Service';
// our account type parameter
final String accountType = 'enterprise';
//
// get the service by name -- resolver looks for service by name and runtime environment ( this can be overloaded)
cqrs_CustomerService service = (cqrs_CustomerService) cqrs_ServiceProvider.newInstance().getService( serviceName);
//
// show some service information
System.debug('++++++++++++++++RESULTs++++++++++++++++++++++++++++');
System.debug('Service Name:' + service.name());
System.debug('Service Guid:' + service.guid());
System.debug('++++++++++++++++RECORDs++++++++++++++++++++++++++++');
//
// iterate over the results (DTO)
//
for ( cqrs_AccountTypeRecordsDTO dto: service.findAccountRecordsByAccountType(accountType)) {
  System.debug('Service Result (' + inx++ + ') Name=' + dto.name);
}

The above Customer Service, cqrs_CustomerService, uses a provider to return the service by name. The service holds similar attributes of a Command or Query (name, guid, user-context). Our service method, findAccountRecordsByAccountType(accountType) passes in an account type, value of enterprise, and gets back a collection (Data Transfer Object) of Account Type Records.

How to install

Download the directory. Assumes you have :

  • SFDX installed
  • Dev Hub,
  • Bash or Git-Bash

you can install this offering by running the following script from the source root directory:

./scripts/inint/install.sh -v YOUR-DEV-HUB -l <#-of-days-the-Scratch-Org-Is-Active>

for example:

./scripts/inint/install.sh -v MyDevHub -l 5

Note, some work was done on a Windows (git-bash), script may have carriage-control, line-feed causing issues in a Unix (Mac) environment

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.