jaydata
Version:
Cross-platform HTML5 data-management, JavaScript Language Query (JSLQ) support for OData, SQLite, WebSQL, IndexedDB, YQL and Facebook (packaged for Node.JS)
302 lines (275 loc) • 13.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SqlStatementBlocks = undefined;
var _core = require("jaydata/core");
var _core2 = _interopRequireDefault(_core);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var SqlStatementBlocks = exports.SqlStatementBlocks = {
beginGroup: "(",
endGroup: ")",
nameSeparator: ".",
valueSeparator: ", ",
select: "SELECT ",
where: " WHERE ",
from: " FROM ",
skip: " OFFSET ",
take: " LIMIT ",
parameter: "?",
order: " ORDER BY ",
as: " AS ",
scalarFieldName: 'd',
rowIdName: 'rowid$$',
count: 'select count(*) cnt from ('
};
(0, _core.$C)('$data.sqLite.SqlBuilder', _core2.default.queryBuilder, null, {
constructor: function constructor(sets, context) {
this.sets = sets;
this.entityContext = context;
},
getExpressionAlias: function getExpressionAlias(setExpression) {
var idx = this.sets.indexOf(setExpression);
if (idx == -1) {
idx = this.sets.push(setExpression) - 1;
}
return "T" + idx;
}
});
(0, _core.$C)('$data.sqLite.SqlCompiler', _core2.default.Expressions.EntityExpressionVisitor, null, {
constructor: function constructor(queryExpression, context) {
this.queryExpression = queryExpression;
this.sets = context.sets;
this.infos = context.infos;
this.entityContext = context.entityContext;
this.associations = [];
this.filters = [];
this.newFilters = {};
this.sortedFilterPart = ['projection', 'from', 'filter', 'order', 'take', 'skip'];
},
compile: function compile() {
var sqlBuilder = _core2.default.sqLite.SqlBuilder.create(this.sets, this.entityContext);
this.Visit(this.queryExpression, sqlBuilder);
if (sqlBuilder.getTextPart('projection') === undefined) {
this.VisitDefaultProjection(sqlBuilder);
}
sqlBuilder.selectTextPart("result");
this.sortedFilterPart.forEach(function (part) {
var part = sqlBuilder.getTextPart(part);
if (part) {
sqlBuilder.addText(part.text);
sqlBuilder.selectedFragment.params = sqlBuilder.selectedFragment.params.concat(part.params);
}
}, this);
var countPart = sqlBuilder.getTextPart('count');
if (countPart !== undefined) {
sqlBuilder.selectedFragment.text = countPart.text + sqlBuilder.selectedFragment.text;
sqlBuilder.addText(SqlStatementBlocks.endGroup);
sqlBuilder.selectedFragment.params = sqlBuilder.selectedFragment.params.concat(countPart.params);
}
sqlBuilder.resetModelBinderProperty();
this.filters.push(sqlBuilder);
},
VisitToArrayExpression: function VisitToArrayExpression(expression, sqlBuilder) {
this.Visit(expression.source, sqlBuilder);
},
VisitCountExpression: function VisitCountExpression(expression, sqlBuilder) {
this.Visit(expression.source, sqlBuilder);
sqlBuilder.selectTextPart('count');
sqlBuilder.addText(SqlStatementBlocks.count);
},
VisitFilterExpression: function VisitFilterExpression(expression, sqlBuilder) {
this.Visit(expression.source, sqlBuilder);
sqlBuilder.selectTextPart('filter');
sqlBuilder.addText(SqlStatementBlocks.where);
var filterCompiler = _core2.default.sqLite.SqlFilterCompiler.create();
filterCompiler.Visit(expression.selector, sqlBuilder);
return expression;
},
VisitOrderExpression: function VisitOrderExpression(expression, sqlBuilder) {
this.Visit(expression.source, sqlBuilder);
sqlBuilder.selectTextPart('order');
if (this.addOrders) {
sqlBuilder.addText(SqlStatementBlocks.valueSeparator);
} else {
this.addOrders = true;
sqlBuilder.addText(SqlStatementBlocks.order);
}
var orderCompiler = _core2.default.sqLite.SqlOrderCompiler.create();
orderCompiler.Visit(expression, sqlBuilder);
return expression;
},
VisitPagingExpression: function VisitPagingExpression(expression, sqlBuilder) {
this.Visit(expression.source, sqlBuilder);
switch (expression.nodeType) {
case _core2.default.Expressions.ExpressionType.Skip:
sqlBuilder.selectTextPart('skip');
sqlBuilder.addText(SqlStatementBlocks.skip);break;
case _core2.default.Expressions.ExpressionType.Take:
sqlBuilder.selectTextPart('take');
sqlBuilder.addText(SqlStatementBlocks.take);break;
default:
_core.Guard.raise("Not supported nodeType");break;
}
var pagingCompiler = _core2.default.sqLite.SqlPagingCompiler.create();
pagingCompiler.Visit(expression, sqlBuilder);
return expression;
},
VisitProjectionExpression: function VisitProjectionExpression(expression, sqlBuilder) {
this.Visit(expression.source, sqlBuilder);
sqlBuilder.selectTextPart('projection');
this.hasProjection = true;
sqlBuilder.addText(SqlStatementBlocks.select);
var projectonCompiler = _core2.default.sqLite.SqlProjectionCompiler.create();
projectonCompiler.Visit(expression, sqlBuilder);
},
VisitEntitySetExpression: function VisitEntitySetExpression(expression, sqlBuilder) {
sqlBuilder.selectTextPart('from');
sqlBuilder.addText(SqlStatementBlocks.from);
sqlBuilder.sets.forEach(function (es, setIndex) {
if (setIndex > 0) {
sqlBuilder.addText(" \n\tLEFT OUTER JOIN ");
}
var alias = sqlBuilder.getExpressionAlias(es);
sqlBuilder.addText(es.instance.tableName + ' ');
sqlBuilder.addText(alias);
if (setIndex > 0) {
sqlBuilder.addText(" ON (");
var toSet = this.infos[setIndex];
var toPrefix = "T" + toSet.AliasNumber;
var fromSetName = toSet.NavigationPath.substring(0, toSet.NavigationPath.lastIndexOf('.'));
var temp = this.infos.filter(function (inf) {
return inf.NavigationPath == fromSetName;
}, this);
var fromPrefix = "T0";
if (temp.length > 0) {
fromPrefix = "T" + temp[0].AliasNumber;
}
toSet.Association.associationInfo.ReferentialConstraint.forEach(function (constrain, index) {
if (index > 0) {
sqlBuilder.addText(" AND ");
}
sqlBuilder.addText(fromPrefix + "." + constrain[toSet.Association.associationInfo.From]);
sqlBuilder.addText(" = ");
sqlBuilder.addText(toPrefix + "." + constrain[toSet.Association.associationInfo.To]);
}, this);
sqlBuilder.addText(")");
}
}, this);
},
VisitDefaultProjection: function VisitDefaultProjection(sqlBuilder) {
sqlBuilder.selectTextPart('projection');
var needAlias = this.infos.filter(function (i) {
return i.IsMapped;
}).length > 1;
if (sqlBuilder.sets.length > 1) {
sqlBuilder.addText(SqlStatementBlocks.select);
sqlBuilder.sets.forEach(function (set, masterIndex) {
if (this.infos[masterIndex].IsMapped) {
var alias = sqlBuilder.getExpressionAlias(set);
set.storageModel.PhysicalType.memberDefinitions.getPublicMappedProperties().forEach(function (memberDef, index) {
if (index > 0 || masterIndex > 0) {
sqlBuilder.addText(SqlStatementBlocks.valueSeparator);
}
sqlBuilder.addText(alias + ".");
sqlBuilder.addText(memberDef.name);
if (needAlias) {
sqlBuilder.addText(SqlStatementBlocks.as);
sqlBuilder.addText(alias + "__" + memberDef.name);
}
}, this);
}
}, this);
} else {
sqlBuilder.addText("SELECT *");
}
}
});
_core2.default.Expressions.ExpressionNode.prototype.monitor = function (monitorDefinition, context) {
var m = _core2.default.sqLite.SqlExpressionMonitor.create(monitorDefinition);
return m.Visit(this, context);
};
(0, _core.$C)('$data.storageProviders.sqLite.SQLiteCompiler', null, null, {
compile: function compile(query) {
/// <param name="query" type="$data.Query" />
var expression = query.expression;
var context = { sets: [], infos: [], entityContext: query.context };
var optimizedIncludeExpression = expression.monitor({
MonitorEntitySetExpression: function MonitorEntitySetExpression(expression, context) {
if (expression.source instanceof _core2.default.Expressions.EntityContextExpression && context.sets.indexOf(expression) == -1) {
this.backupEntitySetExpression = expression;
}
},
VisitCountExpression: function VisitCountExpression(expression, context) {
context.hasCountFrameOperator = true;
return expression;
},
MutateIncludeExpression: function MutateIncludeExpression(expression, context) {
var result = null;
if (context.hasCountFrameOperator) {
result = expression.source;
} else {
var origSelector = expression.selector.value;
_core.Container.createCodeExpression("function(it){return it." + origSelector + ";}", null);
var jsCodeTree = _core.Container.createCodeParser(this.backupEntitySetExpression.source.instance).createExpression("function(it){return it." + origSelector + ";}");
var code2entity = _core.Container.createCodeToEntityConverter(this.backupEntitySetExpression.source.instance);
var includeSelector = code2entity.Visit(jsCodeTree, { queryParameters: undefined, lambdaParameters: [this.backupEntitySetExpression] });
result = _core.Container.createIncludeExpression(expression.source, includeSelector);
}
return result;
}
}, context);
var optimizedExpression = optimizedIncludeExpression.monitor({
MonitorEntitySetExpression: function MonitorEntitySetExpression(expression, context) {
if (expression.source instanceof _core2.default.Expressions.EntityContextExpression && context.sets.indexOf(expression) == -1) {
context.sets.push(expression);
context.infos.push({ AliasNumber: 0, Association: null, FromType: null, FromPropertyName: null, IsMapped: true });
}
},
MutateEntitySetExpression: function MutateEntitySetExpression(expression, context) {
if (expression.source instanceof _core2.default.Expressions.EntityContextExpression) {
this.backupContextExpression = expression.source;
this.path = "";
return expression;
}
if (expression.selector.associationInfo.FromMultiplicity == "0..1" && expression.selector.associationInfo.FromMultiplicity == "*") {
_core.Guard.raise("Not supported query on this navigation property: " + expression.selector.associationInfo.From + " " + expression.selector.associationInfo.FromPropertyName);
}
this.path += '.' + expression.selector.associationInfo.FromPropertyName;
var info = context.infos.filter(function (inf) {
return inf.NavigationPath == this.path;
}, this);
if (info.length > 0) {
return context.sets[info[0].AliasNumber];
}
var memberDefinitions = this.backupContextExpression.instance.getType().memberDefinitions.getMember(expression.storageModel.ItemName);
if (!memberDefinitions) {
_core.Guard.raise("Context schema error");
}
var mi = _core.Container.createMemberInfoExpression(memberDefinitions);
var result = _core.Container.createEntitySetExpression(this.backupContextExpression, mi);
result.instance = this.backupContextExpression.instance[expression.storageModel.ItemName];
var aliasNum = context.sets.push(result);
context.infos.push({
AliasNumber: aliasNum - 1,
Association: expression.selector,
NavigationPath: this.path,
IsMapped: this.isMapped
});
return result;
}
}, context);
var compiler = _core2.default.sqLite.SqlCompiler.create(optimizedExpression, context);
compiler.compile();
var sqlBuilder = _core2.default.sqLite.SqlBuilder.create(this.sets, this.entityContext);
query.modelBinderConfig = {};
var modelBinder = _core2.default.sqLite.sqLite_ModelBinderCompiler.create(query, context);
modelBinder.Visit(optimizedExpression);
var result = {
sqlText: compiler.filters[0].selectedFragment.text,
params: compiler.filters[0].selectedFragment.params,
modelBinderConfig: query.modelBinderConfig
};
return result;
}
}, null);