Permalink
Browse files

Changed my mind - ActiveRecord is based on some smooth Ruby. Lets use…

… C sharp for what its good at. Changed to use named arguments and updated README
  • Loading branch information...
1 parent bb4497e commit 4ae06a0a2174d5c86667db0332498e15bdb993f5 @subsonic subsonic committed Jun 17, 2011
Showing with 78 additions and 15 deletions.
  1. +59 −12 Massive.cs
  2. +19 −3 README.markdown
View
@@ -393,24 +393,71 @@ public class DynamicModel : DynamicObject {
return Query(sql, key).FirstOrDefault();
}
/// <summary>
- /// A little Rails-y love for ya
+ /// A helpful query tool
/// </summary>
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
//parse the method
- var stems = binder.Name.Split('_');
- var sb = new List<string>();
-
- //first should be "FindBy or whatever"
- var op = stems[0];
+ var constraints = new List<string>();
var counter = 0;
- for (int i = 1; i < stems.Length; i++) {
- if (stems[i].Trim().ToLower() != "and") {
- sb.Add(stems[i] + "=@" + counter);
- counter++;
+ var info = binder.CallInfo;
+ // accepting named args only... SKEET!
+ if(info.ArgumentNames.Count != args.Length){
+ throw new InvalidOperationException("Please use named arguments for this type of query - the column name, orderby, columns, etc");
+ }
+
+
+ //first should be "FindBy, Last, Single, First"
+ var op = binder.Name;
+ var columns = " * ";
+ string orderBy = string.Format(" ORDER BY {0}", PrimaryKeyField);
+ string where = "";
+ var whereArgs = new List<object>();
+
+ //loop the named args - see if we have order, columns and constraints
+ if (info.ArgumentNames.Count > 0) {
+
+ for (int i = 0; i < args.Length; i++) {
+ var name = info.ArgumentNames[i].ToLower();
+ switch (name) {
+ case "orderby":
+ orderBy = " ORDER BY " + args[i];
+ break;
+ case "columns":
+ columns = args[i].ToString();
+ break;
+ default:
+ constraints.Add(string.Format(" {0} = @{1}",name,counter));
+ whereArgs.Add(args[i]);
+ counter++;
+ break;
+ }
}
}
- var sql = "SELECT * FROM " + TableName + " WHERE " + string.Join(" AND ", sb.ToArray());
- result = Query(sql, args);
+ //Build the WHERE bits
+ if (constraints.Count > 0) {
+ where = " WHERE " + string.Join(" AND ", constraints.ToArray());
+ }
+ //build the SQL
+ string sql = "SELECT TOP 1 "+columns+" FROM " + TableName + where;
+ var justOne = true;
+
+ //Be sure to sort by DESC on the PK (PK Sort is the default)
+ if (op.StartsWith("Last")) {
+ orderBy = orderBy + " DESC ";
+ } else {
+ //default to multiple
+ sql = "SELECT "+columns+" FROM " + TableName + where;
+ justOne = false;
+ }
+
+ if (justOne) {
+ //return a single record
+ result = Query(sql + orderBy, whereArgs.ToArray()).FirstOrDefault();
+ } else {
+ //return lots
+ result = Query(sql + orderBy, whereArgs.ToArray());
+ }
+
return true;
}
}
View
@@ -104,18 +104,34 @@ Yippee Skippy! Now we get to the fun part - and one of the reasons I had to spen
//Let's update these in bulk, in a transaction shall we?
table.Save(drinks);
-ActiveRecord Syntax
+Named Argument Query Syntax
-------------------
-I recently added the ability to run ActiveRecord style, Rails-y queries using Massive. It relies on TryInvokeMember() and makes your queries very readable:
+I recently added the ability to run more friendly queries using Named Arguments and C#4's Method-on-the-fly syntax. Originally this was trying to be like ActiveRecord, but I figured "C# is NOT Ruby, and Named Arguments can be a lot more clear". In addition, Mark Rendle's Simple.Data is already doing this so ... why duplicate things?
+
+If your needs are more complicated - I would suggest just passing in your own SQL with Query().
//important - must be dynamic
dynamic table = new Products();
- var drinks = table.FindBy_CategoryID(8);
+ var drinks = table.FindBy(CategoryID:8);
//what we get back here is an IEnumerable < ExpandoObject > - we can go to town
foreach(var item in drinks){
Console.WriteLine(item.ProductName);
}
+ //returns the first item in the DB for category 8
+ var first = table.First(CategoryID:8);
+
+ //you dig it - the last as sorted by PK
+ var last = table.Last(CategoryID:8);
+
+ //you can order by whatever you like
+ var firstButReallyLast = table.First(CategoryID:8,OrderBy:"PK DESC");
+
+ //only want one column?
+ var price = table.First(CategoryID:8,Columns:"UnitPrice").UnitPrice;
+
+ //Multiple Criteria?
+ var items = table.Find(CategoryID:5, UnitPrice:100, OrderBy:"UnitPrice DESC");
Asynchronous Execution
----------------------

0 comments on commit 4ae06a0

Please sign in to comment.