UNPKG

@agravity/public

Version:

The Agravity GlobalDAM API which allowes API key authenticated access the Agravity GlobalDAM Backend

166 lines (139 loc) 5.16 kB
import { HttpParams, HttpParameterCodec } from '@angular/common/http'; import { CustomHttpParameterCodec, IdentityHttpParameterCodec } from './encoder'; export enum QueryParamStyle { Json, Form, DeepObject, SpaceDelimited, PipeDelimited } export type Delimiter = ',' | ' ' | '|' | '\t'; export interface ParamOptions { /** When true, serialized as multiple repeated key=value pairs. When false, serialized as a single key with joined values using `delimiter`. */ explode?: boolean; /** Delimiter used when explode=false. The delimiter itself is inserted unencoded between encoded values. */ delimiter?: Delimiter; } interface ParamEntry { values: string[]; options: Required<ParamOptions>; } export class OpenApiHttpParams { private params: Map<string, ParamEntry> = new Map(); private defaults: Required<ParamOptions>; private encoder: HttpParameterCodec; /** * @param encoder Parameter serializer * @param defaults Global defaults used when a specific parameter has no explicit options. * By OpenAPI default, explode is true for query params with style=form. */ constructor(encoder?: HttpParameterCodec, defaults?: { explode?: boolean; delimiter?: Delimiter }) { this.encoder = encoder || new CustomHttpParameterCodec(); this.defaults = { explode: defaults?.explode ?? true, delimiter: defaults?.delimiter ?? ',' }; } private resolveOptions(local?: ParamOptions): Required<ParamOptions> { return { explode: local?.explode ?? this.defaults.explode, delimiter: local?.delimiter ?? this.defaults.delimiter }; } /** * Replace the parameter's values and (optionally) its options. * Options are stored per-parameter (not global). */ set(key: string, values: string[] | string, options?: ParamOptions): this { const arr = Array.isArray(values) ? values.slice() : [values]; const opts = this.resolveOptions(options); this.params.set(key, { values: arr, options: opts }); return this; } /** * Append a single value to the parameter. If the parameter didn't exist it will be created * and use resolved options (global defaults merged with any provided options). */ append(key: string, value: string, options?: ParamOptions): this { const entry = this.params.get(key); if (entry) { // If new options provided, override the stored options for subsequent serialization if (options) { entry.options = this.resolveOptions({ ...entry.options, ...options }); } entry.values.push(value); } else { this.set(key, [value], options); } return this; } /** * Serialize to a query string according to per-parameter OpenAPI options. * - If explode=true for that parameter → repeated key=value pairs (each value encoded). * - If explode=false for that parameter → single key=value where values are individually encoded * and joined using the configured delimiter. The delimiter character is inserted AS-IS * (not percent-encoded). */ toString(): string { const records = this.toRecord(); const parts: string[] = []; for (const key in records) { parts.push(`${key}=${records[key]}`); } return parts.join('&'); } /** * Return parameters as a plain record. * - If a parameter has exactly one value, returns that value directly. * - If a parameter has multiple values, returns a readonly array of values. */ toRecord(): Record<string, string | number | boolean | ReadonlyArray<string | number | boolean>> { const parts: Record<string, string | number | boolean | ReadonlyArray<string | number | boolean>> = {}; for (const [key, entry] of this.params.entries()) { const encodedKey = this.encoder.encodeKey(key); if (entry.options.explode) { parts[encodedKey] = entry.values.map((v) => this.encoder.encodeValue(v)); } else { const encodedValues = entry.values.map((v) => this.encoder.encodeValue(v)); // join with the delimiter *unencoded* parts[encodedKey] = encodedValues.join(entry.options.delimiter); } } return parts; } /** * Return an Angular's HttpParams with an identity parameter codec as the parameters are already encoded. */ toHttpParams(): HttpParams { const records = this.toRecord(); let httpParams = new HttpParams({ encoder: new IdentityHttpParameterCodec() }); return httpParams.appendAll(records); } } export function concatHttpParamsObject( httpParams: OpenApiHttpParams, key: string, item: { [index: string]: any; }, delimiter: Delimiter ): OpenApiHttpParams { let keyAndValues: string[] = []; for (const k in item) { keyAndValues.push(k); const value = item[k]; if (Array.isArray(value)) { keyAndValues.push(...value.map(convertToString)); } else { keyAndValues.push(convertToString(value)); } } return httpParams.set(key, keyAndValues, { explode: false, delimiter: delimiter }); } function convertToString(value: any): string { if (value instanceof Date) { return value.toISOString(); } else { return value.toString(); } }