|
1 | | -import { Repository, EntityManager } from 'typeorm'; |
| 1 | +import { Repository, EntityManager, SelectQueryBuilder } from 'typeorm'; |
2 | 2 | import { EntityRepository } from '../../typeorm-typedi-extensions'; |
3 | 3 | import { FeatureFlag } from '../models/FeatureFlag'; |
4 | 4 | import repositoryError from './utils/repositoryError'; |
@@ -91,26 +91,48 @@ export class FeatureFlagRepository extends Repository<FeatureFlag> { |
91 | 91 | } |
92 | 92 |
|
93 | 93 | public async getFlagsFromContext(context: string): Promise<FeatureFlag[]> { |
94 | | - const result = await this.createQueryBuilder('feature_flag') |
95 | | - .leftJoinAndSelect('feature_flag.featureFlagSegmentInclusion', 'featureFlagSegmentInclusion') |
96 | | - .leftJoinAndSelect('featureFlagSegmentInclusion.segment', 'segmentInclusion') |
97 | | - .leftJoinAndSelect('segmentInclusion.individualForSegment', 'individualForSegment') |
98 | | - .leftJoinAndSelect('segmentInclusion.groupForSegment', 'groupForSegment') |
99 | | - .leftJoinAndSelect('segmentInclusion.subSegments', 'subSegment') |
100 | | - .leftJoinAndSelect('feature_flag.featureFlagSegmentExclusion', 'featureFlagSegmentExclusion') |
101 | | - .leftJoinAndSelect('featureFlagSegmentExclusion.segment', 'segmentExclusion') |
102 | | - .leftJoinAndSelect('segmentExclusion.individualForSegment', 'individualForSegmentExclusion') |
103 | | - .leftJoinAndSelect('segmentExclusion.groupForSegment', 'groupForSegmentExclusion') |
104 | | - .leftJoinAndSelect('segmentExclusion.subSegments', 'subSegmentExclusion') |
105 | | - .where('feature_flag.context @> :searchContext', { searchContext: [context] }) |
106 | | - .andWhere('feature_flag.status = :status', { status: FEATURE_FLAG_STATUS.ENABLED }) |
107 | | - .getMany() |
108 | | - .catch((errorMsg: any) => { |
109 | | - const errorMsgString = repositoryError('FeatureFlagRepository', 'getFlagsFromContext', { context }, errorMsg); |
110 | | - throw errorMsgString; |
111 | | - }); |
| 94 | + const addExclusionJoins = (qb: SelectQueryBuilder<FeatureFlag>) => |
| 95 | + qb |
| 96 | + .leftJoinAndSelect('feature_flag.featureFlagSegmentExclusion', 'featureFlagSegmentExclusion') |
| 97 | + .leftJoinAndSelect('featureFlagSegmentExclusion.segment', 'segmentExclusion') |
| 98 | + .leftJoinAndSelect('segmentExclusion.individualForSegment', 'individualForSegmentExclusion') |
| 99 | + .leftJoinAndSelect('segmentExclusion.groupForSegment', 'groupForSegmentExclusion') |
| 100 | + .leftJoinAndSelect('segmentExclusion.subSegments', 'subSegmentExclusion'); |
112 | 101 |
|
113 | | - return result; |
| 102 | + const addInclusionJoins = (qb: SelectQueryBuilder<FeatureFlag>) => |
| 103 | + qb |
| 104 | + .leftJoinAndSelect('feature_flag.featureFlagSegmentInclusion', 'featureFlagSegmentInclusion') |
| 105 | + .leftJoinAndSelect('featureFlagSegmentInclusion.segment', 'segmentInclusion') |
| 106 | + .leftJoinAndSelect('segmentInclusion.individualForSegment', 'individualForSegment') |
| 107 | + .leftJoinAndSelect('segmentInclusion.groupForSegment', 'groupForSegment') |
| 108 | + .leftJoinAndSelect('segmentInclusion.subSegments', 'subSegment'); |
| 109 | + |
| 110 | + const addBaseConditions = (qb: SelectQueryBuilder<FeatureFlag>) => |
| 111 | + qb |
| 112 | + .where('feature_flag.context @> :searchContext', { searchContext: [context] }) |
| 113 | + .andWhere('feature_flag.status = :status', { status: FEATURE_FLAG_STATUS.ENABLED }); |
| 114 | + |
| 115 | + // INCLUDE_ALL flags: inclusion segments are irrelevant — skip all inclusion joins |
| 116 | + const includeAllQuery = addBaseConditions(addExclusionJoins(this.createQueryBuilder('feature_flag'))).andWhere( |
| 117 | + 'feature_flag.filterMode = :includeAll', |
| 118 | + { includeAll: FILTER_MODE.INCLUDE_ALL } |
| 119 | + ); |
| 120 | + |
| 121 | + // EXCLUDE_ALL flags: both inclusion and exclusion segments are needed |
| 122 | + const excludeAllQuery = addBaseConditions( |
| 123 | + addInclusionJoins(addExclusionJoins(this.createQueryBuilder('feature_flag'))) |
| 124 | + ).andWhere('feature_flag.filterMode = :excludeAll', { excludeAll: FILTER_MODE.EXCLUDE_ALL }); |
| 125 | + |
| 126 | + const [includeAllFlags, excludeAllFlags] = await Promise.all([ |
| 127 | + includeAllQuery.getMany().catch((errorMsg: any) => { |
| 128 | + throw repositoryError('FeatureFlagRepository', 'getFlagsFromContext', { context }, errorMsg); |
| 129 | + }), |
| 130 | + excludeAllQuery.getMany().catch((errorMsg: any) => { |
| 131 | + throw repositoryError('FeatureFlagRepository', 'getFlagsFromContext', { context }, errorMsg); |
| 132 | + }), |
| 133 | + ]); |
| 134 | + |
| 135 | + return [...includeAllFlags, ...excludeAllFlags]; |
114 | 136 | } |
115 | 137 |
|
116 | 138 | public async validateUniqueKey(flagDTO: FeatureFlagValidation) { |
|
0 commit comments