@@ -13,19 +13,6 @@ $data.Class.define('$data.Queryable', null, null,
Object.defineProperty(this, "entitySet", { value: es, enumerable: true, writable: true });
this.expression = rootExpression;
},
_checkRootExpression: function () {
if (!this.expression) {
var ec = Container.createEntityContextExpression(this.entitySet.entityContext);
var name = this.entitySet.collectionName;
var memberdef = this.entitySet.entityContext.getType().getMemberDefinition(name);
var es = Container.createEntitySetExpression(ec,
Container.createMemberInfoExpression(memberdef), null,
this.entitySet);
this.expression = es;
}
},

entitySet: {},

filter: function (predicate, thisArg) {
///<summary>Filters a set of entities using a boolean expression.</summary>
@@ -67,6 +54,7 @@ $data.Class.define('$data.Queryable', null, null,
///</example>
///</signature>

this._checkOperation('filter');
var expression = Container.createCodeExpression(predicate, thisArg);
var expressionSource = this.expression;
if (this.expression instanceof $data.Expressions.FilterExpression) {
@@ -121,6 +109,7 @@ $data.Class.define('$data.Queryable', null, null,
/// </example>
/// </signature>

this._checkOperation('map');
var codeExpression = Container.createCodeExpression(projection, thisArg);
var exp = Container.createProjectionExpression(this.expression, codeExpression);
var q = Container.createQueryable(this, exp);
@@ -156,6 +145,7 @@ $data.Class.define('$data.Queryable', null, null,
/// </example>
/// </signature>

this._checkOperation('length');
var pHandler = new $data.PromiseHandler();
var cbWrapper = pHandler.createCallback(onResult);

@@ -194,6 +184,7 @@ $data.Class.define('$data.Queryable', null, null,
/// </example>
/// </signature>

this._checkOperation('forEach');
var pHandler = new $data.PromiseHandler();
function iteratorFunc(items) { items.forEach(iterator); }
var cbWrapper = pHandler.createCallback(iteratorFunc);
@@ -246,6 +237,7 @@ $data.Class.define('$data.Queryable', null, null,
});
}

this._checkOperation('toArray');
var pHandler = new $data.PromiseHandler();
var cbWrapper = pHandler.createCallback(onResult_items);

@@ -295,6 +287,7 @@ $data.Class.define('$data.Queryable', null, null,
/// </example>
/// </signature>

this._checkOperation('single');
var q = this;
if (filterPredicate) {
q = this.filter(filterPredicate, thisArg);
@@ -318,6 +311,122 @@ $data.Class.define('$data.Queryable', null, null,
return pHandler.getPromise();
},

some: function (filterPredicate, thisArg, onResult) {
/// <summary>Filters a set of entities using a boolean expression and returns true if the query has any result element.</summary>
/// <param name="filterPredicate" type="Function">Filter function</param>
/// <param name="thisArg" type="Function">The query parameters for filter function</param>
/// <param name="onResult_items" type="Function">A callback function</param>
/// <returns type="$data.Promise" />
/// <signature>
/// <summary>Filters a set of entities using a boolean expression and returns true if the query has any result element.</summary>
/// <param name="filterPredicate" type="string">
/// Same as in filter.
/// </param>
/// <param name="onResult" type="Function">
/// The callback function to handle the result, same as in toArray.
/// </param>
/// <returns type="$data.Promise" />
/// </signature>
/// <signature>
/// <summary>Filters a set of entities using a boolean expression and returns true if the query has any result element.</summary>
/// <param name="filterPredicate" type="Function">
/// Same as in filter.
/// </param>
/// <param name="onResult" type="Function">
/// The callback function to handle the result, same as in toArray.
/// </param>
/// <returns type="$data.Promise" />
/// <example>
/// Is there any person who's first name is "George"? &#10;
/// Persons.some( function( person ) { return person.FirstName == this.name; }, { name: "George" }, {&#10;
/// success: function ( result ){ ... },&#10;
/// error: function () { ... }
/// });
/// </example>
/// </signature>

this._checkOperation('some');
var q = this;
if (filterPredicate) {
q = this.filter(filterPredicate, thisArg);
}
q = q.take(1);

var pHandler = new $data.PromiseHandler();
var cbWrapper = pHandler.createCallback(onResult);

var someExpression = Container.createSomeExpression(q.expression);
var preparator = Container.createQueryExpressionCreator(q.entitySet.entityContext);
try {
var expression = preparator.Visit(someExpression);
this.entitySet.entityContext.log({ event: "EntityExpression", data: expression });

q.entitySet.executeQuery(Container.createQueryable(q, expression), cbWrapper);
} catch (e) {
cbWrapper.error(e);
}

return pHandler.getPromise();
},

every: function (filterPredicate, thisArg, onResult) {
/// <summary>Filters a set of entities using a boolean expression and returns true if all elements of the EntitySet is in the result set.</summary>
/// <param name="filterPredicate" type="Function">Filter function</param>
/// <param name="thisArg" type="Function">The query parameters for filter function</param>
/// <param name="onResult_items" type="Function">A callback function</param>
/// <returns type="$data.Promise" />
/// <signature>
/// <summary>Filters a set of entities using a boolean expression and returns a </summary>
/// <param name="filterPredicate" type="string">
/// Same as in filter.
/// </param>
/// <param name="onResult" type="Function">
/// The callback function to handle the result, same as in toArray.
/// </param>
/// <returns type="$data.Promise" />
/// </signature>
/// <signature>
/// <summary>Filters a set of entities using a boolean expression and returns a single element or throws an error if more than one element is filtered.</summary>
/// <param name="filterPredicate" type="Function">
/// Same as in filter.
/// </param>
/// <param name="onResult" type="Function">
/// The callback function to handle the result, same as in toArray.
/// </param>
/// <returns type="$data.Promise" />
/// <example>
/// Result is true when all person are married. &#10;
/// Persons.every( function( person ) { return person.Married == true; }, null, {&#10;
/// success: function ( result ){ ... },&#10;
/// error: function () { ... }
/// });
/// </example>
/// </signature>

this._checkOperation('every');
var q = this;
if (filterPredicate) {
q = this.filter(filterPredicate, thisArg);
}
q = q.take(1);

var pHandler = new $data.PromiseHandler();
var cbWrapper = pHandler.createCallback(onResult);

var everyExpression = Container.createEveryExpression(q.expression);
var preparator = Container.createQueryExpressionCreator(q.entitySet.entityContext);
try {
var expression = preparator.Visit(everyExpression);
this.entitySet.entityContext.log({ event: "EntityExpression", data: expression });

q.entitySet.executeQuery(Container.createQueryable(q, expression), cbWrapper);
} catch (e) {
cbWrapper.error(e);
}

return pHandler.getPromise();
},


take: function (amount) {
/// <summary>Returns only a specified number of elements from the start of the result set.</summary>
@@ -335,6 +444,7 @@ $data.Class.define('$data.Queryable', null, null,
/// </example>
/// </signature>

this._checkOperation('take');
var constExp = Container.createConstantExpression(amount, "number");
var takeExp = Container.createPagingExpression(this.expression, constExp, ExpressionType.Take);
return Container.createQueryable(this, takeExp);
@@ -355,6 +465,7 @@ $data.Class.define('$data.Queryable', null, null,
/// </example>
/// </signature>

this._checkOperation('skip');
var constExp = Container.createConstantExpression(amount, "number");
var takeExp = Container.createPagingExpression(this.expression, constExp, ExpressionType.Skip);
return Container.createQueryable(this, takeExp);
@@ -389,6 +500,7 @@ $data.Class.define('$data.Queryable', null, null,
///</example>
///</signature>

this._checkOperation('orderBy');
var codeExpression = Container.createCodeExpression(selector, thisArg);
var exp = Container.createOrderExpression(this.expression, codeExpression, ExpressionType.OrderBy);
var q = Container.createQueryable(this, exp);
@@ -423,6 +535,7 @@ $data.Class.define('$data.Queryable', null, null,
///</example>
///</signature>

this._checkOperation('orderByDescending');
var codeExpression = Container.createCodeExpression(selector, thisArg);
var exp = Container.createOrderExpression(this.expression, codeExpression, ExpressionType.OrderByDescending);
var q = Container.createQueryable(this, exp);
@@ -458,6 +571,7 @@ $data.Class.define('$data.Queryable', null, null,
/// </example>
/// </signature>

this._checkOperation('first');
var q = this;
if (filterPredicate) {
q = this.filter(filterPredicate, thisArg);
@@ -498,6 +612,7 @@ $data.Class.define('$data.Queryable', null, null,
/// </example>
/// </signature>

this._checkOperation('include');
var constExp = Container.createConstantExpression(selector, "string");
var takeExp = Container.createIncludeExpression(this.expression, constExp);
return Container.createQueryable(this, takeExp);
@@ -533,6 +648,24 @@ $data.Class.define('$data.Queryable', null, null,
//this.expression = expression;
var q = Container.createQueryable(this, expression)
return q.entitySet.getTraceString(q);
}
},

_checkRootExpression: function () {
if (!this.expression) {
var ec = Container.createEntityContextExpression(this.entitySet.entityContext);
var name = this.entitySet.collectionName;
var memberdef = this.entitySet.entityContext.getType().getMemberDefinition(name);
var es = Container.createEntitySetExpression(ec,
Container.createMemberInfoExpression(memberdef), null,
this.entitySet);
this.expression = es;
}
},
_checkOperation: function (name) {
var operation = this.entitySet.entityContext.resolveSetOperations(name);
if (operation.invokable != undefined && !operation.invokable)
Guard.raise(new Exception("Operation '" + name + "' is not invokable with the provider"));
},
entitySet: {}

}, null);
@@ -199,6 +199,28 @@ $data.Class.define('$data.StorageProviderBase', null, null,
return result;
},

supportedSetOperations: {
value: {
toArray: { invokable: true, allowedIn: [] }
},
enumerable: true,
writable: true
},
resolveSetOperations: function (operation, expression, frameType) {
var result = this.supportedSetOperations[operation];
if (!result) {
Guard.raise(new Exception("Operation '" + operation + "' is not supported by the provider"));
};
var allowedIn = result.allowedIn || [];
if (frameType && allowedIn) {
if ((allowedIn instanceof Array && !allowedIn.some(function (type) { return frameType === Container.resolveType(type); })) ||
(!(allowedIn instanceof Array) && frameType !== Container.resolveType(allowedIn))) {
Guard.raise(new Exception(operation + " not supported in: " + frameType.name));
}
}
return result;
},


makePhysicalTypeDefinition: function (entityDefinition, association) {
}
@@ -60,7 +60,7 @@ $data.Class.define('$data.storageProviders.Facebook.FacebookProvider', $data.Sto
value: {
equal: { mapTo: ' = ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
notEqual: { mapTo: ' != ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
equalTyped: { mapTo: ' = ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
equalTyped: { mapTo: ' = ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
notEqualTyped: { mapTo: ' != ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
greaterThan: { mapTo: ' > ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
greaterThanOrEqual: { mapTo: ' >= ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
@@ -97,6 +97,22 @@ $data.Class.define('$data.storageProviders.Facebook.FacebookProvider', $data.Sto
}
}
},
supportedSetOperations: {
value: {
filter: {},
map: {},
forEach: {},
toArray: {},
single: {},
take: {},
skip: {},
orderBy: {},
orderByDescending: {},
first: {}
},
enumerable: true,
writable: true
},
executeQuery: function (query, callBack) {
callBack = $data.typeSystem.createCallbackSetting(callBack);

@@ -35,6 +35,15 @@ $data.Class.define('$data.storageProviders.indexedDb.IndexedDBStorageProvider',
//'in': { mapTo: ' in ', dataType: $data.Boolean, resolvableType: [$data.Array, $data.Queryable] }
}
},
supportedSetOperations: {
value: {
length: {},
toArray: {},
forEach: {}
},
enumerable: true,
writable: true
},
_setupExtensionMethods: function () {
/// <summary>
/// Sets the extension method 'setCallback' on IDBRequest, IDBOpenDBRequest, and IDBTransaction types
@@ -6,6 +6,12 @@ $C('$data.sqLite.sqLite_ModelBinderCompiler', $data.Expressions.EntityExpression
VisitSingleExpression: function (expression) {
this._defaultModelBinder(expression);
},
VisitSomeExpression: function (expression) {
this._defaultModelBinder(expression);
},
VisitEveryExpression: function (expression) {
this._defaultModelBinder(expression);
},
VisitToArrayExpression: function (expression) {
this._defaultModelBinder(expression);
},
@@ -27,7 +27,7 @@ $data.Class.define('$data.storageProviders.sqLite.SqLiteStorageProvider', $data.
storage: this.providerConfiguration.storage
};

if (this.connection) return this.connection;
if (this.connection) return this.connection;

var connection = null;
if (this.providerConfiguration.storage) {
@@ -38,7 +38,7 @@ $data.Class.define('$data.storageProviders.sqLite.SqLiteStorageProvider', $data.
connection = new $data.dbClient.openDatabaseClient.OpenDbConnection(ctorParm);
}

this.connection = connection;
this.connection = connection;

return connection;
},
@@ -125,8 +125,8 @@ $data.Class.define('$data.storageProviders.sqLite.SqLiteStorageProvider', $data.
value: {
equal: { mapTo: '=', dataType: "boolean" },
notEqual: { mapTo: '!=', dataType: "boolean" },
equalTyped: { mapTo: '=', dataType: "boolean" },
notEqualTyped: { mapTo: '!=', dataType: "boolean" },
equalTyped: { mapTo: '=', dataType: "boolean" },
notEqualTyped: { mapTo: '!=', dataType: "boolean" },
greaterThan: { mapTo: '>', dataType: "boolean" },
greaterThanOrEqual: { mapTo: '>=', dataType: "boolean" },

@@ -156,6 +156,25 @@ $data.Class.define('$data.storageProviders.sqLite.SqLiteStorageProvider', $data.
}
},

supportedSetOperations: {
value: {
filter: {},
map: {},
length: {},
forEach: {},
toArray: {},
single: {},
take: {},
skip: {},
orderBy: {},
orderByDescending: {},
first: {},
include: {}
},
enumerable: true,
writable: true
},

buildDbType_modifyInstanceDefinition: function (instanceDefinition, storageModel) {
var buildDbType_copyPropertyDefinition = function (propertyDefinition) {
var cPropertyDef = JSON.parse(JSON.stringify(propertyDefinition));
@@ -299,7 +318,7 @@ $data.Class.define('$data.storageProviders.sqLite.SqLiteStorageProvider', $data.
}
}
that.SqlCommands = that.SqlCommands.concat(deleteCmd);
console.log(deleteCmd);
console.log(deleteCmd);
break;
case $data.storageProviders.sqLite.DbCreationType.DropAllExistingTables:
for (var objName in existObjectInDB) {
@@ -680,8 +699,8 @@ $data.storageProviders.sqLite.DbCreationType = {
DropAllExistingTables: 30
};

if ($data.storageProviders.sqLite.SqLiteStorageProvider.isSupported){
$data.StorageProviderBase.registerProvider("webSql", $data.storageProviders.sqLite.SqLiteStorageProvider);
$data.StorageProviderBase.registerProvider("sqLite", $data.storageProviders.sqLite.SqLiteStorageProvider);
$data.webSqlProvider = $data.storageProviders.sqLite.SqLiteStorageProvider;
if ($data.storageProviders.sqLite.SqLiteStorageProvider.isSupported) {
$data.StorageProviderBase.registerProvider("webSql", $data.storageProviders.sqLite.SqLiteStorageProvider);
$data.StorageProviderBase.registerProvider("sqLite", $data.storageProviders.sqLite.SqLiteStorageProvider);
$data.webSqlProvider = $data.storageProviders.sqLite.SqLiteStorageProvider;
}
@@ -50,7 +50,7 @@ $data.Class.define('$data.storageProviders.YQL.YQLProvider', $data.StorageProvid
value: {
equal: { mapTo: ' = ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
notEqual: { mapTo: ' != ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
equalTyped: { mapTo: ' = ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
equalTyped: { mapTo: ' = ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
notEqualTyped: { mapTo: ' != ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
greaterThan: { mapTo: ' > ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
greaterThanOrEqual: { mapTo: ' >= ', dataType: $data.Boolean, allowedIn: $data.Expressions.FilterExpression },
@@ -66,6 +66,22 @@ $data.Class.define('$data.storageProviders.YQL.YQLProvider', $data.StorageProvid
supportedUnaryOperators: {
value: {}
},
supportedSetOperations: {
value: {
filter: {},
map: {},
forEach: {},
toArray: {},
single: {},
take: {},
skip: {},
orderBy: {},
orderByDescending: {},
first: {}
},
enumerable: true,
writable: true
},
fieldConverter: {
value: {
fromDb: {
@@ -14,6 +14,12 @@ $C('$data.modelBinder.ModelBinderConfigCompiler', $data.Expressions.EntityExpres
VisitSingleExpression: function (expression) {
this._defaultModelBinder(expression);
},
VisitSomeExpression: function (expression) {
this._defaultModelBinder(expression);
},
VisitEveryExpression: function (expression) {
this._defaultModelBinder(expression);
},
VisitToArrayExpression: function (expression) {
this._defaultModelBinder(expression);
},
@@ -24,7 +24,7 @@ $C('$data.storageProviders.oData.oDataCompiler', $data.Expressions.EntityExpress
var queryText = queryFragments.urlText;
var addAmp = false;
for (var name in queryFragments) {
if (name != "urlText" && name != "actionPack" && name != "data" && queryFragments[name] != "") {
if (name != "urlText" && name != "actionPack" && name != "data" && name != "lambda" && queryFragments[name] != "") {
if (addAmp) { queryText += "&"; } else { queryText += "?"; }
addAmp = true;
if(name != "$urlParams"){
@@ -93,7 +93,7 @@ $C('$data.storageProviders.oData.oDataProvider', $data.StorageProviderBase, null
cfg.beforeSend = function (xhr) {
xhr.setRequestHeader("Authorization", "Basic " + encodeBase64(user + ":" + password || ""));
if (typeof origBeforeSend === "function")
origBeforeSend.apply(this, xhr);
origBeforeSend.apply(this, arguments);
}
}
return cfg;
@@ -164,6 +164,9 @@ $C('$data.storageProviders.oData.oDataProvider', $data.StorageProviderBase, null
var requestData = {
url: this.providerConfiguration.oDataServiceHost + sql.queryText,
dataType: "JSON",
beforeSend: function (xhr) {
xhr.setRequestHeader("Accept", "application/json; odata=verbose, text/javascript, */*; q=0.01");
},
success: function (data, textStatus, jqXHR) {
if (callBack.success) {
query.rawDataList = typeof data === 'number' ? [{ cnt: data }] : data;
@@ -426,6 +429,38 @@ $C('$data.storageProviders.oData.oDataProvider', $data.StorageProviderBase, null
enumerable: true,
writable: true
},
supportedSetOperations: {
value: {
filter: { },
map: {},
length: {},
forEach: {},
toArray: {},
single: {},
some: {
invokable: false,
allowedIn: [$data.Expressions.FilterExpression],
parameters: [{ name: "filter", dataType: "$data.Queryable" }],
mapTo: 'any',
frameType: $data.Expressions.SomeExpression
},
every: {
invokable: false,
allowedIn: [$data.Expressions.FilterExpression],
parameters: [{ name: "filter", dataType: "$data.Queryable" }],
mapTo: 'all',
frameType: $data.Expressions.EveryExpression
},
take: {},
skip: {},
orderBy: {},
orderByDescending: {},
first: {},
include: {}
},
enumerable: true,
writable: true
},
fieldConverter: {
value: {
fromDb: {
@@ -1,6 +1,7 @@
$C('$data.storageProviders.oData.oDataWhereCompiler', $data.Expressions.EntityExpressionVisitor, null, {
constructor: function (provider) {
constructor: function (provider, lambdaPrefix) {
this.provider = provider;
this.lambdaPrefix = lambdaPrefix;
},

compile: function (expression, context) {
@@ -108,6 +109,12 @@ $C('$data.storageProviders.oData.oDataWhereCompiler', $data.Expressions.EntityEx

VisitEntityExpression: function (expression, context) {
this.Visit(expression.source, context);

if (this.lambdaPrefix && expression.selector.lambda) {
context.lambda = expression.selector.lambda;
context.data += (expression.selector.lambda + '/');
}

//if (expression.selector instanceof $data.Expressions.EntityExpression) {
// this.Visit(expression.selector, context);
//}
@@ -119,5 +126,43 @@ $C('$data.storageProviders.oData.oDataWhereCompiler', $data.Expressions.EntityEx
this.Visit(expression.selector, context);
context.data += "/";
}
},

VisitFrameOperationExpression: function (expression, context) {
this.Visit(expression.source, context);

Guard.requireType("expression.operation", expression.operation, $data.Expressions.MemberInfoExpression);

//TODO refactor!
var opDef = expression.operation.memberDefinition;
var opName = opDef.mapTo || opDef.name;
context.data += opName;
context.data += "(";
var paramCounter = 0;
var params = opDef.parameters || [{ name: "@expression" }];

var args = params.map(function (item, index) {
if (item.name === "@expression") {
return expression.source;
} else {
return expression.parameters[paramCounter++]
};
});

for (var i = 0; i < args.length; i++) {
var arg = args[i];
if (arg.value instanceof $data.Queryable) {
var frameExpression = new opDef.frameType(arg.value.expression);
var preparator = Container.createQueryExpressionCreator(arg.value.entitySet.entityContext);
var prep_expression = preparator.Visit(frameExpression);

var compiler = new $data.storageProviders.oData.oDataWhereCompiler(this.provider, true);
var frameContext = { data: "" };
var compiled = compiler.compile(prep_expression, frameContext);

context.data += (frameContext.lambda + ': ' + frameContext.data);
};
}
context.data += ")";
}
});
@@ -440,7 +440,7 @@ function T3(providerConfig, msg) {
$news.Types.NewsContext.generateTestData(db, function () {
start(1);

db.Articles.single(function (a) { return a.Id == 1;}, null,{
db.Articles.single(function (a) { return a.Id == 1; }, null, {
success: function (result) {
start(1);
ok(result, 'query failed');
@@ -860,13 +860,136 @@ function T3(providerConfig, msg) {
start(1);
$news.Types.NewsContext.generateTestData(db, function () {
start(1);
db.PrefilteredArticles(4, 'Art').filter(function(a){return a.Id<7}).toArray(function(result){
db.PrefilteredArticles(4, 'Art').filter(function (a) { return a.Id < 7 }).toArray(function (result) {
start(1);
ok(result);
ok(result[0] instanceof $news.Types.Article, 'Return type faild');
ok(result[1].Title.length>0, 'Title faild');
ok(result[1].Title.length > 0, 'Title faild');
})
});
});
});


}

function T3_oDataV3(providerConfig, msg) {
msg = msg || '';
module("DataTestsV3" + msg);


test("OData_Function_sub_frames", function () {
if (providerConfig.name == "sqLite") { ok(true, "Not supported"); return; }
expect(17);
stop(4);
(new $news.Types.NewsContext(providerConfig)).onReady(function (db) {
$news.Types.NewsContext.generateTestData(db, function () {

var articleFilter = db.Articles.filter(function (art) { return art.Title == 'Article1'; });
var q = db.Categories.filter(function (ctg) { return ctg.Articles.some(this.filter); }, { filter: articleFilter });
var c = q.toTraceString();
equal(c.queryText, "/Categories?$filter=Articles/any(art: (art/Title eq 'Article1'))", "A1: Invalid query string");

q.toArray({
success: function (result) {
start();
equal(result.length, 1, 'A1: result length failed');
equal(result[0].Title, 'Sport', 'A1: result value failed');
},
error: function (e) {
start();

ok(false, 'A1: Category some article.Title == "Article1", error: ' + e);
}
});

q = db.Categories.filter(function (ctg) { return ctg.Articles.every(this.filter); }, { filter: articleFilter });
c = q.toTraceString();
equal(c.queryText, "/Categories?$filter=Articles/all(art: (art/Title eq 'Article1'))", "A2: Invalid query string");

q.toArray({
success: function (result) {
start();
equal(result.length, 0, 'A2: result length failed');
},
error: function (e) {
start();
ok(false, 'A2: Category every article.Title == "Article1", error: ' + e);
}
});

articleFilter = db.Articles.filter(function (art) { return art.Author.Profile.FullName == 'Full Name2'; });
q = db.Categories.filter(function (ctg) { return ctg.Articles.some(this.filter); }, { filter: articleFilter });
c = q.toTraceString();
equal(c.queryText, "/Categories?$filter=Articles/any(art: (art/Author/Profile/FullName eq 'Full Name2'))", "A3: Invalid query string");

q.toArray({
success: function (result) {
start();
equal(result.length, 5, 'A3: result length failed');
equal(result[0].Title, 'Sport', 'A3: result value failed');
},
error: function (e) {
start();
ok(false, 'A3: Category some article Author.Profile.Fullname "Full Name2", error: ' + e);
}
});

articleFilter = db.Articles.filter(function (art) { return art.Author.Profile.FullName == 'Starts With Test'; });
q = db.Categories.filter(function (ctg) { return ctg.Articles.some(this.filter); }, { filter: articleFilter });
c = q.toTraceString();
equal(c.queryText, "/Categories?$filter=Articles/any(art: (art/Author/Profile/FullName eq 'Starts With Test'))", "A4: Invalid query string");

q.toArray({
success: function (result) {
start();
equal(result.length, 1, 'A4: result length failed');
equal(result[0].Title, 'Politics', 'A4: result value failed');
},
error: function (e) {
start();
ok(false, 'A4: Category some article Author.Profile.Fullname "Starts With Test", error: ' + e);
}
});


var tagFilter = db.TagConnections.filter(function (tagCon) { return tagCon.Tag.Title == 'Tag1'; });
articleFilter = db.Articles.filter(function (art) { return art.Tags.some(this.filter); }, { filter: tagFilter });
q = db.Categories.filter(function (ctg) { return ctg.Articles.some(this.filter); }, { filter: articleFilter })
c = q.toTraceString();
equal(c.queryText, "/Categories?$filter=Articles/any(art: art/Tags/any(tagCon: (tagCon/Tag/Title eq 'Tag1')))", "A5: Invalid query string");

q.toArray({
success: function (result) {
start();
equal(result.length, 5, 'A5: result length failed');
equal(result[0].Title, 'Sport', 'A5: result value failed');
},
error: function (e) {
start();
ok(false, 'A5: Category some article Author.Profile.Fullname "Starts With Test", error: ' + e);
}
});

tagFilter = db.TagConnections.filter(function (tagCon) { return tagCon.Tag.Title == 'Tag3'; });
articleFilter = db.Articles.filter(function (art) { return art.Tags.some(this.filter) && art.Author.LoginName == 'Usr4'; }, { filter: tagFilter });
q = db.Categories.filter(function (ctg) { return ctg.Articles.some(this.filter); }, { filter: articleFilter })
c = q.toTraceString();
equal(c.queryText, "/Categories?$filter=Articles/any(art: (art/Tags/any(tagCon: (tagCon/Tag/Title eq 'Tag3')) and (art/Author/LoginName eq 'Usr4')))", "A6: Invalid query string");

q.toArray({
success: function (result) {
start();
equal(result.length, 3, 'A6: result length failed');
equal(result[0].Title, 'World', 'A6: result value failed');
},
error: function (e) {
start();
ok(false, 'A6: Category some article Author.Profile.Fullname "Starts With Test", error: ' + e);
}
});
});
});
});

}
@@ -1173,6 +1173,43 @@
equal(q.queryText, "/Users?$filter=(Id gt 0)&$expand=Profile&$select=Id,Profile/Bio", "Invalid query string");
});
});

module('oData_compiler_tests_innerFilter');
test("filter_table_select_sub_frames", 7, function () {
stop(1);
(new $news.Types.NewsContext({ name: "oData" })).onReady(function (db) {
var articleFilter = db.Articles.filter(function (art) { return art.Title == 'Article1'; });
var q = db.Categories.filter(function (ctg) { return ctg.Articles.some(this.filter); }, { filter: articleFilter }).toTraceString();
equal(q.queryText, "/Categories?$filter=Articles/any(art: (art/Title eq 'Article1'))", "Invalid query string");

q = db.Categories.filter(function (ctg) { return ctg.Articles.every(this.filter); }, { filter: articleFilter }).toTraceString();
equal(q.queryText, "/Categories?$filter=Articles/all(art: (art/Title eq 'Article1'))", "Invalid query string");

/*Tag != Tagconnection ( 1..* *..1 ) */
tagFilter = db.TagConnections.filter(function (tagCon) { return tagCon.Id > 0; });
articleFilter = db.Articles.filter(function (art) { return art.Tags.some(this.filter); }, { filter: tagFilter });
q = db.Categories.filter(function (ctg) { return ctg.Articles.some(this.filter); }, { filter: articleFilter }).toTraceString();
equal(q.queryText, "/Categories?$filter=Articles/any(art: art/Tags/any(tagCon: (tagCon/Id gt 0)))", "Invalid query string");

q = db.Categories.filter(function (ctg) { return ctg.Articles.every(this.filter); }, { filter: articleFilter }).toTraceString();
equal(q.queryText, "/Categories?$filter=Articles/all(art: art/Tags/any(tagCon: (tagCon/Id gt 0)))", "Invalid query string");

tagFilter = db.TagConnections.filter(function (tagCon) { return tagCon.Article.Title == 'Article1'; });
articleFilter = db.Articles.filter(function (art) { return art.Tags.some(this.filter); }, { filter: tagFilter });
q = db.Categories.filter(function (ctg) { return ctg.Articles.some(this.filter); }, { filter: articleFilter }).toTraceString();
equal(q.queryText, "/Categories?$filter=Articles/any(art: art/Tags/any(tagCon: (tagCon/Article/Title eq 'Article1')))", "Invalid query string, 1..* *..1 ");
/* ^^ */

articleFilter = db.Articles.filter(function (art) { return art.Title == 'Article1'; });
q = db.Categories.filter(function (ctg) { return ctg.Articles.every(this.filter) && ctg.Title == 'Sport'; }, { filter: articleFilter }).toTraceString();
equal(q.queryText, "/Categories?$filter=(Articles/all(art: (art/Title eq 'Article1')) and (Title eq 'Sport'))", "Invalid query string");

q = db.Categories.filter(function (ctg) { return ctg.Title == 'Sport' && ctg.Articles.some(this.filter); }, { filter: articleFilter }).toTraceString();
equal(q.queryText, "/Categories?$filter=((Title eq 'Sport') and Articles/any(art: (art/Title eq 'Article1')))", "Invalid query string");

start(1);
});
});
test("filter_chain", 1, function () {
stop(1);
(new $news.Types.NewsContext({ name: "oData" })).onReady(function (db) {
@@ -1181,4 +1218,4 @@
equal(q.queryText, "/Users?$filter=((Id gt 0) and substringof('Joe',LoginName))", "Invalid query string");
});
});
});
});
@@ -0,0 +1,164 @@
$(document).ready(function () {
if (!$data.storageProviders.sqLite.SqLiteStorageProvider.isSupported) return;
frameOperatorTests({ name: "oData", databaseName: 'T1', oDataServiceHost: "Services/emptyNewsReader.svc", serviceUrl: 'Services/oDataDbDelete.asmx', dbCreation: $data.storageProviders.sqLite.DbCreationType.DropAllExistingTables });
setOperationTests({ name: "oData", databaseName: 'T1', oDataServiceHost: "Services/emptyNewsReader.svc", serviceUrl: 'Services/oDataDbDelete.asmx', dbCreation: $data.storageProviders.sqLite.DbCreationType.DropAllExistingTables });
});

function frameOperatorTests(providerConfig) {
module("frameOperator Tests");

test("frameOperators", 25, function () {
stop(11);
(new $news.Types.NewsContext(providerConfig)).onReady(function (db) {

$news.Types.NewsContext.generateTestData(db, function () {

notEqual(db.Articles.toArray, undefined, 'toArray on EntitySet failed');
notEqual(db.Articles.filter(function () { return true; }).toArray, undefined, 'toArray on Queryable failed');

db.Articles.toArray(function (articles) {
start();

ok(articles.length > 0, 'result count failed');

});

notEqual(db.Articles.forEach, undefined, 'forEach on EntitySet failed');
notEqual(db.Articles.take(1).forEach, undefined, 'forEach on Queryable failed');

db.Articles.take(1).forEach(function (article) {
start();

ok(true, 'result failed');

});

notEqual(db.Articles.length, undefined, 'length on EntitySet failed');
notEqual(db.Articles.filter(function () { return true; }).length, undefined, 'length on Queryable failed');

db.Articles.length(function (num) {
start();

ok(num > 0, 'result count failed');

});

notEqual(db.Articles.single, undefined, 'single on EntitySet failed');
notEqual(db.Articles.filter(function () { return true; }).single, undefined, 'single on Queryable failed');

db.Articles.filter(function (a) { return a.Id == 1 }).single(null, null, function (val) {
start();

ok(true, 'result failed');

});

db.Articles.single(function (a) { return a.Id == 1 }, null, function (val) {
start();

ok(true, 'result failed');

});

notEqual(db.Articles.first, undefined, 'first on EntitySet failed');
notEqual(db.Articles.filter(function () { return true; }).first, undefined, 'first on Queryable failed');

db.Articles.first(null, null, function (val) {
start();

ok(true, 'result failed');

});

db.Articles.first(function (a) { return a.Id == 1 }, null, function (val) {
start();

ok(true, 'result failed');

});

notEqual(db.Articles.some, undefined, 'some on EntitySet failed');
notEqual(db.Articles.filter(function () { return true; }).some, undefined, 'some on Queryable failed');

try {
db.Articles.some(null, null, function (val) {
start();

equal(val, true, 'result failed');

});

db.Articles.some(function (a) { return a.Id == 1 }, null, function (val) {
start();

equal(val, true, 'result failed');

});
} catch (e) {
ok(true, 'some');
ok(true, e);
start(2);
}

notEqual(db.Articles.every, undefined, 'every on EntitySet failed');
notEqual(db.Articles.filter(function () { return true; }).every, undefined, 'every on Queryable failed');

try {
db.Articles.every(null, null, function (val) {
start();

equal(val, true, 'result failed');

});

db.Articles.every(function (a) { return a.Id == 1 }, null, function (val) {
start();

equal(val, false, 'result failed');

});
} catch (e) {
ok(true, 'every');
ok(true, e);
start(2);
}

});
});
});
};

function setOperationTests(providerConfig) {
module("setOperationTests Tests");

test("setOperationTests oData inline 1:N operators", 3, function () {
stop(1);
(new $news.Types.NewsContext(providerConfig)).onReady(function (db) {
var subsubFilter = db.Tags.filter(function (t) { t.Id == 5 });
var subFilter = db.Articles.filter(function (a) { return a.Tags.some(this.someFilter); }, { someFilter: subsubFilter });
start();

try {
var q = db.Categories.filter(function (c) { return c.Articles.some(this.someFilter); }, { someFilter: subFilter }).toTraceString();
ok(true, 'some on articles collection in query failed');
} catch (e) {
ok(false, 'some on articles collection in query failed');
}

try {
var q = db.Categories.filter(function (c) { return c.Articles.map(this.mapFilter); }, { mapFilter: subFilter }).toTraceString();
ok(false, 'map on articles collection in query failed');
} catch (e) {
ok(true, 'map on articles collection in query failed');
}

try {
var q = db.Categories.filter(function (c) { return c.Title.map(this.mapFilter); }, { mapFilter: subFilter }).toTraceString();
ok(false, 'map on Title in query failed');
} catch (e) {
ok(true, 'map on Title in query failed');
}

});
});
};
@@ -26,9 +26,14 @@
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<add assembly="System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<add assembly="System.Data.Services.Client, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<add assembly="System.Web.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />

<add assembly="Microsoft.Data.Edm, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add assembly="Microsoft.Data.OData, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add assembly="Microsoft.Data.Services, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add assembly="Microsoft.Data.Services.Client, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add assembly="System.Spatial, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

</assemblies>
</compilation>
<authentication mode="Windows">
@@ -58,6 +58,7 @@
<script type="text/javascript" src="Types/Expressions/EntityExpressions/EntityFieldExpression.js"></script>
<script type="text/javascript" src="Types/Expressions/EntityExpressions/EntityFieldOperationExpression.js"></script>
<script type="text/javascript" src="Types/Expressions/EntityExpressions/EntitySetExpression.js"></script>
<script type="text/javascript" src="Types/Expressions/EntityExpressions/FrameOperationExpression.js"></script>
<script type="text/javascript" src="Types/Expressions/EntityExpressions/FilterExpression.js"></script>
<script type="text/javascript" src="Types/Expressions/EntityExpressions/IncludeExpression.js"></script>
<script type="text/javascript" src="Types/Expressions/EntityExpressions/MemberInfoExpression.js"></script>
@@ -171,6 +172,7 @@
<script src="UnitTests/ValidationTests.js" type="text/javascript"></script>

<script src="UnitTests/knockoutTests.js" type="text/javascript"></script>
<script src="UnitTests/setOperationTests.js" type="text/javascript"></script>

<script src="UnitTests/sqLiteProviderTests.js" type="text/javascript"></script>
<script src="UnitTests/sqLiteCompilerTests.js" type="text/javascript"></script>
@@ -30,6 +30,7 @@
<script src="UnitTests/dataDistributeTest.js" type="text/javascript"></script>
<script src="UnitTests/ValidationTests.js" type="text/javascript"></script>
<script src="UnitTests/knockoutTests.js" type="text/javascript"></script>
<script src="UnitTests/setOperationTests.js" type="text/javascript"></script>

<script src="UnitTests/FaceBookProviderTests.js" type="text/javascript"></script>
<script src="UnitTests/YQLProviderTests.js" type="text/javascript"></script>
@@ -28,6 +28,7 @@
<script src="UnitTests/dataDistributeTest.js" type="text/javascript"></script>
<script src="UnitTests/ValidationTests.js" type="text/javascript"></script>
<script src="UnitTests/knockoutTests.js" type="text/javascript"></script>
<script src="UnitTests/setOperationTests.js" type="text/javascript"></script>

<script src="UnitTests/FaceBookProviderTests.js" type="text/javascript"></script>
<script src="UnitTests/YQLProviderTests.js" type="text/javascript"></script>
@@ -30,6 +30,7 @@
<script src="UnitTests/dataDistributeTest.js" type="text/javascript"></script>
<script src="UnitTests/ValidationTests.js" type="text/javascript"></script>
<script src="UnitTests/knockoutTests.js" type="text/javascript"></script>
<script src="UnitTests/setOperationTests.js" type="text/javascript"></script>

<script src="UnitTests/FaceBookProviderTests.js" type="text/javascript"></script>
<script src="UnitTests/YQLProviderTests.js" type="text/javascript"></script>
@@ -28,6 +28,7 @@
<script src="UnitTests/dataDistributeTest.js" type="text/javascript"></script>
<script src="UnitTests/ValidationTests.js" type="text/javascript"></script>
<script src="UnitTests/knockoutTests.js" type="text/javascript"></script>
<script src="UnitTests/setOperationTests.js" type="text/javascript"></script>

<script src="UnitTests/FaceBookProviderTests.js" type="text/javascript"></script>
<script src="UnitTests/YQLProviderTests.js" type="text/javascript"></script>