Skip to content

Commit

Permalink
Added support for nested joins
Browse files Browse the repository at this point in the history
  • Loading branch information
andrei-markeev committed Apr 18, 2018
1 parent 822641f commit 87269cd
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 106 deletions.
7 changes: 5 additions & 2 deletions CamlJS.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
# Visual Studio 15
VisualStudioVersion = 15.0.27428.2015
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CamlJs.TestApp", "CamlJs.TestApp\CamlJs.TestApp.csproj", "{49F4736D-F3B5-4A58-98D9-CF9CA9181C11}"
EndProject
Expand All @@ -27,4 +27,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4590ACD9-412F-42D6-AF30-DE5DA14ACC34}
EndGlobalSection
EndGlobal
11 changes: 8 additions & 3 deletions CamlJs.TestApp/CamlJs.TestApp.csproj
Expand Up @@ -10,18 +10,23 @@
<RootNamespace>CamlJs.TestApp</RootNamespace>
<AssemblyName>CamlJs.TestApp</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetOfficeVersion>16.0</TargetOfficeVersion>
<TargetOfficeVersion>16.1</TargetOfficeVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{C1CDDADD-2546-481F-9697-4EA41081F2FC};{14822709-B5A1-4724-98CA-57A101D1B079};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<MinimumOfficeToolsVersion>11.0</MinimumOfficeToolsVersion>
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
<MinimumOfficeToolsVersion>12.2</MinimumOfficeToolsVersion>
<IncludeAssemblyInPackage>False</IncludeAssemblyInPackage>
<ProjectMode>SharePointApp</ProjectMode>
<AppFeaturePartId>{3a4e814e-bc6c-47b4-8af3-d59559b6f4ce}</AppFeaturePartId>
<WspPartId>{52e6a47b-4d6b-4c7e-a529-ef391ba0cc49}</WspPartId>
<WorkflowPartId>{c7133800-25ed-4691-a5cc-3f006b28a9ec}</WorkflowPartId>
<CspkgPartId>{869f4b06-f1a9-4c12-bc05-019cbedf8e9c}</CspkgPartId>
<SqlPackagePartId>{b545e350-3949-4cc9-a0ef-044b428a93fc}</SqlPackagePartId>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>12.0</OldToolsVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
Expand Down
52 changes: 28 additions & 24 deletions CamlJs.TestApp/Scripts/camljs.js
Expand Up @@ -19,7 +19,7 @@ var CamlBuilder = (function () {
1. SPServices CAMLQuery attribute
2. Creating partial expressions
3. In conjunction with Any & All clauses
*/
*/
CamlBuilder.Expression = function () {
return CamlBuilder.Internal.createExpression();
};
Expand All @@ -31,11 +31,8 @@ var CamlBuilder = (function () {
(function (CamlBuilder) {
var ViewScope;
(function (ViewScope) {
/** */
ViewScope[ViewScope["Recursive"] = 0] = "Recursive";
/** */
ViewScope[ViewScope["RecursiveAll"] = 1] = "RecursiveAll";
/** */
ViewScope[ViewScope["FilesOnly"] = 2] = "FilesOnly";
})(ViewScope = CamlBuilder.ViewScope || (CamlBuilder.ViewScope = {}));
var DateRangesOverlapType;
Expand Down Expand Up @@ -206,7 +203,10 @@ var CamlBuilder = (function () {
{ Name: "ListAlias", Value: join.Alias }
]);
this.builder.WriteStart("Eq");
this.builder.WriteFieldRef(join.RefFieldName, { RefType: "ID" });
var fieldAttrs = { RefType: "ID" };
if (join.FromList)
fieldAttrs["List"] = join.FromList;
this.builder.WriteFieldRef(join.RefFieldName, fieldAttrs);
this.builder.WriteFieldRef("ID", { List: join.Alias });
this.builder.WriteEnd();
this.builder.WriteEnd();
Expand All @@ -226,8 +226,8 @@ var CamlBuilder = (function () {
this.builder.WriteEnd();
}
};
JoinsManager.prototype.Join = function (lookupFieldInternalName, alias, joinType) {
this.joins.push({ RefFieldName: lookupFieldInternalName, Alias: alias, JoinType: joinType });
JoinsManager.prototype.Join = function (lookupFieldInternalName, alias, joinType, fromList) {
this.joins.push({ RefFieldName: lookupFieldInternalName, Alias: alias, JoinType: joinType, FromList: fromList });
return new Join(this.builder, this);
};
JoinsManager.prototype.ProjectedField = function (remoteFieldInternalName, remoteFieldAlias) {
Expand All @@ -246,11 +246,11 @@ var CamlBuilder = (function () {
Join.prototype.Select = function (remoteFieldInternalName, remoteFieldAlias) {
return this.joinsManager.ProjectedField(remoteFieldInternalName, remoteFieldAlias);
};
Join.prototype.InnerJoin = function (lookupFieldInternalName, alias) {
return this.joinsManager.Join(lookupFieldInternalName, alias, "INNER");
Join.prototype.InnerJoin = function (lookupFieldInternalName, alias, fromList) {
return this.joinsManager.Join(lookupFieldInternalName, alias, "INNER", fromList);
};
Join.prototype.LeftJoin = function (lookupFieldInternalName, alias) {
return this.joinsManager.Join(lookupFieldInternalName, alias, "LEFT");
Join.prototype.LeftJoin = function (lookupFieldInternalName, alias, fromList) {
return this.joinsManager.Join(lookupFieldInternalName, alias, "LEFT", fromList);
};
return Join;
}());
Expand Down Expand Up @@ -418,6 +418,11 @@ var CamlBuilder = (function () {
FieldExpression.prototype.ChoiceField = function (internalName) {
return new FieldExpressionToken(this.builder, internalName, "Choice");
};
/** Specifies that a condition will be tested against the field with the specified internal name, and the type of this field is Computed */
FieldExpression.prototype.ComputedField = function (internalName) {
return new FieldExpressionToken(this.builder, internalName, "Computed");
};
;
/** Specifies that a condition will be tested against the field with the specified internal name, and the type of this field is Boolean */
FieldExpression.prototype.BooleanField = function (internalName) {
return new FieldExpressionToken(this.builder, internalName, "Integer");
Expand Down Expand Up @@ -1089,25 +1094,25 @@ if (typeof (window["Sys"]) == "undefined" || window["Sys"] == null) {
this._value = {};
this._len = 0;
};
function Sys$StringBuilder$append(text) {
var Sys$StringBuilder$append = function (text) {
this._parts[this._parts.length] = text;
}
function Sys$StringBuilder$appendLine(text) {
};
var Sys$StringBuilder$appendLine = function (text) {
this._parts[this._parts.length] =
((typeof (text) === 'undefined') || (text === null) || (text === '')) ?
'\r\n' : text + '\r\n';
}
function Sys$StringBuilder$clear() {
};
var Sys$StringBuilder$clear = function () {
this._parts = [];
this._value = {};
this._len = 0;
}
function Sys$StringBuilder$isEmpty() {
};
var Sys$StringBuilder$isEmpty = function () {
if (this._parts.length === 0)
return true;
return this.toString() === '';
}
function Sys$StringBuilder$toString(separator) {
};
var Sys$StringBuilder$toString = function (separator) {
separator = separator || '';
var parts = this._parts;
if (this._len !== parts.length) {
Expand All @@ -1129,7 +1134,7 @@ if (typeof (window["Sys"]) == "undefined" || window["Sys"] == null) {
val[separator] = this._parts.join(separator);
}
return val[separator];
}
};
window["Sys"].StringBuilder.prototype = {
append: Sys$StringBuilder$append,
appendLine: Sys$StringBuilder$appendLine,
Expand All @@ -1140,11 +1145,10 @@ if (typeof (window["Sys"]) == "undefined" || window["Sys"] == null) {
}
if (typeof window["SP"] == 'undefined') {
window["SP"] = {};
function SP_ScriptUtility$isNullOrEmptyString(str) {
var SP_ScriptUtility$isNullOrEmptyString = function (str) {
var strNull = null;
return str === strNull || typeof str === 'undefined' || !str.length;
}
;
};
window["SP"].XmlWriter = function SP_XmlWriter($p0) {
this.$f_0 = [];
this.$1_0 = $p0;
Expand Down
5 changes: 3 additions & 2 deletions CamlJs/CamlJs.csproj
Expand Up @@ -9,13 +9,14 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
<TypeScriptToolsVersion>1.4</TypeScriptToolsVersion>
<TypeScriptToolsVersion>2.6</TypeScriptToolsVersion>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<UseGlobalApplicationHostFile />
<Use64BitIISExpress />
</PropertyGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
Expand All @@ -30,7 +31,7 @@
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>True</UseIIS>
<UseIIS>False</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>49856</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
Expand Down
26 changes: 12 additions & 14 deletions CamlJs/camljs.js
Expand Up @@ -19,7 +19,7 @@ var CamlBuilder = (function () {
1. SPServices CAMLQuery attribute
2. Creating partial expressions
3. In conjunction with Any & All clauses
*/
*/
CamlBuilder.Expression = function () {
return CamlBuilder.Internal.createExpression();
};
Expand All @@ -31,11 +31,8 @@ var CamlBuilder = (function () {
(function (CamlBuilder) {
var ViewScope;
(function (ViewScope) {
/** */
ViewScope[ViewScope["Recursive"] = 0] = "Recursive";
/** */
ViewScope[ViewScope["RecursiveAll"] = 1] = "RecursiveAll";
/** */
ViewScope[ViewScope["FilesOnly"] = 2] = "FilesOnly";
})(ViewScope = CamlBuilder.ViewScope || (CamlBuilder.ViewScope = {}));
var DateRangesOverlapType;
Expand Down Expand Up @@ -206,7 +203,10 @@ var CamlBuilder = (function () {
{ Name: "ListAlias", Value: join.Alias }
]);
this.builder.WriteStart("Eq");
this.builder.WriteFieldRef(join.RefFieldName, { RefType: "ID" });
var fieldAttrs = { RefType: "ID" };
if (join.FromList)
fieldAttrs["List"] = join.FromList;
this.builder.WriteFieldRef(join.RefFieldName, fieldAttrs);
this.builder.WriteFieldRef("ID", { List: join.Alias });
this.builder.WriteEnd();
this.builder.WriteEnd();
Expand All @@ -226,8 +226,8 @@ var CamlBuilder = (function () {
this.builder.WriteEnd();
}
};
JoinsManager.prototype.Join = function (lookupFieldInternalName, alias, joinType) {
this.joins.push({ RefFieldName: lookupFieldInternalName, Alias: alias, JoinType: joinType });
JoinsManager.prototype.Join = function (lookupFieldInternalName, alias, joinType, fromList) {
this.joins.push({ RefFieldName: lookupFieldInternalName, Alias: alias, JoinType: joinType, FromList: fromList });
return new Join(this.builder, this);
};
JoinsManager.prototype.ProjectedField = function (remoteFieldInternalName, remoteFieldAlias) {
Expand All @@ -246,11 +246,11 @@ var CamlBuilder = (function () {
Join.prototype.Select = function (remoteFieldInternalName, remoteFieldAlias) {
return this.joinsManager.ProjectedField(remoteFieldInternalName, remoteFieldAlias);
};
Join.prototype.InnerJoin = function (lookupFieldInternalName, alias) {
return this.joinsManager.Join(lookupFieldInternalName, alias, "INNER");
Join.prototype.InnerJoin = function (lookupFieldInternalName, alias, fromList) {
return this.joinsManager.Join(lookupFieldInternalName, alias, "INNER", fromList);
};
Join.prototype.LeftJoin = function (lookupFieldInternalName, alias) {
return this.joinsManager.Join(lookupFieldInternalName, alias, "LEFT");
Join.prototype.LeftJoin = function (lookupFieldInternalName, alias, fromList) {
return this.joinsManager.Join(lookupFieldInternalName, alias, "LEFT", fromList);
};
return Join;
}());
Expand Down Expand Up @@ -422,6 +422,7 @@ var CamlBuilder = (function () {
FieldExpression.prototype.ComputedField = function (internalName) {
return new FieldExpressionToken(this.builder, internalName, "Computed");
};
;
/** Specifies that a condition will be tested against the field with the specified internal name, and the type of this field is Boolean */
FieldExpression.prototype.BooleanField = function (internalName) {
return new FieldExpressionToken(this.builder, internalName, "Integer");
Expand Down Expand Up @@ -1291,6 +1292,3 @@ if (typeof window["SP"] == 'undefined') {
}
};
}

export default CamlBuilder;
//# sourceMappingURL=camljs.js.map
57 changes: 39 additions & 18 deletions CamlJs/camljs.ts
Expand Up @@ -21,7 +21,7 @@ class CamlBuilder {
1. SPServices CAMLQuery attribute
2. Creating partial expressions
3. In conjunction with Any & All clauses
*/
*/
static Expression(): CamlBuilder.IFieldExpression {
return CamlBuilder.Internal.createExpression();
}
Expand All @@ -33,12 +33,13 @@ class CamlBuilder {

module CamlBuilder {

export interface IView extends IJoinable, IFinalizable {
export interface IView extends IFinalizable {
/** Define query */
Query(): IQuery;
/** Define maximum amount of returned records */
RowLimit(limit: number, paged?: boolean): IView;
/** Define view scope */
Scope(scope: ViewScope): IView;
}
export interface IJoinable {
/** Join the list you're querying with another list.
Joins are only allowed through a lookup field relation.
@param lookupFieldInternalName Internal name of the lookup field, that points to the list you're going to join in.
Expand All @@ -50,22 +51,39 @@ module CamlBuilder {
@alias alias for the joined list */
LeftJoin(lookupFieldInternalName: string, alias: string): IJoin;
}
export interface IJoinable {
/** Join the list you're querying with another list.
Joins are only allowed through a lookup field relation.
@param lookupFieldInternalName Internal name of the lookup field, that points to the list you're going to join in.
@param alias Alias for the joined list
@param fromList (optional) List where the lookup column resides - use it only for nested joins */
InnerJoin(lookupFieldInternalName: string, alias: string, fromList?: string): IJoin;
/** Join the list you're querying with another list.
Joins are only allowed through a lookup field relation.
@param lookupFieldInternalName Internal name of the lookup field, that points to the list you're going to join in.
@param alias Alias for the joined list
@param fromList (optional) List where the lookup column resides - use it only for nested joins */
LeftJoin(lookupFieldInternalName: string, alias: string, fromList?: string): IJoin;
}
export interface IJoin extends IJoinable {
/** Select projected field for using in the main Query body
@param remoteFieldAlias By this alias, the field can be used in the main Query body. */
Select(remoteFieldInternalName: string, remoteFieldAlias: string): IProjectableView;
}
export interface IProjectableView extends IView {
export interface IProjectableView extends IJoinable {
/** Define query */
Query(): IQuery;
/** Define maximum amount of returned records */
RowLimit(limit: number, paged?: boolean): IView;
/** Define view scope */
Scope(scope: ViewScope): IView;
/** Select projected field for using in the main Query body
@param remoteFieldAlias By this alias, the field can be used in the main Query body. */
Select(remoteFieldInternalName: string, remoteFieldAlias: string): IProjectableView;
}
export enum ViewScope {
/** */
Recursive,
/** */
RecursiveAll,
/** */
FilesOnly
}
export interface IQuery extends IGroupable {
Expand Down Expand Up @@ -554,7 +572,10 @@ module CamlBuilder {
{ Name: "ListAlias", Value: join.Alias }
]);
this.builder.WriteStart("Eq");
this.builder.WriteFieldRef(join.RefFieldName, { RefType: "ID" });
var fieldAttrs = { RefType: "ID" };
if (join.FromList)
fieldAttrs["List"] = join.FromList;
this.builder.WriteFieldRef(join.RefFieldName, fieldAttrs);
this.builder.WriteFieldRef("ID", { List: join.Alias });
this.builder.WriteEnd();
this.builder.WriteEnd();
Expand All @@ -574,10 +595,10 @@ module CamlBuilder {
this.builder.WriteEnd();
}
}
private joins: any[];
private joins: { RefFieldName: string, Alias: string, JoinType: string, FromList?: string }[];
private projectedFields: any[];
Join(lookupFieldInternalName: string, alias: string, joinType: string): IJoin {
this.joins.push({ RefFieldName: lookupFieldInternalName, Alias: alias, JoinType: joinType });
Join(lookupFieldInternalName: string, alias: string, joinType: string, fromList?: string): IJoin {
this.joins.push({ RefFieldName: lookupFieldInternalName, Alias: alias, JoinType: joinType, FromList: fromList });
return new Join(this.builder, this);
}
ProjectedField(remoteFieldInternalName: string, remoteFieldAlias: string): IProjectableView {
Expand All @@ -597,11 +618,11 @@ module CamlBuilder {
Select(remoteFieldInternalName: string, remoteFieldAlias: string): IProjectableView {
return this.joinsManager.ProjectedField(remoteFieldInternalName, remoteFieldAlias);
}
InnerJoin(lookupFieldInternalName: string, alias: string): IJoin {
return this.joinsManager.Join(lookupFieldInternalName, alias, "INNER");
InnerJoin(lookupFieldInternalName: string, alias: string, fromList?: string): IJoin {
return this.joinsManager.Join(lookupFieldInternalName, alias, "INNER", fromList);
}
LeftJoin(lookupFieldInternalName: string, alias: string): IJoin {
return this.joinsManager.Join(lookupFieldInternalName, alias, "LEFT");
LeftJoin(lookupFieldInternalName: string, alias: string, fromList?: string): IJoin {
return this.joinsManager.Join(lookupFieldInternalName, alias, "LEFT", fromList);
}
}
class QueryToken implements IExpression {
Expand Down Expand Up @@ -747,8 +768,8 @@ module CamlBuilder {
}

var attrs = [];
for (var i = 0, len = node.attributes.length; i < len; i++) {
attrs.push({ Name: node.attributes[i].name, Value: node.attributes[i].value });
for (var i = 0, len = (<HTMLElement>node).attributes.length; i < len; i++) {
attrs.push({ Name: (<HTMLElement>node).attributes[i].name, Value: (<HTMLElement>node).attributes[i].value });
}
builder.WriteStart(node.nodeName, attrs);
builder.unclosedTags++;
Expand Down

0 comments on commit 87269cd

Please sign in to comment.