Serve es5 bundle if exists
[k0tyk.git] / repo.js
blobca3750a965f926d1d476a2561a4df23ac147f6c0
1 #!/usr/bin/qjs -m
2 /** @license 0BSD 2020 k0tyk <k0tyk@pm.me> */
3 import * as os from "os";
4 import * as std from "std";
5 import * as M from "./m.js";
6 var mq = std.open(std.getenv("PWD") + "/.mq.js", "w+");
7 for (var i in M) {
8   var m = new M[i]();
9   mq.puts(`export class ${Object.getPrototypeOf(m).constructor.name}Q {
10   q = {
11     filters: [{ k: "", t: "", /** @type {any[]} */ v: [] }].splice(),
12     limit: 0,
13     offset: 0,
14     order: [{ k: "", t: "" }].splice(),
15   };
16   constructor() {\n`);
17   for (var k in m) {
18     mq.puts(`    this.${k} = {\n`);
19     for (var t of ["eq"])
20       mq.puts(`      /** @param {${typeof m[k]}} v */ eq: (v) => (
21         this.q.filters.push({ k: "${k}", t: "eq", v: [v] }), this
22       ),\n`);
23     mq.puts(`      /** @param {${typeof m[k]}[]} v */ in: (v) => (
24         this.q.filters.push({ k: "${k}", t: "in", v }), this
25       ),
26     };\n`);
27   }
28   mq.puts(`    this.order = {\n`);
29   for (var k in m)
30     mq.puts(`      ${k}: {
31         asc: () => (this.q.order.push({ k: "${k}", t: "asc" }), this),
32         desc: () => (this.q.order.push({ k: "${k}", t: "desc" }), this),
33       },\n`);
34   mq.puts(`    };
35     /** @param {number} v */ this.limit = (v) => ((this.q.limit = v), this);
36     /** @param {number} v */ this.offset = (v) => ((this.q.offset = v), this);
37   }
38 }\n`);
40 class Q {
41   filters = [{ k: "", t: "", /** @type {any[]} */ v: [] }].splice();
42   limit = 0;
43   offset = 0;
44   order = [{ k: "", t: "" }].splice();
46 export class Repo {
47   q = new Q();
48   /** @param {new () => any} m */ constructor(m) {
49     os.mkdir((this.d = std.getenv("PWD") + "/." + (this.m = m).name));
50   }
51   /** @param {any} a @param {any} b */ order = (a, b) => {
52     for (var { k, t } of this.q.order) {
53       if (a[k] > b[k]) return t == "asc" ? 1 : -1;
54       if (a[k] < b[k]) return t == "asc" ? -1 : 1;
55     }
56     return 0;
57   };
58   /** @param {any} x */ where = (x) => {
59     for (var { k, t, v } of this.q.filters) {
60       if (t == "eq" && x[k] == v[0]) continue;
61       if (t == "gte" && x[k] >= v[0]) continue;
62       if (t == "in" && v.indexOf(x[k]) !== -1) continue;
63       if (t == "lte" && x[k] <= v[0]) continue;
64       if (t == "not.eq" && x[k] !== v[0]) continue;
65       if (t == "not.gte" && x[k] < v[0]) continue;
66       if (t == "not.in" && v.indexOf(x[k]) == -1) continue;
67       if (t == "not.lte" && x[k] > v[0]) continue;
68       return false;
69     }
70     return true;
71   };
72   /** @param {{ q: Q }} mq */ delete(mq) {
73     os.exec([
74       "rm",
75       "-r",
76       "--",
77       ...this.get(mq).map((x) => `${this.d}/${x.id}`),
78     ]);
79   }
80   /** @param {{ q: Q }} mq */ get(mq) {
81     var q = (this.q = mq.q);
82     return os
83       .readdir(this.d)[0]
84       .filter((x) => !/^\.\.?$/.test(x))
85       .map((id) => {
86         var x = new this.m();
87         for (var k in x) {
88           var v = std.loadFile(`${this.d}/${id}/${k}`);
89           x[k] = typeof x[k] == "number" ? Number(v) : v;
90         }
91         return x;
92       })
93       .sort(this.order)
94       .filter(this.where)
95       .slice(q.offset || 0, (q.offset || 0) + (q.limit || Number.MAX_VALUE));
96   }
97   /** @param {any} diff @param {{ q: Q }} mq */ patch(diff, mq) {
98     for (var x of this.get(mq))
99       for (var k in new this.m())
100         if (k in diff && x != "id")
101           std.open(`${this.d}/${x.id}/${k}`, "w").puts(diff[k]);
102   }
103   /** @param {any[]} xs */ post(xs) {
104     for (var x of xs) {
105       os.mkdir(this.d + "/" + x.id);
106       for (var k in new this.m())
107         std.open(`${this.d}/${x.id}/${k}`, "w").puts(x[k]);
108     }
109   }