Skip to content

Commit

Permalink
graph specific query param handling
Browse files Browse the repository at this point in the history
  • Loading branch information
patrick-rodgers committed Apr 4, 2024
1 parent 0d669ef commit 546095b
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 5 deletions.
30 changes: 29 additions & 1 deletion packages/graph/graphqueryable.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isArray, objectDefinedNotNull } from "@pnp/core";
import { IInvokable, Queryable, queryableFactory, op, get, post, patch, del, put } from "@pnp/queryable";
import { IInvokable, QueryParams, Queryable, queryableFactory, op, get, post, patch, del, put } from "@pnp/queryable";

Check warning on line 2 in packages/graph/graphqueryable.ts

View workflow job for this annotation

GitHub Actions / run_pr_tests

'QueryParams' is defined but never used
import { ConsistencyLevel } from "./behaviors/consistency-level.js";
import { IPagedResult, Paged } from "./behaviors/paged.js";

Expand Down Expand Up @@ -34,6 +34,9 @@ export class _GraphQueryable<GetType = any> extends Queryable<GetType> {

super(base, path);

// we need to use the graph implementation to handle our special encoding
this._query = new GraphQueryParams();

if (typeof base === "string") {

this.parentUrl = base;
Expand Down Expand Up @@ -239,3 +242,28 @@ export const graphPatch = <T = any>(o: IGraphQueryable<any>, init?: RequestInit)
export const graphPut = <T = any>(o: IGraphQueryable<any>, init?: RequestInit): Promise<T> => {
return op(o, put, init);
};

class GraphQueryParams extends Map<string, string> {

public toString(): string {

const params = new URLSearchParams();
const literals: string[] = [];

for (const item of this) {

// and here is where we add some "enhanced" parsing as we get issues.
if (/\/any\(.*?\)/i.test(item[1])) {
literals.push(`${item[0]}=${item[1]}`);
} else {
params.append(item[0], item[1]);
}
}

if (params.size > 0) {

Check failure on line 263 in packages/graph/graphqueryable.ts

View workflow job for this annotation

GitHub Actions / run_pr_tests

Property 'size' does not exist on type 'URLSearchParams'.
literals.push(params.toString());
}

return literals.join("&");
}
}
36 changes: 33 additions & 3 deletions packages/queryable/queryable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,41 @@ const DefaultMoments = {

export type QueryableInit = Queryable<any> | string | [Queryable<any>, string];

export type QueryParams = {

// new(init?: string[][] | Record<string, string> | string | QueryParams): QueryParams;

/**
* Sets the value associated to a given search parameter to the given value. If there were several values, delete the others.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/set)
*/
set(name: string, value: string): void;

/**
* Returns the first value associated to the given search parameter.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/get)
*/
get(name: string): string | null;

/**
* Returns a Boolean indicating if such a search parameter exists.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/URLSearchParams/has)
*/
has(name: string, value?: string): boolean;

/** Returns a string containing a query string suitable for use in a URL. Does not include the question mark. */
toString(): string;
};

@invokable()
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
export class Queryable<R> extends Timeline<typeof DefaultMoments> implements IQueryableInternal<R> {

// tracks any query parameters which will be appended to the request url
private _query: URLSearchParams;
protected _query: QueryParams;

// tracks the current url for a given Queryable
protected _url: string;
Expand All @@ -49,6 +78,7 @@ export class Queryable<R> extends Timeline<typeof DefaultMoments> implements IQu

super(DefaultMoments);

// default to use the included URL search params to parse the query string
this._query = new URLSearchParams();

// add an internal moment with specific implementation for promise creation
Expand Down Expand Up @@ -114,7 +144,7 @@ export class Queryable<R> extends Timeline<typeof DefaultMoments> implements IQu
/**
* Querystring key, value pairs which will be included in the request
*/
public get query(): URLSearchParams {
public get query(): QueryParams {
return this._query;
}

Expand Down Expand Up @@ -230,7 +260,7 @@ export interface Queryable<R = any> extends IInvokable<R> { }

// this interface is required to stop the class from recursively referencing itself through the DefaultBehaviors type
export interface IQueryableInternal<R = any> extends Timeline<any>, IInvokable {
readonly query: URLSearchParams;
readonly query: QueryParams;
// new(...params: any[]);
<T = R>(this: IQueryableInternal, init?: RequestInit): Promise<T>;
using(...behaviors: TimelinePipe[]): this;
Expand Down
2 changes: 1 addition & 1 deletion packages/sp/spqueryable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class _SPQueryable<GetType = any> extends Queryable<GetType> {
*/
public toRequestUrl(): string {

const aliasedParams = new URLSearchParams(this.query);
const aliasedParams = new URLSearchParams(<any>this.query);

// this regex is designed to locate aliased parameters within url paths. These may have the form:
// /something(!@p1::value)
Expand Down

0 comments on commit 546095b

Please sign in to comment.