@isrd-isi-edu/ermrestjs 2.0.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/LICENSE +202 -0
- package/README.md +55 -0
- package/dist/ermrest.d.ts +3481 -0
- package/dist/ermrest.js +45 -0
- package/dist/ermrest.js.gz +0 -0
- package/dist/ermrest.js.map +1 -0
- package/dist/ermrest.min.js +45 -0
- package/dist/ermrest.min.js.gz +0 -0
- package/dist/ermrest.min.js.map +1 -0
- package/dist/ermrest.ver.txt +1 -0
- package/dist/stats.html +4949 -0
- package/js/ag_reference.js +1483 -0
- package/js/core.js +4931 -0
- package/js/datapath.js +336 -0
- package/js/export.js +956 -0
- package/js/filters.js +192 -0
- package/js/format.js +344 -0
- package/js/hatrac.js +1130 -0
- package/js/json_ld_validator.js +285 -0
- package/js/parser.js +2320 -0
- package/js/setup/node.js +27 -0
- package/js/utils/helpers.js +2300 -0
- package/js/utils/json_ld_schema.js +680 -0
- package/js/utils/pseudocolumn_helpers.js +2196 -0
- package/package.json +79 -0
- package/src/index.ts +204 -0
- package/src/models/comment.ts +14 -0
- package/src/models/deferred-promise.ts +16 -0
- package/src/models/display-name.ts +5 -0
- package/src/models/errors.ts +408 -0
- package/src/models/path-prefix-alias-mapping.ts +130 -0
- package/src/models/reference/bulk-create-foreign-key-object.ts +133 -0
- package/src/models/reference/citation.ts +98 -0
- package/src/models/reference/contextualize.ts +535 -0
- package/src/models/reference/google-dataset-metadata.ts +72 -0
- package/src/models/reference/index.ts +14 -0
- package/src/models/reference/page.ts +520 -0
- package/src/models/reference/reference-aggregate-fn.ts +37 -0
- package/src/models/reference/reference.ts +2813 -0
- package/src/models/reference/related-reference.ts +467 -0
- package/src/models/reference/tuple.ts +652 -0
- package/src/models/reference-column/asset-pseudo-column.ts +498 -0
- package/src/models/reference-column/column-aggregate.ts +313 -0
- package/src/models/reference-column/facet-column.ts +1380 -0
- package/src/models/reference-column/foreign-key-pseudo-column.ts +626 -0
- package/src/models/reference-column/inbound-foreign-key-pseudo-column.ts +131 -0
- package/src/models/reference-column/index.ts +13 -0
- package/src/models/reference-column/key-pseudo-column.ts +236 -0
- package/src/models/reference-column/pseudo-column.ts +850 -0
- package/src/models/reference-column/reference-column.ts +740 -0
- package/src/models/source-object-node.ts +156 -0
- package/src/models/source-object-wrapper.ts +694 -0
- package/src/models/table-source-definitions.ts +98 -0
- package/src/services/authn.ts +43 -0
- package/src/services/catalog.ts +37 -0
- package/src/services/config.ts +202 -0
- package/src/services/error.ts +247 -0
- package/src/services/handlebars.ts +607 -0
- package/src/services/history.ts +136 -0
- package/src/services/http.ts +536 -0
- package/src/services/logger.ts +70 -0
- package/src/services/mustache.ts +0 -0
- package/src/utils/column-utils.ts +308 -0
- package/src/utils/constants.ts +526 -0
- package/src/utils/markdown-utils.ts +855 -0
- package/src/utils/reference-utils.ts +1658 -0
- package/src/utils/template-utils.ts +0 -0
- package/src/utils/type-utils.ts +89 -0
- package/src/utils/value-utils.ts +127 -0
- package/tsconfig.json +30 -0
- package/vite.config.mts +104 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
// models
|
|
2
|
+
import { Reference, type Tuple, type VisibleColumn } from '@isrd-isi-edu/ermrestjs/src/models/reference';
|
|
3
|
+
import type SourceObjectWrapper from '@isrd-isi-edu/ermrestjs/src/models/source-object-wrapper';
|
|
4
|
+
import { parse } from '@isrd-isi-edu/ermrestjs/js/parser';
|
|
5
|
+
import { CommentType } from '@isrd-isi-edu/ermrestjs/src/models/comment';
|
|
6
|
+
import { DisplayName } from '@isrd-isi-edu/ermrestjs/src/models/display-name';
|
|
7
|
+
import { BatchUnlinkResponse, InvalidInputError } from '@isrd-isi-edu/ermrestjs/src/models/errors';
|
|
8
|
+
|
|
9
|
+
// utils
|
|
10
|
+
import { isObject, isObjectAndNotNull, verify } from '@isrd-isi-edu/ermrestjs/src/utils/type-utils';
|
|
11
|
+
import { renderMarkdown } from '@isrd-isi-edu/ermrestjs/src/utils/markdown-utils';
|
|
12
|
+
import { _facetFilterTypes, _parserAliases } from '@isrd-isi-edu/ermrestjs/src/utils/constants';
|
|
13
|
+
import { _compressSource } from '@isrd-isi-edu/ermrestjs/js/utils/pseudocolumn_helpers';
|
|
14
|
+
import { fixedEncodeURIComponent } from '@isrd-isi-edu/ermrestjs/src/utils/value-utils';
|
|
15
|
+
|
|
16
|
+
import { Catalog, ForeignKeyRef, Table } from '@isrd-isi-edu/ermrestjs/js/core';
|
|
17
|
+
import { Location } from '@isrd-isi-edu/ermrestjs/js/parser';
|
|
18
|
+
import { _isValidModelCommentDisplay, _processSourceObjectComment, generateKeyValueFilters } from '@isrd-isi-edu/ermrestjs/js/utils/helpers';
|
|
19
|
+
|
|
20
|
+
export class RelatedReference extends Reference {
|
|
21
|
+
private _mainTable: Table;
|
|
22
|
+
private _mainTuple?: Tuple;
|
|
23
|
+
private _origFKR: ForeignKeyRef;
|
|
24
|
+
private _compressedDataSource?: any;
|
|
25
|
+
private _derivedAssociationReference?: DerivedAssociationReference;
|
|
26
|
+
|
|
27
|
+
public _relatedKeyColumnPositions: number[];
|
|
28
|
+
public _relatedFkColumnPositions: number[];
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
location: Location,
|
|
32
|
+
catalog: Catalog,
|
|
33
|
+
mainTable: Table,
|
|
34
|
+
origFKR: ForeignKeyRef,
|
|
35
|
+
relatedKeyColumnPositions: number[],
|
|
36
|
+
relatedFkColumnPositions: number[],
|
|
37
|
+
compressedDataSource?: any,
|
|
38
|
+
mainTuple?: Tuple,
|
|
39
|
+
displayname?: DisplayName,
|
|
40
|
+
comment?: CommentType,
|
|
41
|
+
pseudoColumn?: VisibleColumn,
|
|
42
|
+
) {
|
|
43
|
+
super(location, catalog, displayname, comment, pseudoColumn);
|
|
44
|
+
|
|
45
|
+
this._mainTable = mainTable;
|
|
46
|
+
this._mainTuple = mainTuple;
|
|
47
|
+
this._origFKR = origFKR;
|
|
48
|
+
|
|
49
|
+
this._relatedKeyColumnPositions = relatedKeyColumnPositions;
|
|
50
|
+
this._relatedFkColumnPositions = relatedFkColumnPositions;
|
|
51
|
+
|
|
52
|
+
this._compressedDataSource = compressedDataSource;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* the main table
|
|
57
|
+
* NOTE: the table that this reference represents is the related one, and
|
|
58
|
+
* it is not the same as the main table.
|
|
59
|
+
*/
|
|
60
|
+
get mainTable(): Table {
|
|
61
|
+
return this._mainTable;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* the main tuple
|
|
66
|
+
*/
|
|
67
|
+
get mainTuple(): Tuple | undefined {
|
|
68
|
+
return this._mainTuple;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get origFKR(): ForeignKeyRef {
|
|
72
|
+
return this._origFKR;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
get compressedDataSource(): any {
|
|
76
|
+
return this._compressedDataSource;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
set derivedAssociationReference(ref: DerivedAssociationReference) {
|
|
80
|
+
this._derivedAssociationReference = ref;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get derivedAssociationReference(): DerivedAssociationReference | undefined {
|
|
84
|
+
return this._derivedAssociationReference;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* create a new instance with the same properties.
|
|
89
|
+
*
|
|
90
|
+
* you can customized the properties of the new instance by passing new ones to this function.
|
|
91
|
+
* You must pass undefined for other props that you don't want to change.
|
|
92
|
+
*/
|
|
93
|
+
copy(displayname?: DisplayName, comment?: CommentType, pseudoColumn?: VisibleColumn): RelatedReference {
|
|
94
|
+
const res = new RelatedReference(
|
|
95
|
+
this.location,
|
|
96
|
+
this.location.catalogObject,
|
|
97
|
+
this._mainTable,
|
|
98
|
+
this._origFKR,
|
|
99
|
+
this._relatedKeyColumnPositions,
|
|
100
|
+
this._relatedFkColumnPositions,
|
|
101
|
+
this._compressedDataSource,
|
|
102
|
+
this._mainTuple,
|
|
103
|
+
typeof displayname !== 'undefined' ? displayname : this._displayname,
|
|
104
|
+
typeof comment !== 'undefined' ? comment : this._comment,
|
|
105
|
+
typeof pseudoColumn !== 'undefined' ? pseudoColumn : this._pseudoColumn,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
if (this.derivedAssociationReference) {
|
|
109
|
+
res.derivedAssociationReference = this.derivedAssociationReference;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
res.setContext(this.context);
|
|
113
|
+
return res;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* If the current reference is derived from an association related table and filtered, this
|
|
118
|
+
* function will delete the set of tuples included and return a set of success responses and
|
|
119
|
+
* a set of errors for the corresponding delete actions for the provided entity set from the
|
|
120
|
+
* corresponding association table denoted by the list of tuples.
|
|
121
|
+
*
|
|
122
|
+
* For example, assume
|
|
123
|
+
* Table1(K1,C1) <- AssociationTable(FK1, FK2) -> Table2(K2,C2)
|
|
124
|
+
* and the current tuples are from Table2 with k2 = "2" and k2 = "3".
|
|
125
|
+
* With origFKRData = {"k1": "1"} this function will return a set of success and error responses for
|
|
126
|
+
* delete requests to AssociationTable with FK1 = "1" as a part of the path and FK2 = "2" and FK2 = "3"
|
|
127
|
+
* as the filters that define the set and how they are related to Table1.
|
|
128
|
+
*
|
|
129
|
+
* To make sure a deletion occurs only for the tuples specified, we need to verify each reference path that
|
|
130
|
+
* is created includes a parent constraint and has one or more filters based on the other side of the association
|
|
131
|
+
* table's uniqueness constraint. Some more information about the validations that need to occur based on the above example:
|
|
132
|
+
* - parent value has to be not null
|
|
133
|
+
* - FK1 has to have a not null constraint
|
|
134
|
+
* - child values have to have at least 1 value and all not null
|
|
135
|
+
* - for FK2, all selected values are not null
|
|
136
|
+
*
|
|
137
|
+
* @param {Array} mainTuple - an ERMrest.Tuple from Table1 (from example above)
|
|
138
|
+
* @param {Array} tuples - an array of ERMrest.Tuple objects from Table2 (same as self) (from example above)
|
|
139
|
+
* @param {Object} contextHeaderParams the object that we want to log.
|
|
140
|
+
*
|
|
141
|
+
* @returns {Object} an ERMrest.BatchUnlinkResponse "error" object
|
|
142
|
+
**/
|
|
143
|
+
deleteBatchAssociationTuples(
|
|
144
|
+
parentTuple: Tuple,
|
|
145
|
+
tuples: Array<Tuple>,
|
|
146
|
+
contextHeaderParams?: Record<string, unknown>,
|
|
147
|
+
): Promise<BatchUnlinkResponse> {
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
try {
|
|
150
|
+
verify(parentTuple, '`parentTuple` must be specified');
|
|
151
|
+
verify(tuples, '`tuples` must be specified');
|
|
152
|
+
verify(tuples.length > 0, '`tuples` must have at least one row to delete');
|
|
153
|
+
// Can occur using an unfiltered reference
|
|
154
|
+
verify(this.derivedAssociationReference, 'The current reference must have a derived association reference defined');
|
|
155
|
+
|
|
156
|
+
const encode = fixedEncodeURIComponent;
|
|
157
|
+
if (!contextHeaderParams || !isObject(contextHeaderParams)) {
|
|
158
|
+
contextHeaderParams = { action: 'delete' };
|
|
159
|
+
}
|
|
160
|
+
const config = {
|
|
161
|
+
headers: this._generateContextHeader(contextHeaderParams),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
let successTupleData: Array<Record<string, unknown>> = [];
|
|
165
|
+
let failedTupleData: Array<Record<string, unknown>> = [];
|
|
166
|
+
const deleteSubmessage: Array<string> = [];
|
|
167
|
+
const associationRef = this.derivedAssociationReference!;
|
|
168
|
+
const mainKeyCol = associationRef.origFKR.colset.columns[0];
|
|
169
|
+
|
|
170
|
+
// the path starting from association table, with filters based on the fk to the main table
|
|
171
|
+
let compactPath = encode(associationRef.table.schema.name) + ':' + encode(associationRef.table.name) + '/';
|
|
172
|
+
compactPath += encode(mainKeyCol.name) + '=' + encode(parentTuple.data[associationRef.origFKR.mapping.get(mainKeyCol).name]) + '&';
|
|
173
|
+
|
|
174
|
+
// keyColumns should be a set of columns that are unique and not-null
|
|
175
|
+
// columns tells us what the key column names are in the fkr "_to" relationship
|
|
176
|
+
const keyColumns = associationRef.associationToRelatedFKR.colset.columns;
|
|
177
|
+
// mapping tells us what the column name is on the leaf tuple, so we know what data to fetch from each tuple for identifying
|
|
178
|
+
const mapping = associationRef.associationToRelatedFKR.mapping;
|
|
179
|
+
|
|
180
|
+
// add the filters based on the fk to the related table
|
|
181
|
+
const keyFromAssocToRelatedData = tuples.map((t) => {
|
|
182
|
+
const res: Record<string, unknown> = {};
|
|
183
|
+
keyColumns.forEach((col) => {
|
|
184
|
+
res[col.name] = t.data[mapping.get(col).name];
|
|
185
|
+
});
|
|
186
|
+
return res;
|
|
187
|
+
});
|
|
188
|
+
const keyValueRes = generateKeyValueFilters(
|
|
189
|
+
keyColumns,
|
|
190
|
+
keyFromAssocToRelatedData,
|
|
191
|
+
associationRef.table.schema.catalog,
|
|
192
|
+
compactPath.length + 1, // 1 is for added `/` between filter and compactPath
|
|
193
|
+
associationRef.displayname.value as string,
|
|
194
|
+
);
|
|
195
|
+
if (!keyValueRes.successful && keyValueRes.message) {
|
|
196
|
+
reject(new InvalidInputError(keyValueRes.message));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// send the requests one at a time
|
|
201
|
+
const recursiveDelete = (index: number) => {
|
|
202
|
+
const currFilter = keyValueRes.filters![index];
|
|
203
|
+
const url = [associationRef.location.service, 'catalog', associationRef.location.catalog, 'entity', compactPath + currFilter.path].join(
|
|
204
|
+
'/',
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
this.server.http
|
|
208
|
+
.delete(url, config)
|
|
209
|
+
.then(() => {
|
|
210
|
+
successTupleData = successTupleData.concat(currFilter.keyData);
|
|
211
|
+
})
|
|
212
|
+
.catch((err: any) => {
|
|
213
|
+
failedTupleData = failedTupleData.concat(currFilter.keyData);
|
|
214
|
+
deleteSubmessage.push(err.data);
|
|
215
|
+
})
|
|
216
|
+
.finally(() => {
|
|
217
|
+
if (index < keyValueRes.filters!.length - 1) {
|
|
218
|
+
recursiveDelete(index + 1);
|
|
219
|
+
} else {
|
|
220
|
+
resolve(new BatchUnlinkResponse(successTupleData, failedTupleData, deleteSubmessage.join('\n')));
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
recursiveDelete(0);
|
|
226
|
+
} catch (e) {
|
|
227
|
+
reject(e);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export class DerivedAssociationReference extends Reference {
|
|
234
|
+
private _origFKR: ForeignKeyRef;
|
|
235
|
+
private _associationToRelatedFKR: ForeignKeyRef;
|
|
236
|
+
|
|
237
|
+
constructor(location: Location, catalog: Catalog, origFKR: ForeignKeyRef, associationToRelatedFKR: ForeignKeyRef) {
|
|
238
|
+
super(location, catalog);
|
|
239
|
+
|
|
240
|
+
this._associationToRelatedFKR = associationToRelatedFKR;
|
|
241
|
+
this._origFKR = origFKR;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* the main tuple
|
|
245
|
+
*/
|
|
246
|
+
get associationToRelatedFKR(): ForeignKeyRef {
|
|
247
|
+
return this._associationToRelatedFKR;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
get origFKR(): ForeignKeyRef {
|
|
251
|
+
return this._origFKR;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
copy(): DerivedAssociationReference {
|
|
255
|
+
const ref = new DerivedAssociationReference(this.location, this.location.catalogObject, this._origFKR, this._associationToRelatedFKR);
|
|
256
|
+
ref.setContext(this.context);
|
|
257
|
+
return ref;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* given a reference, the first inbound fk, and/or the sourceObjectWrapper summarizing the path, return the related reference.
|
|
263
|
+
* @param mainRef the main reference
|
|
264
|
+
* @param fkr the inbound fk
|
|
265
|
+
* @param mainTuple the main tuple for the main reference
|
|
266
|
+
* @param checkForAssociation whether we should check for association
|
|
267
|
+
* @param sourceObjectWrapper the sourceObjectWrapper summarizing the path
|
|
268
|
+
*/
|
|
269
|
+
export const generateRelatedReference = (
|
|
270
|
+
mainRef: Reference,
|
|
271
|
+
fkr: ForeignKeyRef,
|
|
272
|
+
mainTuple?: Tuple,
|
|
273
|
+
checkForAssociation?: boolean,
|
|
274
|
+
sourceObjectWrapper?: SourceObjectWrapper,
|
|
275
|
+
): RelatedReference => {
|
|
276
|
+
const useFaceting = isObjectAndNotNull(mainTuple);
|
|
277
|
+
|
|
278
|
+
let location, displayname, relatedKeyColumnPositions, relatedFkColumnPositions, derivedAssociationReference;
|
|
279
|
+
let comment, commentDisplayMode, commentRenderMarkdown, tableDisplay, fkDisplay;
|
|
280
|
+
const filterSource: any[] = [];
|
|
281
|
+
const catalog = mainRef.table.schema.catalog;
|
|
282
|
+
let dataSource: any = [{ inbound: fkr.constraint_names[0] }];
|
|
283
|
+
const fkrTable = fkr.colset.columns[0].table;
|
|
284
|
+
let relatedTable;
|
|
285
|
+
|
|
286
|
+
if (checkForAssociation && fkrTable.isPureBinaryAssociation) {
|
|
287
|
+
// find the other foreignkey
|
|
288
|
+
const pureBinaryFKs = fkrTable.pureBinaryForeignKeys;
|
|
289
|
+
let otherFK: ForeignKeyRef;
|
|
290
|
+
for (let j = 0; j < pureBinaryFKs.length; j++) {
|
|
291
|
+
if (pureBinaryFKs[j] !== fkr) {
|
|
292
|
+
otherFK = pureBinaryFKs[j];
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
relatedTable = otherFK!.key.table;
|
|
298
|
+
const assocTable = otherFK!.colset.columns[0].table;
|
|
299
|
+
|
|
300
|
+
// all the display settings must come from the same table (assoc table)
|
|
301
|
+
// so if we get the comment from assoc table, displayname must also be from assoc table
|
|
302
|
+
fkDisplay = otherFK!.getDisplay(mainRef.context);
|
|
303
|
+
tableDisplay = assocTable.getDisplay(mainRef.context);
|
|
304
|
+
|
|
305
|
+
// displayname
|
|
306
|
+
if (fkDisplay.toName) {
|
|
307
|
+
displayname = { isHTML: false, value: fkDisplay.toName, unformatted: fkDisplay.toName };
|
|
308
|
+
} else {
|
|
309
|
+
displayname = assocTable.displayname;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// comment
|
|
313
|
+
if (fkDisplay.toComment) {
|
|
314
|
+
comment = fkDisplay.toComment.unformatted;
|
|
315
|
+
} else {
|
|
316
|
+
comment = tableDisplay.comment ? tableDisplay.comment.unformatted : null;
|
|
317
|
+
}
|
|
318
|
+
if (_isValidModelCommentDisplay(fkDisplay.toCommentDisplayMode)) {
|
|
319
|
+
commentDisplayMode = fkDisplay.toCommentDisplayMode;
|
|
320
|
+
} else {
|
|
321
|
+
commentDisplayMode = tableDisplay.tableCommentDisplayMode;
|
|
322
|
+
}
|
|
323
|
+
if (typeof fkDisplay.commentRenderMarkdown === 'boolean') {
|
|
324
|
+
commentRenderMarkdown = fkDisplay.commentRenderMarkdown;
|
|
325
|
+
} else {
|
|
326
|
+
commentRenderMarkdown = tableDisplay.commentRenderMarkdown;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// uri and location
|
|
330
|
+
if (!useFaceting) {
|
|
331
|
+
location = parse(mainRef.location.compactUri + '/' + fkr.toString() + '/' + otherFK!.toString(true), catalog);
|
|
332
|
+
// constructor will take care of this
|
|
333
|
+
// location.referenceObject = newRef;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// additional values for sorting related references
|
|
337
|
+
relatedKeyColumnPositions = fkr.key.colset._getColumnPositions();
|
|
338
|
+
relatedFkColumnPositions = otherFK!.colset._getColumnPositions();
|
|
339
|
+
|
|
340
|
+
// will be used to determine whether this related reference is derived from association relation or not
|
|
341
|
+
derivedAssociationReference = new DerivedAssociationReference(parse(mainRef.location.compactUri + '/' + fkr.toString()), catalog, fkr, otherFK!);
|
|
342
|
+
|
|
343
|
+
// build the filter source (the alias is used in the read function to get the proper acls)
|
|
344
|
+
filterSource.push({ inbound: otherFK!.constraint_names[0], alias: _parserAliases.ASSOCIATION_TABLE });
|
|
345
|
+
|
|
346
|
+
// build the data source
|
|
347
|
+
dataSource.push({ outbound: otherFK!.constraint_names[0] });
|
|
348
|
+
} else {
|
|
349
|
+
relatedTable = fkrTable;
|
|
350
|
+
fkDisplay = fkr.getDisplay(mainRef.context);
|
|
351
|
+
tableDisplay = relatedTable.getDisplay(mainRef.context);
|
|
352
|
+
|
|
353
|
+
// displayname
|
|
354
|
+
if (fkDisplay.fromName) {
|
|
355
|
+
displayname = { isHTML: false, value: fkDisplay.fromName, unformatted: fkDisplay.fromName };
|
|
356
|
+
} else {
|
|
357
|
+
displayname = relatedTable.displayname;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// comment
|
|
361
|
+
if (fkDisplay.fromComment) {
|
|
362
|
+
comment = fkDisplay.fromComment.unformatted;
|
|
363
|
+
} else {
|
|
364
|
+
comment = tableDisplay.comment ? tableDisplay.comment.unformatted : null;
|
|
365
|
+
}
|
|
366
|
+
if (_isValidModelCommentDisplay(fkDisplay.fromCommentDisplayMode)) {
|
|
367
|
+
commentDisplayMode = fkDisplay.fromCommentDisplayMode;
|
|
368
|
+
} else {
|
|
369
|
+
commentDisplayMode = tableDisplay.tableCommentDisplayMode;
|
|
370
|
+
}
|
|
371
|
+
if (typeof fkDisplay.commentRenderMarkdown === 'boolean') {
|
|
372
|
+
commentRenderMarkdown = fkDisplay.commentRenderMarkdown;
|
|
373
|
+
} else {
|
|
374
|
+
commentRenderMarkdown = tableDisplay.commentRenderMarkdown;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// uri and location
|
|
378
|
+
if (!useFaceting) {
|
|
379
|
+
location = parse(mainRef.location.compactUri + '/' + fkr.toString(), catalog);
|
|
380
|
+
// constructor will take care of this
|
|
381
|
+
// newRef._location.referenceObject = newRef;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// additional values for sorting related references
|
|
385
|
+
relatedKeyColumnPositions = fkr.key.colset._getColumnPositions();
|
|
386
|
+
relatedFkColumnPositions = fkr.colset._getColumnPositions();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
let sourceObject;
|
|
390
|
+
if (sourceObjectWrapper) {
|
|
391
|
+
sourceObject = sourceObjectWrapper.sourceObject;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// if markdown_name in source object is defined
|
|
395
|
+
if (sourceObject && typeof sourceObject.markdown_name === 'string') {
|
|
396
|
+
displayname = {
|
|
397
|
+
value: renderMarkdown(sourceObject.markdown_name, true),
|
|
398
|
+
unformatted: sourceObject.markdown_name,
|
|
399
|
+
isHTML: true,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (sourceObject && sourceObject.source) {
|
|
404
|
+
dataSource = sourceObject.source;
|
|
405
|
+
} else if (relatedTable.shortestKey.length === 1) {
|
|
406
|
+
dataSource = dataSource.concat(relatedTable.shortestKey[0].name);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// complete the path
|
|
410
|
+
filterSource.push({ outbound: fkr.constraint_names[0] });
|
|
411
|
+
|
|
412
|
+
if (useFaceting) {
|
|
413
|
+
let facets;
|
|
414
|
+
location = parse(
|
|
415
|
+
[
|
|
416
|
+
catalog.server.uri,
|
|
417
|
+
'catalog',
|
|
418
|
+
catalog.id,
|
|
419
|
+
'entity',
|
|
420
|
+
fixedEncodeURIComponent(relatedTable.schema.name) + ':' + fixedEncodeURIComponent(relatedTable.name),
|
|
421
|
+
].join('/'),
|
|
422
|
+
catalog,
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
// if the sourceObjectWrapper is passed, filter source is reverse of that.
|
|
426
|
+
// NOTE the related table might have filters, that's why we have to do this and cannot
|
|
427
|
+
// just rely on the structure
|
|
428
|
+
if (isObjectAndNotNull(sourceObjectWrapper)) {
|
|
429
|
+
const addAlias = checkForAssociation && fkrTable.isPureBinaryAssociation;
|
|
430
|
+
facets = sourceObjectWrapper!.getReverseAsFacet(mainTuple!, fkr.key.table, addAlias ? _parserAliases.ASSOCIATION_TABLE : '');
|
|
431
|
+
} else {
|
|
432
|
+
//filters
|
|
433
|
+
const filters: any[] = [];
|
|
434
|
+
fkr.key.table.shortestKey.forEach(function (col) {
|
|
435
|
+
const filter: any = {
|
|
436
|
+
source: filterSource.concat(col.name),
|
|
437
|
+
};
|
|
438
|
+
filter[_facetFilterTypes.CHOICE] = [mainTuple!.data[col.name]];
|
|
439
|
+
filters.push(filter);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
facets = { and: filters };
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// the facets are basd on the value of shortest key of current table
|
|
446
|
+
location.facets = facets;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const newRef = new RelatedReference(
|
|
450
|
+
location!,
|
|
451
|
+
catalog,
|
|
452
|
+
mainRef.table,
|
|
453
|
+
fkr,
|
|
454
|
+
relatedKeyColumnPositions,
|
|
455
|
+
relatedFkColumnPositions,
|
|
456
|
+
_compressSource(dataSource),
|
|
457
|
+
mainTuple,
|
|
458
|
+
displayname,
|
|
459
|
+
_processSourceObjectComment(sourceObject, comment, commentRenderMarkdown, commentDisplayMode),
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
if (derivedAssociationReference) {
|
|
463
|
+
newRef.derivedAssociationReference = derivedAssociationReference;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return newRef;
|
|
467
|
+
};
|