Skip to content

Commit

Permalink
fix: isIterable and useIterableOrValue treat string as a value
Browse files Browse the repository at this point in the history
- isIterable() and useIterableOrValue() will now treat string values as values by default instead of iterable values
  • Loading branch information
dereekb committed May 29, 2022
1 parent 10055ae commit 388d6f0
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 10 deletions.
2 changes: 1 addition & 1 deletion components/demo-firebase/src/lib/auth/claims.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export type DemoApiAuthClaims = {
/**
* Admin role
*/
a?: number;
a?: 1;
};

export const DEMO_AUTH_CLAIMS_SERVICE = authRoleClaimsService<DemoApiAuthClaims>({
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ services:
- ./.firebase/config/:/root/.config:cached
- ./.firebase/data/:/root/data
ports:
- '9229:9229' # node-inspect debug port. Can be disabled if not being used.
# - '9229:9229' # node-inspect debug port. Can be disabled if not being used.
- '9900-9906:9900-9906' # expose for browser access
environment:
# Credentials URL
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { tapLog } from '@dereekb/rxjs';
import { addToSetCopy, AuthClaims, AuthClaimsObject, AuthRoleClaimsService, AuthRoleSet } from '@dereekb/util';
import { map, Observable, switchMap } from 'rxjs';
import { DbxFirebaseAuthService, DbxFirebaseAuthServiceDelegate, DEFAULT_DBX_FIREBASE_AUTH_SERVICE_DELEGATE } from './firebase.auth.service';
Expand All @@ -14,10 +15,17 @@ export function authRolesObsWithClaimsService<T extends AuthClaimsObject>(config
const { addAuthUserStateToRoles: addAuthUserState, claimsService } = config;

return (dbxFirebaseAuthService: DbxFirebaseAuthService): Observable<AuthRoleSet> => {
let obs = dbxFirebaseAuthService.idTokenResult$.pipe(map((x) => claimsService.toRoles(x.claims as AuthClaims<T>)));
let obs = dbxFirebaseAuthService.idTokenResult$.pipe(
tapLog('a'),
map((x) => claimsService.toRoles(x.claims as AuthClaims<T>))
);

if (addAuthUserState) {
obs = obs.pipe(switchMap((authRoleSet: AuthRoleSet) => dbxFirebaseAuthService.authUserState$.pipe(map((userState) => addToSetCopy(authRoleSet, userState)))));
obs = obs.pipe(
tapLog('b'),
switchMap((authRoleSet: AuthRoleSet) => dbxFirebaseAuthService.authUserState$.pipe(map((userState) => addToSetCopy(authRoleSet, [userState])))),
tapLog('c')
);
}

return obs;
Expand Down
25 changes: 25 additions & 0 deletions packages/util/src/lib/iterable/iterable.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ describe('isIterable()', () => {
it('should return true for a map.', () => {
expect(isIterable(new Map())).toBe(true);
});

it('should return false for a string.', () => {
expect(isIterable('test')).toBe(false);
});

it('should return true for a string if treatStringAsIterable = false', () => {
expect(isIterable('test', true)).toBe(true);
});

it('should return false for a number.', () => {
expect(isIterable('test')).toBe(false);
});
});

describe('useIterableOrValue()', () => {
Expand Down Expand Up @@ -43,4 +55,17 @@ describe('useIterableOrValue()', () => {
useIterableOrValue([], () => (used = true));
expect(used).toBe(false);
});

it('should use a string as a value', () => {
let count = 0;
useIterableOrValue('test', () => (count += 1));
expect(count).toBe(1);
});

it('should use a string as an iterable if useStringAsIterable=true', () => {
let count = 0;
const value = 'test';
useIterableOrValue(value, () => (count += 1), true);
expect(count).toBe(value.length);
});
});
16 changes: 12 additions & 4 deletions packages/util/src/lib/iterable/iterable.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { Maybe } from '../value/maybe';

// MARK: Types
/**
* An Iterable or a value.
*
* Note that strings are a valid Iterable, allowing iteration over characters.
*/
export type IterableOrValue<T> = T | Iterable<T>;

// MARK: Functions
/**
* Returns true if the input is an Iterable.
*
* Can specify whether or not to treat string values as iterable values. Is false by default.
*
* @param values
* @param treatStringAsIterable
* @returns
*/
export function isIterable<T = unknown>(values: unknown): values is Iterable<T> {
if (values && (values as Iterable<T>)[Symbol.iterator]) {
export function isIterable<T = unknown>(values: unknown, treatStringAsIterable = false): values is Iterable<T> {
if (values && (values as Iterable<T>)[Symbol.iterator] && (treatStringAsIterable || typeof values !== 'string')) {
return true;
} else {
return false;
Expand Down Expand Up @@ -71,9 +79,9 @@ export function forEachInIterable<T>(values: Iterable<T>, fn: (value: T) => void
* @param values
* @param fn
*/
export function useIterableOrValue<T>(values: Maybe<IterableOrValue<T>>, fn: (value: T) => void): void {
export function useIterableOrValue<T>(values: Maybe<IterableOrValue<T>>, fn: (value: T) => void, treatStringAsIterable = false): void {
if (values != null) {
if (isIterable(values)) {
if (isIterable(values, treatStringAsIterable)) {
forEachInIterable(values, fn);
} else {
fn(values);
Expand Down
2 changes: 1 addition & 1 deletion setup/templates/components/firebase/src/lib/auth/claims.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export type APP_CODE_PREFIXApiAuthClaims = {
/**
* Admin role
*/
a?: number;
a?: 1;
}

export const APP_CODE_PREFIX_UPPER_AUTH_CLAIMS_SERVICE = authRoleClaimsService<APP_CODE_PREFIXApiAuthClaims>({
Expand Down
2 changes: 1 addition & 1 deletion setup/templates/components/firebase/src/lib/collection.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FirestoreContext } from '@dereekb/firebase';
import { exampleFirestoreCollection, ExampleFirestoreCollection, ExampleFirestoreCollections } from './example/example';
import { exampleFirestoreCollection, ExampleFirestoreCollection, ExampleFirestoreCollections } from './models';

export abstract class APP_CODE_PREFIXFirestoreCollections implements ExampleFirestoreCollections {
abstract readonly exampleFirestoreCollection: ExampleFirestoreCollection;
Expand Down

0 comments on commit 388d6f0

Please sign in to comment.