https://github.com/hugojosefson/deno-prevalence
Prevalence for Deno, like Prevayler.
https://github.com/hugojosefson/deno-prevalence
deno deno-kv prevalence prevayler
Last synced: 3 months ago
JSON representation
Prevalence for Deno, like Prevayler.
- Host: GitHub
- URL: https://github.com/hugojosefson/deno-prevalence
- Owner: hugojosefson
- License: mit
- Created: 2023-06-07T21:57:47.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2023-10-08T12:56:21.000Z (over 2 years ago)
- Last Synced: 2025-03-26T15:55:21.603Z (over 1 year ago)
- Topics: deno, deno-kv, prevalence, prevayler
- Language: TypeScript
- Homepage: https://deno.land/x/prevalence
- Size: 345 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# prevalence
[System prevalence](https://en.wikipedia.org/wiki/System_prevalence) as a typed
library, using [Deno.Kv](https://deno.com/kv) for storage.
[](https://deno.land/x/prevalence)
[](https://github.com/hugojosefson/deno-prevalence/actions/workflows/ci.yaml)
TypeScript implementation for Deno of the Prevalence design pattern, as
introduced by Klaus Wuestefeld in 1998 with [Prevayler](https://prevayler.org/).
Saves periodical snapshots of the whole model for faster startup, and keeps a
journal of executed actions since last snapshot, using a
[Persister](https://deno.land/x/prevalence/mod.ts?s=Persister). The `Persister`
uses a [Marshaller](https://deno.land/x/prevalence/mod.ts?s=Marshaller) to
serialize/deserialize the model and the journal.
## Requirements
Requires [Deno](https://deno.land/) v1.32 or later, with the `--unstable` flag.
## API
Please see the
[auto-generated API documentation](https://deno.land/x/prevalence?doc).
## Example usage
```typescript
import {
Action,
KvPersister,
logger,
Marshaller,
Model,
Persister,
Prevalence,
SerializableClassesContainer,
SuperserialMarshaller,
} from "https://deno.land/x/prevalence/mod.ts";
import { Serializer } from "https://deno.land/x/superserial@0.3.4/serializer.ts";
const log = logger(import.meta.url);
class User {
constructor(
readonly uuid: string,
public displayName: string,
) {}
}
const alice: User = new User("1", "Alice");
type Post = {
id: string;
subject: string;
};
class MyModel implements Model {
constructor(
public posts: Record,
public users: Record,
) {}
}
class AddPostAction implements Action {
constructor(public post: Post) {}
execute(model: MyModel): void {
model.posts[this.post.id] = this.post;
}
}
class RemovePostAction implements Action {
constructor(public postId: string) {}
execute(model: MyModel): void {
delete model.posts[this.postId];
}
}
class AddUserAction implements Action {
constructor(public user: User) {}
execute(model: MyModel): void {
model.users[this.user.uuid] = this.user;
}
}
class RemoveUserAction implements Action {
constructor(public userId: string) {}
execute(model: MyModel): void {
delete model.users[this.userId];
}
}
const classes: SerializableClassesContainer = {
User,
MyModel,
AddPostAction,
RemovePostAction,
AddUserAction,
RemoveUserAction,
};
const marshaller: Marshaller = new SuperserialMarshaller<
MyModel
>(
new Serializer({ classes }),
);
const kv: Deno.Kv = await Deno.openKv("example-person-invoice.db");
const persister: Persister = new KvPersister(
marshaller,
kv,
);
const defaultInitialModel: MyModel = { posts: {}, users: {} };
const prevalence: Prevalence = await Prevalence.create(
defaultInitialModel,
{ persister, classes },
);
await prevalence.execute(new AddPostAction({ id: "post#1", subject: "Lorem" }));
await prevalence.execute(new AddPostAction({ id: "post#2", subject: "Ipsum" }));
await prevalence.execute(new AddPostAction({ id: "post#3", subject: "Dolor" }));
await prevalence.execute(new RemovePostAction("post#2"));
await prevalence.execute(new AddUserAction(alice));
const posts: Post[] = Object.values(prevalence.model.posts);
log("Posts:");
for (const post of posts) {
log(`${post.id}: ${post.subject}`);
}
log("Users:");
for (const user of Object.values(prevalence.model.users)) {
log(`${user.uuid}: ${user.displayName}`);
}
await prevalence.execute(new RemoveUserAction(alice.uuid));
log("Users:");
for (const user of Object.values(prevalence.model.users)) {
log(`${user.uuid}: ${user.displayName}`);
}
await prevalence.snapshot();
log("Done.");
```
You may run the above example with:
```sh
DEBUG='*' deno run --unstable --allow-env=DEBUG --reload --allow-write=example-person-invoice.db --allow-read=example-person-invoice.db https://deno.land/x/prevalence/readme/person-invoice.ts
```
For further usage examples, see the tests:
- [test/prevalence.test.ts](test/prevalence.test.ts)