Skip to content

Commit a8b6fe0

Browse files
authored
Merge pull request #41 from CloudBoltSoftware/feature/add-functionality
Expose helper classes. Add abort controller integration. Add service.
2 parents 6a8d78f + b464768 commit a8b6fe0

File tree

10 files changed

+135
-19
lines changed

10 files changed

+135
-19
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@cloudbolt/cb-api-helper",
3-
"version": "0.4.8",
3+
"version": "0.5.0",
44
"scripts": {
55
"co:login": "aws sso login && aws codeartifact login --tool npm --repository cloudbolt-npm --domain cloudbolt --domain-owner 499620025628",
66
"husky:install": "husky install",

src/api/baseApi.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import axios from 'axios'
22

33
const BASE_URL = '/api'
44

5+
let abortController
6+
57
/**
68
* Base Axios Instance for CloudBolt API
79
*/
@@ -23,3 +25,18 @@ export const setAuthHeader = (authToken) => {
2325
export const clearAuthHeader = () => {
2426
baseApi.defaults.headers.common['Authorization'] = ''
2527
}
28+
29+
export const setAbortController = () => {
30+
const controller = new AbortController()
31+
abortController = controller
32+
baseApi.defaults.signal = controller.signal
33+
}
34+
35+
export const getAbortController = () => {
36+
return abortController
37+
}
38+
39+
export const removeAbortController = () => {
40+
abortController = null
41+
baseApi.defaults.signal = null
42+
}
Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const FILTER = 'filter'
22
const ID = 'id'
3+
const GLOBAL_ID = 'global_id'
34
const JOIN_AND = ';'
5+
const JOIN_OR = ','
46
const ICONTAINS = 'icontains'
57
const IEXACT = 'iexact'
68
const IN = 'in'
@@ -9,41 +11,79 @@ const PYTHON_FALSE = 'False'
911
const PYTHON_TRUE = 'True'
1012

1113
export class FilterExpressionBuilder {
12-
andExpressions = []
14+
expressions = []
1315
withFieldEquals(field, value) {
14-
this.andExpressions.push(`${field}.${IEXACT}:${value}`)
16+
this.expressions.push(`${field}.${IEXACT}:${value}`)
1517
return this
1618
}
1719

1820
withFieldEqualsBoolean(field, value) {
1921
const booleanValue = value ? PYTHON_TRUE : PYTHON_FALSE
20-
this.andExpressions.push(`${field}:${booleanValue}`)
22+
this.expressions.push(`${field}:${booleanValue}`)
2123
return this
2224
}
2325

24-
withFieldId(field, value) {
25-
this.andExpressions.push(`${field}.${ID}:${value}`)
26+
withId(field, value) {
27+
this.expressions.push(`${field}.${ID}:${value}`)
28+
return this
29+
}
30+
31+
withIdIn(field, list) {
32+
this.expressions.push(`${field}__${ID}__${IN}:[${list}]`)
33+
return this
34+
}
35+
36+
withGlobalId(field, value) {
37+
this.expressions.push(`${field}.${GLOBAL_ID}:${value}`)
38+
return this
39+
}
40+
41+
withGlobalIdIn(field, list) {
42+
this.expressions.push(
43+
`"${field}__${GLOBAL_ID}__${IN}":["${list.join('","')}"]`
44+
)
2645
return this
2746
}
2847

2948
withFieldILike(field, value) {
30-
this.andExpressions.push(`${field}.${ICONTAINS}:${value}`)
49+
this.expressions.push(`${field}.${ICONTAINS}:${value}`)
3150
return this
3251
}
3352

3453
withFieldIn(field, list) {
35-
this.andExpressions.push(`${field}.${IN}:[${list}]`)
54+
this.expressions.push(`${field}.${IN}:[${list}]`)
3655
return this
3756
}
3857

3958
withFieldNotIn(field, list) {
40-
this.andExpressions.push(`${field}.${NOT_IN}:[${list}]`)
59+
this.expressions.push(`${field}.${NOT_IN}:[${list}]`)
4160
return this
4261
}
4362

44-
build() {
45-
return this.andExpressions.length
46-
? `${FILTER}=${this.andExpressions.join(JOIN_AND)}`
47-
: ''
63+
/**
64+
* Takes the list of expressions and joins them
65+
* together in either AND or OR syntax. Optionally include
66+
* the filter key in the query string.
67+
*
68+
* @param {object} options Optional options object
69+
* @param {string} options.join Either 'and' or 'or'
70+
* @param {boolean} options.includeKey Whether to include the filter key in the query string
71+
* @returns {string}
72+
* @example
73+
* // returns 'filter=[{related__id__in:[1,2,3]},{id__in:[4,5,6]}]'
74+
* builder.buildQueryString({ join: 'or', includeKey: true })
75+
* @example
76+
* //return 'related__id__in:[1,2,3]};{id__in:[4,5,6]'
77+
* builder.buildQueryString({ join: 'and', includeKey: false })
78+
* */
79+
build(options = { join: 'and', includeKey: true }) {
80+
const join = options.join === 'and' ? JOIN_AND : `}${JOIN_OR}{`
81+
const and = options.join === 'and' ? true : false
82+
if (this.expressions.length) {
83+
return `${options.includeKey ? `${FILTER}=` : ''}${
84+
and ? '' : '[{'
85+
}${this.expressions.join(join)}${and ? '' : '}]'}`
86+
}
87+
return ''
4888
}
4989
}

src/api/helpers/FilterExpressionBuilder.test.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ describe('FilterExpressionBuilder builds expression', () => {
3131
expect(response).toEqual('filter=testField:False')
3232
})
3333

34-
it('withFieldId', () => {
34+
it('withId', () => {
3535
const filterExpressionBuilder = new FilterExpressionBuilder()
3636

3737
const response = filterExpressionBuilder
38-
.withFieldId(testField, testValue)
38+
.withId(testField, testValue)
3939
.build()
4040
expect(response).toEqual('filter=testField.id:testValue')
4141
})
@@ -71,11 +71,23 @@ describe('FilterExpressionBuilder builds expression', () => {
7171
const filterExpressionBuilder = new FilterExpressionBuilder()
7272

7373
const response = filterExpressionBuilder
74-
.withFieldId(testField, testValue)
74+
.withId(testField, testValue)
7575
.withFieldEquals(testField, testValue)
7676
.build()
7777
expect(response).toEqual(
7878
'filter=testField.id:testValue;testField.iexact:testValue'
7979
)
8080
})
81+
82+
it('creates an expression to OR multiple expressions', () => {
83+
const filterExpressionBuilder = new FilterExpressionBuilder()
84+
85+
const response = filterExpressionBuilder
86+
.withId(testField, testValue)
87+
.withFieldEquals(testField, testValue)
88+
.build({ join: 'or', includeKey: true })
89+
expect(response).toEqual(
90+
'filter=[{testField.id:testValue},{testField.iexact:testValue}]'
91+
)
92+
})
8193
})

src/api/helpers/index.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { AttributesBuilder } from './AttributesBuilder'
2+
import { FilterExpressionBuilder } from './FilterExpressionBuilder'
3+
import { default as ResponseParser } from './ResponseParser'
4+
import { RestOptionsBuilder } from './RestOptionsBuilder'
5+
import { SortBuilder } from './SortBuilder'
6+
7+
export default {
8+
AttributesBuilder,
9+
FilterExpressionBuilder,
10+
ResponseParser,
11+
RestOptionsBuilder,
12+
SortBuilder
13+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import crud from '../../../crudOperations'
2+
3+
const URL = 'v3/cmp/catalog/blueprints'
4+
5+
export default {
6+
/**
7+
* Retrieve a list of existing Blueprints
8+
* @param options anything parsable by URLSearchParams. See useful options here https://docs.cloudbolt.io/articles/#!cloudbolt-latest-docs/api-conventions/a/h2__904191799
9+
* @returns {Promise} resolves with a cloudbolt API Response list of Blueprint objects
10+
*/
11+
list: (options) => crud.getItems(URL, options),
12+
13+
/**
14+
* Retrieve an existing Blueprint for a given id
15+
* @param {string} id or global_id
16+
* @returns {Promise} resolves with a cloudbolt API Response object of a Blueprint object
17+
*/
18+
get: (id) => crud.getItemById(URL, id)
19+
}

src/api/services/v3/cmp/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import BlueprintCategoriesService from './BlueprintCategoriesService'
44
import BlueprintFiltersService from './BlueprintFiltersService'
55
import BlueprintsService from './BlueprintsService'
66
import BrandedPortalsService from './BrandedPortalsService'
7+
import CatalogBlueprintsService from './CatalogBlueprintsService'
78
import CitService from './CitService'
89
import EnvironmentsService from './EnvironmentsService'
910
import EulaService from './EulaService'
@@ -44,6 +45,7 @@ export default {
4445
blueprintFilters: BlueprintFiltersService,
4546
blueprints: BlueprintsService,
4647
brandedPortals: BrandedPortalsService,
48+
catalogBlueprints: CatalogBlueprintsService,
4749
citService: CitService,
4850
environments: EnvironmentsService,
4951
eula: EulaService,

src/api/services/v3/cmp/index.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const services = [
1313
'blueprintFilters',
1414
'blueprints',
1515
'brandedPortals',
16+
'catalogBlueprints',
1617
'citService',
1718
'environments',
1819
'eula',

src/index.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
import { baseApi, clearAuthHeader, setAuthHeader } from './api/baseApi'
1+
import {
2+
baseApi,
3+
clearAuthHeader,
4+
getAbortController,
5+
removeAbortController,
6+
setAbortController,
7+
setAuthHeader
8+
} from './api/baseApi'
29
import crud, { setErrorHandler } from './api/crudOperations'
10+
import helpers from './api/helpers'
311
import v3 from './api/services/v3'
412

513
/**
@@ -13,8 +21,12 @@ export const createApi = ({ errorHandler } = {}) => {
1321
base: {
1422
instance: baseApi,
1523
crud,
24+
helpers,
1625
setAuthHeader,
1726
clearAuthHeader,
27+
setAbortController,
28+
getAbortController,
29+
removeAbortController,
1830
setErrorHandler
1931
},
2032
v3

0 commit comments

Comments
 (0)