UNPKG

@orbit/records

Version:

A flexible data access and synchronization layer.

216 lines 26.4 kB
import { QueryTerm } from '@orbit/data'; import { isObject } from '@orbit/utils'; import { ValidationError } from './record-exceptions'; import { StandardRecordValidators } from './record-validators/standard-record-validators'; function isFilterSpecifier(param) { return param.kind !== undefined; } function isAttributeFilterParam(param) { return param.attribute !== undefined; } function isRelatedRecordFilterParam(param) { return (param.relation !== undefined && param.record !== undefined); } function isRelatedRecordsFilterParam(param) { return (param.relation !== undefined && param.records !== undefined); } export class BaseRecordQueryTerm extends QueryTerm { constructor(queryBuilder, expression) { super(expression); this.$queryBuilder = queryBuilder; } toQueryExpression() { const expression = super.toQueryExpression(); const validatorFor = this.$queryBuilder.$validatorFor; if (validatorFor) { const schema = this.$queryBuilder.$schema; const validateRecordQueryExpression = validatorFor(StandardRecordValidators.RecordQueryExpression); const issues = validateRecordQueryExpression(expression, { validatorFor, schema }); if (issues !== undefined) { throw new ValidationError('Validation isssues encountered while building a query expression', issues); } } return expression; } } /** * A query term representing a single record. */ export class FindRecordTerm extends BaseRecordQueryTerm { constructor(queryBuilder, record) { super(queryBuilder, { op: 'findRecord', record }); } } export class FindRelatedRecordTerm extends BaseRecordQueryTerm { constructor(queryBuilder, record, relationship) { super(queryBuilder, { op: 'findRelatedRecord', record, relationship }); } } export class FindRecordsTerm extends BaseRecordQueryTerm { /** * Applies sorting to a collection query. * * Sort specifiers can be expressed in object form, like: * * ```ts * { attribute: 'name', order: 'descending' } * { attribute: 'name', order: 'ascending' } * ``` * * Or in string form, like: * * ```ts * '-name' // descending order * 'name' // ascending order * ``` */ sort(...params) { var _a; const specifiers = params.map((p) => this.$sortParamToSpecifier(p)); this._expression.sort = ((_a = this._expression.sort) !== null && _a !== void 0 ? _a : []).concat(specifiers); return this; } /** * Applies pagination to a collection query. */ page(param) { this._expression.page = this.$pageParamToSpecifier(param); return this; } /** * Apply a filter expression. * * For example: * * ```ts * oqb * .records('planet') * .filter({ attribute: 'atmosphere', value: true }, * { attribute: 'classification', value: 'terrestrial' }); * ``` */ filter(...params) { var _a; const specifiers = params.map((p) => this.$filterParamToSpecifier(p)); this._expression.filter = ((_a = this._expression.filter) !== null && _a !== void 0 ? _a : []).concat(specifiers); return this; } $filterParamToSpecifier(param) { var _a; let specifier; if (isFilterSpecifier(param)) { specifier = param; } else { const op = (_a = param.op) !== null && _a !== void 0 ? _a : 'equal'; if (isAttributeFilterParam(param)) { const { attribute, value } = param; specifier = { kind: 'attribute', op, attribute, value }; } else if (isRelatedRecordFilterParam(param)) { const { relation } = param; let record; if (Array.isArray(param.record)) { record = param.record.map((ri) => this.$queryBuilder.$normalizeRecordIdentity(ri)); } else if (param.record) { record = this.$queryBuilder.$normalizeRecordIdentity(param.record); } else { record = null; } specifier = { kind: 'relatedRecord', op, relation, record }; } else if (isRelatedRecordsFilterParam(param)) { const { relation } = param; let records = param.records.map((ri) => this.$queryBuilder.$normalizeRecordIdentity(ri)); specifier = { kind: 'relatedRecords', op, relation, records }; } } if (specifier === undefined) { throw new ValidationError('Unrecognized `filter` param encountered while building query expression'); } return specifier; } $pageParamToSpecifier(param) { let specifier; if (param.hasOwnProperty('offset') || param.hasOwnProperty('limit')) { specifier = { kind: 'offsetLimit', offset: param.offset, limit: param.limit }; } if (specifier === undefined) { throw new ValidationError('Unrecognized `page` param encountered while building query expression'); } return specifier; } $sortParamToSpecifier(param) { let specifier; if (isObject(param)) { if (param.hasOwnProperty('kind')) { specifier = param; } else if (param.hasOwnProperty('attribute')) { specifier = { kind: 'attribute', attribute: param.attribute, order: param.order || 'ascending' }; } } else if (typeof param === 'string') { specifier = this.$parseSortParamString(param); } if (specifier === undefined) { throw new ValidationError('Unrecognized `sort` param encountered while building query expression'); } return specifier; } $parseSortParamString(sortSpecifier) { let attribute; let order; if (sortSpecifier[0] === '-') { attribute = sortSpecifier.slice(1); order = 'descending'; } else { attribute = sortSpecifier; order = 'ascending'; } return { kind: 'attribute', attribute, order }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb3JkLXF1ZXJ5LXRlcm0uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVjb3JkLXF1ZXJ5LXRlcm0udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN4QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRXhDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQXFCdEQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sZ0RBQWdELENBQUM7QUFzQzFGLFNBQVMsaUJBQWlCLENBQ3hCLEtBQXNCO0lBRXRCLE9BQVEsS0FBeUIsQ0FBQyxJQUFJLEtBQUssU0FBUyxDQUFDO0FBQ3ZELENBQUM7QUFFRCxTQUFTLHNCQUFzQixDQUM3QixLQUFzQjtJQUV0QixPQUFRLEtBQThCLENBQUMsU0FBUyxLQUFLLFNBQVMsQ0FBQztBQUNqRSxDQUFDO0FBRUQsU0FBUywwQkFBMEIsQ0FDakMsS0FBc0I7SUFFdEIsT0FBTyxDQUNKLEtBQXNDLENBQUMsUUFBUSxLQUFLLFNBQVM7UUFDN0QsS0FBc0MsQ0FBQyxNQUFNLEtBQUssU0FBUyxDQUM3RCxDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsMkJBQTJCLENBQ2xDLEtBQXNCO0lBRXRCLE9BQU8sQ0FDSixLQUF1QyxDQUFDLFFBQVEsS0FBSyxTQUFTO1FBQzlELEtBQXVDLENBQUMsT0FBTyxLQUFLLFNBQVMsQ0FDL0QsQ0FBQztBQUNKLENBQUM7QUFFRCxNQUFNLE9BQU8sbUJBSVgsU0FBUSxTQUFhO0lBR3JCLFlBQVksWUFBd0MsRUFBRSxVQUFjO1FBQ2xFLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNsQixJQUFJLENBQUMsYUFBYSxHQUFHLFlBQVksQ0FBQztJQUNwQyxDQUFDO0lBRUQsaUJBQWlCO1FBQ2YsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLGlCQUFpQixFQUFF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QUssQ0FBQyxDQUFDO1NBQy9DO1FBRUQsSUFBSSxTQUFTLEtBQUssU0FBUyxFQUFFO1lBQzNCLE1BQU0sSUFBSSxlQUFlLENBQ3ZCLHVFQUF1RSxDQUN4RSxDQUFDO1NBQ0g7UUFFRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRUQscUJBQXFCLENBQUMsYUFBcUI7UUFDekMsSUFBSSxTQUFpQixDQUFDO1FBQ3RCLElBQUksS0FBZ0IsQ0FBQztRQUVyQixJQUFJLGFBQWEsQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLEVBQUU7WUFDNUIsU0FBUyxHQUFHLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDbkMsS0FBSyxHQUFHLFlBQVksQ0FBQztTQUN0QjthQUFNO1lBQ0wsU0FBUyxHQUFHLGFBQWEsQ0FBQztZQUMxQixLQUFLLEdBQUcsV0FBVyxDQUFDO1NBQ3JCO1FBRUQsT0FBTztZQUNMLElBQUksRUFBRSxXQUFXO1lBQ2pCLFNBQVM7WUFDVCxLQUFLO1NBQ04sQ0FBQztJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFF1ZXJ5VGVybSB9IGZyb20gJ0BvcmJpdC9kYXRhJztcbmltcG9ydCB7IGlzT2JqZWN0IH0gZnJvbSAnQG9yYml0L3V0aWxzJztcbmltcG9ydCB7IFJlY29yZElkZW50aXR5IH0gZnJvbSAnLi9yZWNvcmQnO1xuaW1wb3J0IHsgVmFsaWRhdGlvbkVycm9yIH0gZnJvbSAnLi9yZWNvcmQtZXhjZXB0aW9ucyc7XG5pbXBvcnQgeyBSZWNvcmRRdWVyeUJ1aWxkZXIgfSBmcm9tICcuL3JlY29yZC1xdWVyeS1idWlsZGVyJztcbmltcG9ydCB7XG4gIEF0dHJpYnV0ZUZpbHRlclNwZWNpZmllcixcbiAgQXR0cmlidXRlU29ydFNwZWNpZmllcixcbiAgRmlsdGVyU3BlY2lmaWVyLFxuICBGaW5kUmVjb3JkLFxuICBGaW5kUmVjb3JkcyxcbiAgRmluZFJlbGF0ZWRSZWNvcmQsXG4gIEZpbmRSZWxhdGVkUmVjb3JkcyxcbiAgUGFnZVNwZWNpZmllcixcbiAgUmVjb3JkUXVlcnlFeHByZXNzaW9uLFxuICBSZWxhdGVkUmVjb3JkRmlsdGVyU3BlY2lmaWVyLFxuICBSZWxhdGVkUmVjb3Jkc0ZpbHRlclNwZWNpZmllcixcbiAgU2V0Q29tcGFyaXNvbk9wZXJhdG9yLFxuICBTb3J0T3JkZXIsXG4gIFNvcnRTcGVjaWZpZXIsXG4gIFZhbHVlQ29tcGFyaXNvbk9wZXJhdG9yXG59IGZyb20gJy4vcmVjb3JkLXF1ZXJ5LWV4cHJlc3Npb24nO1xuaW1wb3J0IHsgUmVjb3JkU2NoZW1hIH0gZnJvbSAnLi9yZWNvcmQtc2NoZW1hJztcbmltcG9ydCB7IFJlY29yZFF1ZXJ5RXhwcmVzc2lvblZhbGlkYXRvciB9IGZyb20gJy4vcmVjb3JkLXZhbGlkYXRvcnMvcmVjb3JkLXF1ZXJ5LWV4cHJlc3Npb24tdmFsaWRhdG9yJztcbmltcG9ydCB7IFN0YW5kYXJkUmVjb3JkVmFsaWRhdG9ycyB9IGZyb20gJy4vcmVjb3JkLXZhbGlkYXRvcnMvc3RhbmRhcmQtcmVjb3JkLXZhbGlkYXRvcnMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEF0dHJpYnV0ZVNvcnRQYXJhbSB7XG4gIGF0dHJpYnV0ZTogc3RyaW5nO1xuICBvcmRlcj86IFNvcnRPcmRlcjtcbn1cblxuZXhwb3J0IHR5cGUgU29ydFBhcmFtID0gU29ydFNwZWNpZmllciB8IEF0dHJpYnV0ZVNvcnRQYXJhbSB8IHN0cmluZztcblxuZXhwb3J0IGludGVyZmFjZSBQYWdlUGFyYW0ge1xuICBvZmZzZXQ/OiBudW1iZXI7XG4gIGxpbWl0PzogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEF0dHJpYnV0ZUZpbHRlclBhcmFtIHtcbiAgb3A/OiBWYWx1ZUNvbXBhcmlzb25PcGVyYXRvcjtcbiAgYXR0cmlidXRlOiBzdHJpbmc7XG4gIHZhbHVlOiBhbnk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVsYXRlZFJlY29yZEZpbHRlclBhcmFtPFJJID0gUmVjb3JkSWRlbnRpdHk+IHtcbiAgb3A/OiBTZXRDb21wYXJpc29uT3BlcmF0b3I7XG4gIHJlbGF0aW9uOiBzdHJpbmc7XG4gIHJlY29yZDogUkkgfCBSSVtdIHwgbnVsbDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZWxhdGVkUmVjb3Jkc0ZpbHRlclBhcmFtPFJJID0gUmVjb3JkSWRlbnRpdHk+IHtcbiAgb3A/OiBTZXRDb21wYXJpc29uT3BlcmF0b3I7XG4gIHJlbGF0aW9uOiBzdHJpbmc7XG4gIHJlY29yZHM6IFJJW107XG59XG5cbmV4cG9ydCB0eXBlIEZpbHRlclBhcmFtPFJJID0gUmVjb3JkSWRlbnRpdHk+ID1cbiAgfCBGaWx0ZXJTcGVjaWZpZXJcbiAgfCBBdHRyaWJ1dGVGaWx0ZXJQYXJhbVxuICB8IFJlbGF0ZWRSZWNvcmRGaWx0ZXJQYXJhbTxSST5cbiAgfCBSZWxhdGVkUmVjb3Jkc0ZpbHRlclBhcmFtPFJJPjtcblxuZnVuY3Rpb24gaXNGaWx0ZXJTcGVjaWZpZXI8UkkgPSBSZWNvcmRJZGVudGl0eT4oXG4gIHBhcmFtOiBGaWx0ZXJQYXJhbTxSST5cbik6IHBhcmFtIGlzIEZpbHRlclNwZWNpZmllciB7XG4gIHJldHVybiAocGFyYW0gYXMgRmlsdGVyU3BlY2lmaWVyKS5raW5kICE9PSB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIGlzQXR0cmlidXRlRmlsdGVyUGFyYW08UkkgPSBSZWNvcmRJZGVudGl0eT4oXG4gIHBhcmFtOiBGaWx0ZXJQYXJhbTxSST5cbik6IHBhcmFtIGlzIEF0dHJpYnV0ZUZpbHRlclBhcmFtIHtcbiAgcmV0dXJuIChwYXJhbSBhcyBBdHRyaWJ1dGVGaWx0ZXJQYXJhbSkuYXR0cmlidXRlICE9PSB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIGlzUmVsYXRlZFJlY29yZEZpbHRlclBhcmFtPFJJID0gUmVjb3JkSWRlbnRpdHk+KFxuICBwYXJhbTogRmlsdGVyUGFyYW08Ukk+XG4pOiBwYXJhbSBpcyBSZWxhdGVkUmVjb3JkRmlsdGVyUGFyYW08Ukk+IHtcbiAgcmV0dXJuIChcbiAgICAocGFyYW0gYXMgUmVsYXRlZFJlY29yZEZpbHRlclBhcmFtPFJJPikucmVsYXRpb24gIT09IHVuZGVmaW5lZCAmJlxuICAgIChwYXJhbSBhcyBSZWxhdGVkUmVjb3JkRmlsdGVyUGFyYW08Ukk+KS5yZWNvcmQgIT09IHVuZGVmaW5lZFxuICApO1xufVxuXG5mdW5jdGlvbiBpc1JlbGF0ZWRSZWNvcmRzRmlsdGVyUGFyYW08UkkgPSBSZWNvcmRJZGVudGl0eT4oXG4gIHBhcmFtOiBGaWx0ZXJQYXJhbTxSST5cbik6IHBhcmFtIGlzIFJlbGF0ZWRSZWNvcmRzRmlsdGVyUGFyYW08Ukk+IHtcbiAgcmV0dXJuIChcbiAgICAocGFyYW0gYXMgUmVsYXRlZFJlY29yZHNGaWx0ZXJQYXJhbTxSST4pLnJlbGF0aW9uICE9PSB1bmRlZmluZWQgJiZcbiAgICAocGFyYW0gYXMgUmVsYXRlZFJlY29yZHNGaWx0ZXJQYXJhbTxSST4pLnJlY29yZHMgIT09IHVuZGVmaW5lZFxuICApO1xufVxuXG5leHBvcnQgY2xhc3MgQmFzZVJlY29yZFF1ZXJ5VGVybTxcbiAgUUUgZXh0ZW5kcyBSZWNvcmRRdWVyeUV4cHJlc3Npb24sXG4gIFJUID0gc3RyaW5nLFxuICBSSSA9IFJlY29yZElkZW50aXR5XG4+IGV4dGVuZHMgUXVlcnlUZXJtPFFFPiB7XG4gICRxdWVyeUJ1aWxkZXI6IFJlY29yZFF1ZXJ5QnVpbGRlcjxSVCwgUkk+O1xuXG4gIGNvbnN0cnVjdG9yKHF1ZXJ5QnVpbGRlcjogUmVjb3JkUXVlcnlCdWlsZGVyPFJULCBSST4sIGV4cHJlc3Npb246IFFFKSB7XG4gICAgc3VwZXIoZXhwcmVzc2lvbik7XG4gICAgdGhpcy4kcXVlcnlCdWlsZGVyID0gcXVlcnlCdWlsZGVyO1xuICB9XG5cbiAgdG9RdWVyeUV4cHJlc3Npb24oKTogUUUge1xuICAgIGNvbnN0IGV4cHJlc3Npb24gPSBzdXBlci50b1F1ZXJ5RXhwcmVzc2lvbigpO1xuXG4gICAgY29uc3QgdmFsaWRhdG9yRm9yID0gdGhpcy4kcXVlcnlCdWlsZGVyLiR2YWxpZGF0b3JGb3I7XG4gICAgaWYgKHZhbGlkYXRvckZvcikge1xuICAgICAgY29uc3Qgc2NoZW1hID0gdGhpcy4kcXVlcnlCdWlsZGVyLiRzY2hlbWEgYXMgUmVjb3JkU2NoZW1hO1xuICAgICAgY29uc3QgdmFsaWRhdGVSZWNvcmRRdWVyeUV4cHJlc3Npb24gPSB2YWxpZGF0b3JGb3IoXG4gICAgICAgIFN0YW5kYXJkUmVjb3JkVmFsaWRhdG9ycy5SZWNvcmRRdWVyeUV4cHJlc3Npb25cbiAgICAgICkgYXMgUmVjb3JkUXVlcnlFeHByZXNzaW9uVmFsaWRhdG9yO1xuXG4gICAgICBjb25zdCBpc3N1ZXMgPSB2YWxpZGF0ZVJlY29yZFF1ZXJ5RXhwcmVzc2lvbihleHByZXNzaW9uLCB7XG4gICAgICAgIHZhbGlkYXRvckZvcixcbiAgICAgICAgc2NoZW1hXG4gICAgICB9KTtcblxuICAgICAgaWYgKGlzc3VlcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXG4gICAgICAgICAgJ1ZhbGlkYXRpb24gaXNzc3VlcyBlbmNvdW50ZXJlZCB3aGlsZSBidWlsZGluZyBhIHF1ZXJ5IGV4cHJlc3Npb24nLFxuICAgICAgICAgIGlzc3Vlc1xuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBleHByZXNzaW9uO1xuICB9XG59XG5cbi8qKlxuICogQSBxdWVyeSB0ZXJtIHJlcHJlc2VudGluZyBhIHNpbmdsZSByZWNvcmQuXG4gKi9cbmV4cG9ydCBjbGFzcyBGaW5kUmVjb3JkVGVybTxcbiAgUlQgPSBzdHJpbmcsXG4gIFJJID0gUmVjb3JkSWRlbnRpdHlcbj4gZXh0ZW5kcyBCYXNlUmVjb3JkUXVlcnlUZXJtPEZpbmRSZWNvcmQsIFJULCBSST4ge1xuICBjb25zdHJ1Y3RvcihcbiAgICBxdWVyeUJ1aWxkZXI6IFJlY29yZFF1ZXJ5QnVpbGRlcjxSVCwgUkk+LFxuICAgIHJlY29yZDogUmVjb3JkSWRlbnRpdHlcbiAgKSB7XG4gICAgc3VwZXIocXVlcnlCdWlsZGVyLCB7XG4gICAgICBvcDogJ2ZpbmRSZWNvcmQnLFxuICAgICAgcmVjb3JkXG4gICAgfSk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIEZpbmRSZWxhdGVkUmVjb3JkVGVybTxcbiAgUlQgPSBzdHJpbmcsXG4gIFJJID0gUmVjb3JkSWRlbnRpdHlcbj4gZXh0ZW5kcyBCYXNlUmVjb3JkUXVlcnlUZXJtPEZpbmRSZWxhdGVkUmVjb3JkLCBSVCwgUkk+IHtcbiAgY29uc3RydWN0b3IoXG4gICAgcXVlcnlCdWlsZGVyOiBSZWNvcmRRdWVyeUJ1aWxkZXI8UlQsIFJJPixcbiAgICByZWNvcmQ6IFJlY29yZElkZW50aXR5LFxuICAgIHJlbGF0aW9uc2hpcDogc3RyaW5nXG4gICkge1xuICAgIHN1cGVyKHF1ZXJ5QnVpbGRlciwge1xuICAgICAgb3A6ICdmaW5kUmVsYXRlZFJlY29yZCcsXG4gICAgICByZWNvcmQsXG4gICAgICByZWxhdGlvbnNoaXBcbiAgICB9KTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgRmluZFJlY29yZHNUZXJtPFxuICBSVCA9IHN0cmluZyxcbiAgUkkgPSBSZWNvcmRJZGVudGl0eVxuPiBleHRlbmRzIEJhc2VSZWNvcmRRdWVyeVRlcm08RmluZFJlY29yZHMgfCBGaW5kUmVsYXRlZFJlY29yZHMsIFJULCBSST4ge1xuICAvKipcbiAgICogQXBwbGllcyBzb3J0aW5nIHRvIGEgY29sbGVjdGlvbiBxdWVyeS5cbiAgICpcbiAgICogU29ydCBzcGVjaWZpZXJzIGNhbiBiZSBleHByZXNzZWQgaW4gb2JqZWN0IGZvcm0sIGxpa2U6XG4gICAqXG4gICAqIGBgYHRzXG4gICAqIHsgYXR0cmlidXRlOiAnbmFtZScsIG9yZGVyOiAnZGVzY2VuZGluZycgfVxuICAgKiB7IGF0dHJpYnV0ZTogJ25hbWUnLCBvcmRlcjogJ2FzY2VuZGluZycgfVxuICAgKiBgYGBcbiAgICpcbiAgICogT3IgaW4gc3RyaW5nIGZvcm0sIGxpa2U6XG4gICAqXG4gICAqIGBgYHRzXG4gICAqICctbmFtZScgLy8gZGVzY2VuZGluZyBvcmRlclxuICAgKiAnbmFtZScgIC8vIGFzY2VuZGluZyBvcmRlclxuICAgKiBgYGBcbiAgICovXG4gIHNvcnQoLi4ucGFyYW1zOiBTb3J0UGFyYW1bXSk6IHRoaXMge1xuICAgIGNvbnN0IHNwZWNpZmllcnMgPSBwYXJhbXMubWFwKChwKSA9PiB0aGlzLiRzb3J0UGFyYW1Ub1NwZWNpZmllcihwKSk7XG4gICAgdGhpcy5fZXhwcmVzc2lvbi5zb3J0ID0gKHRoaXMuX2V4cHJlc3Npb24uc29ydCA/PyBbXSkuY29uY2F0KHNwZWNpZmllcnMpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFwcGxpZXMgcGFnaW5hdGlvbiB0byBhIGNvbGxlY3Rpb24gcXVlcnkuXG4gICAqL1xuICBwYWdlKHBhcmFtOiBQYWdlUGFyYW0pOiB0aGlzIHtcbiAgICB0aGlzLl9leHByZXNzaW9uLnBhZ2UgPSB0aGlzLiRwYWdlUGFyYW1Ub1NwZWNpZmllcihwYXJhbSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQXBwbHkgYSBmaWx0ZXIgZXhwcmVzc2lvbi5cbiAgICpcbiAgICogRm9yIGV4YW1wbGU6XG4gICAqXG4gICAqIGBgYHRzXG4gICAqIG9xYlxuICAgKiAgIC5yZWNvcmRzKCdwbGFuZXQnKVxuICAgKiAgIC5maWx0ZXIoeyBhdHRyaWJ1dGU6ICdhdG1vc3BoZXJlJywgdmFsdWU6IHRydWUgfSxcbiAgICogICAgICAgICAgIHsgYXR0cmlidXRlOiAnY2xhc3NpZmljYXRpb24nLCB2YWx1ZTogJ3RlcnJlc3RyaWFsJyB9KTtcbiAgICogYGBgXG4gICAqL1xuICBmaWx0ZXIoLi4ucGFyYW1zOiBGaWx0ZXJQYXJhbTxSST5bXSk6IHRoaXMge1xuICAgIGNvbnN0IHNwZWNpZmllcnMgPSBwYXJhbXMubWFwKChwKSA9PiB0aGlzLiRmaWx0ZXJQYXJhbVRvU3BlY2lmaWVyKHApKTtcbiAgICB0aGlzLl9leHByZXNzaW9uLmZpbHRlciA9ICh0aGlzLl9leHByZXNzaW9uLmZpbHRlciA/PyBbXSkuY29uY2F0KFxuICAgICAgc3BlY2lmaWVyc1xuICAgICk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAkZmlsdGVyUGFyYW1Ub1NwZWNpZmllcihwYXJhbTogRmlsdGVyUGFyYW08Ukk+KTogRmlsdGVyU3BlY2lmaWVyIHtcbiAgICBsZXQgc3BlY2lmaWVyOiBGaWx0ZXJTcGVjaWZpZXIgfCB1bmRlZmluZWQ7XG5cbiAgICBpZiAoaXNGaWx0ZXJTcGVjaWZpZXI8Ukk+KHBhcmFtKSkge1xuICAgICAgc3BlY2lmaWVyID0gcGFyYW07XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG9wID0gcGFyYW0ub3AgPz8gJ2VxdWFsJztcbiAgICAgIGlmIChpc0F0dHJpYnV0ZUZpbHRlclBhcmFtKHBhcmFtKSkge1xuICAgICAgICBjb25zdCB7IGF0dHJpYnV0ZSwgdmFsdWUgfSA9IHBhcmFtO1xuICAgICAgICBzcGVjaWZpZXIgPSB7XG4gICAgICAgICAga2luZDogJ2F0dHJpYnV0ZScsXG4gICAgICAgICAgb3AsXG4gICAgICAgICAgYXR0cmlidXRlLFxuICAgICAgICAgIHZhbHVlXG4gICAgICAgIH0gYXMgQXR0cmlidXRlRmlsdGVyU3BlY2lmaWVyO1xuICAgICAgfSBlbHNlIGlmIChpc1JlbGF0ZWRSZWNvcmRGaWx0ZXJQYXJhbTxSST4ocGFyYW0pKSB7XG4gICAgICAgIGNvbnN0IHsgcmVsYXRpb24gfSA9IHBhcmFtO1xuICAgICAgICBsZXQgcmVjb3JkOiBSZWNvcmRJZGVudGl0eVtdIHwgUmVjb3JkSWRlbnRpdHkgfCBudWxsO1xuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShwYXJhbS5yZWNvcmQpKSB7XG4gICAgICAgICAgcmVjb3JkID0gcGFyYW0ucmVjb3JkLm1hcCgocmkpID0+XG4gICAgICAgICAgICB0aGlzLiRxdWVyeUJ1aWxkZXIuJG5vcm1hbGl6ZVJlY29yZElkZW50aXR5KHJpKVxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSBpZiAocGFyYW0ucmVjb3JkKSB7XG4gICAgICAgICAgcmVjb3JkID0gdGhpcy4kcXVlcnlCdWlsZGVyLiRub3JtYWxpemVSZWNvcmRJZGVudGl0eShwYXJhbS5yZWNvcmQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJlY29yZCA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgc3BlY2lmaWVyID0ge1xuICAgICAgICAgIGtpbmQ6ICdyZWxhdGVkUmVjb3JkJyxcbiAgICAgICAgICBvcCxcbiAgICAgICAgICByZWxhdGlvbixcbiAgICAgICAgICByZWNvcmRcbiAgICAgICAgfSBhcyBSZWxhdGVkUmVjb3JkRmlsdGVyU3BlY2lmaWVyO1xuICAgICAgfSBlbHNlIGlmIChpc1JlbGF0ZWRSZWNvcmRzRmlsdGVyUGFyYW08Ukk+KHBhcmFtKSkge1xuICAgICAgICBjb25zdCB7IHJlbGF0aW9uIH0gPSBwYXJhbTtcbiAgICAgICAgbGV0IHJlY29yZHMgPSBwYXJhbS5yZWNvcmRzLm1hcCgocmkpID0+XG4gICAgICAgICAgdGhpcy4kcXVlcnlCdWlsZGVyLiRub3JtYWxpemVSZWNvcmRJZGVudGl0eShyaSlcbiAgICAgICAgKTtcbiAgICAgICAgc3BlY2lmaWVyID0ge1xuICAgICAgICAgIGtpbmQ6ICdyZWxhdGVkUmVjb3JkcycsXG4gICAgICAgICAgb3AsXG4gICAgICAgICAgcmVsYXRpb24sXG4gICAgICAgICAgcmVjb3Jkc1xuICAgICAgICB9IGFzIFJlbGF0ZWRSZWNvcmRzRmlsdGVyU3BlY2lmaWVyO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChzcGVjaWZpZXIgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihcbiAgICAgICAgJ1VucmVjb2duaXplZCBgZmlsdGVyYCBwYXJhbSBlbmNvdW50ZXJlZCB3aGlsZSBidWlsZGluZyBxdWVyeSBleHByZXNzaW9uJ1xuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc3BlY2lmaWVyO1xuICB9XG5cbiAgJHBhZ2VQYXJhbVRvU3BlY2lmaWVyKHBhcmFtOiBQYWdlUGFyYW0pOiBQYWdlU3BlY2lmaWVyIHtcbiAgICBsZXQgc3BlY2lmaWVyOiBQYWdlU3BlY2lmaWVyIHwgdW5kZWZpbmVkO1xuXG4gICAgaWYgKHBhcmFtLmhhc093blByb3BlcnR5KCdvZmZzZXQnKSB8fCBwYXJhbS5oYXNPd25Qcm9wZXJ0eSgnbGltaXQnKSkge1xuICAgICAgc3BlY2lmaWVyID0ge1xuICAgICAgICBraW5kOiAnb2Zmc2V0TGltaXQnLFxuICAgICAgICBvZmZzZXQ6IHBhcmFtLm9mZnNldCxcbiAgICAgICAgbGltaXQ6IHBhcmFtLmxpbWl0XG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmIChzcGVjaWZpZXIgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihcbiAgICAgICAgJ1VucmVjb2duaXplZCBgcGFnZWAgcGFyYW0gZW5jb3VudGVyZWQgd2hpbGUgYnVpbGRpbmcgcXVlcnkgZXhwcmVzc2lvbidcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNwZWNpZmllcjtcbiAgfVxuXG4gICRzb3J0UGFyYW1Ub1NwZWNpZmllcihwYXJhbTogU29ydFBhcmFtKTogU29ydFNwZWNpZmllciB7XG4gICAgbGV0IHNwZWNpZmllcjogU29ydFNwZWNpZmllciB8IHVuZGVmaW5lZDtcblxuICAgIGlmIChpc09iamVjdChwYXJhbSkpIHtcbiAgICAgIGlmIChwYXJhbS5oYXNPd25Qcm9wZXJ0eSgna2luZCcpKSB7XG4gICAgICAgIHNwZWNpZmllciA9IHBhcmFtIGFzIFNvcnRTcGVjaWZpZXI7XG4gICAgICB9IGVsc2UgaWYgKHBhcmFtLmhhc093blByb3BlcnR5KCdhdHRyaWJ1dGUnKSkge1xuICAgICAgICBzcGVjaWZpZXIgPSB7XG4gICAgICAgICAga2luZDogJ2F0dHJpYnV0ZScsXG4gICAgICAgICAgYXR0cmlidXRlOiAocGFyYW0gYXMgQXR0cmlidXRlU29ydFBhcmFtKS5hdHRyaWJ1dGUsXG4gICAgICAgICAgb3JkZXI6IChwYXJhbSBhcyBBdHRyaWJ1dGVTb3J0UGFyYW0pLm9yZGVyIHx8ICdhc2NlbmRpbmcnXG4gICAgICAgIH0gYXMgQXR0cmlidXRlU29ydFNwZWNpZmllcjtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBwYXJhbSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHNwZWNpZmllciA9IHRoaXMuJHBhcnNlU29ydFBhcmFtU3RyaW5nKHBhcmFtKTtcbiAgICB9XG5cbiAgICBpZiAoc3BlY2lmaWVyID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXG4gICAgICAgICdVbnJlY29nbml6ZWQgYHNvcnRgIHBhcmFtIGVuY291bnRlcmVkIHdoaWxlIGJ1aWxkaW5nIHF1ZXJ5IGV4cHJlc3Npb24nXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiBzcGVjaWZpZXI7XG4gIH1cblxuICAkcGFyc2VTb3J0UGFyYW1TdHJpbmcoc29ydFNwZWNpZmllcjogc3RyaW5nKTogQXR0cmlidXRlU29ydFNwZWNpZmllciB7XG4gICAgbGV0IGF0dHJpYnV0ZTogc3RyaW5nO1xuICAgIGxldCBvcmRlcjogU29ydE9yZGVyO1xuXG4gICAgaWYgKHNvcnRTcGVjaWZpZXJbMF0gPT09ICctJykge1xuICAgICAgYXR0cmlidXRlID0gc29ydFNwZWNpZmllci5zbGljZSgxKTtcbiAgICAgIG9yZGVyID0gJ2Rlc2NlbmRpbmcnO1xuICAgIH0gZWxzZSB7XG4gICAgICBhdHRyaWJ1dGUgPSBzb3J0U3BlY2lmaWVyO1xuICAgICAgb3JkZXIgPSAnYXNjZW5kaW5nJztcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAga2luZDogJ2F0dHJpYnV0ZScsXG4gICAgICBhdHRyaWJ1dGUsXG4gICAgICBvcmRlclxuICAgIH07XG4gIH1cbn1cblxuZXhwb3J0IHR5cGUgUmVjb3JkUXVlcnlUZXJtPFJUID0gc3RyaW5nLCBSSSA9IFJlY29yZElkZW50aXR5PiA9XG4gIHwgRmluZFJlY29yZFRlcm08UlQsIFJJPlxuICB8IEZpbmRSZWxhdGVkUmVjb3JkVGVybTxSVCwgUkk+XG4gIHwgRmluZFJlY29yZHNUZXJtPFJULCBSST47XG4iXX0=