diff --git a/cli/build.zsh b/cli/build.zsh index 82ea3aa..49067eb 100644 --- a/cli/build.zsh +++ b/cli/build.zsh @@ -8,7 +8,7 @@ mkdir ui cd ismism.ts deno bundle src/serve.ts ../cli/serve.js -deno bundle cli/dbinit.ts ../cli/dbinit.js +deno bundle cli/dbreset.ts ../cli/dbreset.js deno bundle cli/smstst.ts ../cli/smstst.js cp ui/index.html ../ui/index.html diff --git a/cli/dbimport.zsh b/cli/dbimport.zsh index a4ea054..d2a0ef5 100644 --- a/cli/dbimport.zsh +++ b/cli/dbimport.zsh @@ -4,9 +4,3 @@ for c in $coll; do echo importing $1/$c.json to ismism.$c mongoimport --jsonArray -d=ismism -c=$c --mode=upsert --file=$1/$c.json done - -mongosh ismism --eval 'db.getCollectionNames().forEach(coll => { - const idx = db.getCollection(coll).getIndexes() - console.log(`${coll}:`) - printjson(idx) -})' diff --git a/cli/dbpull.zsh b/cli/dbpull.zsh index 5d84210..7f56072 100644 --- a/cli/dbpull.zsh +++ b/cli/dbpull.zsh @@ -3,9 +3,9 @@ ssh i zsh < cli/dbexport.zsh rm -rf dbexport scp -r i:dbexport dbexport -deno run --allow-all cli/dbinit.js - -zsh cli/dbimport.zsh dbexport - cd dbexport zip -r ~/work/ismism/dbexport/dbexport-$(date +%Y%m%d-%H%M).zip . +cd .. + +deno run --allow-all cli/dbreset.js +zsh cli/dbimport.zsh dbexport diff --git a/cli/release.zsh b/cli/release.zsh index ae2b027..f333633 100644 --- a/cli/release.zsh +++ b/cli/release.zsh @@ -1,3 +1,4 @@ +zsh cli/dbpull.zsh zsh cli/build.zsh rm -rf release diff --git a/ismism.ts/cli/dbinit.ts b/ismism.ts/cli/dbinit.ts deleted file mode 100644 index f2903fb..0000000 --- a/ismism.ts/cli/dbinit.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { init } from "../src/db.ts" - -const coll = await init() -console.log(`collections created:\n${coll.join("\n")}`) diff --git a/ismism.ts/cli/dbreset.ts b/ismism.ts/cli/dbreset.ts new file mode 100644 index 0000000..2fa0945 --- /dev/null +++ b/ismism.ts/cli/dbreset.ts @@ -0,0 +1,4 @@ +import { reset } from "../src/db.ts" + +const coll = await reset() +console.log(`done resetting db:\n${coll.join("\n")}`) diff --git a/ismism.ts/deno.json b/ismism.ts/deno.json index 183d6ff..b3d597e 100644 --- a/ismism.ts/deno.json +++ b/ismism.ts/deno.json @@ -14,6 +14,7 @@ "include": [ "src/", "ui/", + "cli/", "tst/" ] }, @@ -32,6 +33,7 @@ "include": [ "src/", "ui/", + "cli/", "tst/" ] }, diff --git a/ismism.ts/src/db.ts b/ismism.ts/src/db.ts index c1606fd..80d5e6a 100644 --- a/ismism.ts/src/db.ts +++ b/ismism.ts/src/db.ts @@ -1,11 +1,12 @@ import { Collection, MongoClient } from "https://deno.land/x/mongo@v0.31.1/mod.ts" -import { Agenda, Fund, Dat, Soc, User, Work, Worker, Rec, Id, Role, Imgsrc, Txt } from "./typ.ts" +import { Agenda, Fund, Soc, User, Work, Worker, Imgsrc, Txt } from "./typ.ts" const uri = "mongodb://127.0.0.1:27017" const mongo = new MongoClient() await mongo.connect(uri) -export const db = mongo.database("ismism") +const db = mongo.database("ismism") + export const coll = { user: db.collection("user"), soc: db.collection("soc"), @@ -16,21 +17,10 @@ export const coll = { imgsrc: db.collection("imgsrc"), txt: db.collection("txt"), } +export type Coll = Collection +export type CollId = (typeof coll)["user" | "soc" | "agenda"] -export type CollRec = "work" | "worker" | "fund" - -export function collrec( - s: CollRec | string -): Collection | null { - switch (s) { - case "work": return coll.work - case "worker": return coll.worker - case "fund": return coll.fund - } - return null -} - -export async function init( +export async function reset( ) { try { await db.dropDatabase() } catch (e) { console.error(e) } await coll.user.createIndexes({ @@ -92,163 +82,3 @@ export async function init( }) return await db.listCollectionNames() } - -export function is_id( - id: number -) { - return id > 0 -} -export function not_id( - id: number -) { - return !(id > 0) -} - -export async function idname( - c: Collection, - id: number[], -): Promise<[number, string][]> { - id = [...new Set(id.filter(is_id))] - const d = await c.find( - { _id: { $in: id } }, - { projection: { _id: 1, name: 1 } } - ).toArray() - return d.map(d => [d._id, d.name]) -} - -async function uid_of_sid( - sid: number -): Promise | null> { - if (not_id(sid)) return null - const projection = { _id: 0, uid: 1 } - return await coll.soc.findOne({ _id: sid }, { projection }) ?? null -} - -export type URole = [number, [number, Role][]][] - -async function urole( - uid: number[] -): Promise { - const r = await coll.worker.aggregate([{ - $match: { "_id.uid": { $in: uid.filter(is_id) } } - }, { - $group: { _id: "$_id.uid", r: { $push: { aid: "$_id.aid", role: "$role" } } } - }]).toArray() as unknown as { _id: number, r: { aid: number, role: Role }[] }[] - return r.map(({ _id, r }) => [_id, r.map(r => [r.aid, r.role])]) -} - -export type NRec = { - worker: number, - work: number, - fund: number -} - -export async function nrec( -): Promise { - const [worker, work, fund] = await Promise.all([ - coll.worker.estimatedDocumentCount(), - coll.work.estimatedDocumentCount(), - coll.fund.estimatedDocumentCount(), - ]) - return { worker, work, fund } -} -export async function nrec_of_uid( - uid: number[] -): Promise { - const filter = { "_id.uid": { $in: uid.filter(is_id) } } - const [worker, work, fund] = await Promise.all([ - coll.worker.countDocuments(filter), - coll.work.countDocuments(filter), - coll.fund.countDocuments(filter), - ]) - return { worker, work, fund } -} -export async function nrec_of_aid( - aid: number -): Promise { - if (not_id(aid)) return { worker: 0, work: 0, fund: 0 } - const filter = { "_id.aid": aid } - const [worker, work, fund] = await Promise.all([ - coll.worker.countDocuments(filter), - coll.work.countDocuments(filter), - coll.fund.countDocuments(filter), - ]) - return { worker, work, fund } -} - -export type RecOf = { - rec: T[], - uname: [number, string][], - aname: [number, string][], - urole: URole, -} - -export async function rec_of_recent( - c: Collection, - utc_lt: number, - limit: number -): Promise> { - const rec = await c.find( - // deno-lint-ignore no-explicit-any - { "_id.utc": { $lt: utc_lt } } as any, { - sort: { "_id.utc": -1 }, - limit - }).toArray() - const uid = rec.flatMap(r => [r._id.uid, ...r.referer]) - const [uname, aname, ur] = await Promise.all([ - idname(coll.user, uid), - idname(coll.agenda, rec.map(r => r._id.aid)), - urole(uid), - ]) - return { rec, uname, aname, urole: ur } -} -export async function rec_of_uid( - c: Collection, - uid: number[], -): Promise> { - uid = uid.filter(is_id) - const rec = await c.find( - // deno-lint-ignore no-explicit-any - { "_id.uid": { $in: uid } } as any, - { sort: { "_id.utc": -1 } } - ).toArray() - const [uname, aname, ur] = await Promise.all([ - idname(coll.user, [...uid, ...rec.flatMap(r => r.referer)]), - idname(coll.agenda, rec.map(r => r._id.aid)), - urole(uid), - ]) - return { rec, uname, aname, urole: ur } -} -export async function rec_of_sid( - c: Collection, - sid: number, -): Promise> { - const uid = (await uid_of_sid(sid))?.uid ?? [] - return rec_of_uid(c, uid) -} -export async function rec_of_aid( - c: Collection, - aid: number, -): Promise> { - if (not_id(aid)) return { rec: [], uname: [], aname: [], urole: [] } - const rec = await c.find( - // deno-lint-ignore no-explicit-any - { "_id.aid": aid } as any, - { sort: { "_id.utc": -1 } } - ).toArray() - const uid = rec.flatMap(r => [r._id.uid, ...r.referer]) - const [uname, aname, ur] = await Promise.all([ - idname(coll.user, uid), - idname(coll.agenda, [aid]), - urole(uid), - ]) - return { rec, uname, aname, urole: ur } -} - -export async function dat( - c: Collection, - _id?: Dat["_id"] -): Promise { - if (!_id) return undefined - return await c.findOne({ _id }, { projection: { _id: 0 } }) -} diff --git a/ismism.ts/src/query.ts b/ismism.ts/src/query.ts index d1315b4..aed1e56 100644 --- a/ismism.ts/src/query.ts +++ b/ismism.ts/src/query.ts @@ -1,5 +1,5 @@ -import { collrec, rec_of_aid, rec_of_recent, rec_of_sid, rec_of_uid } from "./db.ts" import { agenda } from "./query/agenda.ts" +import { collrec, rec_of_aid, rec_of_recent, rec_of_sid, rec_of_uid } from "./query/rec.ts" import { soc } from "./query/soc.ts" import { user } from "./query/user.ts" diff --git a/ismism.ts/src/query/agenda.ts b/ismism.ts/src/query/agenda.ts index b1a4d4b..ca0b6f4 100644 --- a/ismism.ts/src/query/agenda.ts +++ b/ismism.ts/src/query/agenda.ts @@ -1,4 +1,6 @@ -import { coll, nrec_of_aid, nrec, dat } from "../db.ts" +import { coll } from "../db.ts" +import { dat } from "./dat.ts" +import { nrec, nrec_of_aid } from "./rec.ts" export async function agenda( ) { diff --git a/ismism.ts/src/query/dat.ts b/ismism.ts/src/query/dat.ts new file mode 100644 index 0000000..6930503 --- /dev/null +++ b/ismism.ts/src/query/dat.ts @@ -0,0 +1,10 @@ +import { Coll } from "../db.ts" +import { Dat } from "../typ.ts" + +export async function dat( + c: Coll, + _id?: Dat["_id"] +): Promise { + if (!_id) return undefined + return await c.findOne({ _id }, { projection: { _id: 0 } }) +} diff --git a/ismism.ts/src/query/id.ts b/ismism.ts/src/query/id.ts new file mode 100644 index 0000000..b15265e --- /dev/null +++ b/ismism.ts/src/query/id.ts @@ -0,0 +1,46 @@ +import { coll, CollId } from "../db.ts" +import { Agenda, Id, Role, Soc, User } from "../typ.ts" + +export function is_id( + id: Id["_id"] +) { + return id > 0 +} +export function not_id( + id: Id["_id"] +) { + return !(id > 0) +} + +export async function idname( + c: CollId, + id: Id["_id"][], +): Promise<[Id["_id"], Id["name"]][]> { + id = [...new Set(id.filter(is_id))] + const d = await c.find( + { _id: { $in: id } }, + { projection: { _id: 1, name: 1 } } + ).toArray() + return d.map(d => [d._id, d.name]) +} + +export async function uid_of_sid( + sid: Soc["_id"] +): Promise | null> { + if (not_id(sid)) return null + const projection = { _id: 0, uid: 1 } + return await coll.soc.findOne({ _id: sid }, { projection }) ?? null +} + +export type URole = [User["_id"], [Agenda["_id"], Role][]][] + +export async function urole( + uid: User["_id"][] +): Promise { + const r = await coll.worker.aggregate([{ + $match: { "_id.uid": { $in: uid.filter(is_id) } } + }, { + $group: { _id: "$_id.uid", r: { $push: { aid: "$_id.aid", role: "$role" } } } + }]).toArray() as unknown as { _id: number, r: { aid: number, role: Role }[] }[] + return r.map(({ _id, r }) => [_id, r.map(r => [r.aid, r.role])]) +} diff --git a/ismism.ts/src/query/rec.ts b/ismism.ts/src/query/rec.ts new file mode 100644 index 0000000..19127d2 --- /dev/null +++ b/ismism.ts/src/query/rec.ts @@ -0,0 +1,124 @@ +import { Coll, coll } from "../db.ts" +import { Agenda, Id, Rec, User } from "../typ.ts" +import { idname, is_id, not_id, uid_of_sid, urole, URole } from "./id.ts" + +export type NRec = { + worker: number, + work: number, + fund: number +} + +export async function nrec( +): Promise { + const [worker, work, fund] = await Promise.all([ + coll.worker.estimatedDocumentCount(), + coll.work.estimatedDocumentCount(), + coll.fund.estimatedDocumentCount(), + ]) + return { worker, work, fund } +} +export async function nrec_of_uid( + uid: User["_id"][] +): Promise { + const filter = { "_id.uid": { $in: uid.filter(is_id) } } + const [worker, work, fund] = await Promise.all([ + coll.worker.countDocuments(filter), + coll.work.countDocuments(filter), + coll.fund.countDocuments(filter), + ]) + return { worker, work, fund } +} +export async function nrec_of_aid( + aid: Agenda["_id"] +): Promise { + if (not_id(aid)) return { worker: 0, work: 0, fund: 0 } + const filter = { "_id.aid": aid } + const [worker, work, fund] = await Promise.all([ + coll.worker.countDocuments(filter), + coll.work.countDocuments(filter), + coll.fund.countDocuments(filter), + ]) + return { worker, work, fund } +} + +export type RecOf = { + rec: T[], + uname: [User["_id"], User["name"]][], + aname: [Agenda["_id"], Agenda["name"]][], + urole: URole, +} + +export type CollRec = "work" | "worker" | "fund" + +export function collrec( + c: CollRec | string +): Coll | null { + switch (c) { + case "work": return coll.work + case "worker": return coll.worker + case "fund": return coll.fund + } + return null +} + +export async function rec_of_recent( + c: Coll, + utc_lt: Id["utc"], + limit: number +): Promise> { + const rec = await c.find( + // deno-lint-ignore no-explicit-any + { "_id.utc": { $lt: utc_lt } } as any, { + sort: { "_id.utc": -1 }, + limit + }).toArray() + const uid = rec.flatMap(r => [r._id.uid, ...r.referer]) + const [uname, aname, ur] = await Promise.all([ + idname(coll.user, uid), + idname(coll.agenda, rec.map(r => r._id.aid)), + urole(uid), + ]) + return { rec, uname, aname, urole: ur } +} +export async function rec_of_uid( + c: Coll, + uid: Id["utc"][], +): Promise> { + uid = uid.filter(is_id) + const rec = await c.find( + // deno-lint-ignore no-explicit-any + { "_id.uid": { $in: uid } } as any, + { sort: { "_id.utc": -1 } } + ).toArray() + const [uname, aname, ur] = await Promise.all([ + idname(coll.user, [...uid, ...rec.flatMap(r => r.referer)]), + idname(coll.agenda, rec.map(r => r._id.aid)), + urole(uid), + ]) + return { rec, uname, aname, urole: ur } +} +export async function rec_of_sid( + c: Coll, + sid: number, +): Promise> { + const uid = (await uid_of_sid(sid))?.uid ?? [] + return rec_of_uid(c, uid) +} +export async function rec_of_aid( + c: Coll, + aid: number, +): Promise> { + if (not_id(aid)) return { rec: [], uname: [], aname: [], urole: [] } + const rec = await c.find( + // deno-lint-ignore no-explicit-any + { "_id.aid": aid } as any, + { sort: { "_id.utc": -1 } } + ).toArray() + const uid = rec.flatMap(r => [r._id.uid, ...r.referer]) + const [uname, aname, ur] = await Promise.all([ + idname(coll.user, uid), + idname(coll.agenda, [aid]), + urole(uid), + ]) + return { rec, uname, aname, urole: ur } +} diff --git a/ismism.ts/src/query/recent.ts b/ismism.ts/src/query/recent.ts index 04bbfe6..7f73d9b 100644 --- a/ismism.ts/src/query/recent.ts +++ b/ismism.ts/src/query/recent.ts @@ -1,4 +1,4 @@ -import { nrec } from "../db.ts"; +import { nrec } from "./rec.ts" export async function recent( ) { diff --git a/ismism.ts/src/query/soc.ts b/ismism.ts/src/query/soc.ts index e7aab38..f624961 100644 --- a/ismism.ts/src/query/soc.ts +++ b/ismism.ts/src/query/soc.ts @@ -1,5 +1,7 @@ -import { coll, idname, not_id, nrec_of_uid } from "../db.ts" +import { nrec_of_uid } from "./rec.ts" import { Soc } from "../typ.ts" +import { idname, not_id } from "./id.ts" +import { coll } from "../db.ts" async function soc_of_sid( sid: number diff --git a/ismism.ts/src/query/user.ts b/ismism.ts/src/query/user.ts index bc9bdab..1ff6a84 100644 --- a/ismism.ts/src/query/user.ts +++ b/ismism.ts/src/query/user.ts @@ -1,5 +1,7 @@ -import { coll, idname, not_id, nrec_of_uid } from "../db.ts" +import { coll } from "../db.ts" import { User } from "../typ.ts" +import { idname, not_id } from "./id.ts" +import { nrec_of_uid } from "./rec.ts" import { soc_of_uid } from "./soc.ts" async function user_of_uid( diff --git a/ismism.ts/tst/query.test.ts b/ismism.ts/tst/query.test.ts index e4e156e..83d134d 100644 --- a/ismism.ts/tst/query.test.ts +++ b/ismism.ts/tst/query.test.ts @@ -1,12 +1,16 @@ -import { assert, assertEquals } from "https://deno.land/std@0.154.0/testing/asserts.ts"; -import type { RecOf } from "../src/db.ts" +import { assert, assertEquals } from "https://deno.land/std@0.163.0/testing/asserts.ts" +import type { CollRec, RecOf } from "../src/query/rec.ts" import { Agenda, query, Soc, User } from "../src/query.ts" -import type { Work, Worker, Fund } from "../src/typ.ts" - +import type * as T from "../src/typ.ts" function p( - // deno-lint-ignore no-explicit-any - obj: any + obj: { + coll?: CollRec, + uid?: T.User["_id"], + sid?: T.Soc["_id"], + aid?: T.Agenda["_id"], + utc?: T.Id["utc"], + } ) { return new URLSearchParams(Object.entries(obj).map(([k, v]) => [k, `${v}`])) } @@ -18,9 +22,9 @@ Deno.test("user", async () => { const uname = new Map(u.uname) assert(uname.get(u.referer[0]) === "未明子") const [worker, work, fund] = await Promise.all([ - await query("rec_of_uid", p({ coll: "worker", uid: 728 })) as RecOf, - await query("rec_of_uid", p({ coll: "work", uid: 728 })) as RecOf, - await query("rec_of_uid", p({ coll: "fund", uid: 728 })) as RecOf, + await query("rec_of_uid", p({ coll: "worker", uid: 728 })) as RecOf, + await query("rec_of_uid", p({ coll: "work", uid: 728 })) as RecOf, + await query("rec_of_uid", p({ coll: "fund", uid: 728 })) as RecOf, ]) assert(worker.rec.length === 1 && work.rec.length === 2 && fund.rec.length === 3) assertEquals(work.urole, [[728, [[1, "志愿者"]]]]) @@ -35,9 +39,9 @@ Deno.test("soc", async () => { assert(uname.get(s.uid[1]) === "万大可" && uname.get(s.referer[0]) === "未明子") assert(s.nrec.worker === 2 && s.nrec.work === 4 && s.nrec.fund === 3) const [worker, work, fund] = await Promise.all([ - await query("rec_of_sid", p({ coll: "worker", sid: 2 })) as RecOf, - await query("rec_of_sid", p({ coll: "work", sid: 2 })) as RecOf, - await query("rec_of_sid", p({ coll: "fund", sid: 2 })) as RecOf, + await query("rec_of_sid", p({ coll: "worker", sid: 2 })) as RecOf, + await query("rec_of_sid", p({ coll: "work", sid: 2 })) as RecOf, + await query("rec_of_sid", p({ coll: "fund", sid: 2 })) as RecOf, ]) assert(worker.rec.length === 2 && work.rec.length === 4 && fund.rec.length === 3) assertEquals(work.urole.sort(), [[137, [[1, "志愿者"]]], [728, [[1, "志愿者"]]]].sort()) @@ -52,9 +56,9 @@ Deno.test("agenda", async () => { assertEquals(a1.referer, [1, 2]) assertEquals(a4.referer, [1, 2]) const [worker, work, fund] = await Promise.all([ - await query("rec_of_aid", p({ coll: "worker", aid: a1._id })) as RecOf, - await query("rec_of_aid", p({ coll: "work", aid: a1._id })) as RecOf, - await query("rec_of_aid", p({ coll: "fund", aid: a1._id })) as RecOf, + await query("rec_of_aid", p({ coll: "worker", aid: a1._id })) as RecOf, + await query("rec_of_aid", p({ coll: "work", aid: a1._id })) as RecOf, + await query("rec_of_aid", p({ coll: "fund", aid: a1._id })) as RecOf, ]) assert(worker.rec.length === 6 && work.rec.length === 8 && fund.rec.length === 6) assert(a4.imgsrc && a4.imgsrc.img.length === 4 && a1.imgsrc === undefined) @@ -64,9 +68,9 @@ Deno.test("agenda", async () => { Deno.test("recent", async () => { const { nrec: r } = await query("agenda", p({})) as Agenda const [worker, work, fund] = await Promise.all([ - await query("rec_of_recent", p({ coll: "worker", utc: Date.now() })) as RecOf, - await query("rec_of_recent", p({ coll: "work", utc: Date.now() })) as RecOf, - await query("rec_of_recent", p({ coll: "fund", utc: Date.now() })) as RecOf, + await query("rec_of_recent", p({ coll: "worker", utc: Date.now() })) as RecOf, + await query("rec_of_recent", p({ coll: "work", utc: Date.now() })) as RecOf, + await query("rec_of_recent", p({ coll: "fund", utc: Date.now() })) as RecOf, ]) assert(worker.rec.length === r.worker && work.rec.length == r.work && fund.rec.length == r.fund) }) diff --git a/ismism.ts/ui/bind.ts b/ismism.ts/ui/bind.ts index 7f21ece..754aaa0 100644 --- a/ismism.ts/ui/bind.ts +++ b/ismism.ts/ui/bind.ts @@ -1,10 +1,10 @@ // deno-lint-ignore-file no-window-prefix import { utc_medium, utc_short } from "../src/ontic/utc.ts" import type { Agenda, Soc, User } from "../src/query.ts" +import { NRec, RecOf } from "../src/query/rec.ts" import type { Goal, Tag, Rec, Work, Worker, Fund, Role } from "../src/typ.ts" -import type { NRec, RecOf } from "../src/db.ts" -const ver = "ismism-0.0.3-20221217" +const ver = "ismism-0.0.3-20221218" let hash = "" let agenda: Agenda const role = new Map>() @@ -186,8 +186,6 @@ function erecof( }) } - - function esum( el: HTMLElement, nrec: NRec diff --git a/ismism.ts/ui/index.html b/ismism.ts/ui/index.html index ba7da5f..3c674da 100644 --- a/ismism.ts/ui/index.html +++ b/ismism.ts/ui/index.html @@ -5,6 +5,7 @@ 主义主义 活动公示 + diff --git a/mongod.yaml b/mongod.yaml index bd88f09..5a9c633 100644 --- a/mongod.yaml +++ b/mongod.yaml @@ -6,3 +6,5 @@ storage: dbPath: db net: bindIp: 127.0.0.1, ::1 +setParameter: + notablescan: 1