Skip to content

Commit

Permalink
Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
sjaanus committed Dec 12, 2024
1 parent 8d2181e commit 6b077f1
Show file tree
Hide file tree
Showing 8 changed files with 460 additions and 448 deletions.

Large diffs are not rendered by default.

208 changes: 104 additions & 104 deletions src/lib/features/client-feature-toggles/cache/revision-cache.test.ts
Original file line number Diff line number Diff line change
@@ -1,110 +1,110 @@
import { RevisionCache } from "./revision-cache";
import { Revision } from "./client-feature-toggle-cache";
import { RevisionCache } from './revision-cache';
import type { Revision } from './client-feature-toggle-cache';

describe("RevisionCache", () => {
it("should create a new base when trying to add a new revision at the max limit", () => {
const initialRevisions: Revision[] = [
{
revisionId: 1,
updated: [
{
name: "test-flag",
type: "release",
enabled: false,
project: "default",
stale: false,
strategies: [
{
name: "flexibleRollout",
constraints: [],
parameters: {
groupId: "test-flag",
rollout: "100",
stickiness: "default",
},
variants: [],
},
],
variants: [],
description: null,
impressionData: false,
},
],
removed: [],
},
{
revisionId: 2,
updated: [
{
name: "my-feature-flag",
type: "release",
enabled: true,
project: "default",
stale: false,
strategies: [
{
name: "flexibleRollout",
constraints: [],
parameters: {
groupId: "my-feature-flag",
rollout: "100",
stickiness: "default",
},
variants: [],
},
],
variants: [],
description: null,
impressionData: false,
},
],
removed: [],
},
];
describe('RevisionCache', () => {
it('should create a new base when trying to add a new revision at the max limit', () => {
const initialRevisions: Revision[] = [
{
revisionId: 1,
updated: [
{
name: 'test-flag',
type: 'release',
enabled: false,
project: 'default',
stale: false,
strategies: [
{
name: 'flexibleRollout',
constraints: [],
parameters: {
groupId: 'test-flag',
rollout: '100',
stickiness: 'default',
},
variants: [],
},
],
variants: [],
description: null,
impressionData: false,
},
],
removed: [],
},
{
revisionId: 2,
updated: [
{
name: 'my-feature-flag',
type: 'release',
enabled: true,
project: 'default',
stale: false,
strategies: [
{
name: 'flexibleRollout',
constraints: [],
parameters: {
groupId: 'my-feature-flag',
rollout: '100',
stickiness: 'default',
},
variants: [],
},
],
variants: [],
description: null,
impressionData: false,
},
],
removed: [],
},
];

const maxLength = 2;
const deltaCache = new RevisionCache(initialRevisions, maxLength);
const maxLength = 2;
const deltaCache = new RevisionCache(initialRevisions, maxLength);

// Add a new revision to trigger changeBase
deltaCache.addRevision({
revisionId: 3,
updated: [
{
name: "another-feature-flag",
type: "release",
enabled: true,
project: "default",
stale: false,
strategies: [
{
name: "flexibleRollout",
constraints: [],
parameters: {
groupId: "another-feature-flag",
rollout: "100",
stickiness: "default",
},
variants: [],
},
],
variants: [],
description: null,
impressionData: false,
},
],
removed: [],
});
// Add a new revision to trigger changeBase
deltaCache.addRevision({
revisionId: 3,
updated: [
{
name: 'another-feature-flag',
type: 'release',
enabled: true,
project: 'default',
stale: false,
strategies: [
{
name: 'flexibleRollout',
constraints: [],
parameters: {
groupId: 'another-feature-flag',
rollout: '100',
stickiness: 'default',
},
variants: [],
},
],
variants: [],
description: null,
impressionData: false,
},
],
removed: [],
});

const revisions = deltaCache.getRevisions();
const revisions = deltaCache.getRevisions();

// Check that the base has been changed and merged correctly
expect(revisions.length).toBe(2);
expect(revisions[0].updated.length).toBe(2);
expect(revisions[0].updated).toEqual(
expect.arrayContaining([
expect.objectContaining({ name: "test-flag" }),
expect.objectContaining({ name: "my-feature-flag" }),
]),
);
});
// Check that the base has been changed and merged correctly
expect(revisions.length).toBe(2);
expect(revisions[0].updated.length).toBe(2);
expect(revisions[0].updated).toEqual(
expect.arrayContaining([
expect.objectContaining({ name: 'test-flag' }),
expect.objectContaining({ name: 'my-feature-flag' }),
]),
);
});
});
82 changes: 42 additions & 40 deletions src/lib/features/client-feature-toggles/cache/revision-cache.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,48 @@
import { Revision } from "./client-feature-toggle-cache";
import type { Revision } from './client-feature-toggle-cache';

const mergeWithoutDuplicates = (arr1: any[], arr2: any[]) => {
const map = new Map();
arr1.concat(arr2).forEach((item) => {
map.set(item.name, item);
});
return Array.from(map.values());
const map = new Map();
arr1.concat(arr2).forEach((item) => {
map.set(item.name, item);
});
return Array.from(map.values());
};

export class RevisionCache {
private cache: Revision[];
private maxLength: number;

constructor(data: Revision[] = [], maxLength: number = 100) {
this.cache = data;
this.maxLength = maxLength;
}

public addRevision(revision: Revision): void {
if (this.cache.length >= this.maxLength) {
this.changeBase();
}

this.cache = [...this.cache, revision];
}

public getRevisions(): Revision[] {
return this.cache;
}

public hasRevision(revisionId: number): boolean {
return this.cache.some((revision) => revision.revisionId === revisionId);
}

private changeBase(): void {
if (!(this.cache.length >= 2)) return;
const base = this.cache[0];
const newBase = this.cache[1];

newBase.removed = mergeWithoutDuplicates(base.removed, newBase.removed);
newBase.updated = mergeWithoutDuplicates(base.updated, newBase.updated);

this.cache = [newBase, ...this.cache.slice(2)];
}
private cache: Revision[];
private maxLength: number;

constructor(data: Revision[] = [], maxLength: number = 100) {
this.cache = data;
this.maxLength = maxLength;
}

public addRevision(revision: Revision): void {
if (this.cache.length >= this.maxLength) {
this.changeBase();
}

this.cache = [...this.cache, revision];
}

public getRevisions(): Revision[] {
return this.cache;
}

public hasRevision(revisionId: number): boolean {
return this.cache.some(
(revision) => revision.revisionId === revisionId,
);
}

private changeBase(): void {
if (!(this.cache.length >= 2)) return;
const base = this.cache[0];
const newBase = this.cache[1];

newBase.removed = mergeWithoutDuplicates(base.removed, newBase.removed);
newBase.updated = mergeWithoutDuplicates(base.updated, newBase.updated);

this.cache = [newBase, ...this.cache.slice(2)];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,6 @@ export default class FeatureToggleClientStore
)
.leftJoin('segments', `segments.id`, `fss.segment_id`)
.leftJoin('dependent_features as df', 'df.child', 'features.name');
if (featureQuery?.toggleNames && featureQuery?.toggleNames.length > 0) {
query = query.whereIn('features.name', featureQuery.toggleNames);
}

if (isAdmin) {
query = query.leftJoin(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ export default class FeatureController extends Controller {
req: IAuthRequest,
res: Response<ClientFeatureChange>,
): Promise<void> {
if (!this.flagResolver.isEnabled('deltaApi')) {
throw new NotFoundError();
}
const query = await this.resolveQuery(req);
const etag = req.headers['if-none-match'];
const meta = await this.calculateMeta(query);
Expand Down
7 changes: 6 additions & 1 deletion src/lib/types/experimental.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ export type IFlagKey =
| 'granularAdminPermissions'
| 'streaming'
| 'etagVariant'
| 'oidcRedirect';
| 'oidcRedirect'
| 'deltaApi';

export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;

Expand Down Expand Up @@ -295,6 +296,10 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_OIDC_REDIRECT,
false,
),
deltaApi: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_DELTA_API,
false,
),
};

export const defaultExperimentalOptions: IExperimentalOptions = {
Expand Down
1 change: 0 additions & 1 deletion src/lib/types/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,6 @@ export interface IFeatureToggleQuery {
namePrefix?: string;
environment?: string;
inlineSegmentConstraints?: boolean;
toggleNames?: string[];
}

export interface ITag {
Expand Down
1 change: 1 addition & 0 deletions src/server-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ process.nextTick(async () => {
flagOverviewRedesign: false,
licensedUsers: true,
granularAdminPermissions: true,
deltaApi: true,
},
},
authentication: {
Expand Down

0 comments on commit 6b077f1

Please sign in to comment.