@desmat/redis-store 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/example.js CHANGED
@@ -7,22 +7,131 @@ const index_1 = __importDefault(require("./index"));
7
7
  require('dotenv').config();
8
8
  const ThingOptions = {
9
9
  lookups: {
10
- user: "createdBy", // enable .find({ user: <USERID> })
10
+ user: "createdBy",
11
+ category: "category", // enable .find({ category: <CATEGORYID> })
11
12
  },
12
13
  };
13
14
  // with environment variables KV_REST_API_URL and KV_REST_API_TOKEN
14
15
  // or `url` and `token` keys provided to RedisStore constructor
16
+ const debug = true;
15
17
  const store = {
16
- users: new index_1.default({ key: "user" }),
17
- haikuUsers: new index_1.default({ key: "haikuuser" }),
18
- userHaikus: new index_1.default({ key: "userhaiku" }),
19
- // things: new RedisStore<Thing>({ key: "thing", options: ThingOptions }),
18
+ users: new index_1.default({ key: "example-user", debug }),
19
+ categories: new index_1.default({ key: "example-category", setKey: "example-categories", debug }),
20
+ things: new index_1.default({ key: "example-thing", options: ThingOptions, debug }),
20
21
  };
22
+ async function cleanup() {
23
+ // cleanup all from previous session
24
+ let [users, categories, things,] = await Promise.all([
25
+ store.users.ids({ scan: "*" }),
26
+ store.categories.ids({ scan: "*" }),
27
+ store.things.ids({ scan: "*" }),
28
+ ]);
29
+ // console.log("users to delete", { usersToDelete, postsToDelete, userPostsToDelete });
30
+ return Promise.all([
31
+ // @ts-ignore
32
+ ...Array.from(users).map((id) => store.users.delete(id, { hardDelete: true })),
33
+ // @ts-ignore
34
+ ...Array.from(categories).map((id) => store.categories.delete(id, { hardDelete: true })),
35
+ // @ts-ignore
36
+ ...Array.from(things).map((id) => store.things.delete(id, { hardDelete: true })),
37
+ ]);
38
+ }
21
39
  (async function () {
22
- const [users, haikuUsers, userHaikus] = await Promise.all([
23
- store.users.ids({ scan: "*", count: 999999 }),
24
- store.haikuUsers.ids({ scan: "*", count: 999999 }),
25
- store.userHaikus.ids({ scan: "*", count: 999999 }),
40
+ // fully cleanup previous session
41
+ // await cleanup();
42
+ // create users
43
+ const users = await Promise.all([
44
+ store.users.create({ name: "User One" }),
45
+ store.users.create({ name: "User Two" }),
46
+ ]);
47
+ // Redis commands executed:
48
+ // JSON.SET user:<UUID> $ '{ "id": "<UUID>", "createdAt": <TIMEINMILLIS>, "name": "User One" }'
49
+ // ZADD users <TIMEINMILLIS> <UUID>
50
+ // ...
51
+ console.log("users", users);
52
+ // users (2 entries): [
53
+ // { id: '<UUID>', createdAt: <TIMEINMILLIS>, name: 'User One' },
54
+ // ...
55
+ // ]
56
+ // create categories and things
57
+ const categories = await Promise.all([
58
+ store.categories.create({ id: "category1", name: "Category One" }),
59
+ store.categories.create({ id: "category2", name: "Category Two" }),
60
+ ]);
61
+ const things = await Promise.all([
62
+ store.things.create({
63
+ createdBy: users[0].id,
64
+ category: categories[0].id,
65
+ label: "A thing for user one",
66
+ }),
67
+ store.things.create({
68
+ createdBy: users[0].id,
69
+ category: categories[0].id,
70
+ label: "Another thing for user one",
71
+ }),
72
+ store.things.create({
73
+ createdBy: users[0].id,
74
+ category: categories[1].id,
75
+ label: "Yet another thing for user one",
76
+ }),
77
+ store.things.create({
78
+ createdBy: users[1].id,
79
+ category: categories[1].id,
80
+ label: "A thing for user two",
81
+ }),
82
+ ]);
83
+ // Adding additional sets for lookup:
84
+ // JSON.SET thing:<UUID> $ '{ "id": "<UUID>", "createdAt": <TIMEINMILLIS>, "createdBy": "<USER_UUID>", "categoryId": "<CATEGORY_UUID>", label": "Another thing for user one" }'
85
+ // ZADD things <TIMEINMILLIS> <UUID>
86
+ // ZADD things:user:<USER_UUID> <TIMEINMILLIS> <UUID>
87
+ // ZADD things:category:<CATEGORY_UUID> <TIMEINMILLIS> <UUID>
88
+ // ...
89
+ console.log("things", things);
90
+ // things (4 entries): [
91
+ // {
92
+ // id: '<UUID>',
93
+ // createdAt: <TIMEINMILLIS>,
94
+ // createdBy: '<USER_UUID>',
95
+ // category: `<CATEGORY_UUID>',
96
+ // label: 'A thing for user one'
97
+ // },
98
+ // ...
99
+ // ]
100
+ // all things
101
+ const allThings = await store.things.find();
102
+ // Get thing ids from set of all things then pull their values:
103
+ // ZRANGE things 0 -1 REV
104
+ // JSON.MGET thing:<THING1_UUID> thing:<THING2_UUID> ...
105
+ console.log("allThings", allThings); // 4 entries
106
+ // latest things from first user
107
+ const latestUserThings = await store.things.find({ user: users[0].id });
108
+ // Get thing ids from set of user lookup things then pull their values:
109
+ // ZRANGE things:user:<USER_UUID> 0 -1 REV
110
+ // JSON.MGET thing:<THING1_UUID> thing:<THING2_UUID> thing:<THING3_UUID>
111
+ console.log("latestUserThings", latestUserThings); // 3 entries
112
+ // latest things from first user in first category
113
+ const latestUserThingsOfCategory1 = await store.things.find({
114
+ user: users[0].id,
115
+ category: categories[0].id,
116
+ });
117
+ // Get thing ids from both set of user lookup things
118
+ // and category lookup things, calculate intersection,
119
+ // then pull their values:
120
+ // ZRANGE things:user:<USER_UUID> 0 -1 REV
121
+ // ZRANGE things:category:<CATEGORY_UUID> 0 -1 REV
122
+ // JSON.MGET thing:<THING1_UUID> thing:<THING2_UUID> thing:<THING3_UUID>
123
+ console.log("latestUserThingsOfCategory1", latestUserThingsOfCategory1); // 2 entries
124
+ // cleanup from this session (soft delete by default)
125
+ await Promise.all([
126
+ ...users.map((user) => store.users.delete(user.id)),
127
+ ...categories.map((user) => store.categories.delete(user.id)),
128
+ ...things.map((thing) => store.things.delete(thing.id)),
26
129
  ]);
27
- console.log("counts", { users: users.size, haikuUsers: haikuUsers.size, userHaikus: userHaikus.size });
130
+ // JSON.SET user:<UUID> $.deletedAt <TIMEINMILLIS>
131
+ // ZREM users <UUID>
132
+ // ...
133
+ // JSON.SET thing:<UUID> $.deletedAt <TIMEINMILLIS>
134
+ // ZREM things <UUID>
135
+ // ZREM testthings:user:<USER_UUID> <UUID>
136
+ // ...
28
137
  })();
package/dist/index.js CHANGED
@@ -22,6 +22,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
22
22
  const moment_1 = __importDefault(require("moment"));
23
23
  const utils_1 = require("@desmat/utils");
24
24
  const redis_1 = require("@upstash/redis");
25
+ // polyfill Set.intersection
26
+ ;
27
+ (function () {
28
+ // @ts-ignore
29
+ if (!Set.prototype.intersection) {
30
+ // @ts-ignore
31
+ Set.prototype.intersection = function (other) {
32
+ return new Set(Array.from(this).filter((value) => other.has(value)));
33
+ };
34
+ }
35
+ })();
25
36
  class RedisStore {
26
37
  constructor({ url, token, key, setKey, options, debug, }) {
27
38
  const _url = url || process.env.KV_REST_API_URL;
@@ -126,47 +137,30 @@ class RedisStore {
126
137
  delete query.offset;
127
138
  delete query.count;
128
139
  const queryEntries = query && Object.entries(query);
129
- // TODO: support more than one
130
- if ((queryEntries === null || queryEntries === void 0 ? void 0 : queryEntries.length) > 1) {
131
- throw `redis.find(query) only supports a single query entry pair`;
140
+ // .ids() or .ids({})
141
+ if (!(queryEntries === null || queryEntries === void 0 ? void 0 : queryEntries.length)) {
142
+ // get all keys via the index set
143
+ return new Set(await this.redis.zrange(`${this.setKey}`, min, max, { rev: true }));
132
144
  }
133
- let ids = [];
134
- const queryEntry = queryEntries && queryEntries[0];
135
- const [queryKey, queryVal] = queryEntry || [];
136
- if (queryKey == "id" && Array.isArray(queryVal)) {
137
- this.debug && console.log(`RedisStore<${this.key}>.ids special case: query is for IDs`, { ids: queryVal });
138
- ids = queryVal;
139
- }
140
- else {
141
- if (queryKey) {
142
- /* NOT SUPPORTED FOR NOW
143
- if (queryVal == "*") {
144
- // lookup keys via the foos:bars lookup set
145
- keys = (await this.kv.zrange(`${this.setKey}:${queryKey}s`, 0, -1))
146
- // @ts-ignore
147
- .map((key: string) => `${this.key}:${key}`);
148
- } else */ if (queryVal) {
149
- // lookup keys via the foos:bar:123 lookup set
150
- // @ts-ignore
151
- ids = await this.redis.zrange(`${this.setKey}:${queryKey}:${queryVal}`, min, max, { rev: true });
152
- }
153
- else {
154
- throw `redis.find(query) query must have key and value`;
155
- }
156
- this.debug && console.log(`RedisStore<${this.key}>.ids queried lookup key`, { query, ids });
145
+ // .ids({ foo: "FOO", bar: "BAR", ... })
146
+ const setOfIds = await Promise.all(queryEntries.map(([queryKey, queryVal]) => {
147
+ if (queryVal) {
148
+ // lookup keys via the foos:bar:123 lookup set
149
+ return this.redis.zrange(`${this.setKey}:${queryKey}:${queryVal}`, min, max, { rev: true });
157
150
  }
158
151
  else {
159
- // get all keys via the index set
160
- // @ts-ignore
161
- ids = await this.redis.zrange(`${this.setKey}`, min, max, { rev: true });
152
+ throw `redis.find(query) query must have key and value`;
162
153
  }
163
- }
164
- return new Set(ids);
154
+ }));
155
+ // @ts-ignore
156
+ const ids = setOfIds.reduce((prev, curr) => new Set(curr).intersection(prev || new Set(curr)), undefined);
157
+ this.debug && console.log(`RedisStore<${this.key}>.ids queried lookup key`, { query, setOfIds, ids });
158
+ return ids;
165
159
  }
166
160
  async find(query = {}) {
167
161
  this.debug && console.log(`RedisStore<${this.key}>.find`, { query });
168
162
  const keys = Array.isArray(query.id)
169
- ? Array.from(await this.ids(query))
163
+ ? query.id
170
164
  .map((id) => id && this.valueKey(id))
171
165
  .filter(Boolean)
172
166
  : Array.from(await this.ids(query))
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,323 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const index_1 = __importDefault(require("./index"));
7
+ require('dotenv').config();
8
+ const debug = true;
9
+ const store = {
10
+ users: new index_1.default({
11
+ key: "ViceUser",
12
+ // options: Options,
13
+ debug,
14
+ }),
15
+ vices: new index_1.default({
16
+ key: "Vice",
17
+ // options: Options,
18
+ debug,
19
+ }),
20
+ categories: new index_1.default({
21
+ key: "ViceCategory",
22
+ setKey: "ViceCategories",
23
+ options: {
24
+ lookups: {
25
+ vice: "viceId",
26
+ }
27
+ },
28
+ debug,
29
+ }),
30
+ types: new index_1.default({
31
+ key: "ViceType",
32
+ options: {
33
+ lookups: {
34
+ category: "categoryId",
35
+ }
36
+ },
37
+ debug,
38
+ }),
39
+ entries: new index_1.default({
40
+ key: "ViceEntry",
41
+ setKey: "ViceEntries",
42
+ options: {
43
+ lookups: {
44
+ vice: "viceId",
45
+ type: "typeId",
46
+ user: "createdBy",
47
+ }
48
+ },
49
+ debug,
50
+ }),
51
+ hourlySummaries: new index_1.default({
52
+ key: "ViceHourlySummary",
53
+ setKey: "ViceHourlySummaries",
54
+ // options: Options,
55
+ debug,
56
+ }),
57
+ dailySummaries: new index_1.default({
58
+ key: "ViceDailySummary",
59
+ setKey: "ViceDailySummaries",
60
+ // options: Options,
61
+ debug,
62
+ }),
63
+ };
64
+ async function cleanup() {
65
+ // cleanup all from previous session
66
+ let [vices, categories, types, entries, hourlySummaries, dailySummaries,] = await Promise.all([
67
+ store.vices.ids({ scan: "*" }),
68
+ store.categories.ids({ scan: "*" }),
69
+ store.types.ids({ scan: "*" }),
70
+ store.entries.ids({ scan: "*" }),
71
+ store.hourlySummaries.ids({ scan: "*" }),
72
+ store.dailySummaries.ids({ scan: "*" }),
73
+ ]);
74
+ // console.log("users to delete", { usersToDelete, postsToDelete, userPostsToDelete });
75
+ return Promise.all([
76
+ // @ts-ignore
77
+ ...Array.from(vices).map((id) => store.vices.delete(id, { hardDelete: true })),
78
+ // @ts-ignore
79
+ ...Array.from(categories).map((id) => store.categories.delete(id, { hardDelete: true })),
80
+ // @ts-ignore
81
+ ...Array.from(types).map((id) => store.types.delete(id, { hardDelete: true })),
82
+ // @ts-ignore
83
+ ...Array.from(entries).map((id) => store.entries.delete(id, { hardDelete: true })),
84
+ // @ts-ignore
85
+ ...Array.from(hourlySummaries).map((id) => store.hourlySummaries.delete(id, { hardDelete: true })),
86
+ // @ts-ignore
87
+ ...Array.from(dailySummaries).map((id) => store.dailySummaries.delete(id, { hardDelete: true })),
88
+ ]);
89
+ }
90
+ (async function () {
91
+ await cleanup();
92
+ const userId = "user_2nnoSDL2mdJD8XiQpYKqBT3pEK5";
93
+ const vices = await Promise.all([
94
+ store.vices.create({
95
+ name: "alcohol",
96
+ unit: "standard drink (14g)",
97
+ }),
98
+ ]);
99
+ console.log("created", { vices });
100
+ const categories = await Promise.all([
101
+ store.categories.create({
102
+ vice: vices[0].name,
103
+ viceId: vices[0].id,
104
+ name: "beer/cider",
105
+ }),
106
+ store.categories.create({
107
+ vice: vices[0].name,
108
+ viceId: vices[0].id,
109
+ name: "wine",
110
+ }),
111
+ store.categories.create({
112
+ vice: vices[0].name,
113
+ viceId: vices[0].id,
114
+ name: "spirits/cocktails",
115
+ }),
116
+ ]);
117
+ console.log("created", { categories });
118
+ const types = await Promise.all([
119
+ store.types.create({
120
+ vice: vices[0].id,
121
+ viceId: vices[0].id,
122
+ category: categories[0].name,
123
+ categoryId: categories[0].id,
124
+ name: "beer (small)",
125
+ units: 0.75,
126
+ }),
127
+ store.types.create({
128
+ vice: vices[0].name,
129
+ viceId: vices[0].id,
130
+ category: categories[0].name,
131
+ categoryId: categories[0].id,
132
+ name: "beer",
133
+ units: 1,
134
+ }),
135
+ store.types.create({
136
+ vice: vices[0].name,
137
+ viceId: vices[0].id,
138
+ category: categories[0].name,
139
+ categoryId: categories[0].id,
140
+ name: "beer (strong)",
141
+ units: 1.25,
142
+ }),
143
+ store.types.create({
144
+ vice: vices[0].name,
145
+ viceId: vices[0].id,
146
+ category: categories[0].name,
147
+ categoryId: categories[0].id,
148
+ name: "beer (large)",
149
+ units: 1.25,
150
+ }),
151
+ store.types.create({
152
+ vice: vices[0].name,
153
+ viceId: vices[0].id,
154
+ category: categories[0].name,
155
+ categoryId: categories[0].id,
156
+ name: "beer (xlarge/xstrong/large-strong)",
157
+ units: 1.5,
158
+ }),
159
+ store.types.create({
160
+ vice: vices[0].name,
161
+ viceId: vices[0].id,
162
+ category: categories[1].name,
163
+ categoryId: categories[1].id,
164
+ name: "wine (2.5oz)",
165
+ units: 0.5,
166
+ }),
167
+ store.types.create({
168
+ vice: vices[0].name,
169
+ viceId: vices[0].id,
170
+ category: categories[1].name,
171
+ categoryId: categories[1].id,
172
+ name: "wine (3.5oz)",
173
+ units: 0.75,
174
+ }),
175
+ store.types.create({
176
+ vice: vices[0].name,
177
+ viceId: vices[0].id,
178
+ category: categories[1].name,
179
+ categoryId: categories[1].id,
180
+ name: "wine (5oz)",
181
+ units: 1,
182
+ }),
183
+ store.types.create({
184
+ vice: vices[0].name,
185
+ viceId: vices[0].id,
186
+ category: categories[1].name,
187
+ categoryId: categories[1].id,
188
+ name: "wine (6.5oz)",
189
+ units: 1.25,
190
+ }),
191
+ store.types.create({
192
+ vice: vices[0].name,
193
+ viceId: vices[0].id,
194
+ category: categories[1].name,
195
+ categoryId: categories[1].id,
196
+ name: "wine (7.5oz)",
197
+ units: 1.5,
198
+ }),
199
+ store.types.create({
200
+ vice: vices[0].name,
201
+ viceId: vices[0].id,
202
+ category: categories[1].name,
203
+ categoryId: categories[1].id,
204
+ name: "wine (9oz)",
205
+ units: 1.75,
206
+ }),
207
+ store.types.create({
208
+ vice: vices[0].name,
209
+ viceId: vices[0].id,
210
+ category: categories[1].name,
211
+ categoryId: categories[1].id,
212
+ name: "wine (500ml bottle)",
213
+ units: 3.5,
214
+ }),
215
+ store.types.create({
216
+ vice: vices[0].name,
217
+ viceId: vices[0].id,
218
+ category: categories[1].name,
219
+ categoryId: categories[1].id,
220
+ name: "wine (750ml bottle)",
221
+ units: 5,
222
+ }),
223
+ store.types.create({
224
+ vice: vices[0].name,
225
+ viceId: vices[0].id,
226
+ category: categories[2].name,
227
+ categoryId: categories[2].id,
228
+ name: "spirit (1oz)",
229
+ units: 0.75,
230
+ }),
231
+ store.types.create({
232
+ vice: vices[0].name,
233
+ viceId: vices[0].id,
234
+ category: categories[2].name,
235
+ categoryId: categories[2].id,
236
+ name: "spirit (1.5oz)",
237
+ units: 1,
238
+ }),
239
+ store.types.create({
240
+ vice: vices[0].name,
241
+ viceId: vices[0].id,
242
+ category: categories[2].name,
243
+ categoryId: categories[2].id,
244
+ name: "spirit (2oz)",
245
+ units: 1.25,
246
+ }),
247
+ store.types.create({
248
+ vice: vices[0].name,
249
+ viceId: vices[0].id,
250
+ category: categories[2].name,
251
+ categoryId: categories[2].id,
252
+ name: "cocktail",
253
+ units: 1.5,
254
+ }),
255
+ ]);
256
+ // console.log("created", { types });
257
+ // const entries = await Promise.all([
258
+ // store.entries.create({
259
+ // ])
260
+ // console.log("created", { types });
261
+ // const entries = await Promise.all([
262
+ // store.entries.create({
263
+ // createdBy: userId,
264
+ // vice: vices[0].id,
265
+ // categoryId: categories[0].id,
266
+ // categoryName: categories[0].name,
267
+ // typeId: types[2].id,
268
+ // units: 1.5,
269
+ // date: "20241107",
270
+ // hour: "14",
271
+ // }),
272
+ // store.entries.create({
273
+ // createdBy: userId,
274
+ // vice: vices[0].id,
275
+ // categoryId: categories[0].id,
276
+ // categoryName: categories[0].name,
277
+ // typeId: types[2].id,
278
+ // units: ,
279
+ // date: "20241107",
280
+ // hour: "",
281
+ // }),
282
+ // store.entries.create({
283
+ // createdBy: userId,
284
+ // vice: vices[0].id,
285
+ // categoryId: categories[0].id,
286
+ // categoryName: categories[0].name,
287
+ // typeId: types[2].id,
288
+ // units: ,
289
+ // date: "20241107",
290
+ // hour: "",
291
+ // }),
292
+ // store.entries.create({
293
+ // createdBy: userId,
294
+ // vice: vices[0].id,
295
+ // categoryId: categories[0].id,
296
+ // categoryName: categories[0].name,
297
+ // typeId: types[3].id,
298
+ // units: 1.5,
299
+ // date: "20241107",
300
+ // hour: "20",
301
+ // }),
302
+ // store.entries.create({
303
+ // createdBy: userId,
304
+ // vice: vices[0].id,
305
+ // categoryId: categories[0].id,
306
+ // categoryName: categories[0].name,
307
+ // typeId: types[2].id,
308
+ // units: 1.25,
309
+ // date: "20241107",
310
+ // hour: "21",
311
+ // }),
312
+ // store.entries.create({
313
+ // createdBy: userId,
314
+ // vice: vices[0].id,
315
+ // categoryId: categories[0].id,
316
+ // categoryName: categories[0].name,
317
+ // typeId: types[3].id,
318
+ // units: 1.5,
319
+ // date: "20241107",
320
+ // hour: "22",
321
+ // }),
322
+ // ])
323
+ })();
@@ -0,0 +1,68 @@
1
+ export declare const SuggestedExerciseTypes: string[];
2
+ export type Exercise = {
3
+ name: string;
4
+ id: string;
5
+ createdAt: number;
6
+ createdBy?: string;
7
+ deletedAt?: number;
8
+ deletedBy?: string;
9
+ updatedAt?: number;
10
+ updatedBy?: string;
11
+ prompt?: string;
12
+ status?: string;
13
+ description?: string;
14
+ instructions?: string[];
15
+ level?: string;
16
+ category?: string;
17
+ directions?: ExerciseDirections;
18
+ variations?: Exercise[];
19
+ };
20
+ export type ExerciseDirections = {
21
+ duration?: number | number[];
22
+ sets?: number | number[];
23
+ reps?: number | number[];
24
+ };
25
+ export type Workout = {
26
+ id: string;
27
+ createdAt: number;
28
+ createdBy?: string;
29
+ deletedAt?: number;
30
+ deletedBy?: string;
31
+ updatedAt?: number;
32
+ updatedBy?: string;
33
+ prompt?: string;
34
+ status?: string;
35
+ name: string;
36
+ exercises?: Exercise[];
37
+ defaultMode?: SessionMode;
38
+ };
39
+ export type WorkoutSession = {
40
+ id: string;
41
+ createdBy?: string;
42
+ createdAt: number;
43
+ deletedAt?: number;
44
+ updatedAt?: number;
45
+ status?: string;
46
+ workout: Workout;
47
+ sets: WorkoutSet[];
48
+ mode?: SessionMode;
49
+ };
50
+ export type WorkoutSet = {
51
+ id?: string;
52
+ createdBy?: string;
53
+ createdAt?: number;
54
+ startedAt?: number;
55
+ stoppedAt?: number;
56
+ status?: string;
57
+ sets?: number;
58
+ reps?: number;
59
+ duration?: number;
60
+ exercise: Exercise;
61
+ offset: number;
62
+ };
63
+ export type SessionMode = {
64
+ countdown: boolean;
65
+ shuffle: boolean;
66
+ repeat: boolean;
67
+ };
68
+ export declare function restore(filename: string): Promise<any>;
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.restore = exports.SuggestedExerciseTypes = void 0;
7
+ const fs_1 = require("fs");
8
+ const moment_1 = __importDefault(require("moment"));
9
+ const index_1 = __importDefault(require("./index"));
10
+ require('dotenv').config();
11
+ const debug = true;
12
+ exports.SuggestedExerciseTypes = [
13
+ "Push Up",
14
+ "Pull Up",
15
+ "Sit Up",
16
+ ];
17
+ const store = {
18
+ exercises: new index_1.default({
19
+ key: "workout-exercise",
20
+ setKey: "workout-exercises",
21
+ options: {
22
+ lookups: {
23
+ createdBy: "createdBy",
24
+ }
25
+ },
26
+ debug,
27
+ }),
28
+ workouts: new index_1.default({
29
+ key: "workout",
30
+ setKey: "workouts",
31
+ options: {
32
+ lookups: {
33
+ createdBy: "createdBy",
34
+ }
35
+ },
36
+ debug,
37
+ }),
38
+ workoutSessions: new index_1.default({
39
+ key: "workout-session",
40
+ setKey: "workout-sessions",
41
+ options: {
42
+ lookups: {
43
+ createdBy: "createdBy",
44
+ }
45
+ },
46
+ debug,
47
+ }),
48
+ };
49
+ async function cleanup() {
50
+ // cleanup all from previous session
51
+ let [exercises, workouts, workoutSessions,] = await Promise.all([
52
+ store.exercises.ids({ scan: "*" }),
53
+ store.workouts.ids({ scan: "*" }),
54
+ store.workoutSessions.ids({ scan: "*" }),
55
+ ]);
56
+ // console.log("users to delete", { usersToDelete, postsToDelete, userPostsToDelete });
57
+ return Promise.all([
58
+ // @ts-ignore
59
+ ...Array.from(exercises).map((id) => store.exercises.delete(id, { hardDelete: true })),
60
+ // @ts-ignore
61
+ ...Array.from(workouts).map((id) => store.workouts.delete(id, { hardDelete: true })),
62
+ // @ts-ignore
63
+ ...Array.from(workoutSessions).map((id) => store.workoutSessions.delete(id, { hardDelete: true })),
64
+ ]);
65
+ }
66
+ async function backup() {
67
+ console.log('>> app.services.admin.backup', {});
68
+ const keys = Object.keys(store);
69
+ // .filter((key: string) => {
70
+ // return entities?.length
71
+ // ? entities.includes(key)
72
+ // : haikuIds?.length
73
+ // ? key == "haikus"
74
+ // : true
75
+ // });
76
+ if (!keys)
77
+ throw 'No entities to backup';
78
+ // TODO maybe do in chucks
79
+ const values = await Promise.all(
80
+ // @ts-ignore
81
+ keys.map((key) => store[key].find({ scan: "*" })));
82
+ // @ts-ignore
83
+ const keyValues = Object.fromEntries(await Promise.all(keys
84
+ .map(async (k, i) => {
85
+ const versionedValues = await Promise.all(values[i]
86
+ // .filter((v: any) => v.id == "fab762bf") // just the one for testing
87
+ // .filter((v: any) => v.id == "c43aa3c6") // just the one for testing
88
+ .map(async (currentValue) => {
89
+ const previousVersionIds = Array.from(Array(currentValue.version || 0).keys())
90
+ .map((version) => `${currentValue.id}:${version}`);
91
+ // console.log('>> app.services.admin.backup', { previousVersionIds });
92
+ const previousValues = (previousVersionIds === null || previousVersionIds === void 0 ? void 0 : previousVersionIds.length) > 0
93
+ // @ts-ignore
94
+ ? await store[k].find({ id: previousVersionIds })
95
+ : [];
96
+ // console.log('>> app.services.admin.backup', { previousValues });
97
+ return [currentValue, ...previousValues];
98
+ }));
99
+ // console.log('>> app.services.admin.backup', { k, v: versionedValues[i] });
100
+ return [k, versionedValues.flat()];
101
+ })));
102
+ // console.log('>> app.services.admin.backup', { keyValues });
103
+ // return keyValues;
104
+ const p = { name: "workout", version: "1.0.0" }; //require('/package.json');
105
+ const filename = `${p.name}_${p.version}_${(0, moment_1.default)().format("YYYYMMDD_kkmmss")}.json`;
106
+ // const buffer = Buffer.from(JSON.stringify(keyValues), 'utf8');
107
+ // const blob = await put(filename, buffer, {
108
+ // access: 'public',
109
+ // addRandomSuffix: false,
110
+ // });
111
+ const content = JSON.stringify(keyValues);
112
+ (0, fs_1.writeFileSync)(filename, content);
113
+ // return { filename: blob.pathname, size: formatBytes(Buffer.byteLength(buffer)), url: blob.url };
114
+ // console.log("BACKUP", JSON.stringify(keyValues));
115
+ }
116
+ async function restore(filename) {
117
+ console.log('>> app.services.admin.restore', { filename });
118
+ // const res = await fetch(url);
119
+ // // console.log('>> app.services.admin.restore', { res });
120
+ // if (res.status != 200) {
121
+ // console.error(`Error fetching '${url}': ${res.statusText} (${res.status})`)
122
+ // }
123
+ // const data = await res.json();
124
+ // console.log('>> app.services.admin.restore', { data });
125
+ const data = JSON.parse((0, fs_1.readFileSync)(filename).toString());
126
+ console.log('>> app.services.admin.restore', { data });
127
+ // return;
128
+ const result = {};
129
+ await Promise.all(Object.entries(data).map(async ([key, values]) => {
130
+ // console.log('>> app.services.admin.restore', { key, values });
131
+ if (!Array.isArray(values)) {
132
+ console.warn('>> app.services.admin.restore UNEXPECTED VALUES TYPE', { key, values });
133
+ return;
134
+ }
135
+ // const options = key == "userHaikus" ? UserHaikuSaveOptions : {};
136
+ return await Promise.all(values.map(async (value) => {
137
+ // @ts-ignore
138
+ const record = await store[key].get(value.id);
139
+ const options = value.deprecated || value.deprecatedAt
140
+ ? {
141
+ noIndex: true,
142
+ noLookup: true,
143
+ }
144
+ : {};
145
+ if (record) {
146
+ // for now don't restore if already exists
147
+ result[`${key}_skipped`] = (result[`${key}_skipped`] || 0) + 1;
148
+ // @ts-ignore
149
+ // await store[key].update("(system)", value, options);
150
+ // result[`${key}_updated`] = (result[`${key}_updated`] || 0) + 1;
151
+ }
152
+ else {
153
+ // @ts-ignore
154
+ await store[key].create(value, options);
155
+ result[`${key}_created`] = (result[`${key}_created`] || 0) + 1;
156
+ }
157
+ }));
158
+ }));
159
+ console.log('>> app.services.admin.restore >>>RESULTS<<<', { result });
160
+ return result;
161
+ }
162
+ exports.restore = restore;
163
+ (async function () {
164
+ await cleanup();
165
+ // const ret = await backup();
166
+ const ret = await restore("workout_1.0.0_20241120_142135.json");
167
+ console.log("workout-schema", { ret });
168
+ // let [
169
+ // exercises,
170
+ // workouts,
171
+ // workoutSessions,
172
+ // ] = await Promise.all([
173
+ // store.exercises.ids({ scan: "*" }),
174
+ // store.workouts.ids({ scan: "*" }),
175
+ // store.workoutSessions.ids({ scan: "*" }),
176
+ // ]);
177
+ // console.log("exercises", { exercises });
178
+ // console.log("workouts", { workouts });
179
+ // console.log("workoutSessions", { workoutSessions });
180
+ })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desmat/redis-store",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "exports": {