@pnp/sp
Version:
pnp - provides a fluent api for working with SharePoint REST
424 lines • 14.7 kB
JavaScript
import { combine, isUrlAbsolute, isArray, stringIsNullOrEmpty } from "@pnp/core";
import { Queryable, queryableFactory, op, get, post, patch, del } from "@pnp/queryable";
export const spInvokableFactory = (f) => {
return queryableFactory(f);
};
/**
* SharePointQueryable Base Class
*
*/
export class _SPQueryable extends Queryable {
/**
* Creates a new instance of the SharePointQueryable class
*
* @constructor
* @param base A string or SharePointQueryable that should form the base part of the url
*
*/
constructor(base, path) {
if (typeof base === "string") {
let url = "";
let parentUrl = "";
// we need to do some extra parsing to get the parent url correct if we are
// being created from just a string.
if (isUrlAbsolute(base) || base.lastIndexOf("/") < 0) {
parentUrl = base;
url = combine(base, path);
}
else if (base.lastIndexOf("/") > base.lastIndexOf("(")) {
// .../items(19)/fields
const index = base.lastIndexOf("/");
parentUrl = base.slice(0, index);
path = combine(base.slice(index), path);
url = combine(parentUrl, path);
}
else {
// .../items(19)
const index = base.lastIndexOf("(");
parentUrl = base.slice(0, index);
url = combine(base, path);
}
// init base with corrected string value
super(url);
this.parentUrl = parentUrl;
}
else {
super(base, path);
const q = isArray(base) ? base[0] : base;
this.parentUrl = isArray(base) ? base[1] : q.toUrl();
}
}
/**
* Gets the full url with query information
*/
toRequestUrl() {
const aliasedParams = new URLSearchParams(this.query);
// this regex is designed to locate aliased parameters within url paths
let url = this.toUrl().replace(/'!(@.+?)::((?:[^']|'')+)'/ig, (match, labelName, value) => {
this.log(`Rewriting aliased parameter from match ${match} to label: ${labelName} value: ${value}`, 0);
aliasedParams.set(labelName, `'${value}'`);
return labelName;
});
const query = aliasedParams.toString();
if (!stringIsNullOrEmpty(query)) {
url += `${url.indexOf("?") > -1 ? "&" : "?"}${query}`;
}
return url;
}
/**
* Choose which fields to return
*
* @param selects One or more fields to return
*/
select(...selects) {
if (selects.length > 0) {
this.query.set("$select", selects.join(","));
}
return this;
}
/**
* Expands fields such as lookups to get additional data
*
* @param expands The Fields for which to expand the values
*/
expand(...expands) {
if (expands.length > 0) {
this.query.set("$expand", expands.join(","));
}
return this;
}
/**
* Gets a parent for this instance as specified
*
* @param factory The contructor for the class to create
*/
getParent(factory, path, base = this.parentUrl) {
return factory([this, base], path);
}
}
export const SPQueryable = spInvokableFactory(_SPQueryable);
/**
* Represents a REST collection which can be filtered, paged, and selected
*
*/
export class _SPCollection extends _SPQueryable {
/**
* Filters the returned collection (https://msdn.microsoft.com/en-us/library/office/fp142385.aspx#bk_supported)
*
* @param filter The string representing the filter query
*/
filter(filter) {
if (typeof filter === "object") {
this.query.set("$filter", filter.toString());
return this;
}
if (typeof filter === "function") {
this.query.set("$filter", filter(SPOData.Where()).toString());
return this;
}
this.query.set("$filter", filter.toString());
return this;
}
/**
* Orders based on the supplied fields
*
* @param orderby The name of the field on which to sort
* @param ascending If false DESC is appended, otherwise ASC (default)
*/
orderBy(orderBy, ascending = true) {
const o = "$orderby";
const query = this.query.has(o) ? this.query.get(o).split(",") : [];
query.push(`${orderBy} ${ascending ? "asc" : "desc"}`);
this.query.set(o, query.join(","));
return this;
}
/**
* Skips the specified number of items
*
* @param skip The number of items to skip
*/
skip(skip) {
this.query.set("$skip", skip.toString());
return this;
}
/**
* Limits the query to only return the specified number of items
*
* @param top The query row limit
*/
top(top) {
this.query.set("$top", top.toString());
return this;
}
}
export const SPCollection = spInvokableFactory(_SPCollection);
/**
* Represents an instance that can be selected
*
*/
export class _SPInstance extends _SPQueryable {
}
export const SPInstance = spInvokableFactory(_SPInstance);
/**
* Adds the a delete method to the tagged class taking no parameters and calling spPostDelete
*/
export function deleteable() {
return function () {
return spPostDelete(this);
};
}
export function deleteableWithETag() {
return function (eTag = "*") {
return spPostDeleteETag(this, {}, eTag);
};
}
export const spGet = (o, init) => {
return op(o, get, init);
};
export const spPost = (o, init) => op(o, post, init);
export const spPostMerge = (o, init) => {
init = init || {};
init.headers = { ...init.headers, "X-HTTP-Method": "MERGE" };
return spPost(o, init);
};
export const spPostDelete = (o, init) => {
init = init || {};
init.headers = { ...init.headers || {}, "X-HTTP-Method": "DELETE" };
return spPost(o, init);
};
export const spPostDeleteETag = (o, init, eTag = "*") => {
init = init || {};
init.headers = { ...init.headers || {}, "IF-Match": eTag };
return spPostDelete(o, init);
};
export const spDelete = (o, init) => op(o, del, init);
export const spPatch = (o, init) => op(o, patch, init);
var FilterOperation;
(function (FilterOperation) {
FilterOperation["Equals"] = "eq";
FilterOperation["NotEquals"] = "ne";
FilterOperation["GreaterThan"] = "gt";
FilterOperation["GreaterThanOrEqualTo"] = "ge";
FilterOperation["LessThan"] = "lt";
FilterOperation["LessThanOrEqualTo"] = "le";
FilterOperation["StartsWith"] = "startswith";
FilterOperation["SubstringOf"] = "substringof";
})(FilterOperation || (FilterOperation = {}));
var FilterJoinOperator;
(function (FilterJoinOperator) {
FilterJoinOperator["And"] = "and";
FilterJoinOperator["AndWithSpace"] = " and ";
FilterJoinOperator["Or"] = "or";
FilterJoinOperator["OrWithSpace"] = " or ";
})(FilterJoinOperator || (FilterJoinOperator = {}));
class SPOData {
static Where() {
return new InitialFieldQuery([]);
}
}
// Linting complains that TBaseInterface is unused, but without it all the intellisense is lost since it's carrying it through the chain
class BaseQuery {
constructor(query) {
this.query = [];
this.query = query;
}
}
class QueryableFields extends BaseQuery {
constructor(q) {
super(q);
}
text(internalName) {
return new TextField([...this.query, internalName]);
}
choice(internalName) {
return new TextField([...this.query, internalName]);
}
multiChoice(internalName) {
return new TextField([...this.query, internalName]);
}
number(internalName) {
return new NumberField([...this.query, internalName]);
}
date(internalName) {
return new DateField([...this.query, internalName]);
}
boolean(internalName) {
return new BooleanField([...this.query, internalName]);
}
lookup(internalName) {
return new LookupQueryableFields([...this.query], internalName);
}
lookupId(internalName) {
const col = internalName.endsWith("Id") ? internalName : `${internalName}Id`;
return new NumberField([...this.query, col]);
}
}
class QueryableAndResult extends QueryableFields {
or(...queries) {
return new ComparisonResult([...this.query, `(${queries.map(x => x.toString()).join(FilterJoinOperator.OrWithSpace)})`]);
}
}
class QueryableOrResult extends QueryableFields {
and(...queries) {
return new ComparisonResult([...this.query, `(${queries.map(x => x.toString()).join(FilterJoinOperator.AndWithSpace)})`]);
}
}
class InitialFieldQuery extends QueryableFields {
or(...queries) {
if (queries == null || queries.length === 0) {
return new QueryableFields([...this.query, FilterJoinOperator.Or]);
}
return new ComparisonResult([...this.query, `(${queries.map(x => x.toString()).join(FilterJoinOperator.OrWithSpace)})`]);
}
and(...queries) {
if (queries == null || queries.length === 0) {
return new QueryableFields([...this.query, FilterJoinOperator.And]);
}
return new ComparisonResult([...this.query, `(${queries.map(x => x.toString()).join(FilterJoinOperator.AndWithSpace)})`]);
}
}
class LookupQueryableFields extends BaseQuery {
constructor(q, LookupField) {
super(q);
this.LookupField = LookupField;
}
Id(id) {
return new ComparisonResult([...this.query, `${this.LookupField}/Id`, FilterOperation.Equals, id.toString()]);
}
text(internalName) {
return new TextField([...this.query, `${this.LookupField}/${internalName}`]);
}
number(internalName) {
return new NumberField([...this.query, `${this.LookupField}/${internalName}`]);
}
}
class NullableField extends BaseQuery {
constructor(q) {
super(q);
this.LastIndex = q.length - 1;
this.InternalName = q[this.LastIndex];
}
toODataValue(value) {
return `'${value}'`;
}
isNull() {
return new ComparisonResult([...this.query, FilterOperation.Equals, "null"]);
}
isNotNull() {
return new ComparisonResult([...this.query, FilterOperation.NotEquals, "null"]);
}
}
class ComparableField extends NullableField {
equals(value) {
return new ComparisonResult([...this.query, FilterOperation.Equals, this.toODataValue(value)]);
}
notEquals(value) {
return new ComparisonResult([...this.query, FilterOperation.NotEquals, this.toODataValue(value)]);
}
in(...values) {
return SPOData.Where().or(...values.map(x => this.equals(x)));
}
notIn(...values) {
return SPOData.Where().and(...values.map(x => this.notEquals(x)));
}
}
class TextField extends ComparableField {
startsWith(value) {
const filter = `${FilterOperation.StartsWith}(${this.InternalName}, ${this.toODataValue(value)})`;
this.query[this.LastIndex] = filter;
return new ComparisonResult([...this.query]);
}
contains(value) {
const filter = `${FilterOperation.SubstringOf}(${this.toODataValue(value)}, ${this.InternalName})`;
this.query[this.LastIndex] = filter;
return new ComparisonResult([...this.query]);
}
}
class BooleanField extends NullableField {
toODataValue(value) {
return `${value == null ? "null" : value ? 1 : 0}`;
}
isTrue() {
return new ComparisonResult([...this.query, FilterOperation.Equals, this.toODataValue(true)]);
}
isFalse() {
return new ComparisonResult([...this.query, FilterOperation.Equals, this.toODataValue(false)]);
}
isFalseOrNull() {
const filter = `(${[
this.InternalName,
FilterOperation.Equals,
this.toODataValue(null),
FilterJoinOperator.Or,
this.InternalName,
FilterOperation.Equals,
this.toODataValue(false),
].join(" ")})`;
this.query[this.LastIndex] = filter;
return new ComparisonResult([...this.query]);
}
}
class NumericField extends ComparableField {
greaterThan(value) {
return new ComparisonResult([...this.query, FilterOperation.GreaterThan, this.toODataValue(value)]);
}
greaterThanOrEquals(value) {
return new ComparisonResult([...this.query, FilterOperation.GreaterThanOrEqualTo, this.toODataValue(value)]);
}
lessThan(value) {
return new ComparisonResult([...this.query, FilterOperation.LessThan, this.toODataValue(value)]);
}
lessThanOrEquals(value) {
return new ComparisonResult([...this.query, FilterOperation.LessThanOrEqualTo, this.toODataValue(value)]);
}
}
class NumberField extends NumericField {
toODataValue(value) {
return `${value}`;
}
}
class DateField extends NumericField {
toODataValue(value) {
return `'${value.toISOString()}'`;
}
isBetween(startDate, endDate) {
const filter = `(${[
this.InternalName,
FilterOperation.GreaterThan,
this.toODataValue(startDate),
FilterJoinOperator.And,
this.InternalName,
FilterOperation.LessThan,
this.toODataValue(endDate),
].join(" ")})`;
this.query[this.LastIndex] = filter;
return new ComparisonResult([...this.query]);
}
isToday() {
const StartToday = new Date();
StartToday.setHours(0, 0, 0, 0);
const EndToday = new Date();
EndToday.setHours(23, 59, 59, 999);
return this.isBetween(StartToday, EndToday);
}
}
class ComparisonResult extends BaseQuery {
// eslint-disable-next-line max-len
and(...queries) {
if (queries == null || queries.length === 0) {
return new QueryableAndResult([...this.query, FilterJoinOperator.And]);
}
return new ComparisonResult([...this.query, FilterJoinOperator.And, `(${queries.map(x => x.toString()).join(FilterJoinOperator.AndWithSpace)})`]);
}
// eslint-disable-next-line max-len
or(...queries) {
if (queries == null || queries.length === 0) {
return new QueryableOrResult([...this.query, FilterJoinOperator.Or]);
}
return new ComparisonResult([...this.query, FilterJoinOperator.Or, `(${queries.map(x => x.toString()).join(FilterJoinOperator.OrWithSpace)})`]);
}
toString() {
return this.query.join(" ");
}
}
//# sourceMappingURL=spqueryable.js.map