Migrated all resources into the resources' directory.
This commit is contained in:
1 parent
8449cf94ee
commit
eca4820fd2
16 files changed
+3
-7
No files matched your search
@@ -0,0 +1,183 @@
|
||||
import {Command} from "https://deno.land/x/cliffy@v0.25.7/command/mod.ts";
|
||||
import {concat, partial} from 'https://deno.land/x/lodash@4.17.15-es/lodash.js';
|
||||
import {dirname, join} from "https://deno.land/std@0.171.0/path/mod.ts";
|
||||
import avro from "npm:avro-js@1.11.1";
|
||||
|
||||
|
||||
enum AvroPrimitives {
|
||||
Null = "null",
|
||||
Boolean = "boolean",
|
||||
Int = "int",
|
||||
Long = "long",
|
||||
Float = "float",
|
||||
Double = "double",
|
||||
Bytes = "bytes",
|
||||
String = "string"
|
||||
}
|
||||
|
||||
interface AvroRecordField {
|
||||
name: string,
|
||||
doc?: string,
|
||||
default?: any,
|
||||
type: AvroTypes,
|
||||
}
|
||||
|
||||
interface AvroRecord {
|
||||
name: string,
|
||||
type: "record",
|
||||
namespace?: string,
|
||||
doc?: string,
|
||||
aliases?: string[]
|
||||
fields: AvroRecordField[]
|
||||
}
|
||||
|
||||
interface AvroEnum {
|
||||
name: string,
|
||||
namespace?: string,
|
||||
aliases?: string[],
|
||||
type: "enum",
|
||||
symbols: string[],
|
||||
}
|
||||
|
||||
type AvroUnion = AvroTypes[];
|
||||
|
||||
type AvroTypes = AvroPrimitives | AvroRecord | AvroUnion | AvroEnum;
|
||||
|
||||
const CacheChequeEvent: AvroRecord = {
|
||||
name: "CacheChequeEvent",
|
||||
type: "record",
|
||||
fields: [
|
||||
{name: "account", type: AvroPrimitives.Long},
|
||||
]
|
||||
}
|
||||
|
||||
const BogusEvent: AvroRecord = {
|
||||
name: "BogusEvent",
|
||||
type: "record",
|
||||
fields: [
|
||||
{name: "account", type: AvroPrimitives.Long},
|
||||
{name: "foo", type: AvroPrimitives.Long},
|
||||
]
|
||||
}
|
||||
|
||||
const allEvents: AvroRecord[] = [CacheChequeEvent, BogusEvent]
|
||||
|
||||
const eventTypes: AvroEnum = {
|
||||
type: "enum",
|
||||
name: "EventType",
|
||||
symbols: allEvents.map(x => x.name),
|
||||
}
|
||||
|
||||
const LedgerEventsSchema: AvroRecord = {
|
||||
name: "LedgerEvent",
|
||||
type: "record",
|
||||
fields: [
|
||||
{name: "event_type", type: eventTypes},
|
||||
{name: "event", type: allEvents},
|
||||
]
|
||||
};
|
||||
|
||||
interface CliOptions {
|
||||
dry: boolean,
|
||||
output: string,
|
||||
}
|
||||
|
||||
type Serializer = (rec: AvroRecord) => Promise<void>;
|
||||
|
||||
function getOutputFileName(outputDir: string, rec: AvroRecord): string {
|
||||
return join(outputDir, rec.name + '.json');
|
||||
}
|
||||
|
||||
async function drySerializer(outputDir: string, rec: AvroRecord): Promise<void> {
|
||||
console.log(getOutputFileName(outputDir, rec) + " : " + JSON.stringify(rec));
|
||||
}
|
||||
|
||||
async function fileSerializer(outputDir: string, rec: AvroRecord): Promise<void> {
|
||||
const outputFile = getOutputFileName(outputDir, rec);
|
||||
await Deno.mkdir(dirname(outputFile), { recursive: true });
|
||||
await Deno.writeTextFile(outputFile, JSON.stringify(rec, null, 4));
|
||||
|
||||
}
|
||||
|
||||
function getSerializer(dry: boolean, outputDir: string): Serializer {
|
||||
return dry ? partial(drySerializer, outputDir) : partial(fileSerializer, outputDir);
|
||||
}
|
||||
|
||||
async function buildSchemata(options: CliOptions): Promise<void> {
|
||||
const serializer = getSerializer(options.dry, options.output);
|
||||
for (const e of concat([], allEvents, LedgerEventsSchema, eventTypes)) {
|
||||
await serializer(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function testShit(): Promise<void> {
|
||||
const type = avro.parse(CacheChequeEvent);
|
||||
const buff = await Deno.readFile("/tmp/foo.data");
|
||||
console.log(buff);
|
||||
console.log(type.fromBuffer(buff));
|
||||
}
|
||||
|
||||
async function createMockData(): Promise<void> {
|
||||
const type = avro.parse(
|
||||
{
|
||||
"name": "CacheChequeEvent",
|
||||
"type": "record",
|
||||
"fields": [
|
||||
{
|
||||
"name": "account",
|
||||
"type": "long"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
);
|
||||
const e = {
|
||||
account: 666
|
||||
// event_type: CacheChequeEvent.name,
|
||||
// event: {CacheChequeEvent: {account: 1788301184}}
|
||||
};
|
||||
const encoder = avro.createFileEncoder("/tmp/foo.data", type);
|
||||
encoder.write({account: 666});
|
||||
encoder.end();
|
||||
return;
|
||||
// const file = await Deno.open("/tmp/foo.data", {write: true, create: true});
|
||||
// for (let i = 0; i < 1; i++) {
|
||||
// await Deno.write(file.rid, type.toBuffer(e).buffer);
|
||||
// }
|
||||
}
|
||||
|
||||
function buildSchemataCommand() {
|
||||
return new Command()
|
||||
.description("Build the avro schemata")
|
||||
.option("--dry [value:boolean]", "Do not output any files", {
|
||||
default: false,
|
||||
})
|
||||
.option("--output [value:file]", "directory to output schemata", {
|
||||
default: '.',
|
||||
})
|
||||
.action(buildSchemata);
|
||||
}
|
||||
|
||||
function buildMockEventsCommand() {
|
||||
return new Command()
|
||||
.description("Generate mock data")
|
||||
.option("--output [value:file]", "output data file", {
|
||||
default: '.',
|
||||
})
|
||||
.action(createMockData);
|
||||
}
|
||||
|
||||
function buildTestingCommand() {
|
||||
return new Command()
|
||||
.description("Test mock data")
|
||||
.action(testShit);
|
||||
|
||||
}
|
||||
|
||||
await new Command()
|
||||
.name("ledger-avro-schemata-builder")
|
||||
.version("0.1.0")
|
||||
.command('build-schema', buildSchemataCommand())
|
||||
.command('create-mock-data', buildMockEventsCommand())
|
||||
.command('testing', buildTestingCommand())
|
||||
.parse(Deno.args);
|
||||
@@ -0,0 +1,94 @@
|
||||
CREATE TABLE IF NOT EXISTS users
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
public_key TEXT NOT NULL,
|
||||
creation_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS security_types
|
||||
(
|
||||
name TEXT PRIMARY KEY
|
||||
) STRICT;
|
||||
|
||||
INSERT INTO security_types(name)
|
||||
VALUES ('currency'),
|
||||
('bond');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS securities
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
security_type TEXT NOT NULL,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
symbol TEXT NOT NULL UNIQUE,
|
||||
creation_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (security_type) REFERENCES security_types (name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS account_types
|
||||
(
|
||||
name TEXT PRIMARY KEY
|
||||
) STRICT;
|
||||
|
||||
INSERT INTO account_types(name)
|
||||
VALUES ('checking'),
|
||||
('security_emitter');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS accounts
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
version INTEGER NOT NULL CHECK ( version >= 0 ),
|
||||
security INTEGER NOT NULL,
|
||||
account_type TEXT NOT NULL,
|
||||
|
||||
amount INTEGER NOT NULL,
|
||||
timestamp DATETIME NOT NULL,
|
||||
creation_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
FOREIGN KEY (security) REFERENCES securities (id),
|
||||
FOREIGN KEY (account_type) REFERENCES account_types (name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS accounts_history
|
||||
(
|
||||
account_id INTEGER NOT NULL,
|
||||
account_version INTEGER NOT NULL,
|
||||
amount INTEGER NOT NULL,
|
||||
timestamp DATETIME NOT NULL,
|
||||
FOREIGN KEY (account_id) REFERENCES accounts (id),
|
||||
PRIMARY KEY (account_id, account_version)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS account_user_permissions
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account_id INTEGER NOT NULL,
|
||||
user_id INTEGER NOT NULL,
|
||||
creation_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
FOREIGN KEY (account_id) REFERENCES accounts (id),
|
||||
FOREIGN KEY (user_id) REFERENCES users (id)
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS cashed_cheques
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
drawer_user_id INTEGER NOT NULL,
|
||||
drawer_account_id INTEGER NOT NULL,
|
||||
drawer_account_version INTEGER NOT NULL,
|
||||
cheque_number INTEGER NOT NULL,
|
||||
amount INTEGER NOT NULL,
|
||||
underlying_security INTEGER NOT NULL,
|
||||
payee_user_id INTEGER NOT NULL,
|
||||
payee_account_id INTEGER NOT NULL,
|
||||
payee_account_version INTEGER NOT NULL,
|
||||
creation_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
FOREIGN KEY (underlying_security) REFERENCES securities (id),
|
||||
FOREIGN KEY (drawer_user_id) REFERENCES users (id),
|
||||
FOREIGN KEY (drawer_account_id) REFERENCES accounts (id),
|
||||
FOREIGN KEY (payee_user_id) REFERENCES users (id),
|
||||
FOREIGN KEY (payee_account_id) REFERENCES accounts (id),
|
||||
CONSTRAINT double_spending UNIQUE (drawer_user_id, cheque_number) -- no double spending
|
||||
);
|
||||
@@ -0,0 +1,40 @@
|
||||
{% set active_navbar_item = 'actions' %}
|
||||
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div>
|
||||
<form>
|
||||
<fieldset class="uk-fieldset">
|
||||
|
||||
<legend class="uk-legend">Create new item</legend>
|
||||
<div class="uk-margin">
|
||||
<select name="event_type"
|
||||
class="uk-select"
|
||||
aria-label="Select"
|
||||
class="uk-button uk-button-default"
|
||||
hx-get="/partials/actions/action-form"
|
||||
hx-trigger="change,load"
|
||||
hx-target="#action-form"
|
||||
hx-swap="innerHTML">>
|
||||
<option value="create_user">Create User</option>
|
||||
<option value="create_security">Create Security</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="action-form"></div>
|
||||
|
||||
|
||||
<div id="submit-button"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<table class="uk-table uk-table-small">
|
||||
<thead></thead>
|
||||
<tbody id="event-table-first-row"></tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,40 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ledger</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.15.23/dist/css/uikit.min.css" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/uikit@3.15.23/dist/js/uikit.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/uikit@3.15.23/dist/js/uikit-icons.min.js"></script>
|
||||
<script src="https://unpkg.com/htmx.org@1.8.5"></script>
|
||||
<script src="https://unpkg.com/htmx.org/dist/ext/json-enc.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<nav class="uk-navbar-container" uk-navbar>
|
||||
<div class="uk-navbar-left">
|
||||
<a href="/" class="uk-navbar-item uk-logo">Ledger</a>
|
||||
<ul class="uk-navbar-nav">
|
||||
{% set nav_bar_items = [{'id': 'overview', 'label': 'Overview'},
|
||||
{'id': 'actions', 'label': 'Actions'}]%}
|
||||
{% for itm in nav_bar_items %}
|
||||
<li class="{% if active_navbar_item == itm.id %}uk-active"{% endif %}"><a href="{{ itm.id }}">{{ itm.label }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="uk-grid">
|
||||
<div class="uk-width-1-6@m"></div>
|
||||
<div class="uk-width-2-3@m">
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="uk-width-1-6@m"></div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Whitespace-only changes.
@@ -0,0 +1,18 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
<h2>Securities</h2>
|
||||
<table class="uk-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Security</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>UAD</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,12 @@
|
||||
{% set active_navbar_item = 'overview' %}
|
||||
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
overview
|
||||
|
||||
{% for i in [{'a': 90}, 2, 3] %}
|
||||
lll {{ i }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
<label class="uk-label">
|
||||
<input type="text" name="event.name">
|
||||
|
||||
</label>
|
||||
|
||||
{%include "partials/actions/submit_button.html"%}
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label">Event [JSON5]</label>
|
||||
<textarea class="uk-textarea"
|
||||
name="event"
|
||||
style="font: 0.875rem/1.5 Consolas,monaco,monospace"
|
||||
rows="5"
|
||||
placeholder="JSON"></textarea>
|
||||
</div>
|
||||
|
||||
{%include "partials/actions/submit_button.html"%}
|
||||
@@ -0,0 +1,9 @@
|
||||
<button id="submit-button"
|
||||
class="uk-button uk-button-default"
|
||||
hx-post="/v1/events/{{event_type}}"
|
||||
hx-trigger="click"
|
||||
hx-target="#event-table-first-row"
|
||||
hx-ext="json-enc"
|
||||
hx-swap="outerHTML">
|
||||
Submit ss
|
||||
</button>
|
||||
@@ -0,0 +1,2 @@
|
||||
<tbody id="event-table-first-row"></tbody>
|
||||
<tr><td>une</td><td>{{ event_type }}</td></tr>
|
||||
@@ -0,0 +1,14 @@
|
||||
(function() {
|
||||
htmx.defineExtension('embedded-json-enc', {
|
||||
onEvent: function (name, evt) {
|
||||
if (name === "htmx:configRequest") {
|
||||
evt.detail.headers['Content-Type'] = "application/json";
|
||||
}
|
||||
},
|
||||
|
||||
encodeParameters : function(xhr, parameters, elt) {
|
||||
xhr.overrideMimeType('text/json');
|
||||
return (JSON.stringify(parameters));
|
||||
}
|
||||
});
|
||||
})()
|
||||
Reference in new issue
Block a user