Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make replicated data types generic #327

Merged
merged 1 commit into from
May 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ type RemoveShoppingCart = proto.com.example.shoppingcart.RemoveShoppingCart;

type Context = replicatedentity.ReplicatedEntityCommandContext;

type Product = proto.com.example.shoppingcart.domain.IProduct & protobuf.Message;

// end::types[]
// tag::class[]
const entity = new replicatedentity.ReplicatedEntity( // <1>
Expand All @@ -45,7 +47,7 @@ const entity = new replicatedentity.ReplicatedEntity( // <1>
// end::class[]

// tag::defaultValue[]
entity.defaultValue = () => new replicatedentity.ReplicatedCounterMap(); // <1>
entity.defaultValue = () => new replicatedentity.ReplicatedCounterMap<Product>(); // <1>
// end::defaultValue[]

// tag::types[]
Expand All @@ -69,7 +71,7 @@ function addItem(addLineItem: AddLineItem, context: Context) {
return replies.failure(`Quantity for item ${addLineItem.productId} must be greater than zero`); // <1>
}

const cart = context.state as replicatedentity.ReplicatedCounterMap; // <2>
const cart = context.state as replicatedentity.ReplicatedCounterMap<Product>; // <2>

const product = Product.create({
id: addLineItem.productId, // <3>
Expand All @@ -83,7 +85,7 @@ function addItem(addLineItem: AddLineItem, context: Context) {
// end::addItem[]

function removeItem(removeLineItem: RemoveLineItem, context: Context) {
const cart = context.state as replicatedentity.ReplicatedCounterMap;
const cart = context.state as replicatedentity.ReplicatedCounterMap<Product>;

const product = Product.create({
id: removeLineItem.productId,
Expand All @@ -101,7 +103,7 @@ function removeItem(removeLineItem: RemoveLineItem, context: Context) {

// tag::getCart[]
function getCart(getShoppingCart: GetShoppingCart, context: Context) {
const cart = context.state as replicatedentity.ReplicatedCounterMap; // <1>
const cart = context.state as replicatedentity.ReplicatedCounterMap<Product>; // <1>

const items = Array.from(cart.keys()) // <2>
.map(product => ({
Expand Down
18 changes: 18 additions & 0 deletions sdk/bin/compile-protobuf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,24 @@ $PROTOC \
rm -rf test/proto
cp -r proto test/

pbjs -t static-module -w commonjs \
-o ./test/proto/test-protobuf-bundle.js \
-p ./proto -p ./protoc/include \
./proto/kalix/*.proto \
./proto/kalix/protocol/*.proto \
./proto/kalix/component/*.proto \
./proto/kalix/component/*/*.proto \
./test/*.proto

pbjs -t static-module \
-p ./proto -p ./protoc/include \
./proto/kalix/*.proto \
./proto/kalix/protocol/*.proto \
./proto/kalix/component/*.proto \
./proto/kalix/component/*/*.proto \
./test/*.proto \
| pbts -o ./test/proto/test-protobuf-bundle.d.ts -

OUT_DIR="${PWD}/test/proto"
TS_OUT_DIR="${PWD}/test/proto"

Expand Down
2 changes: 1 addition & 1 deletion sdk/src/event-sourced-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export namespace EventSourcedEntity {
* @param state - The entity state
* @returns The new entity state
*/
export type BehaviorCallback = (state: Serializable) => Behavior;
export type BehaviorCallback = (state: any) => Behavior;

/**
* Initial state callback.
Expand Down
36 changes: 20 additions & 16 deletions sdk/src/replicated-data/counter-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,23 @@ namespace protocol {
proto.kalix.component.replicatedentity.IReplicatedCounterMapEntryDelta;
}

interface Entry {
key: Serializable;
interface Entry<Key extends Serializable> {
key: Key;
counter: ReplicatedCounter;
}

/**
* A replicated map of counters.
*
* @typeParam Key - Type of keys for the Replicated Counter Map
*
* @public
*/
export class ReplicatedCounterMap implements ReplicatedData {
private counters = new Map<Comparable, Entry>();
private removed = new Map<Comparable, Serializable>();
export class ReplicatedCounterMap<Key extends Serializable = Serializable>
implements ReplicatedData
{
private counters = new Map<Comparable, Entry<Key>>();
private removed = new Map<Comparable, Key>();
private cleared = false;

/**
Expand All @@ -55,7 +59,7 @@ export class ReplicatedCounterMap implements ReplicatedData {
* @param key - The key to get
* @returns The counter value, or undefined if no value is defined at that key
*/
get = (key: Serializable): number | undefined => {
get = (key: Key): number | undefined => {
const entry = this.counters.get(AnySupport.toComparable(key));
return entry !== undefined ? entry.counter.value : undefined;
};
Expand All @@ -66,7 +70,7 @@ export class ReplicatedCounterMap implements ReplicatedData {
* @param key - The key to get
* @returns The counter value as a long, or undefined if no value is defined at that key
*/
getLong = (key: Serializable): Long.Long | undefined => {
getLong = (key: Key): Long.Long | undefined => {
const entry = this.counters.get(AnySupport.toComparable(key));
return entry !== undefined ? entry.counter.longValue : undefined;
};
Expand All @@ -79,9 +83,9 @@ export class ReplicatedCounterMap implements ReplicatedData {
* @returns This counter map
*/
increment = (
key: Serializable,
key: Key,
increment: Long.Long | number,
): ReplicatedCounterMap => {
): ReplicatedCounterMap<Key> => {
this.getOrCreateCounter(key).increment(increment);
return this;
};
Expand All @@ -94,9 +98,9 @@ export class ReplicatedCounterMap implements ReplicatedData {
* @returns This counter map
*/
decrement = (
key: Serializable,
key: Key,
decrement: Long.Long | number,
): ReplicatedCounterMap => {
): ReplicatedCounterMap<Key> => {
this.getOrCreateCounter(key).decrement(decrement);
return this;
};
Expand All @@ -107,7 +111,7 @@ export class ReplicatedCounterMap implements ReplicatedData {
* @param key - The key to check
* @returns True if this counter map contains a value for the given key
*/
has = (key: Serializable): boolean => {
has = (key: Key): boolean => {
return this.counters.has(AnySupport.toComparable(key));
};

Expand All @@ -121,7 +125,7 @@ export class ReplicatedCounterMap implements ReplicatedData {
/**
* Return an (iterable) iterator of the keys of this counter map.
*/
keys = (): IterableIterator<Serializable> => {
keys = (): IterableIterator<Key> => {
return iterators.map(this.counters.values(), (entry) => entry.key);
};

Expand All @@ -132,7 +136,7 @@ export class ReplicatedCounterMap implements ReplicatedData {
* @returns This counter map
*/

delete = (key: Serializable): ReplicatedCounterMap => {
delete = (key: Key): ReplicatedCounterMap<Key> => {
const comparableKey = AnySupport.toComparable(key);
if (this.counters.has(comparableKey)) {
this.counters.delete(comparableKey);
Expand All @@ -146,7 +150,7 @@ export class ReplicatedCounterMap implements ReplicatedData {
*
* @returns This counter map
*/
clear = (): ReplicatedCounterMap => {
clear = (): ReplicatedCounterMap<Key> => {
if (this.counters.size > 0) {
this.cleared = true;
this.counters.clear();
Expand All @@ -155,7 +159,7 @@ export class ReplicatedCounterMap implements ReplicatedData {
return this;
};

private getOrCreateCounter(key: Serializable): ReplicatedCounter {
private getOrCreateCounter(key: Key): ReplicatedCounter {
const comparableKey = AnySupport.toComparable(key);
const entry = this.counters.get(comparableKey);
if (entry) {
Expand Down
Loading