148 lines
3.3 KiB
TypeScript
148 lines
3.3 KiB
TypeScript
import { openDB, type IDBPDatabase } from "idb";
|
|
import type { Readable } from "svelte/motion";
|
|
import { readable, writable } from "svelte/store";
|
|
|
|
// #####################
|
|
// ###
|
|
export const intervalInSeconds = 15 * 60;
|
|
// ###
|
|
// #####################
|
|
|
|
|
|
export interface IGalleryImage {
|
|
id: IDBValidKey;
|
|
when: Date;
|
|
dataUrl: string;
|
|
}
|
|
|
|
export interface IFetchGalleryImagesArgs {
|
|
constraint?: IDBKeyRange;
|
|
direction?: IDBCursorDirection;
|
|
take?: number;
|
|
skip?: number;
|
|
}
|
|
|
|
export interface IFetchGalleryImagesPage {
|
|
count: number;
|
|
images: Array<IGalleryImage>;
|
|
}
|
|
|
|
export interface IFetchGalleryImagesQuery {
|
|
result: Readable<IFetchGalleryImagesPage>;
|
|
|
|
refresh() : Promise<void>;
|
|
|
|
setArgs(args: IFetchGalleryImagesArgs): void;
|
|
}
|
|
|
|
export interface IGalleryDb {
|
|
storeImage (image: Omit<IGalleryImage, 'id'>) : Promise<IDBValidKey>;
|
|
|
|
selectImages (index: string): IFetchGalleryImagesQuery;
|
|
}
|
|
|
|
const storeName = "images";
|
|
|
|
export async function initGallery() {
|
|
const updates = Array<CallableFunction>();
|
|
|
|
const db = await openDB("image-diary", 1, {
|
|
upgrade(db) {
|
|
const images = db.createObjectStore(storeName, { keyPath: "id", autoIncrement: true });
|
|
|
|
images.createIndex("ix_when", ["when"]);
|
|
},
|
|
});
|
|
|
|
const fnStoreImage = async (image: IGalleryImage) => {
|
|
const tx = db.transaction(storeName, "readwrite");
|
|
const id = await tx.objectStore(storeName).add(image);
|
|
|
|
await tx.done;
|
|
|
|
for (const update of updates) {
|
|
update();
|
|
}
|
|
|
|
return id;
|
|
}
|
|
|
|
const fnSelectImages = (index: string): IFetchGalleryImagesQuery => {
|
|
var skip = 0;
|
|
var take = 5;
|
|
var direction: IDBCursorDirection = 'next';
|
|
var constraint: IDBKeyRange | null = null;
|
|
|
|
const setters = new Array<(v: IFetchGalleryImagesPage) => void>();
|
|
|
|
const fnRefresh = async () => {
|
|
if (setters.length == 0) {
|
|
return;
|
|
}
|
|
|
|
// console.log('refresh', 'skip', skip, 'take', take, 'direction', direction, 'constraint', constraint);
|
|
|
|
const tx = db.transaction(storeName, "readonly");
|
|
const store = tx.objectStore(storeName);
|
|
const index = store.index("ix_when");
|
|
|
|
var shouldSkip = skip;
|
|
var shouldTake = take;
|
|
|
|
var result = new Array<IGalleryImage>();
|
|
|
|
const count = await index.count();
|
|
|
|
for await (const cursor of index.iterate(constraint, direction)) {
|
|
if (shouldSkip > 0) {
|
|
cursor.advance(skip);
|
|
|
|
shouldSkip = 0;
|
|
continue;
|
|
}
|
|
|
|
if (shouldTake > 0) {
|
|
result.push(cursor.value);
|
|
|
|
shouldTake--;
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
for (const set of setters) {
|
|
set({
|
|
count: count,
|
|
images: result
|
|
});
|
|
}
|
|
|
|
await tx.done;
|
|
};
|
|
|
|
return {
|
|
result: readable<IFetchGalleryImagesPage>({count: 0, images: []}, (set) => {
|
|
setters.push(set);
|
|
updates.push(fnRefresh);
|
|
|
|
return () => {
|
|
setters.splice(setters.indexOf(set), 1);
|
|
updates.splice(updates.indexOf(fnRefresh), 1);
|
|
};
|
|
}),
|
|
refresh: fnRefresh,
|
|
setArgs: (args) => {
|
|
constraint = args.constraint ?? null;
|
|
direction = args.direction ?? 'next';
|
|
skip = args.skip ?? 0;
|
|
take = args.take ?? 5;
|
|
},
|
|
}
|
|
}
|
|
|
|
return {
|
|
storeImage: fnStoreImage,
|
|
selectImages: fnSelectImages,
|
|
};
|
|
} |