@openstax/ts-utils 1.3.0 → 1.3.2

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.
@@ -86,19 +86,33 @@ const fileSystemLrsGateway = (initializer) => (configProvider) => (authProvider)
86
86
  await save;
87
87
  return statementsWithDefaults;
88
88
  };
89
- const getAllXapiStatements = async ({ user, anyUser, ...options }) => {
89
+ const getAllXapiStatements = async ({ user, anyUser, fetchUntil, ...options }) => {
90
90
  const authUser = await authProvider.getUser();
91
91
  await load;
92
- return (data || []).filter(statement => {
92
+ let filteredData = (data || []).filter(statement => {
93
93
  var _a, _b, _c, _d;
94
+ const statementDate = new Date(statement.timestamp);
95
+ const sinceDate = options.since ? new Date(options.since) : null;
96
+ const untilDate = options.until ? new Date(options.until) : null;
94
97
  return (anyUser === true || statement.actor.account.name === (user || (0, assertions_1.assertDefined)(authUser, new errors_1.UnauthorizedError()).uuid))
95
98
  && (!options.verb || statement.verb.id === options.verb)
96
99
  && (!options.registration || ((_a = statement.context) === null || _a === void 0 ? void 0 : _a.registration) === options.registration)
97
100
  && (!options.activity || (options.related_activities
98
101
  ? ((statement.object.id === options.activity && statement.object.objectType === 'Activity')
99
102
  || (!!((_d = (_c = (_b = statement.context) === null || _b === void 0 ? void 0 : _b.contextActivities) === null || _c === void 0 ? void 0 : _c.parent) === null || _d === void 0 ? void 0 : _d.find(parent => parent.id === options.activity && parent.objectType === 'Activity'))))
100
- : (statement.object.id === options.activity && statement.object.objectType === 'Activity')));
103
+ : (statement.object.id === options.activity && statement.object.objectType === 'Activity')))
104
+ && (!sinceDate || statementDate >= sinceDate)
105
+ && (!untilDate || statementDate <= untilDate);
101
106
  });
107
+ if (fetchUntil) {
108
+ for (let i = 0; i < filteredData.length; i += pageSize) {
109
+ if (fetchUntil(filteredData.slice(0, i + pageSize))) {
110
+ filteredData = filteredData.slice(0, i + pageSize);
111
+ break;
112
+ }
113
+ }
114
+ }
115
+ return filteredData;
102
116
  };
103
117
  const getMoreXapiStatements = async (more) => {
104
118
  const { args, offset } = JSON.parse(more);
@@ -90,6 +90,8 @@ export declare const lrsGateway: <C extends string = "lrs">(initializer: Initial
90
90
  related_activities?: boolean | undefined;
91
91
  user?: string | undefined;
92
92
  anyUser?: boolean | undefined;
93
+ since?: string | undefined;
94
+ until?: string | undefined;
93
95
  } & {
94
96
  ensureSync?: boolean | undefined;
95
97
  }) => Promise<{
@@ -100,15 +102,19 @@ export declare const lrsGateway: <C extends string = "lrs">(initializer: Initial
100
102
  more: string;
101
103
  statements: XapiStatement[];
102
104
  }>;
103
- getAllXapiStatements: (params: {
105
+ getAllXapiStatements: ({ fetchUntil, ...params }: {
104
106
  verb?: string | undefined;
105
107
  activity?: string | undefined;
106
108
  registration?: string | undefined;
107
109
  related_activities?: boolean | undefined;
108
110
  user?: string | undefined;
109
111
  anyUser?: boolean | undefined;
112
+ since?: string | undefined;
113
+ until?: string | undefined;
110
114
  } & {
111
115
  ensureSync?: boolean | undefined;
116
+ } & {
117
+ fetchUntil?: ((statements: XapiStatement[]) => boolean) | undefined;
112
118
  }) => Promise<XapiStatement[]>;
113
119
  };
114
120
  export {};
@@ -123,9 +123,9 @@ ${await response.text()}`);
123
123
  return formatGetXapiStatementsResponse(fetchXapiStatements(fetchParams));
124
124
  }
125
125
  };
126
- const getAllXapiStatements = async (params) => {
126
+ const getAllXapiStatements = async ({ fetchUntil, ...params }) => {
127
127
  const loadRemaining = async (result) => {
128
- if (!result.more) {
128
+ if (!result.more || (fetchUntil && fetchUntil(result.statements))) {
129
129
  return result.statements;
130
130
  }
131
131
  const { more, statements } = await getMoreXapiStatements(result.more);
@@ -1,6 +1,6 @@
1
- declare type Filter = {
1
+ export declare type Filter = {
2
2
  key: string;
3
- value: string | string[];
3
+ value: string | string[] | boolean;
4
4
  };
5
5
  declare type Field = {
6
6
  key: string;
@@ -9,6 +9,9 @@ declare type Field = {
9
9
  } | {
10
10
  key: string;
11
11
  type: 'keyword';
12
+ } | {
13
+ key: string;
14
+ type: 'boolean';
12
15
  };
13
16
  export interface IndexOptions<T> {
14
17
  body: T;
@@ -18,6 +21,11 @@ export interface SearchOptions {
18
21
  page?: number;
19
22
  query: string | undefined;
20
23
  fields: Field[];
24
+ /**
25
+ * @deprecated use `must` instead
26
+ */
21
27
  filter?: Filter[];
28
+ must?: Filter[];
29
+ must_not?: Filter[];
22
30
  }
23
31
  export {};
@@ -2,18 +2,43 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.memorySearchTheBadWay = void 0;
4
4
  const __1 = require("../..");
5
+ const errors_1 = require("../../errors");
5
6
  const guards_1 = require("../../guards");
6
7
  const MIN_MATCH = 0.5;
7
8
  const MAX_RESULTS = 10;
9
+ var MatchType;
10
+ (function (MatchType) {
11
+ MatchType[MatchType["Must"] = 0] = "Must";
12
+ MatchType[MatchType["MustNot"] = 1] = "MustNot";
13
+ })(MatchType || (MatchType = {}));
8
14
  const resolveField = (document, field) => field.key.toString().split('.').reduce((result, key) => result[key], document);
9
15
  const memorySearchTheBadWay = ({ loadAllDocumentsTheBadWay }) => {
10
16
  return {
11
17
  ensureIndexCreated: async () => undefined,
12
18
  index: async (_options) => undefined,
13
19
  search: async (options) => {
20
+ const getFieldType = (field) => { var _a; return (_a = options.fields.find(f => f.key == field.key)) === null || _a === void 0 ? void 0 : _a.type; };
14
21
  const results = (await loadAllDocumentsTheBadWay())
15
22
  .map(document => {
16
23
  let weight = 0;
24
+ const matchFilters = (filters, mustMatch) => {
25
+ for (const field of filters) {
26
+ const docValues = (0, __1.coerceArray)(resolveField(document, field));
27
+ const coerceValue = getFieldType(field) === 'boolean'
28
+ ? (input) => {
29
+ if ([true, 'true', '1', 1].includes(input)) {
30
+ return true;
31
+ }
32
+ if ([false, 'false', '0', 0, ''].includes(input)) {
33
+ return false;
34
+ }
35
+ throw new errors_1.InvalidRequestError('input is not a valid boolean filter');
36
+ }
37
+ : (x) => x;
38
+ const hasMatch = (0, __1.coerceArray)(field.value).map(coerceValue).some(v => docValues.includes(v));
39
+ return !((mustMatch === MatchType.Must && !hasMatch) || (mustMatch === MatchType.MustNot && hasMatch));
40
+ }
41
+ };
17
42
  if (options.query !== undefined) {
18
43
  for (const field of options.fields) {
19
44
  if (field.type !== undefined && field.type !== 'text') {
@@ -33,11 +58,13 @@ const memorySearchTheBadWay = ({ loadAllDocumentsTheBadWay }) => {
33
58
  }
34
59
  }
35
60
  }
36
- for (const field of options.filter || []) {
37
- const value = resolveField(document, field);
38
- if (!(0, __1.coerceArray)(field.value).some(v => (0, __1.coerceArray)(value).includes(v))) {
39
- return undefined;
40
- }
61
+ const { must_not } = options;
62
+ const must = 'filter' in options ? options.filter : options.must;
63
+ if ((must === null || must === void 0 ? void 0 : must.length) && !matchFilters(must, MatchType.Must)) {
64
+ return undefined;
65
+ }
66
+ if ((must_not === null || must_not === void 0 ? void 0 : must_not.length) && !matchFilters(must_not, MatchType.MustNot)) {
67
+ return undefined;
41
68
  }
42
69
  return { document, weight };
43
70
  })