web_lib

Common web application libraries
git clone https://radroots.dev/git/web_lib.git
Log | Files | Refs | LICENSE

commit caa3746d154386c09a4c171e3a01efa0f04a0aa8
parent 9be97c83006f2a88302d8b5705c4e6755a215170
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Fri, 30 Aug 2024 21:56:55 +0000

client: update iclient, add `nostr_note` model

Diffstat:
Mclient/src/capacitor/sql.ts | 158++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mclient/src/types.ts | 4++++
2 files changed, 144 insertions(+), 18 deletions(-)

diff --git a/client/src/capacitor/sql.ts b/client/src/capacitor/sql.ts @@ -1,7 +1,7 @@ -import { Capacitor } from '@capacitor/core'; import { CapacitorSQLite, SQLiteConnection, SQLiteDBConnection, type DBSQLiteValues, type capSQLiteChanges, type capSQLiteUpgradeOptions, type capSQLiteVersionUpgrade } from '@radroots/capacitor-sqlite'; -import { LocationGcsSchema, location_gcs_sort, models_initial_upgrade, parse_location_gcs_form_field_types, parse_location_gcss, type ILocationGcsGet, type ILocationGcsGetList, type ILocationGcsQueryBindValues, type ILocationGcsQueryBindValuesTuple, type ILocationGcsUpdate, type IModelsQueryBindValueOpt, type IModelsQueryBindValueTuple, type IModelsQueryParam, type LocationGcs, type LocationGcsFields, type LocationGcsFormFields } from "@radroots/models"; -import { err_msg, time_created_on, uuidv4 } from '@radroots/utils'; +import { Capacitor } from '@capacitor/core'; +import { time_created_on, uuidv4, err_msg } from '@radroots/utils'; +import { type IModelsQueryParam, type IModelsQueryBindValue, type IModelsQueryBindValueTuple, type IModelsQueryBindValueOpt, models_initial_upgrade, parse_location_gcs_form_field_types, location_gcs_sort, type ILocationGcsGetList, type ILocationGcsGet, type ILocationGcsUpdate, type ILocationGcsQueryBindValues, type ILocationGcsQueryBindValuesKey, type ILocationGcsQueryBindValuesTuple, parse_location_gcs, parse_location_gcss, type LocationGcs, type LocationGcsFields, type LocationGcsFormFields, LocationGcsSchema, parse_nostr_note_form_field_types, nostr_note_sort, type INostrNoteGetList, type INostrNoteGet, type INostrNoteUpdate, type INostrNoteQueryBindValues, type INostrNoteQueryBindValuesKey, type INostrNoteQueryBindValuesTuple, parse_nostr_note, parse_nostr_notes, type NostrNote, type NostrNoteFields, type NostrNoteFormFields, NostrNoteSchema} from "@radroots/models"; const models_upgrades = [ { @@ -20,9 +20,10 @@ export type IISQLiteServiceOpenDatabase = { version: number; }; -export type IISQLiteServiceMessage = - - | "*-location-gcs-geohash-unique" | "*-validate" +export type IISQLiteServiceMessage = + | "*-location-gcs-geohash-unique" + | "*-nostr-note-ev-id-unique" + | "*-validate" | "*-result" | "*-fields" | "*-open" @@ -183,6 +184,7 @@ export class CapacitorClientSQLite { } catch (e) { const { error } = err_msg(e, "execute"); if (String(e).includes("UNIQUE constraint failed: location_gcs.geohash")) return "*-location-gcs-geohash-unique"; + else if (String(e).includes("UNIQUE constraint failed: nostr_note.ev_id")) return "*-nostr-note-ev-id-unique"; return this.append_logs("*-exe", bv_o, query, error); }; }; @@ -237,7 +239,7 @@ export class CapacitorClientSQLite { }; } - private location_gcs_add_validate(opts: LocationGcsFormFields): LocationGcsFields | string[] { + private location_gcs_add_validate(opts: LocationGcsFormFields): LocationGcsFields | string[] { const opts_filtered = Object.entries(opts).reduce((acc: Record<string, (string | number)>, [key, value]) => { if (!!value) { switch (parse_location_gcs_form_field_types(key)) { @@ -254,7 +256,7 @@ export class CapacitorClientSQLite { const location_gcs_v = LocationGcsSchema.safeParse(opts_filtered); if (!location_gcs_v.success) return location_gcs_v.error.issues.map(i => i.message); else return { - ...location_gcs_v.data, + ...location_gcs_v.data, }; }; @@ -263,9 +265,9 @@ export class CapacitorClientSQLite { if (Array.isArray(optsv)) return optsv; const fields = Object.entries(optsv); if (!fields.length) return "*-fields"; - const id = uuidv4(); + const id = uuidv4(); const bind_values_tup: IModelsQueryBindValueTuple[] = [ - ["id", id], + ["id", id], ["created_at", time_created_on()] ]; for (const field of this.filter_bind_value_fields(fields)) bind_values_tup.push(field); @@ -273,7 +275,7 @@ export class CapacitorClientSQLite { const query = `INSERT INTO location_gcs (${bind_values_tup.map(([k]) => k).join(", ")}) VALUES (${bind_values_tup.map((_, num) => `$${1 + num}`).join(", ")});`; try { const result = await this.execute(query, bind_values); - if (typeof result !== "string" && typeof result.changes?.changes === "number" && result.changes.changes > 0) return { id }; + if (typeof result !== "string" && typeof result.changes?.changes === "number" && result.changes.changes > 0) return { id }; else if (typeof result === "string") return result; return "*-result"; } catch (e) { @@ -281,12 +283,12 @@ export class CapacitorClientSQLite { }; }; - private location_gcs_query_bind_values = (opts: ILocationGcsQueryBindValues): ILocationGcsQueryBindValuesTuple => { + private location_gcs_query_bind_values = (opts: ILocationGcsQueryBindValues): ILocationGcsQueryBindValuesTuple => { if ("id" in opts) return ["id", opts.id]; - else return ["geohash", opts.geohash]; + else return ["geohash", opts.geohash]; }; - private location_gcs_get_query_list = (opts: ILocationGcsGetList): IModelsQueryParam => { + private location_gcs_get_query_list = (opts: ILocationGcsGetList): IModelsQueryParam => { const sort = location_gcs_sort[opts.sort || "newest"]; let query = ""; let bind_values = null; @@ -300,7 +302,7 @@ export class CapacitorClientSQLite { }; }; - private location_gcs_get_parse_opts = (opts: ILocationGcsGet): IModelsQueryParam => { + private location_gcs_get_parse_opts = (opts: ILocationGcsGet): IModelsQueryParam => { if ("list" in opts) return this.location_gcs_get_query_list(opts); else { const bv_tup = this.location_gcs_query_bind_values(opts); @@ -311,7 +313,7 @@ export class CapacitorClientSQLite { }; }; - public async location_gcs_get(opts: ILocationGcsGet): Promise<LocationGcs[] | IISQLiteServiceMessage> { + public async location_gcs_get(opts: ILocationGcsGet): Promise<LocationGcs[] | IISQLiteServiceMessage> { const { query, bind_values } = this.location_gcs_get_parse_opts(opts); try { const response = await this.select(query, bind_values); @@ -326,7 +328,7 @@ export class CapacitorClientSQLite { }; }; - public async location_gcs_delete(opts: ILocationGcsQueryBindValues): Promise<true | IISQLiteServiceMessage> { + public async location_gcs_delete(opts: ILocationGcsQueryBindValues): Promise<true | IISQLiteServiceMessage> { const bv_tup = this.location_gcs_query_bind_values(opts); const bind_values = [bv_tup[1]]; const query = `DELETE FROM location_gcs WHERE ${bv_tup[0]} = $1;`; @@ -340,7 +342,7 @@ export class CapacitorClientSQLite { }; }; - public async location_gcs_update(opts: ILocationGcsUpdate): Promise<true | string[] | IISQLiteServiceMessage> { + public async location_gcs_update(opts: ILocationGcsUpdate): Promise<true | string[] | IISQLiteServiceMessage> { const optsv = this.location_gcs_add_validate(opts.fields); if (Array.isArray(optsv)) return optsv; const fields = this.filter_bind_value_fields(Object.entries(optsv)); @@ -357,4 +359,124 @@ export class CapacitorClientSQLite { return this.append_logs("*", [], query, ["location_gcs_update", e]); }; }; + + private nostr_note_add_validate(opts: NostrNoteFormFields): NostrNoteFields | string[] { + const opts_filtered = Object.entries(opts).reduce((acc: Record<string, (string | number)>, [key, value]) => { + if (!!value) { + switch (parse_nostr_note_form_field_types(key)) { + case "string": + acc[key] = value; + break; + case "number": + acc[key] = Number(value); + break; + } + }; + return acc; + }, {}); + const nostr_note_v = NostrNoteSchema.safeParse(opts_filtered); + if (!nostr_note_v.success) return nostr_note_v.error.issues.map(i => i.message); + else return { + ...nostr_note_v.data, + }; + }; + + public async nostr_note_add(opts: NostrNoteFormFields): Promise<{ id: string; } | string[] | IISQLiteServiceMessage> { + const optsv = this.nostr_note_add_validate(opts); + if (Array.isArray(optsv)) return optsv; + const fields = Object.entries(optsv); + if (!fields.length) return "*-fields"; + const id = uuidv4(); + const bind_values_tup: IModelsQueryBindValueTuple[] = [ + ["id", id], + ["created_at", time_created_on()] + ]; + for (const field of this.filter_bind_value_fields(fields)) bind_values_tup.push(field); + const bind_values = bind_values_tup.map(([_, v]) => v); + const query = `INSERT INTO nostr_note (${bind_values_tup.map(([k]) => k).join(", ")}) VALUES (${bind_values_tup.map((_, num) => `$${1 + num}`).join(", ")});`; + try { + const result = await this.execute(query, bind_values); + if (typeof result !== "string" && typeof result.changes?.changes === "number" && result.changes.changes > 0) return { id }; + else if (typeof result === "string") return result; + return "*-result"; + } catch (e) { + return this.append_logs("*", bind_values, query, ["nostr_note_add", e]); + }; + }; + + private nostr_note_query_bind_values = (opts: INostrNoteQueryBindValues): INostrNoteQueryBindValuesTuple => { + return ["id", opts.id]; + }; + + private nostr_note_get_query_list = (opts: INostrNoteGetList): IModelsQueryParam => { + const sort = nostr_note_sort[opts.sort || "newest"]; + let query = ""; + let bind_values = null; + if (opts.list[0] === "all") { + query = `SELECT * FROM nostr_note ORDER BY ${sort};`; + } + if (!query) throw new Error("Error: Missing query (nostr_note_get_query_list)") + return { + query, + bind_values + }; + }; + + private nostr_note_get_parse_opts = (opts: INostrNoteGet): IModelsQueryParam => { + if ("list" in opts) return this.nostr_note_get_query_list(opts); + else { + const bv_tup = this.nostr_note_query_bind_values(opts); + return { + query: `SELECT * FROM nostr_note WHERE ${bv_tup[0]} = $1;`, + bind_values: [bv_tup[1]] + }; + }; + }; + + public async nostr_note_get(opts: INostrNoteGet): Promise<NostrNote[] | IISQLiteServiceMessage> { + const { query, bind_values } = this.nostr_note_get_parse_opts(opts); + try { + const response = await this.select(query, bind_values); + if (typeof response === "string") return response; + else { + const result = parse_nostr_notes(response); + if (result) return result; + } + return "*-result"; + } catch (e) { + return this.append_logs("*", opts, query, ["nostr_note_get", e]); + }; + }; + + public async nostr_note_delete(opts: INostrNoteQueryBindValues): Promise<true | IISQLiteServiceMessage> { + const bv_tup = this.nostr_note_query_bind_values(opts); + const bind_values = [bv_tup[1]]; + const query = `DELETE FROM nostr_note WHERE ${bv_tup[0]} = $1;`; + try { + const response = await this.execute(query, bind_values); + if (typeof response === "string") return response; + else if (typeof response.changes?.changes === "number" && response.changes.changes > 0) return true; + return "*-result"; + } catch (e) { + return this.append_logs("*", [], query, ["nostr_note_delete", e]); + }; + }; + + public async nostr_note_update(opts: INostrNoteUpdate): Promise<true | string[] | IISQLiteServiceMessage> { + const optsv = this.nostr_note_add_validate(opts.fields); + if (Array.isArray(optsv)) return optsv; + const fields = this.filter_bind_value_fields(Object.entries(optsv)); + if (!fields.length) return "*-fields"; + const bv_tup = this.nostr_note_query_bind_values(opts.on); + const bind_values = [bv_tup[1], ...fields.map(([_, v]) => v)]; + const query = `UPDATE nostr_note SET ${fields.map(([k], num) => `${k} = $${1 + num}`).join(", ")} WHERE ${bv_tup[0]} = $1;`; + try { + const response = await this.execute(query, bind_values); + if (typeof response === "string") return response; + else if (typeof response.changes?.changes === "number" && response.changes.changes > 0) return true; + return "*-result"; + } catch (e) { + return this.append_logs("*", [], query, ["nostr_note_update", e]); + }; + }; }; \ No newline at end of file diff --git a/client/src/types.ts b/client/src/types.ts @@ -4,6 +4,7 @@ import { type ScanResult } from '@radroots/capacitor-bluetooth-le'; import { IOSSettings, type AndroidSettings } from '@radroots/capacitor-native-settings'; import { type ConnectToWifiResult, type GetCurrentWifiResult, type PermissionStatus, type ScanWifiResult } from '@radroots/capacitor-wifi'; import { type ErrorResponse } from '@radroots/utils'; +import { CapacitorClientSQLite } from './capacitor/sql'; export type IClient = { nostr: IClientNostr; @@ -23,6 +24,7 @@ export type IClient = { window: IClientWindow; ble: IClientBluetoothLe; settings: IClientSettings; + db: IClientDb; }; export type IClientNostr = { @@ -32,6 +34,8 @@ export type IClientNostr = { export type IClientPlatform = `androiď` | `ios` | `web`; +export type IClientDb = CapacitorClientSQLite; + export type IClientKeystore = { init: () => Promise<void>; set(key: string, val: string): Promise<boolean>;