Compare commits
No commits in common. "7c9a29b16c99cb21cc27c60a4e6321f8f814d5cb" and "54f16d0ac262e588410f6c50b667e6eea626442f" have entirely different histories.
7c9a29b16c
...
54f16d0ac2
80
.gitignore
vendored
80
.gitignore
vendored
@ -1,40 +1,40 @@
|
|||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
.npm
|
.npm
|
||||||
|
|
||||||
# yarn v2
|
# yarn v2
|
||||||
.yarn/cache
|
.yarn/cache
|
||||||
.yarn/unplugged
|
.yarn/unplugged
|
||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
# Dependency directories
|
# Dependency directories
|
||||||
node_modules/
|
node_modules/
|
||||||
jspm_packages/
|
jspm_packages/
|
||||||
|
|
||||||
|
|
||||||
# dotenv environment variable files
|
# dotenv environment variable files
|
||||||
.env
|
.env
|
||||||
.env.development.local
|
.env.development.local
|
||||||
.env.test.local
|
.env.test.local
|
||||||
.env.production.local
|
.env.production.local
|
||||||
.env.local
|
.env.local
|
||||||
|
|
||||||
# IDEs
|
# IDEs
|
||||||
|
|
||||||
.vscode
|
.vscode
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
.cache
|
.cache
|
||||||
.parcel-cache
|
.parcel-cache
|
||||||
|
|
||||||
# build directory
|
# build directory
|
||||||
dist/
|
dist/
|
||||||
|
|||||||
10
.parcelrc
10
.parcelrc
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": "@parcel/config-default",
|
"extends": "@parcel/config-default",
|
||||||
"transformers": {
|
"transformers": {
|
||||||
"*.riot": ["@riotjs/parcel-transformer-riot"]
|
"*.riot": ["@riotjs/parcel-transformer-riot"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17
README.md
17
README.md
@ -1,17 +0,0 @@
|
|||||||
# TimeChain
|
|
||||||
|
|
||||||
A straightforward program for pasting text, HTML, photos, or anything else. The FILO interface is straightforward: tag it, timestamp it, then view it.
|
|
||||||
|
|
||||||
# Build
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
# Tests
|
|
||||||
|
|
||||||
Type the following commands to run tests:
|
|
||||||
|
|
||||||
```
|
|
||||||
npx jest
|
|
||||||
```
|
|
||||||
40
index.html
40
index.html
@ -1,21 +1,21 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||||
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||||
<title>Time Chain</title>
|
<title>Time Chain</title>
|
||||||
<link rel="stylesheet" href="src/css/main.css">
|
<link rel="stylesheet" href="src/css/main.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="loading" >
|
<div class="loading" >
|
||||||
<h1>Time Chain!</h1>
|
<h1>Time Chain!</h1>
|
||||||
<p>Time traveling your data! Comming soon...</p>
|
<p>Time traveling your data! Comming soon...</p>
|
||||||
<p id="timestamp"></p>
|
<p id="timestamp"></p>
|
||||||
<img src="src/img/chain2.svg" class="rotate">
|
<img src="src/img/chain2.svg" class="rotate">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="module" src="src/dist/start.js"></script>
|
<script type="module" src="src/dist/start.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
5035
package-lock.json
generated
5035
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "electron .",
|
"start": "electron .",
|
||||||
"build": "parcel build --dist-dir ./src/dist --target \"jason\" start.js"
|
"compile": "parcel build --dist-dir ./src/dist --target \"jason\" start.js"
|
||||||
},
|
},
|
||||||
"browserslist": "> 0.5%, last 2 versions, not dead",
|
"browserslist": "> 0.5%, last 2 versions, not dead",
|
||||||
"targets": {
|
"targets": {
|
||||||
@ -25,14 +25,12 @@
|
|||||||
"@riotjs/compiler": "^6.1.3",
|
"@riotjs/compiler": "^6.1.3",
|
||||||
"@riotjs/parcel-transformer-riot": "^7.0.3",
|
"@riotjs/parcel-transformer-riot": "^7.0.3",
|
||||||
"electron": "^16.0.7",
|
"electron": "^16.0.7",
|
||||||
"jest": "^27.4.7",
|
|
||||||
"parcel": "^2.2.1"
|
"parcel": "^2.2.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"better-sqlite3": "^7.5.0",
|
"better-sqlite3": "^7.5.0",
|
||||||
"dayjs": "^1.10.7",
|
"dayjs": "^1.10.7",
|
||||||
"es6-interface": "^3.2.1",
|
"es6-interface": "^3.2.1",
|
||||||
"nanoid": "^3.2.0",
|
|
||||||
"pubsub-js": "^1.9.4",
|
"pubsub-js": "^1.9.4",
|
||||||
"riot": "^6.1.2"
|
"riot": "^6.1.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,31 +1,31 @@
|
|||||||
body {
|
body {
|
||||||
background-color: #333;
|
background-color: #333;
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading {
|
.loading {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 5em;
|
padding: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading img {
|
.loading img {
|
||||||
width: 30%;
|
width: 30%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading p {
|
.loading p {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rotate {
|
.rotate {
|
||||||
animation: rotation 2s infinite linear;
|
animation: rotation 2s infinite linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes rotation {
|
@keyframes rotation {
|
||||||
from {
|
from {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
to {
|
to {
|
||||||
transform: rotate(359deg);
|
transform: rotate(359deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,35 +1,35 @@
|
|||||||
const InterfaceRecord = {
|
const InterfaceRecord = {
|
||||||
find(search,sort,limit,offset){},
|
find(search,limit,offset){},
|
||||||
get(uuid){},
|
get(uuid){},
|
||||||
add(uuid,timestamp,content,mime,hash){},
|
add(uuid,timestamp,content,mime,hash){},
|
||||||
update(uuid,content,mime,hash){},
|
update(uuid,timestamp,content,mime,hash){},
|
||||||
delete(uuid){},
|
delete(uuid){},
|
||||||
}
|
}
|
||||||
|
|
||||||
const InterfaceFile = {
|
const InterfaceFile = {
|
||||||
add(uuid_record,uuid,timestamp,content,mime,hash){},
|
add(uuid_record,uuid,timestamp,content,mime,hash){},
|
||||||
getByRecord(uuid_record){},
|
getByRecord(uuid_record){},
|
||||||
get(uuid){},
|
get(uuid){},
|
||||||
delete(uuid){},
|
delete(uuid){},
|
||||||
deleteRecord(uuid_record){},
|
deleteRecord(uuid_record){},
|
||||||
update(uuid,timestamp,content,mime,hash){}
|
update(uuid,timestamp,content,mime,hash){}
|
||||||
}
|
}
|
||||||
|
|
||||||
const InterfaceTag = {
|
const InterfaceTag = {
|
||||||
add(tag){},
|
add(uuid,word){},
|
||||||
delete(tag){}
|
delete(uuid){}
|
||||||
}
|
}
|
||||||
|
|
||||||
const InterfaceTagLink = {
|
const InterfaceTagLink = {
|
||||||
add(uuid,tag){},
|
add(uuid_record,uuid_tag){},
|
||||||
delete(uuid,tag){},
|
delete(uuid_record,uuid_tag){},
|
||||||
deleteTag(tag){},
|
deleteTag(uuid){},
|
||||||
deleteRecord(uuid){}
|
deleteRecord(uuid){}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
InterfaceTagLink,
|
InterfaceTagLink,
|
||||||
InterfaceTag,
|
InterfaceTag,
|
||||||
InterfaceFile,
|
InterfaceFile,
|
||||||
InterfaceRecord
|
InterfaceRecord
|
||||||
}
|
}
|
||||||
@ -1,76 +1,76 @@
|
|||||||
const { ipcMain } = require('electron');
|
const { ipcMain } = require('electron');
|
||||||
|
|
||||||
const {app} = require('electron');
|
const {app} = require('electron');
|
||||||
const config = app.getPath('userData');
|
const config = app.getPath('userData');
|
||||||
|
|
||||||
const Conf = require('conf');
|
const Conf = require('conf');
|
||||||
const config = new Conf();
|
const config = new Conf();
|
||||||
|
|
||||||
|
|
||||||
// ** Extra Data
|
// ** Extra Data
|
||||||
ipcMain.on('timechain-config-dir', (event,arg) => {
|
ipcMain.on('timechain-config-dir', (event,arg) => {
|
||||||
const configDir = app.getPath('userData');
|
const configDir = app.getPath('userData');
|
||||||
event.reply('timechain-config-dir-reply', configDir);
|
event.reply('timechain-config-dir-reply', configDir);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ** RECORD **
|
// ** RECORD **
|
||||||
|
|
||||||
ipcMain.on('timechain-record-add', (event, arg) => {
|
ipcMain.on('timechain-record-add', (event, arg) => {
|
||||||
event.reply('timechain-record-add-reply', 'pong')
|
event.reply('timechain-record-add-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('timechain-record-delete', (event, arg) => {
|
ipcMain.on('timechain-record-delete', (event, arg) => {
|
||||||
event.reply('timechain-record-delete-reply', 'pong')
|
event.reply('timechain-record-delete-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('timechain-record-update', (event, arg) => {
|
ipcMain.on('timechain-record-update', (event, arg) => {
|
||||||
event.reply('timechain-record-update-reply', 'pong')
|
event.reply('timechain-record-update-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('timechain-record-find', (event, arg) => {
|
ipcMain.on('timechain-record-find', (event, arg) => {
|
||||||
event.reply('timechain-record-find-reply', 'pong')
|
event.reply('timechain-record-find-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
// ** FILE **
|
// ** FILE **
|
||||||
|
|
||||||
ipcMain.on('timechain-file-find', (event, arg) => {
|
ipcMain.on('timechain-file-find', (event, arg) => {
|
||||||
event.reply('timechain-file-find-reply', 'pong')
|
event.reply('timechain-file-find-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('timechain-file-add', (event, arg) => {
|
ipcMain.on('timechain-file-add', (event, arg) => {
|
||||||
event.reply('timechain-file-add-reply', 'pong')
|
event.reply('timechain-file-add-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('timechain-file-update', (event, arg) => {
|
ipcMain.on('timechain-file-update', (event, arg) => {
|
||||||
event.reply('timechain-file-update-reply', 'pong')
|
event.reply('timechain-file-update-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('timechain-file-delete', (event, arg) => {
|
ipcMain.on('timechain-file-delete', (event, arg) => {
|
||||||
event.reply('timechain-file-delete-reply', 'pong')
|
event.reply('timechain-file-delete-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
// ** TAG **
|
// ** TAG **
|
||||||
ipcMain.on('timechain-tag-add', (event, arg) => {
|
ipcMain.on('timechain-tag-add', (event, arg) => {
|
||||||
event.reply('timechain-tag-add-reply', 'pong')
|
event.reply('timechain-tag-add-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('timechain-tag-delete', (event, arg) => {
|
ipcMain.on('timechain-tag-delete', (event, arg) => {
|
||||||
event.reply('timechain-tag-delete-reply', 'pong')
|
event.reply('timechain-tag-delete-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
// ** TAG LINK **
|
// ** TAG LINK **
|
||||||
ipcMain.on('timechain-taglink-add', (event, arg) => {
|
ipcMain.on('timechain-taglink-add', (event, arg) => {
|
||||||
event.reply('timechain-taglink-add-reply', 'pong')
|
event.reply('timechain-taglink-add-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('timechain-taglink-delete', (event, arg) => {
|
ipcMain.on('timechain-taglink-delete', (event, arg) => {
|
||||||
event.reply('timechain-taglink-delete-reply', 'pong')
|
event.reply('timechain-taglink-delete-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('timechain-taglink-deleteTag', (event, arg) => {
|
ipcMain.on('timechain-taglink-deleteTag', (event, arg) => {
|
||||||
event.reply('timechain-taglink-deleteTag-reply', 'pong')
|
event.reply('timechain-taglink-deleteTag-reply', 'pong')
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('timechain-taglink-deleteRecord', (event, arg) => {
|
ipcMain.on('timechain-taglink-deleteRecord', (event, arg) => {
|
||||||
event.reply('timechain-taglink-deleteRecord-reply', 'pong')
|
event.reply('timechain-taglink-deleteRecord-reply', 'pong')
|
||||||
});
|
});
|
||||||
@ -1,392 +1,264 @@
|
|||||||
const Interface = require("es6-interface");
|
const Interface = require("es6-interface");
|
||||||
const {InterfaceRecord,InterfaceFile,InterfaceTag,InterfaceTagLink} = require("./interfaces");
|
const {InterfaceRecord,InterfaceFile,InterfaceTag,InterfaceTagLink} = require("./interfaces");
|
||||||
|
|
||||||
let db = null;
|
let db = null;
|
||||||
|
|
||||||
const ConnectToDatabase = (path)=>{
|
const connectToDatabase = (path)=>{
|
||||||
db = require('better-sqlite3')(path, {});
|
db = require('better-sqlite3')(path, {});
|
||||||
return db;
|
}
|
||||||
}
|
|
||||||
|
class TimeChainDataSqliteTag extends Interface(InterfaceTag) {
|
||||||
class TimeChainDataSqliteTag extends Interface(InterfaceTag) {
|
|
||||||
|
constructor(){
|
||||||
constructor(){
|
|
||||||
super();
|
}
|
||||||
const table = `CREATE TABLE IF NOT EXISTS "tags" (
|
|
||||||
"tag" TEXT UNIQUE,
|
add(uuid,word){
|
||||||
"created_at" INTEGER NOT NULL,
|
|
||||||
"updated_at" INTEGER NOT NULL,
|
}
|
||||||
PRIMARY KEY("tag")
|
|
||||||
);`;
|
delete(uuid){
|
||||||
|
|
||||||
const table_idx = ``;
|
}
|
||||||
|
|
||||||
if(!db){
|
}
|
||||||
throw new Error("Database is not connected");
|
|
||||||
}
|
class TimeChainDataSqliteTagLink extends Interface(InterfaceTagLink) {
|
||||||
|
|
||||||
|
constructor(){
|
||||||
db.exec(table + "\n" + table_idx);
|
|
||||||
this.db = db;
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
get table_add(){
|
|
||||||
if(!this._table_add){
|
class TimeChainDataSqliteFile extends Interface(InterfaceFile) {
|
||||||
this._table_add = db.prepare("INSERT INTO tags (tag,created_at,updated_at) VALUES (?,?,?)");
|
|
||||||
}
|
constructor(){
|
||||||
return this.table_add;
|
const table = `CREATE TABLE IF NOT EXISTS "files" (
|
||||||
}
|
"uuid" TEXT UNIQUE,
|
||||||
|
"uuid_record" TEXT NOT NULL,
|
||||||
get table_delete(){
|
"timestamp" INTEGER NOT NULL,
|
||||||
if(!this._table_delete){
|
"content" BLOB NOT NULL,
|
||||||
this._table_delete = db.prepare("DELETE FROM tags WHERE tag = ?");
|
"mime" TEXT NOT NULL,
|
||||||
}
|
"hash" TEXT,
|
||||||
return this._table_delete;
|
"created_at" INTEGER NOT NULL,
|
||||||
}
|
"updated_at" INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY("uuid")
|
||||||
add(tag){
|
);`;
|
||||||
return new Promise(resolve=>{
|
const table_idx = `
|
||||||
const dt = Math.floor(Date.now());
|
CREATE INDEX IF NOT EXISTS "files_idx_record" ON "files" (
|
||||||
const res = this.table_add.run(tag,dt,dt);
|
"uuid_record"
|
||||||
return resolve(res?.changes);
|
);
|
||||||
});
|
CREATE INDEX IF NOT EXISTS "files_idx_time" ON "files" (
|
||||||
}
|
"timestamp" DESC
|
||||||
|
);`;
|
||||||
delete(tag){
|
|
||||||
return new Promise(resolve=>{
|
if(!db){
|
||||||
const dt = Math.floor(Date.now());
|
throw new Error("Database is not connected");
|
||||||
const res = this.table_delete.run(tag);
|
}
|
||||||
return resolve(res?.changes);
|
|
||||||
});
|
db.exec(table + "\n" + table_idx);
|
||||||
}
|
this.db = db;
|
||||||
|
}
|
||||||
}
|
|
||||||
|
get table_insert() {
|
||||||
class TimeChainDataSqliteTagLink extends Interface(InterfaceTagLink) {
|
if(!this._table_insert){
|
||||||
|
this._table_insert = db.prepare(`INSERT INTO files (uuid,uuid_record,timestamp,content,mime,hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?)`);
|
||||||
constructor(){
|
}
|
||||||
super();
|
return this._table_insert;
|
||||||
|
}
|
||||||
this.table = `CREATE TABLE IF NOT EXISTS "taglink" (
|
|
||||||
"uuid" TEXT NOT NULL,
|
get table_update() {
|
||||||
"tag" TEXT NOT NULL,
|
if(!this._table_update){
|
||||||
"created_at" INTEGER NOT NULL
|
this._table_update = db.prepare(`UPDATE files SET timestamp = ?, content = ?, mime = ? hash = ?, updated_at = ? WHERE uuid = ?`);
|
||||||
);`;
|
}
|
||||||
this.table_idx = `
|
return this._table_update;
|
||||||
CREATE INDEX IF NOT EXISTS "uuid_idx" ON "taglink" (
|
}
|
||||||
"uuid"
|
|
||||||
);
|
get table_delete() {
|
||||||
CREATE INDEX IF NOT EXISTS "tag_idx" ON "taglink" (
|
if(!this._table_delete){
|
||||||
"tag"
|
this._table_delete = db.prepare(`DELETE FROM files WHERE uuid = ?`);
|
||||||
);
|
}
|
||||||
`;
|
return this._table_delete;
|
||||||
|
}
|
||||||
db.exec(this.table + "\n" + this.table_idx);
|
|
||||||
this.db = db;
|
get table_delete_record() {
|
||||||
}
|
|
||||||
|
if(!this._table_delete_record){
|
||||||
get table_add(){
|
this._table_delete_record = db.prepare(`DELETE FROM files WHERE uuid_record = ?`);
|
||||||
if(!_table_add){
|
}
|
||||||
this._table_add = db.prepare('INSERT INTO taglink (uuid,tag,created_at) VALUES (?,?,?)');
|
|
||||||
}
|
return this._table_delete_record;
|
||||||
return this._table_add;
|
}
|
||||||
}
|
|
||||||
|
get table_find_one() {
|
||||||
get table_delete(){
|
if(!this._table_find_one){
|
||||||
if(!this._table_delete){
|
this._table_find_one = db.prepare(`SELECT * FROM files WHERE uuid = ?`);
|
||||||
this._table_delete = db.prepare('DELETE FROM taglink WHERE uuid=? AND tag=?');
|
}
|
||||||
}
|
return this._table_find_one;
|
||||||
return this._table_delete;
|
}
|
||||||
}
|
|
||||||
|
get table_find_record(){
|
||||||
get table_delete_tag(){
|
if(!this._table_find_record){
|
||||||
if(!this._table_delete_tag){
|
this._table_find_record = db.prepare(`SELECT * FROM files WHERE uuid_record = ?`);
|
||||||
this._table_delete_tag = db.prepare('DELETE FROM taglink WHERE tag=?');
|
}
|
||||||
}
|
return this._table_find_record;
|
||||||
return this._table_delete_tag;
|
}
|
||||||
}
|
|
||||||
|
add(uuid_record,uuid,timestamp,content,mime,hash){
|
||||||
get table_delete_record(){
|
return new Promise(resolve=>{
|
||||||
if(!this._table_delete_record){
|
const dt = Math.floor(Date.now());
|
||||||
this._table_delete_record = db.prepare('DELETE FROM taglink WHERE uuid=?');
|
const res = this.table_insert.exec(uuid,uuid_record,timestamp,content,mime,hash,dt,dt);
|
||||||
}
|
return resolve(res?.changes);
|
||||||
}
|
});
|
||||||
|
}
|
||||||
add(uuid,tag){
|
|
||||||
return new Promise(resolve=>{
|
getByRecord(uuid_record){
|
||||||
const prepare = this.table_add;
|
return new Promise(resolve => {
|
||||||
const dt = Math.floor(Date.now());
|
const res = this.table_find_record.get(uuid_record);
|
||||||
const res = prepare.run(uuid,tag,dt);
|
return resolve(res);
|
||||||
return resolve(res?.changes);
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
get(uuid){
|
||||||
delete(uuid,tag){
|
return new Promise(resolve => {
|
||||||
return new Promise(resolve=>{
|
const res = this.table_fine_one.get(uuid);
|
||||||
const prepare = this.table_delete;
|
return resolve(res);
|
||||||
const res = prepare.run(uuid,tag);
|
});
|
||||||
return resolve(res?.changes);
|
}
|
||||||
});
|
|
||||||
}
|
delete(uuid){
|
||||||
|
return new Promise(resolve=>{
|
||||||
deleteTag(tag){
|
const res = this.table_delete.exec(uuid);
|
||||||
return new Promise(resolve=>{
|
return resolve(res?.changes);
|
||||||
const prepare = this.table_delete_tag;
|
})
|
||||||
const res = prepare.run(tag);
|
}
|
||||||
return resolve(res?.changes);
|
|
||||||
});
|
deleteRecord(){
|
||||||
}
|
return new Promise(resolve=>{
|
||||||
|
const res = this.table_delete_record.exec(uuid_record);
|
||||||
deleteRecord(uuid){
|
return resolve(res?.changes);
|
||||||
return new Promise(resolve=>{
|
})
|
||||||
const prepare = this.table_delete_record;
|
}
|
||||||
const res = prepare.run(uuid);
|
|
||||||
return resolve(res?.changes);
|
update(uuid,timestamp,content,mime,hash){
|
||||||
});
|
return new Promise(resolve=>{
|
||||||
}
|
const res = this.table_update.exec(timestamp,content,mime,hash,uuid);
|
||||||
}
|
return resolve(res?.changes);
|
||||||
|
})
|
||||||
class TimeChainDataSqliteFile extends Interface(InterfaceFile) {
|
}
|
||||||
|
}
|
||||||
constructor(){
|
|
||||||
super();
|
class TimeChainDataSqliteRecord extends Interface(InterfaceRecord) {
|
||||||
const table = `CREATE TABLE IF NOT EXISTS "files" (
|
|
||||||
"uuid" TEXT UNIQUE,
|
constructor(){
|
||||||
"uuid_record" TEXT NOT NULL,
|
//TODO: Create Tables Here if not exist
|
||||||
"timestamp" INTEGER NOT NULL,
|
const table = `CREATE TABLE IF NOT EXISTS "records" (
|
||||||
"content" BLOB NOT NULL,
|
"uuid" TEXT NOT NULL UNIQUE,
|
||||||
"mime" TEXT NOT NULL,
|
"timestamp" INTEGER NOT NULL,
|
||||||
"hash" TEXT,
|
"content" TEXT NOT NULL,
|
||||||
"created_at" INTEGER NOT NULL,
|
"mime" TEXT NOT NULL,
|
||||||
"updated_at" INTEGER NOT NULL,
|
"hash" TEXT,
|
||||||
PRIMARY KEY("uuid")
|
"created_at" INTEGER NOT NULL,
|
||||||
);`;
|
"updated_at" INTEGER NOT NULL,
|
||||||
const table_idx = `
|
PRIMARY KEY("uuid")
|
||||||
CREATE INDEX IF NOT EXISTS "files_idx_record" ON "files" (
|
);`;
|
||||||
"uuid_record"
|
const table_idx = `CREATE INDEX IF NOT EXISTS "records_idx_timestamp" ON "records" (
|
||||||
);
|
"timestamp" DESC
|
||||||
CREATE INDEX IF NOT EXISTS "files_idx_time" ON "files" (
|
);`
|
||||||
"timestamp" DESC
|
|
||||||
);`;
|
if(!db){
|
||||||
|
throw new Error("Database is not connected");
|
||||||
if(!db){
|
}
|
||||||
throw new Error("Database is not connected");
|
|
||||||
}
|
db.exec(table + "\n" + table_idx);
|
||||||
|
this.db = db;
|
||||||
db.exec(table + "\n" + table_idx);
|
}
|
||||||
this.db = db;
|
|
||||||
}
|
get table_insert() {
|
||||||
|
if(!this._table_insert){
|
||||||
get table_insert() {
|
this._table_insert = db.prepare(`INSERT INTO records (uuid,timestamp,content,mime,hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?)`);
|
||||||
if(!this._table_insert){
|
}
|
||||||
this._table_insert = db.prepare(`INSERT INTO files (uuid,uuid_record,timestamp,content,mime,hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?)`);
|
return this._table_insert;
|
||||||
}
|
}
|
||||||
return this._table_insert;
|
|
||||||
}
|
get table_update(){
|
||||||
|
if(!this._table_update){
|
||||||
get table_update() {
|
this._table_update = db.prepare(`UPDATE records SET timestamp = ?, content = ?, mime = ?, hash = ? updated_at = ? WHERE uuid = ?`);
|
||||||
if(!this._table_update){
|
}
|
||||||
this._table_update = db.prepare(`UPDATE files SET timestamp = ?, content = ?, mime = ? hash = ?, updated_at = ? WHERE uuid = ?`);
|
return this._table_update;
|
||||||
}
|
}
|
||||||
return this._table_update;
|
|
||||||
}
|
get table_delete(){
|
||||||
|
if(!this._table_delete){
|
||||||
get table_delete() {
|
this._table_delete = db.prepare(`DELETE FROM records WHERE uuid = ?`);
|
||||||
if(!this._table_delete){
|
}
|
||||||
this._table_delete = db.prepare(`DELETE FROM files WHERE uuid = ?`);
|
return this._table_delete;
|
||||||
}
|
}
|
||||||
return this._table_delete;
|
|
||||||
}
|
get table_fine_one(){
|
||||||
|
if(!this._table_fine_one){
|
||||||
get table_delete_record() {
|
this._table_fine_one = db.prepare(`SELECT * FROM records WHERE uuid = ?`);
|
||||||
|
}
|
||||||
if(!this._table_delete_record){
|
return this._table_fine_one;
|
||||||
this._table_delete_record = db.prepare(`DELETE FROM files WHERE uuid_record = ?`);
|
}
|
||||||
}
|
|
||||||
|
add(uuid,timestamp,content,mime,hash){
|
||||||
return this._table_delete_record;
|
return new Promise(resolve=>{
|
||||||
}
|
const dt = Math.floor(Date.now());
|
||||||
|
const res = this.table_insert.run(uuid,timestamp,content,mime,hash,dt,dt);
|
||||||
get table_find_one() {
|
return resolve(res?.changes);
|
||||||
if(!this._table_find_one){
|
});
|
||||||
this._table_find_one = db.prepare(`SELECT * FROM files WHERE uuid = ?`);
|
}
|
||||||
}
|
|
||||||
return this._table_find_one;
|
get(uuid){
|
||||||
}
|
return new Promise(resolve=>{
|
||||||
|
const rec = this.table_fine_one.get(uuid);
|
||||||
get table_find_record(){
|
return resolve(rec);
|
||||||
if(!this._table_find_record){
|
});
|
||||||
this._table_find_record = db.prepare(`SELECT * FROM files WHERE uuid_record = ?`);
|
}
|
||||||
}
|
|
||||||
return this._table_find_record;
|
find(search,sort=null,limit=undefined,offset=0){
|
||||||
}
|
//TODO: add logic for seach and sort (Currently does nothing)
|
||||||
|
return new Promise(resolve=>{
|
||||||
add(uuid_record,uuid,timestamp,content,mime,hash){
|
const rescount = this.db.prepare("SELECT count(*) as cnt FROM records").get();
|
||||||
return new Promise(resolve=>{
|
|
||||||
const dt = Math.floor(Date.now());
|
if(limit){
|
||||||
const res = this.table_insert.run(uuid,uuid_record,timestamp,content,mime,hash,dt,dt);
|
const res = this.db.prepare("SELECT * FROM records ORDER BY timestamp DESC LIMIT ? OFFSET ?").all(limit,offset);
|
||||||
return resolve(res?.changes);
|
}else{
|
||||||
});
|
const res = this.db.prepare("SELECT * FROM records ORDER BY timestamp DESC").all();
|
||||||
}
|
}
|
||||||
|
|
||||||
getByRecord(uuid_record){
|
return resolve({
|
||||||
return new Promise(resolve => {
|
data: res,
|
||||||
const res = this.table_find_record.get(uuid_record);
|
count: rescount?.cnt,
|
||||||
return resolve(res);
|
limit: limit,
|
||||||
});
|
offset: offset
|
||||||
}
|
});
|
||||||
|
|
||||||
get(uuid){
|
})
|
||||||
return new Promise(resolve => {
|
}
|
||||||
const res = this.table_fine_one.get(uuid);
|
|
||||||
return resolve(res);
|
delete(uuid){
|
||||||
});
|
return new Promise(resolve=>{
|
||||||
}
|
const res = this.table_delete.exec(uuid);
|
||||||
|
return resolve(res?.changes);
|
||||||
delete(uuid){
|
});
|
||||||
return new Promise(resolve=>{
|
}
|
||||||
const prepare = this.table_delete;
|
|
||||||
const res = prepare.exec(uuid);
|
update(uuid,content,mime,hash){
|
||||||
return resolve(res?.changes);
|
return new Promise(resolve=>{
|
||||||
})
|
const dt = Math.floor(Date.now());
|
||||||
}
|
const res = this.table_update.exec(content,mime,hash,dt,uuid);
|
||||||
|
return resolve(res?.changes);
|
||||||
deleteRecord(uuid_record){
|
})
|
||||||
return new Promise(resolve=>{
|
}
|
||||||
const res = this.table_delete_record.run(uuid_record);
|
|
||||||
return resolve(res?.changes);
|
}
|
||||||
})
|
|
||||||
}
|
class TimeChainDataSqlite {
|
||||||
|
|
||||||
update(uuid,timestamp,content,mime,hash){
|
}
|
||||||
return new Promise(resolve=>{
|
|
||||||
const res = this.table_update.run(timestamp,content,mime,hash,uuid);
|
|
||||||
return resolve(res?.changes);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TimeChainDataSqliteRecord extends Interface(InterfaceRecord) {
|
|
||||||
|
|
||||||
constructor(){
|
|
||||||
super();
|
|
||||||
//TODO: Create Tables Here if not exist
|
|
||||||
const table = `CREATE TABLE IF NOT EXISTS "records" (
|
|
||||||
"uuid" TEXT NOT NULL UNIQUE,
|
|
||||||
"timestamp" INTEGER NOT NULL,
|
|
||||||
"content" TEXT NOT NULL,
|
|
||||||
"mime" TEXT NOT NULL,
|
|
||||||
"hash" TEXT,
|
|
||||||
"created_at" INTEGER NOT NULL,
|
|
||||||
"updated_at" INTEGER NOT NULL,
|
|
||||||
PRIMARY KEY("uuid")
|
|
||||||
);`;
|
|
||||||
const table_idx = `CREATE INDEX IF NOT EXISTS "records_idx_timestamp" ON "records" (
|
|
||||||
"timestamp" DESC
|
|
||||||
);`
|
|
||||||
|
|
||||||
if(!db){
|
|
||||||
throw new Error("Database is not connected");
|
|
||||||
}
|
|
||||||
|
|
||||||
db.exec(table + "\n" + table_idx);
|
|
||||||
this.db = db;
|
|
||||||
}
|
|
||||||
|
|
||||||
get table_insert() {
|
|
||||||
if(!this._table_insert){
|
|
||||||
this._table_insert = db.prepare(`INSERT INTO records (uuid,timestamp,content,mime,hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?)`);
|
|
||||||
}
|
|
||||||
return this._table_insert;
|
|
||||||
}
|
|
||||||
|
|
||||||
get table_update(){
|
|
||||||
if(!this._table_update){
|
|
||||||
this._table_update = db.prepare(`UPDATE records SET timestamp = ?, content = ?, mime = ?, hash = ? updated_at = ? WHERE uuid = ?`);
|
|
||||||
}
|
|
||||||
return this._table_update;
|
|
||||||
}
|
|
||||||
|
|
||||||
get table_delete(){
|
|
||||||
if(!this._table_delete){
|
|
||||||
this._table_delete = db.prepare(`DELETE FROM records WHERE uuid = ?`);
|
|
||||||
}
|
|
||||||
return this._table_delete;
|
|
||||||
}
|
|
||||||
|
|
||||||
get table_fine_one(){
|
|
||||||
if(!this._table_fine_one){
|
|
||||||
this._table_fine_one = db.prepare(`SELECT * FROM records WHERE uuid = ?`);
|
|
||||||
}
|
|
||||||
return this._table_fine_one;
|
|
||||||
}
|
|
||||||
|
|
||||||
add(uuid,timestamp,content,mime,hash){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const dt = Math.floor(Date.now());
|
|
||||||
const res = this.table_insert.run(uuid,timestamp,content,mime,hash,dt,dt);
|
|
||||||
return resolve(res?.changes);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get(uuid){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const rec = this.table_fine_one.get(uuid);
|
|
||||||
return resolve(rec);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
find(search,sort=null,limit=undefined,offset=0){
|
|
||||||
//TODO: add logic for seach and sort (Currently does nothing)
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const rescount = this.db.prepare("SELECT count(*) as cnt FROM records").get();
|
|
||||||
|
|
||||||
if(limit){
|
|
||||||
const res = this.db.prepare("SELECT * FROM records ORDER BY timestamp DESC LIMIT ? OFFSET ?").all(limit,offset);
|
|
||||||
}else{
|
|
||||||
const res = this.db.prepare("SELECT * FROM records ORDER BY timestamp DESC").all();
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolve({
|
|
||||||
data: res,
|
|
||||||
count: rescount?.cnt,
|
|
||||||
limit: limit,
|
|
||||||
offset: offset
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(uuid){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const prepare = this.table_delete;
|
|
||||||
const res = prepare.run(uuid);
|
|
||||||
return resolve(res?.changes);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
update(uuid,content,mime,hash){
|
|
||||||
return new Promise(resolve=>{
|
|
||||||
const dt = Math.floor(Date.now());
|
|
||||||
const res = this.table_update.run(content,mime,hash,dt,uuid);
|
|
||||||
return resolve(res?.changes);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class TimeChainDataSqlite {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
ConnectToDatabase,
|
|
||||||
TimeChainDataSqlite,
|
|
||||||
TimeChainDataSqliteRecord,
|
|
||||||
TimeChainDataSqliteFile,
|
|
||||||
TimeChainDataSqliteTagLink,
|
|
||||||
TimeChainDataSqliteTag
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
<app>
|
|
||||||
|
|
||||||
</app>
|
|
||||||
12
start.js
12
start.js
@ -1,7 +1,7 @@
|
|||||||
import Timestamp from './src/ui/timestamp.riot'
|
import Timestamp from './timestamp.riot'
|
||||||
import { component } from 'riot'
|
import { component } from 'riot'
|
||||||
|
|
||||||
|
|
||||||
component(Timestamp)(document.getElementById('timestamp'))
|
component(Timestamp)(document.getElementById('timestamp'))
|
||||||
|
|
||||||
console.log("yes!");
|
console.log("yes!");
|
||||||
@ -1,77 +0,0 @@
|
|||||||
const {TimeChainDataSqliteRecord,ConnectToDatabase, TimeChainDataSqliteFile, TimeChainDataSqliteTag, TimeChainDataSqliteTagLink} = require('../src/data/sqlite');
|
|
||||||
const { nanoid } = require('nanoid');
|
|
||||||
const { unsubscribe } = require('pubsub-js');
|
|
||||||
|
|
||||||
let db = null;
|
|
||||||
|
|
||||||
beforeAll(() => {
|
|
||||||
db = ConnectToDatabase(__dirname + "/test.db");
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(()=>{
|
|
||||||
db.close();
|
|
||||||
})
|
|
||||||
|
|
||||||
test("Should create a records table", ()=>{
|
|
||||||
const rec = new TimeChainDataSqliteRecord();
|
|
||||||
|
|
||||||
const st = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?");
|
|
||||||
const res = st.get('records');
|
|
||||||
|
|
||||||
expect(res).not.toBeNull();
|
|
||||||
expect(res.name).toEqual('records');
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Should create a files table", ()=>{
|
|
||||||
const file = new TimeChainDataSqliteFile();
|
|
||||||
|
|
||||||
const st = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?");
|
|
||||||
const res = st.get('files');
|
|
||||||
|
|
||||||
expect(res).not.toBeNull();
|
|
||||||
expect(res.name).toEqual('files');
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Should create a tags table", ()=>{
|
|
||||||
const tags = new TimeChainDataSqliteTag();
|
|
||||||
|
|
||||||
const st = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?");
|
|
||||||
const res = st.get('tags');
|
|
||||||
|
|
||||||
expect(res).not.toBeNull();
|
|
||||||
expect(res.name).toEqual('tags');
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Should create a tags link table", ()=>{
|
|
||||||
const links = new TimeChainDataSqliteTagLink();
|
|
||||||
|
|
||||||
const st = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?");
|
|
||||||
const res = st.get('taglink');
|
|
||||||
|
|
||||||
expect(res).not.toBeNull();
|
|
||||||
expect(res.name).toEqual('taglink');
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Should create a record in the database and then remove it",async ()=>{
|
|
||||||
const rec = new TimeChainDataSqliteRecord();
|
|
||||||
const id = nanoid();
|
|
||||||
const hash = "fakehash";
|
|
||||||
const content = "This is a test";
|
|
||||||
const mime = "text/plain";
|
|
||||||
const ts = Math.floor(Date.now());
|
|
||||||
|
|
||||||
return rec.add(id,ts,content,mime,hash).then(res=>{
|
|
||||||
expect(res).toEqual(1);
|
|
||||||
return rec.get(id).then(res=>{
|
|
||||||
expect(res.uuid).toEqual(id);
|
|
||||||
expect(res.timestamp).toEqual(ts);
|
|
||||||
expect(res.mime).toEqual(mime);
|
|
||||||
expect(res.content).toEqual(content);
|
|
||||||
expect(res.hash).toEqual(hash);
|
|
||||||
return rec.delete(id);
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
BIN
test/test.db
BIN
test/test.db
Binary file not shown.
@ -1,34 +1,34 @@
|
|||||||
<timestamp>
|
<timestamp>
|
||||||
|
|
||||||
<div class="timestamp">
|
<div class="timestamp">
|
||||||
<div class="timestamp-icon">
|
<div class="timestamp-icon">
|
||||||
<div class="timestamp-text">{ state.time_text }</div>
|
<div class="timestamp-text">{ state.time_text }</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
const pubsub = require('pubsub-js');
|
const pubsub = require('pubsub-js');
|
||||||
const dayjs = require('dayjs');
|
const dayjs = require('dayjs');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
state: {
|
state: {
|
||||||
time_text: "",
|
time_text: "",
|
||||||
format: "long"
|
format: "long"
|
||||||
},
|
},
|
||||||
onMounted(){
|
onMounted(){
|
||||||
this.start();
|
this.start();
|
||||||
},
|
},
|
||||||
start(){
|
start(){
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
this.makeString();
|
this.makeString();
|
||||||
this.start();
|
this.start();
|
||||||
},200);
|
},200);
|
||||||
},
|
},
|
||||||
makeString(){
|
makeString(){
|
||||||
if(this.state.format=="long"){
|
if(this.state.format=="long"){
|
||||||
this.update({time_text:dayjs().format("MMMM D, YYYY h:mm:ss A")});
|
this.update({time_text:dayjs().format("MMMM D, YYYY h:mm:ss A")});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
</timestamp>
|
</timestamp>
|
||||||
Loading…
x
Reference in New Issue
Block a user