@shaxpir/duiduidui-models 1.5.2 → 1.5.4

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.
@@ -1,8 +1,8 @@
1
- import { MultiTime } from "@shaxpir/shaxpir-common";
1
+ import { CompactDateTime } from "@shaxpir/shaxpir-common";
2
2
  export type ReviewResult = 'FAIL' | 'HARD' | 'GOOD' | 'EASY';
3
3
  export interface ReviewLike {
4
4
  result: ReviewResult;
5
- at: MultiTime;
5
+ at_utc_time: CompactDateTime;
6
6
  }
7
7
  export interface Review extends ReviewLike {
8
8
  text: string;
@@ -3,7 +3,6 @@ import { MultiTime } from "@shaxpir/shaxpir-common";
3
3
  import { ShareSync } from '../repo';
4
4
  import { Content, ContentBody, ContentId, ContentMeta, ContentRef } from "./Content";
5
5
  import { Review } from './Review';
6
- import { ArrayView } from './ArrayView';
7
6
  export interface SessionPayload {
8
7
  start: MultiTime;
9
8
  end: MultiTime;
@@ -11,6 +10,7 @@ export interface SessionPayload {
11
10
  device_id: ContentId;
12
11
  duration_minutes: number;
13
12
  reviews: Review[];
13
+ review_count: number;
14
14
  }
15
15
  export interface SessionBody extends ContentBody {
16
16
  meta: ContentMeta;
@@ -29,7 +29,8 @@ export declare class Session extends Content {
29
29
  get tzOffset(): number;
30
30
  get durationMinutes(): number;
31
31
  get deviceId(): ContentId;
32
- get reviews(): ArrayView<Review>;
33
- modelUpdated(): Promise<void>;
32
+ get reviews(): Review[];
33
+ get reviewCount(): number;
34
34
  addReview(review: Review): void;
35
+ modelUpdated(): Promise<void>;
35
36
  }
@@ -3,12 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Session = void 0;
4
4
  const shaxpir_common_1 = require("@shaxpir/shaxpir-common");
5
5
  const repo_1 = require("../repo");
6
+ const ArrayView_1 = require("./ArrayView");
6
7
  const Content_1 = require("./Content");
7
8
  const ContentKind_1 = require("./ContentKind");
8
9
  const Metric_1 = require("./Metric");
9
10
  const Operation_1 = require("./Operation");
10
11
  const Workspace_1 = require("./Workspace");
11
- const ArrayView_1 = require("./ArrayView");
12
12
  class Session extends Content_1.Content {
13
13
  constructor(doc, shouldAcquire, shareSync) {
14
14
  super(doc, shouldAcquire, shareSync);
@@ -40,7 +40,8 @@ class Session extends Content_1.Content {
40
40
  tz_offset: (new Date()).getTimezoneOffset(),
41
41
  duration_minutes: 0,
42
42
  device_id: deviceId,
43
- reviews: []
43
+ reviews: [],
44
+ review_count: 0
44
45
  }
45
46
  });
46
47
  }
@@ -79,20 +80,41 @@ class Session extends Content_1.Content {
79
80
  this.checkDisposed("Session.deviceId");
80
81
  return this.payload.device_id;
81
82
  }
83
+ // NOTE: We are not offering a getter for the `_reviewsView` because ArrayView offers its own mutator
84
+ // methods (push, etc), and we don't want to circumvent the `addReview` method, which has important
85
+ // constraints and side effects.
82
86
  get reviews() {
83
- this.checkDisposed("Session.reviews");
84
- return this._reviewsView;
87
+ this.checkDisposed("Session.getReviews");
88
+ return this._reviewsView.values;
89
+ }
90
+ get reviewCount() {
91
+ this.checkDisposed("Session.getReviewCount");
92
+ return this._reviewsView.length;
93
+ }
94
+ addReview(review) {
95
+ this.checkDisposed("Session.addReview");
96
+ if (review.hasOwnProperty('context') && review.hasOwnProperty('weight')) {
97
+ throw new Error("Implied reviews cannot be added to a Session");
98
+ }
99
+ this._reviewsView.push({
100
+ text: review.text,
101
+ sense_rank: review.sense_rank,
102
+ result: review.result,
103
+ at_utc_time: review.at_utc_time
104
+ });
105
+ const batch = new Operation_1.BatchOperation(this);
106
+ batch.setPathValue(['payload', 'review_count'], this._reviewsView.length);
107
+ batch.commit();
85
108
  }
86
109
  async modelUpdated() {
87
110
  this.checkDisposed("Session.modelUpdated");
88
111
  await super.modelUpdated();
89
112
  const shareSync = this.shareSync;
90
- const sessionId = this.id;
91
113
  const userId = this.owner;
92
114
  const date = shaxpir_common_1.Time.dateFrom(this.createdAt.local_time);
93
115
  const workspaceId = Workspace_1.Workspace.makeWorkspaceId(userId);
94
116
  const workspace = await this.shareSync.acquire(ContentKind_1.ContentKind.WORKSPACE, workspaceId);
95
- const sessionsOnDate = await workspace.acquireSessionsFromDate(sessionId, date);
117
+ const sessionsOnDate = await workspace.acquireSessionsFromDate(date);
96
118
  workspace.release();
97
119
  let minutesStudyingOnDate = 0;
98
120
  let reviewCountOnDate = 0;
@@ -113,9 +135,5 @@ class Session extends Content_1.Content {
113
135
  reviewCountMetric.setDateAmount(date, reviewCountOnDate);
114
136
  reviewCountMetric.release();
115
137
  }
116
- addReview(review) {
117
- this.checkDisposed("Session.addReview");
118
- this._reviewsView.push(review);
119
- }
120
138
  }
121
139
  exports.Session = Session;
@@ -1,10 +1,10 @@
1
1
  import { Doc } from '@shaxpir/sharedb/lib/client';
2
2
  import { CompactDateTime } from "@shaxpir/shaxpir-common";
3
+ import { ShareSync } from '../repo';
3
4
  import { BayesianScore } from './BayesianScore';
4
5
  import { Content, ContentBody, ContentId, ContentMeta } from "./Content";
5
6
  import { BuiltInPhrase, Phrase, PhraseExample } from './Phrase';
6
- import { ReviewLike } from "./Review";
7
- import { ShareSync } from '../repo';
7
+ import { ImpliedReview, ReviewLike } from "./Review";
8
8
  export interface TermSummary {
9
9
  text: string;
10
10
  sense_rank: number;
@@ -16,6 +16,7 @@ export interface TermSummary {
16
16
  theta: number;
17
17
  uncertainty: number;
18
18
  review_count: number;
19
+ implied_review_count: number;
19
20
  last_review_utc: CompactDateTime;
20
21
  }
21
22
  export interface TermPayload extends BayesianScore {
@@ -32,6 +33,8 @@ export interface TermPayload extends BayesianScore {
32
33
  reviews: ReviewLike[];
33
34
  review_count: number;
34
35
  last_review_utc: CompactDateTime;
36
+ implied_reviews: ImpliedReview[];
37
+ implied_review_count: number;
35
38
  hanzi_count?: number;
36
39
  pinyin?: string;
37
40
  pinyin_tokenized?: string;
@@ -49,23 +52,30 @@ export interface TermBody extends ContentBody {
49
52
  export declare class Term extends Content {
50
53
  static makeTermId(userId: ContentId, text: string, senseRank: number): ContentId;
51
54
  private _reviewsView;
55
+ private _impliedReviewsView;
56
+ private _tagsView;
52
57
  constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
53
58
  static forUserPhrase(userId: ContentId, text: string, senseRank: number, difficulty: number, phraseId?: number): Term;
54
59
  static forUserPhrase(userId: ContentId, phrase: Phrase): Term;
55
60
  static forBuiltinPhrase(userId: ContentId, phrase: BuiltInPhrase): Term;
56
61
  get payload(): TermPayload;
57
- getText(): string;
58
- getSenseRank(): number;
59
- getDifficulty(): number;
60
- getAlpha(): number;
61
- getBeta(): number;
62
- getTheta(): number;
63
- getUncertainty(): number;
64
- getReviews(): ReviewLike[];
65
- getStarredAt(): CompactDateTime | null;
62
+ get text(): string;
63
+ get senseRank(): number;
64
+ get difficulty(): number;
65
+ get alpha(): number;
66
+ get beta(): number;
67
+ get theta(): number;
68
+ get uncertainty(): number;
69
+ get starredAt(): CompactDateTime | null;
70
+ get tags(): string[];
71
+ addTag(value: string): void;
72
+ removeTag(value: string): void;
73
+ get lastReviewUtc(): CompactDateTime | null;
66
74
  setStarredAt(value: CompactDateTime | null): void;
67
75
  updateBayesianScore(alpha: number, beta: number, theta: number): void;
76
+ get reviews(): ReviewLike[];
77
+ get impliedReviews(): ImpliedReview[];
78
+ get reviewCount(): number;
79
+ get impliedReviewCount(): number;
68
80
  addReview(review: ReviewLike): void;
69
- getReviewCount(): number;
70
- getLastReviewUtc(): CompactDateTime | null;
71
81
  }
@@ -2,12 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Term = void 0;
4
4
  const shaxpir_common_1 = require("@shaxpir/shaxpir-common");
5
+ const repo_1 = require("../repo");
6
+ const ArrayView_1 = require("./ArrayView");
5
7
  const BayesianScore_1 = require("./BayesianScore");
6
8
  const Content_1 = require("./Content");
7
9
  const ContentKind_1 = require("./ContentKind");
8
- const repo_1 = require("../repo");
9
10
  const Operation_1 = require("./Operation");
10
- const ArrayView_1 = require("./ArrayView");
11
11
  class Term extends Content_1.Content {
12
12
  static makeTermId(userId, text, senseRank) {
13
13
  return shaxpir_common_1.CachingHasher.makeMd5Base62Hash(`${ContentKind_1.ContentKind.TERM}-${userId}-${text}-${senseRank}`);
@@ -15,6 +15,8 @@ class Term extends Content_1.Content {
15
15
  constructor(doc, shouldAcquire, shareSync) {
16
16
  super(doc, shouldAcquire, shareSync);
17
17
  this._reviewsView = new ArrayView_1.ArrayView(this, ['payload', 'reviews']);
18
+ this._impliedReviewsView = new ArrayView_1.ArrayView(this, ['payload', 'implied_reviews']);
19
+ this._tagsView = new ArrayView_1.ArrayView(this, ['payload', 'tags']);
18
20
  }
19
21
  static forUserPhrase(userId, textOrPhrase, senseRank, difficulty, phraseId) {
20
22
  const now = shaxpir_common_1.ClockService.getClock().now();
@@ -71,7 +73,9 @@ class Term extends Content_1.Content {
71
73
  uncertainty: BayesianScore_1.BayesianScoreModel.calculateUncertainty(0.5, 0.5),
72
74
  reviews: [],
73
75
  review_count: 0,
74
- last_review_utc: null
76
+ last_review_utc: null,
77
+ implied_reviews: [],
78
+ implied_review_count: 0,
75
79
  }
76
80
  });
77
81
  }
@@ -100,7 +104,9 @@ class Term extends Content_1.Content {
100
104
  uncertainty: BayesianScore_1.BayesianScoreModel.calculateUncertainty(0.5, 0.5),
101
105
  reviews: [],
102
106
  review_count: 0,
103
- last_review_utc: null
107
+ last_review_utc: null,
108
+ implied_reviews: [],
109
+ implied_review_count: 0,
104
110
  }
105
111
  });
106
112
  }
@@ -108,42 +114,60 @@ class Term extends Content_1.Content {
108
114
  this.checkDisposed("Term.payload");
109
115
  return this.doc.data.payload;
110
116
  }
111
- getText() {
112
- this.checkDisposed("Term.getText");
117
+ get text() {
118
+ this.checkDisposed("Term.text");
113
119
  return this.payload.text;
114
120
  }
115
- getSenseRank() {
116
- this.checkDisposed("Term.getSenseRank");
121
+ get senseRank() {
122
+ this.checkDisposed("Term.senseRank");
117
123
  return this.payload.sense_rank;
118
124
  }
119
- getDifficulty() {
120
- this.checkDisposed("Term.getDifficulty");
125
+ get difficulty() {
126
+ this.checkDisposed("Term.difficulty");
121
127
  return this.payload.difficulty;
122
128
  }
123
- getAlpha() {
124
- this.checkDisposed("Term.getAlpha");
129
+ get alpha() {
130
+ this.checkDisposed("Term.alpha");
125
131
  return this.payload.alpha;
126
132
  }
127
- getBeta() {
128
- this.checkDisposed("Term.getBeta");
133
+ get beta() {
134
+ this.checkDisposed("Term.beta");
129
135
  return this.payload.beta;
130
136
  }
131
- getTheta() {
132
- this.checkDisposed("Term.getTheta");
137
+ get theta() {
138
+ this.checkDisposed("Term.theta");
133
139
  return this.payload.theta;
134
140
  }
135
- getUncertainty() {
136
- this.checkDisposed("Term.getUncertainty");
141
+ get uncertainty() {
142
+ this.checkDisposed("Term.uncertainty");
137
143
  return this.payload.uncertainty;
138
144
  }
139
- getReviews() {
140
- this.checkDisposed("Term.getReviews");
141
- return this.payload.reviews;
142
- }
143
- getStarredAt() {
144
- this.checkDisposed("Term.getStarredAt");
145
+ get starredAt() {
146
+ this.checkDisposed("Term.starredAt");
145
147
  return this.payload.starred_at;
146
148
  }
149
+ get tags() {
150
+ this.checkDisposed("Term.tags");
151
+ return this._tagsView.values;
152
+ }
153
+ addTag(value) {
154
+ this.checkDisposed("Term.addTag");
155
+ const index = this._tagsView.indexOf(value);
156
+ if (index === -1) {
157
+ this._tagsView.push(value);
158
+ }
159
+ }
160
+ removeTag(value) {
161
+ this.checkDisposed("Term.removeTag");
162
+ const index = this._tagsView.indexOf(value);
163
+ if (index !== -1) {
164
+ this._tagsView.removeAt(index);
165
+ }
166
+ }
167
+ get lastReviewUtc() {
168
+ this.checkDisposed("Term.lastReviewUtc");
169
+ return this.payload.last_review_utc;
170
+ }
147
171
  setStarredAt(value) {
148
172
  this.checkDisposed("Term.setStarredAt");
149
173
  if (this.payload.starred_at !== value) {
@@ -161,34 +185,56 @@ class Term extends Content_1.Content {
161
185
  batch.setPathValue(['payload', 'uncertainty'], BayesianScore_1.BayesianScoreModel.calculateUncertainty(alpha, beta));
162
186
  batch.commit();
163
187
  }
188
+ // NOTE: We are not offering a getter for the `_reviewsView` because ArrayView offers its own mutator
189
+ // methods (push, etc), and we don't want to circumvent the `addReview` method, which has important
190
+ // constraints and side effects.
191
+ get reviews() {
192
+ this.checkDisposed("Session.reviews");
193
+ return this._reviewsView.values;
194
+ }
195
+ // NOTE: We are not offering a getter for the `_impliedReviewsView` because ArrayView offers its own
196
+ // mutator methods (push, etc), and we don't want to circumvent the `addReview` method, which has
197
+ // important constraints and side effects.
198
+ get impliedReviews() {
199
+ this.checkDisposed("Term.impliedReviews");
200
+ return this._impliedReviewsView.values;
201
+ }
202
+ get reviewCount() {
203
+ this.checkDisposed("Term.reviewCount");
204
+ return this.payload.review_count;
205
+ }
206
+ get impliedReviewCount() {
207
+ this.checkDisposed("Term.impliedReviewCount");
208
+ return this.payload.implied_review_count;
209
+ }
210
+ // Add either an implied or explicit review
164
211
  addReview(review) {
165
212
  this.checkDisposed("Term.addReview");
166
- this._reviewsView.push(review);
167
- // Count reviews again.
168
- let reviewCount = 0;
169
- let lastReviewUtc = null;
170
- this._reviewsView.forEach((idx, r) => {
171
- // We only count *actual* reviews, not implied reviews...
172
- if (!r.hasOwnProperty('context') && !r.hasOwnProperty('weight')) {
173
- const reviewUtc = r.at.utc_time;
174
- if (!lastReviewUtc || shaxpir_common_1.Time.isDateTimeAfter(reviewUtc, lastReviewUtc)) {
175
- lastReviewUtc = reviewUtc;
176
- }
177
- reviewCount++;
213
+ if (review.hasOwnProperty('context') &&
214
+ review.hasOwnProperty('weight')) {
215
+ const r = review;
216
+ this._impliedReviewsView.push({
217
+ result: r.result,
218
+ at_utc_time: r.at_utc_time,
219
+ context: r.context,
220
+ weight: r.weight
221
+ });
222
+ const batch = new Operation_1.BatchOperation(this);
223
+ batch.setPathValue(['payload', 'implied_review_count'], this._impliedReviewsView.length);
224
+ batch.commit();
225
+ }
226
+ else {
227
+ this._reviewsView.push({
228
+ result: review.result,
229
+ at_utc_time: review.at_utc_time
230
+ });
231
+ const batch = new Operation_1.BatchOperation(this);
232
+ batch.setPathValue(['payload', 'review_count'], this._reviewsView.length);
233
+ if (this.lastReviewUtc == null || shaxpir_common_1.Time.isDateTimeAfter(review.at_utc_time, this.lastReviewUtc)) {
234
+ batch.setPathValue(['payload', 'last_review_utc'], review.at_utc_time);
178
235
  }
179
- });
180
- const batch = new Operation_1.BatchOperation(this);
181
- batch.setPathValue(['payload', 'review_count'], reviewCount);
182
- batch.setPathValue(['payload', 'last_review_utc'], lastReviewUtc);
183
- batch.commit();
184
- }
185
- getReviewCount() {
186
- this.checkDisposed("Term.getReviewCount");
187
- return this.payload.review_count;
188
- }
189
- getLastReviewUtc() {
190
- this.checkDisposed("Term.getLastReviewUtc");
191
- return this.payload.last_review_utc;
236
+ batch.commit();
237
+ }
192
238
  }
193
239
  }
194
240
  exports.Term = Term;
@@ -31,7 +31,8 @@ export declare class Workspace extends Content {
31
31
  static create(userId: ContentId, payload: WorkspacePayload): Workspace;
32
32
  get sessions(): ArrayView<MultiTime>;
33
33
  get devices(): ArrayView<ContentId>;
34
- acquireSessionsFromDate(sessionId: ContentId, localDate: CompactDate): Promise<Session[]>;
34
+ acquireSessionForUtcTime(utcTime: CompactDateTime): Promise<Session | null>;
35
+ acquireSessionsFromDate(localDate: CompactDate): Promise<Session[]>;
35
36
  hasJourneyDate(journeyKey: string): boolean;
36
37
  getJourneyDate(journeyKey: string): CompactDateTime;
37
38
  setJourneyDate(journeyKey: string, journeyDate: CompactDateTime): void;
@@ -49,7 +49,26 @@ class Workspace extends Content_1.Content {
49
49
  this.checkDisposed("Workspace.devices");
50
50
  return this._devicesView;
51
51
  }
52
- async acquireSessionsFromDate(sessionId, localDate) {
52
+ async acquireSessionForUtcTime(utcTime) {
53
+ this.checkDisposed("Workspace.acquireSessionForUtcTime");
54
+ const shareSync = repo_1.ShareSyncFactory.get();
55
+ for (let i = 0, len = this.sessions.length; i < len; i++) {
56
+ const sessionCreatedAt = this.sessions.get(i);
57
+ if (shaxpir_common_1.Time.isDateTimeBefore(sessionCreatedAt.utc_time, utcTime)) {
58
+ const sessionRef = Session_1.Session.makeSessionRef(this.owner, sessionCreatedAt);
59
+ const session = await shareSync.acquire(ContentKind_1.ContentKind.SESSION, sessionRef);
60
+ const sessionUpdatedAt = session.updatedAt;
61
+ if (shaxpir_common_1.Time.isDateTimeAfter(sessionUpdatedAt.utc_time, utcTime)) {
62
+ return session;
63
+ }
64
+ else {
65
+ session.release();
66
+ }
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ async acquireSessionsFromDate(localDate) {
53
72
  this.checkDisposed("Workspace.loadSessionsFromDate");
54
73
  const shareSync = repo_1.ShareSyncFactory.get();
55
74
  const sessions = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaxpir/duiduidui-models",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/shaxpir/duiduidui-models"