Skip to content

Commit

Permalink
Merge branch 'main' into remove-msr
Browse files Browse the repository at this point in the history
  • Loading branch information
nickboldt authored Oct 15, 2024
2 parents b3846ee + ca5e8cc commit 903d286
Show file tree
Hide file tree
Showing 22 changed files with 818 additions and 582 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "root",
"version": "3.3.0",
"version": "3.4.0",
"private": true,
"engines": {
"node": "20"
Expand Down
2 changes: 1 addition & 1 deletion plugins/keycloak-backend/dist-dynamic/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@janus-idp/backstage-plugin-keycloak-backend-dynamic",
"version": "2.0.7",
"version": "2.0.8",
"description": "A Backend backend plugin for Keycloak",
"main": "./dist/index.cjs.js",
"types": "./dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion plugins/keycloak-backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@janus-idp/backstage-plugin-keycloak-backend",
"version": "2.0.7",
"version": "2.0.8",
"description": "A Backend backend plugin for Keycloak",
"main": "src/index.ts",
"types": "src/index.ts",
Expand Down
4 changes: 4 additions & 0 deletions plugins/orchestrator-backend/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
### Dependencies

* **@janus-idp/backstage-plugin-orchestrator-common:** upgraded to 1.21.0

### Dependencies

* **@janus-idp/backstage-plugin-orchestrator-common:** upgraded to 1.20.0
* **@janus-idp/cli:** upgraded to 1.15.2

Expand Down
2 changes: 1 addition & 1 deletion plugins/orchestrator-backend/dist-dynamic/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@janus-idp/backstage-plugin-orchestrator-backend-dynamic",
"version": "2.2.2",
"version": "2.3.1",
"license": "Apache-2.0",
"main": "./dist/index.cjs.js",
"types": "src/index.ts",
Expand Down
4 changes: 2 additions & 2 deletions plugins/orchestrator-backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@janus-idp/backstage-plugin-orchestrator-backend",
"version": "2.2.2",
"version": "2.3.1",
"license": "Apache-2.0",
"main": "src/index.ts",
"types": "src/index.ts",
Expand Down Expand Up @@ -78,7 +78,7 @@
"@backstage/plugin-permission-node": "^0.8.0",
"@backstage/plugin-scaffolder-backend": "^1.23.0",
"@backstage/plugin-scaffolder-node": "^0.4.8",
"@janus-idp/backstage-plugin-orchestrator-common": "*",
"@janus-idp/backstage-plugin-orchestrator-common": "1.21.0",
"@urql/core": "^4.1.4",
"ajv-formats": "^2.1.1",
"cloudevents": "^8.0.0",
Expand Down
203 changes: 203 additions & 0 deletions plugins/orchestrator-backend/src/helpers/filterBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import {
FieldFilter,
FieldFilterOperatorEnum,
Filter,
IntrospectionField,
LogicalFilter,
TypeName,
} from '@janus-idp/backstage-plugin-orchestrator-common';

function isLogicalFilter(filter: Filter): filter is LogicalFilter {
return (filter as LogicalFilter).filters !== undefined;
}

function handleLogicalFilter(
introspection: IntrospectionField[],
filter: LogicalFilter,
): string {
if (!filter.operator) return '';

const subClauses = filter.filters.map(f =>
buildFilterCondition(introspection, f),
);

return `${filter.operator.toLowerCase()}: {${subClauses.join(', ')}}`;
}

function handleBetweenOperator(filter: FieldFilter): string {
if (!Array.isArray(filter.value) || filter.value.length !== 2) {
throw new Error('Between operator requires an array of two elements');
}
return `${filter.field}: {${getGraphQLOperator(FieldFilterOperatorEnum.Between)}: {from: "${filter.value[0]}", to: "${filter.value[1]}"}}`;
}

function handleIsNullOperator(filter: FieldFilter): string {
return `${filter.field}: {${getGraphQLOperator(FieldFilterOperatorEnum.IsNull)}: ${convertToBoolean(filter.value)}}`;
}

function handleBinaryOperator(
binaryFilter: FieldFilter,
fieldDef: IntrospectionField,
): string {
const formattedValue = Array.isArray(binaryFilter.value)
? `[${binaryFilter.value.map(v => formatValue(binaryFilter.field, v, fieldDef)).join(', ')}]`
: formatValue(binaryFilter.field, binaryFilter.value, fieldDef);

return `${binaryFilter.field}: {${getGraphQLOperator(binaryFilter.operator)}: ${formattedValue}}`;
}

export function buildFilterCondition(
introspection: IntrospectionField[],
filters?: Filter,
): string {
if (!filters) {
return '';
}

if (isLogicalFilter(filters)) {
return handleLogicalFilter(introspection, filters);
}

if (!isOperatorSupported(filters.operator)) {
throw new Error(`Unsopported operator ${filters.operator}`);
}

const fieldDef = introspection.find(f => f.name === filters.field);
if (!fieldDef) {
throw new Error(`Can't find field "${filters.field}" definition`);
}

if (!isOperatorAllowedForField(filters.operator, fieldDef)) {
throw new Error(`Unsupported field type ${fieldDef.type.name}`);
}

switch (filters.operator) {
case FieldFilterOperatorEnum.IsNull:
return handleIsNullOperator(filters);
case FieldFilterOperatorEnum.Between:
return handleBetweenOperator(filters);
case FieldFilterOperatorEnum.Eq:
case FieldFilterOperatorEnum.Like:
case FieldFilterOperatorEnum.In:
case FieldFilterOperatorEnum.Gt:
case FieldFilterOperatorEnum.Gte:
case FieldFilterOperatorEnum.Lt:
case FieldFilterOperatorEnum.Lte:
return handleBinaryOperator(filters, fieldDef);

default:
throw new Error(`Can't build filter condition`);
}
}

function isOperatorSupported(operator: FieldFilterOperatorEnum): boolean {
return (
operator === FieldFilterOperatorEnum.Eq ||
operator === FieldFilterOperatorEnum.Like ||
operator === FieldFilterOperatorEnum.In ||
operator === FieldFilterOperatorEnum.IsNull ||
operator === FieldFilterOperatorEnum.Gt ||
operator === FieldFilterOperatorEnum.Gte ||
operator === FieldFilterOperatorEnum.Lt ||
operator === FieldFilterOperatorEnum.Lte ||
operator === FieldFilterOperatorEnum.Between
);
}

function isFieldFilterSupported(fieldDef: IntrospectionField): boolean {
return fieldDef?.type.name === TypeName.String;
}

function isOperatorAllowedForField(
operator: FieldFilterOperatorEnum,
fieldDef: IntrospectionField,
): boolean {
const allowedOperators: Record<TypeName, FieldFilterOperatorEnum[]> = {
[TypeName.String]: [
FieldFilterOperatorEnum.In,
FieldFilterOperatorEnum.Like,
FieldFilterOperatorEnum.IsNull,
FieldFilterOperatorEnum.Eq,
],
[TypeName.Id]: [
FieldFilterOperatorEnum.In,
FieldFilterOperatorEnum.IsNull,
FieldFilterOperatorEnum.Eq,
],
[TypeName.Date]: [
FieldFilterOperatorEnum.IsNull,
FieldFilterOperatorEnum.Eq,
FieldFilterOperatorEnum.Gt,
FieldFilterOperatorEnum.Gte,
FieldFilterOperatorEnum.Lt,
FieldFilterOperatorEnum.Lte,
FieldFilterOperatorEnum.Between,
],
[TypeName.StringArray]: [],
};
const allowedForType = allowedOperators[fieldDef.type.name];
return allowedForType ? allowedForType.includes(operator) : false;
}

function convertToBoolean(value: any): boolean {
if (typeof value === 'boolean') {
return value;
}
if (typeof value === 'string') {
return value.toLowerCase() === 'true';
}
if (typeof value === 'number') {
return value === 1;
}
return false; // Default to false for unsupported types
}

function formatValue(
fieldName: string,
fieldValue: any,
fieldDef: IntrospectionField,
): string {
if (!isFieldFilterSupported) {
throw new Error(`Unsupported field type ${fieldDef.type.name}`);
}

if (
fieldDef.type.name === TypeName.String ||
fieldDef.type.name === TypeName.Id ||
fieldDef.type.name === TypeName.Date
) {
return `"${fieldValue}"`;
}
throw new Error(
`Failed to format value for ${fieldName} ${fieldValue} with type ${fieldDef.type.name}`,
);
}

function getGraphQLOperator(operator: FieldFilterOperatorEnum): string {
switch (operator) {
case 'EQ':
return 'equal';
case 'LIKE':
return 'like';
case 'IN':
return 'in';
case 'IS_NULL':
return 'isNull';
case 'GT':
return 'greaterThan';
case 'GTE':
return 'greaterThanEqual';
case 'LT':
return 'lessThan';
case 'LTE':
return 'lessThanEqual';
// case 'CONTAINS':
// return "contains"
// case 'CONTAINS_ALL':
// case 'CONTAINS_ANY':
case 'BETWEEN':
return 'between';
default:
throw new Error(`Operation "${operator}" not supported`);
}
}
Loading

0 comments on commit 903d286

Please sign in to comment.