             return false
         case .not(let aqt):
             return !self.matches(query: Query(aqt: aqt))
+        case .contains(let key, let val):
+            switch doc[key] {
+            case .string(let stringVal):
+                if let d = val.val.stringValue {
+                    return stringVal.contains(d)
+                } else {
+                    return false
+                }
+            default:
+                return false
+            }
+        case .startsWith(let key, let val):
+            switch doc[key] {
+            case .string(let stringVal):
+                if let d = val.val.stringValue {
+                    return stringVal.hasPrefix(d)
+                } else {
+                    return false
+                }
+            default:
+                return false
+            }
+        case .endsWith(let key, let val):
+            switch doc[key] {
+            case .string(let stringVal):
+                if let d = val.val.stringValue {
+                    return stringVal.hasSuffix(d)
+                } else {
+                    return false
+                }
+            default:
+                return false
+            }
         case .nothing:
             return true
         }

    
    /// Whether nothing needs to be matched. Is always true and just a placeholder
    case nothing
}

/// The protocol all queries need to comply to

            return ["$or": .array(Document(array: expressions)) ]
        case .not(let aqt):
            return ["$not": ~aqt.document]
        case .contains(let key, let val):
            return [key: .string("/\(val.val)/")]
        case .startsWith(let key, let val):
            return [key: .string("/^\(val.val)/")]
        case .endsWith(let key, let val):
            return [key: .string("/\(val.val)$/")]
        case .nothing:
            return []
        }
