supply_chain 4.0.3
supply_chain: ^4.0.3 copied to clipboard
Supply Chain (SC) is a data flow and state management architecture.
Supply Chain - Data Flow & State Management #
Supply Chain (SC) is a data flow and state management framework.
Features #
- ✅ Efficiently manage application state
- ✅ Visualize application data flow & dependencies
- ✅ Smoothly animate state transitions
- ✅ Efficient processing using caching and priorization
- ✅ Prevent unneccessary updates
- ✅ Query nodes and scopes
- ✅ Modify supply chains using plugins
- ✅ Create auto connecting smart nodes
Concept #
A customer nodes receive components from one or more supplier nodes. Each node
creates a product, that is delivered to customer nodes. The application state
is modelled as an supply chain. Nodes again are put into nested scopes. A
supply chain manager (SCM) coordinates the process.

Basics #
// @license
// Copyright (c) ggsuite
//
// Use of this source code is governed by terms that can be
// found in the LICENSE file in the root of this package.
import 'package:gg_golden/gg_golden.dart';
import 'package:supply_chain/supply_chain.dart';
import 'package:test/test.dart';
void main() {
test('Basic Tutorial', () async {
// .............................
// Create a supply chain manager
// Setting isTest to true will apply all changes
// once flush is called
final scm = Scm(isTest: true);
// ...................
// Create a root scope
final rootScope = Scope.root(key: 'root', scm: scm);
// Create a main scope
const scopeBp = ScopeBluePrint(key: 'scope');
final scope = scopeBp.instantiate(scope: rootScope);
// ......................
// Create a supplier node
// First create a blue print
const supplierBp = NodeBluePrint<int>(initialProduct: 1, key: 'supplier');
// Instantiate the blue print
final supplier = supplierBp.instantiate(scope: scope);
// ......................
// Create a customer node
// doubling the product of the supplier
final customerBp = NodeBluePrint<int>(
key: 'customer',
initialProduct: 1,
suppliers: ['supplier'],
produce: (components, previousProduct, node) {
final supplier = components[0] as int;
return supplier * 2;
},
);
final customer = customerBp.instantiate(scope: scope);
// .................
// Apply all changes
scm.flush();
// ......................
// The customer has doubled the product of the supplier
expect(supplier.product, 1);
expect(customer.product, 1 * 2);
// ........................
// Change and apply changes
// Change the supplier value
supplier.product = 5;
// Apply the changes
scm.flush();
// The customer value is also changed
expect(supplier.product, 5);
expect(customer.product, 5 * 2);
// .............
// Search a node just using the key. The first found scope is returned.
final foundCustomer = rootScope.findNode<int>('customer');
expect(foundCustomer, customer);
// Add more context to be more precise
final foundCustomer1 = rootScope.findNode<int>('scope/customer');
expect(foundCustomer1, customer);
// Use the complete path to find a very special node
final foundCustomer2 = rootScope.findNode<int>('root/scope/customer');
expect(foundCustomer2, customer);
// If a node cannot be found, findNode returns null
final foundCustomer3 = rootScope.findNode<int>('xyz');
expect(foundCustomer3, isNull);
// In the same way scopes can be searched
final foundScope = customer.scope.findScope('scope');
expect(foundScope, scope);
// ..........................
// Print node and scope graph
final graph = scope.mermaid();
await writeGolden(fileName: 'basic_01.mmd', data: graph);
// ...............................
// Show all node pathes of a scope
final allNodePathes = rootScope.ls();
await writeGolden(fileName: 'all_node_pathes.json', data: allNodePathes);
expect(allNodePathes, ['scope', 'scope/supplier', 'scope/customer']);
});
}
Debugging #
// @license
// Copyright (c) ggsuite
//
// Use of this source code is governed by terms that can be
// found in the LICENSE file in the root of this package.
import 'package:supply_chain/supply_chain.dart';
import 'package:test/test.dart';
void main() {
test('Debugging Tutorial', () async {
// Create a supply chain
final main = Scope.example();
final scm = main.scm;
// Create a supplier that delivers an int
final supplier = const NodeBluePrint(
key: 'supplier',
initialProduct: 1,
).instantiate(scope: main);
// Create a producer blue print which doubles the value provided by supplier
final producer = NodeBluePrint(
key: 'producer',
initialProduct: 0,
suppliers: ['supplier'],
produce: (components, previousProduct, node) {
final [int val] = components;
return val * 2;
},
);
// Create three child scopes within main
final child0 = const ScopeBluePrint(key: 'child0').instantiate(scope: main);
final child1 = const ScopeBluePrint(key: 'child1').instantiate(scope: main);
final child2 = const ScopeBluePrint(key: 'child2').instantiate(scope: main);
// Within each of the child scope, instantiate a producer
final producer0 = producer.instantiate(scope: child0);
final producer1 = producer.instantiate(scope: child1);
final producer2 = producer.instantiate(scope: child2);
// Apply all changes
scm.flush();
// Now all producers will have the supplier doubled value
expect(supplier.product, 1);
expect(producer0.product, 2);
expect(producer1.product, 2);
expect(producer2.product, 2);
// Place a breakpoint in the produce function at the line "return val * 2;"
// Run this test in debugging mode.
// The breakpoint will stop three times, for producer0, 1 and 2.
// How can you make sure, that the breakpoint only stops for producer1?
// 1. List all node paths of the supply chain.
final paths = main.ls();
expect(paths, [
'child0',
'child0/producer',
'child1',
'child1/producer',
'child2',
'child2/producer',
'supplier',
]);
// 2. Identify the path of producer1, i.e. "child1/producer"
// 3. Edit the breakpoint created before and add the following condition:
// node.path.contains('child1/producer')
// 4. Re-run the tests in debugging node. The debugger now will stop only
// on producer1. Print "node.path" to see if this is true.
});
}
Features and bugs #
Please file feature requests and bugs at GitHub.