Skip to content
Permalink
Browse files

feat(api): JS-30 - reconstitute Filter/Clause/Restrictions from JSON

This commit adds .fromJson() methods to Clause, Filter,
NestedRestriction, and Restriction, and related support
changes.
  • Loading branch information...
RangerRick committed Mar 21, 2019
1 parent 5e9cf88 commit 891bbd1cb69e6accaf69f0d4eb6b135dbdd7c422
Showing with 88 additions and 6 deletions.
  1. +12 −0 src/api/Clause.ts
  2. +12 −1 src/api/Filter.ts
  3. +11 −0 src/api/NestedRestriction.ts
  4. +6 −1 src/api/Operator.ts
  5. +6 −0 src/api/Restriction.ts
  6. +6 −4 test/api/Comparator.spec.ts
  7. +35 −0 test/api/Filter.spec.ts
@@ -7,6 +7,18 @@ import {NestedRestriction} from './NestedRestriction';
* @module Clause
*/
export class Clause {
/** Given a clause JSON structure, return a Clause object. */
public static fromJson(clause) {
const operator = Operator.forLabel(clause.operator.label);
if (clause.restriction.clauses) {
const nestedRestriction = NestedRestriction.fromJson(clause.restriction);
return new Clause(nestedRestriction, operator);
} else {
const restriction = Restriction.fromJson(clause.restriction);
return new Clause(restriction, operator);
}
}

/** The associated restriction. */
public restriction: Restriction|NestedRestriction;

@@ -1,3 +1,4 @@

import {NestedRestriction} from './NestedRestriction';

/**
@@ -6,9 +7,19 @@ import {NestedRestriction} from './NestedRestriction';
* @param T the model type (OnmsAlarm, OnmsEvent, etc.)
*/
export class Filter extends NestedRestriction {
/** given a filter JSON structure, return a Filter object */
public static fromJson(filter): Filter {
const newFilter = new Filter();
if (filter) {
newFilter.limit = filter.limit;
const nested = NestedRestriction.fromJson(filter);
newFilter.clauses = nested.clauses;
}
return newFilter;
}

/** how many results to get back by default */
public limit = 1000;

/** TODO: add (multiple) orderBy/order support */

}
@@ -7,6 +7,17 @@ import {Restriction} from './Restriction';
* @module NestedRestriction
*/
export class NestedRestriction {
/** given a nested restriction JSON structure, return a NestedRestriction object */
public static fromJson(nestedRestriction): NestedRestriction {
const newNestedRestriction = new NestedRestriction();
if (nestedRestriction && nestedRestriction.clauses) {
nestedRestriction.clauses.forEach((clause) => {
newNestedRestriction.withClause(Clause.fromJson(clause));
});
}
return newNestedRestriction;
}

/** The clauses containing the nested restrictions and their logical operators. */
public clauses = [] as Clause[];

@@ -1,10 +1,15 @@
import {OnmsEnum} from '../internal/OnmsEnum';
import {OnmsEnum, forLabel} from '../internal/OnmsEnum';

/**
* Represents a filter comparator.
* @module Comparator
*/
export class Operator extends OnmsEnum<number> {
/** Given a label ('and', 'or'), return the corresponding operator. */
public static forLabel(label: string) {
return forLabel(Operators, label);
}

/** Aliases for the command-line. */
private aliases = [] as string[];

@@ -9,6 +9,12 @@ const symbolPattern = /^(\w+?)\s*(\=\=|\=|\!\=|\>\=|\<\=|\>|\<)\s*(\w+?)$/;
* @module Restriction
*/
export class Restriction {
/** Given a restriction JSON structure, return a Restriction object. */
public static fromJson(restriction) {
const comparator = Comparator.find(restriction.comparator.label);
return new Restriction(restriction.attribute, comparator, restriction.value);
}

/**
* Convert a filter string into a restriction.
*/
@@ -2,6 +2,7 @@ declare const describe, beforeEach, it, expect;

import {Comparator, Comparators} from '../../src/api/Comparator';

/* tslint:disable:object-literal-sort-keys */
const matches = {
'=': Comparators.EQ,
'==': Comparators.EQ,
@@ -20,11 +21,12 @@ const matches = {
'le': Comparators.LE,
'null': Comparators.NULL,
'isnull': Comparators.NULL,
'notnull': Comparators.NOTNULL
}
'notnull': Comparators.NOTNULL,
};
/* tslint:enable:object-literal-sort-keys */

describe('Comparators: Lower-Case', () => {
for (const match in matches) {
for (const match of Object.keys(matches)) {
const comparator = matches[match];
it(comparator.label + ' should match ' + match.toLowerCase(), () => {
expect(comparator.matches(match.toLowerCase())).toBeTruthy();
@@ -33,7 +35,7 @@ describe('Comparators: Lower-Case', () => {
});

describe('Comparators: Upper-Case', () => {
for (const match in matches) {
for (const match of Object.keys(matches)) {
const comparator = matches[match];
it(comparator.label + ' should match ' + match.toUpperCase(), () => {
expect(comparator.matches(match.toUpperCase())).toBeTruthy();
@@ -0,0 +1,35 @@
declare const describe, it, expect;

// import {Clause} from '../../src/api/Clause';
import {Comparators} from '../../src/api/Comparator';
import {Filter} from '../../src/api/Filter';
import {NestedRestriction} from '../../src/api/NestedRestriction';
// import {Operators} from '../../src/api/Operator';
import {Restriction} from '../../src/api/Restriction';

describe('Filter.fromJson', () => {
const apiFilter = new Filter()
.withAndRestriction(new Restriction('key', Comparators.EQ, 'value'))
.withAndRestriction(new Restriction('key2', Comparators.EQ, 'value2'))
.withAndRestriction(new NestedRestriction()
.withOrRestriction(new Restriction('key3', Comparators.NE, 'value3')));

it('should clone already initialized', (done) => {
const otherFilter = Filter.fromJson(apiFilter);
expect(apiFilter).toEqual(otherFilter);

done();
});

it('should clone', (done) => {
const jsonString = JSON.stringify(apiFilter);
const object = JSON.parse(jsonString);
expect(object).not.toBeInstanceOf(Filter);

const filterObject = Filter.fromJson(object);
expect(filterObject).toBeInstanceOf(Filter);
expect(apiFilter).toEqual(filterObject);

done();
});
});

0 comments on commit 891bbd1

Please sign in to comment.
You can’t perform that action at this time.