It's possible to use date functions like "strftime"? - sqlite.swift

I tried to create a expression like this
let performedDate = Expression<String>("strftime('%Y-%m-%d', performedDate)")
and then compare with another string using filter method.
But the generated SQL is
"strftime('%Y-%m-%d', performedDate)" = '2017-08-17'.
There is a way to remove quotation marks from "strftime('%Y-%m-%d', performedDate)" or I have to use raw SQL string?

I solved my problem by creating a extension on Expression type like this
extension Expression {
public func strftime(format: String) -> Expression {
return Expression("strftime('\(format)', \(template))", bindings)
}
}
and then use
let date = Expression<String>("startDate")
let dateFormat = date.strftime(format: "%Y-%m-%d")
You can use dateFormat as projection or in filter method as well.

Related

CKQuery with NSPredicate fails when using "CONTAINS" operator

According to Apples Class Reference CKQuery, the operator CONTAINS is one of the supported operators. However, that doesn't seem to work. I have a RecordType called myRecord, and a record with field name name type String. I try to fetch the record with two different predicates, one with "==" operator, and one with CONTAINS operator.
func getRecords() {
let name = "John"
let Predicate1 = NSPredicate(format: "name == %#",name)
let Predicate2 = NSPredicate(format: "name CONTAINS %#",name)
let sort = NSSortDescriptor(key: "Date", ascending: false)
let query = CKQuery(recordType: "myRecord", predicate: Predicate1)
// let query = CKQuery(recordType: "myRecord", predicate: Predicate2)
query.sortDescriptors = [sort]
let operation = CKQueryOperation(query: query)
operation.desiredKeys = ["name", "Date"]
operation.recordFetchedBlock = { (record) in
print(record["name"])
operation.queryCompletionBlock = { [unowned self] (cursor, error) in
dispatch_async(dispatch_get_main_queue()) {
if error == nil {
print ("sucess")
} else {
print("couldn't fetch record error:\(error?.localizedDescription)")
}
}
}
CKContainer.defaultContainer().publicCloudDatabase.addOperation(operation)
}
Using Predicate1, output is:
Optional(John)
sucess
Using Predicate2, output is:
couldn't fetch record error:Optional("Field \'name\' has a value type of STRING and cannot be queried using filter type LIST_CONTAINS")
Also using [c] to ignore casings gives a server issue.
How do I use the operator CONTAINS correctly?
EDIT:
I have now looked closer at the documentation, and seen that CONTAINS can only be used with SELF. Meaning that all String fields will be used for searching. Isn't there a better way?
It's an exception mentioned as below:
With one exception, the CONTAINS operator can be used only to test
list membership. The exception is when you use it to perform full-text
searches in conjunction with the self key path. The self key path
causes the server to look in searchable string-based fields for the
specified token string. For example, a predicate string of #"self
contains 'blue'" searches for the word “blue” in all fields marked for
inclusion in full-text searches. You cannot use the self key path to
search in fields whose type is not a string.
So, you can use 'self' instead of '%K' in order to search sub-text of string field.
For the full document written by Apple

Create a CSV of class members from a list<T>

I have a List of a Simple Struct that contains int's and strings.
Struct:
public struct ErrorType
{
public int RowNumber;
public int ColumnNumber;
public string ErrorMessage;
}
On of My methods return A list of these structs.
I want to convert each member in the list to its string form and separate it by a comma so that List is now an Array of strings. I could write a function to do this manually but I'd perfer to use linq to have a cleaner solution.
Having the array of strings I'll write it to a file using
string path = #"c:\temp\MyTest.txt";
// This text is added only once to the file.
if (!File.Exists(path))
{
// Create a file to write to.
List<ErrorType> ErrorTypesList = GetErrors();
//do some work to iterate over the members and do a string.join after
string[] ErrorListArray = ErrorTypesList.foreach( e => { });
File.WriteAllLines(path, createText);
}
does anyone have suggestions on how to fill in the foreach so that it returns each members in its ToString form followed by a comma?
The only way you'd be able to use LINQ for property iteration is if you're using reflection, and you shouldn't do that unless you absolutely have to (which it really doesn't look like you do).
The best you can do, though, still isn't too bad.
var rows = ErrorTypesList
.Select(c => "\"" + string.Join("\",\"", c.RowNumber, c.ColumnNumber, c.ErrorMessage) + "\"");
File.WriteAllLines(path, rows);
I took the liberty of putting fields in quotes as well, you may or may not want that, but it's easy to fix that code to do what you do want. You might also want to add in some escape logic, pending what sorts of contents c.ErrorMessage might have.
You could also use string.Format if you're more comfortable with that, but it doesn't really make a difference here.
var rows = ErrorTypesList
.Select(c => string.Format("\"{0}\", \"{1}\", \"{2}\"", c.RowNumber, c.ColumnNumber, c.ErrorMessage));
It seems you want something like this:
string[] ErrorListArray = ErrorTypesList
.Select(e => string.Join(",", e.RowNumber, e.ColumnNumber, e.ErrorMessage))
.ToArray();

searching by special character on linq

I need a searching process on linq like this. For example, I will make searching on Name column,and user enters "Ca?an" word to textbox. Question mark will e used for sprecial search character for this sitution.
It will search by Name column and, find Canan,Calan,Cazan etc.
I hope I can explain my problem correctly.
Can anyone give me an idea about this linq query. Thank in advance...
You can use this regular expression (if you are using C#) to check for the "Ca?an".
string d = "DDDDDDDDDDCasanDDDDDDDDDD";
Regex r = new Regex(#"Ca([a-zA-Z]{1})an");
string t = r.Match(d).Value;
Output will be:
"Casan"
You have all your colum stored in a database, then do something like:
List<Person> list = new List<Person>(); //Filled
var res = list.Select(x => r.Match(x.Name));
Output will be a IEnumerable with all the "Persons" who contains in the Name "Ca?an", being ? no matter which letter
You need to convert your search-syntax into an existing search-engine - I'd suggest Regex. So the steps will be:
Safely convert the entered search-string into Regex-pattern
Perform the search in Linq on name-property
Solution:
1: Safely convert search string by replacing '?' with Regex-version of wildchar:
var userInput = "Ca?an";
var regexPattern = Regex.Escape(userInput).Replace(#"\?", ".");
2: Perform search in Linq (assuming itemList implements IEnumerable):
var results = itemList.Where(item => Regex.IsMatch(item.Name, regexPattern));
Hope this helps!

How to extend this LINQ List<>.Contains to work with any Property using Reflection?

I have the following snippet that I currently use to run a .Contains() with a list of Ids passed as a comma separated list from users. This code works perfectly and the data is filtered exactly as I want it to be:
// Handle id in() statements explicitly, dynamic expression can't parse them
var idIn = new Regex("id in ?(.*)", RegexOptions.IgnoreCase);
if (idIn.IsMatch(predicate))
{
Match list = new Regex(#"in ?\((.*)\)", RegexOptions.IgnoreCase).Match(predicate);
string ins = list.Groups[1].ToString();
// Split ins and store as List<>
List<int> splitValues = ins.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i)).ToList();
return source.Where(u => splitValues.Contains(u.Id));
}
I want to be able to use this same idea, except with ANY property of the u object using reflection. I had a version of this working at some point, but cannot for the life of me figure out what has changed or why it stopped working. Here is the version I have that I cannot get working again:
Match splitIn = new Regex(#"([a-zA-Z0-9\.]*) IN ?\((.*)\)", RegexOptions.IgnoreCase).Match(predicate);
string property = splitIn.Groups[1].ToString();
string ins = splitIn.Groups[2].ToString().Trim(new[] {'\'', '"'}); // Trim off separator quotes
List<string> splitValues = ins.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList();
for (int i = 0; i < splitValues.Count; i++)
{
splitValues[i] = splitValues[i].Trim(new[] {'\'', '"'});
}
Expression<Func<U, bool>> contains = u => ListContainsProperty(u, splitValues, property);
return source.Where(contains);
private static bool ListContainsProperty<U>(U u, ICollection<string> list, string property)
{
string[] split = property.Split(new[] {"."}, StringSplitOptions.RemoveEmptyEntries);
object value = split.Aggregate<string, object>(u, (current, prop) => current.GetType().GetProperty(prop).GetValue(current, null));
return list.Contains(value.ToString());
}
As I said I once had SOME version of this working, but cannot figure out what has changed. Is there something blatantly obvious that I am missing that would help me get this functional again?
Edit: As far as I can tell the ListContainsProperty method is never actually running. Adding a "throw new Exception()" does nothing. I just get the full unfiltered list back.
I think the underlying problem is using "Expression"
you need to compile an Expression.
For example in your code
Expression<Func<U, bool>> contains = u => ListContainsProperty(u, splitValues, property);
is data and not a function. In order to use it you need to compile it.
Func<U, bool> compiled = contains.Compile();
"compiled" variable will call the "ListContainsProperty" method.

Use enum in LinQ

need help
I have this enum which sets the PayClassNo to Direct and Indirect. I want to use this enum in my LinQ query.
Here's my scratch LinQ query:
var jDef = from jd in context.GetTable<RJVDefinition>()
select new PayrollJVDefinition
{
JVdefNo = jd.JVDefNo,
AccntCode = jd.AccntCode,
AccntDesc = jd.AccntDesc,
PayClass = enum.GetValue(jd.PayClassNo),
IsFixed = jd.IsFixed,
IsEmployee = jd.IsFixed,
IsAR = jd.IsAR,
CreatedByNo = jd.CreatedByNo,
CreatedDate = jd.CreatedDate,
ModifiedByNo = jd.ModifiedByNo,
ModifiedDate = jd.ModifiedDate
};
Need help because I'm not sure if this will work.
You could certainly do the translation in code, similar to your example (using Enum.Parse), but you don't need to. You can use the designer to set the object property type to an enumerated value. See this article for details.
You just need to parse the Enum just use something like
Enum.Parse(jb.PayClassNo, YourEnumType)

Resources