enum giving error with vapor 4 and fluent - enums

This puzzles me:
I have a model in which I want to use an enum. I first declare the enum:
enum MenuChoices: String, Codable {
case reachableAt
case attentionTo
case reasonVisit
case reasonProblem
}
Then it is in my fields of the class:
#Enum(key: "menu_choices")
var menuChoices: MenuChoices
I then create it in the database using a migration:
struct CreateUserMenu: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
return database.enum("menu_choices")
.case("reachable_at")
.case("attention_to")
.case("reason_visit")
.case("reason_problem")
.create()
.flatMap { menu_choices in
return database.schema("user_menus")
.id()
.field("created_at", .datetime, .required)
.field("updated_at",.datetime, .required)
.field("deleted_at",.datetime)
.field("menu_choices", menu_choices)
.field("be_nl", .string)
.field("be_fr", .string)
.field("en_us", .string)
.create()
}
}
}
So far so good. This migration works and the database looks ok. But when I want to add some data to seed the database in another migration I get an error :
let test = UserMenu( menuChoices: MenuChoices.reachableAt, beNl: "nl", beFr: "fra", enUs: "eng")
let _ = test.save(on: database)
+ App.addUserMenus on default
Would you like to continue?
y/n> y
[ ERROR ] previousError(MySQL error: Server error: Data truncated for column 'menu_choices' at row 1)
Fatal error: Error raised at top level: previousError(MySQL error: Server error: Data truncated for column 'menu_choices' at row 1): file /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1103.8.25.8/swift/stdlib/public/core/ErrorType.swift, line 200
USSS-Voyager-II:24yours data$
Unfortunately this error doesn’t really help to pinpoint the source of the problem

The problem is that there is no mapping between the swift definition of the enum and the Fluent enum. Putting a string literal value for your swift enum definition that matches the string literal value of the Fluent will fix the problem.
enum MenuChoices: String, Codable {
case reachableAt = "reachable_at"
case attentionTo = "attention_to"
case reasonVisit = "reason_visit"
case reasonProblem = "reason_problem"
}

Related

Cannot get property because an index signature declaring the expected key / value type is missing in null or undefined [1]

I am testing PermissionDetail component which has graphql fragment, that is the data of node of PermissionTable component. I am getting a flow type error in this line when getting mock data from query const permissionDetail = data.viewPermissionScheme?.grantGroups[0].grantHolders?.edges[0].node.permission;.
Component hierarchy:
App -> PermissionTable (Paginated component fragment) -> PermissionDetail (fragment)
const TestRenderer = () => {
const data = useLazyLoadQuery<examplesPermissionQuery>(
graphql`
query examplesPermissionQuery #relay_test_operation {
viewPermission(id: "test-scheme-id") {
... on PermissionView {
groups {
holders(first: 10) {
edges {
node {
permission {
...permissionDetailsFragment
}
}
}
}
}
}
}
}
`,
{},
);
// Getting Flowtype Error here: Cannot get `data.viewPermission?.groups[0]` because an index signature declaring the expected key / value type is missing in null or undefined [1]
const permissionDetail =
data.viewPermissionScheme?.grantGroups[0].grantHolders?.edges[0].node.permission;
return permissionDetail ? (<PermissionDetails permissionDetail={permissionDetail}/>) : null;
};
What is the correct way to test such components? I am new to flow and graphql and relay. So need to understand the best way to test this.
I think the error is simply that data.viewPermission?.groups can be null or undefined. Therefore you are not allowed to access an(y) index on this property. One way to fix this is by using data.viewPermission?.groups?[0] to access the property.
You could also make groups non-nullable in your GraphQL schema. Some people like a lot of nullable fields because that allows the server to return as much partial data as possible in the case of an error. But for the developer this means that every field has to be checked for null.

swift 4.2 - how can I check with guard if a var has a valid enum value

I need to check if a var, f.e. passed by a func, is a valid enum value. Not per se passed but just as an example here.
enum CollectionDict : String { // Mapping to String Model = "Model" or should I ...
case Model
case Type
case Element
case ....
}
....
guard InColectionDict != CollectionDict else { return false }
....
Obviously my sample guards line is wrong. What should I use or do to get the guard right or at least just compare/validate the InColectionDict variable with the enum CollectionDict in a one-liner?
I did hope to get away with..
func makeItem ( _ item: String , with key : String , inCollection : CollectionDict ) -> Bool {
guard let res = CollectionDict.inCollection else { return false }
But it give me an error.
Of course thank you in advance.
Swift is strongly typed. If your function has an non-optional Enum parameter, then at run-time it's guaranteed to be a valid enum value.

Migrating Custom Push Row to Eureka 4.1

I'm having quite a hard time migrating a custom row from a previous version of Eureka (around 3.0) to Eureka 4.1. The custom row is a custom push row so the label can have multiple lines and so the view controller that is pushed can have a custom section header. There may be a better way to accomplish that than having a custom row, so that is one possible solution, but I'm not sure if that's a possibility.
So there are 2 problems: The custom row and the the custom selector view controller. Here's the custom row:
open class _StackedPushRow: SelectorRow<StackedPushCell, CustomSelectorViewController<String>> {
public typealias StackedRow = PushRow<String>
var dontClearWhenDisabled: Bool = false
required public init(tag: String?) {
super.init(tag: tag)
cellProvider = CellProvider(nibName: "StackedPushCell")
presentationMode = .show(controllerProvider: ControllerProvider.callback {
return CustomSelectorViewController<Cell.Value> { _ in } },
onDismiss: { vc in
self.cell.update()
_ = vc.navigationController?.popViewController(animated: true)
})
}
}
/// A generic inline row where the user can pick an option from a presented view controller
public final class StackedPushRow: _StackedPushRow, RowType {
required public init(tag: String?) {
super.init(tag: tag)
}
}
and here's the custom selector view controller:
public final class CustomSelectorViewController<T: Equatable>: SelectorViewController<T> {
open override func viewDidLoad() {
super.viewDidLoad()
form.first?.header = HeaderFooterView.caliberStyleSectionHeader(title: row.title ?? "")
}
static func presentationMode<T: Equatable>() -> PresentationMode<SelectorViewController<T>> {
return .show(controllerProvider: ControllerProvider.callback {
return CustomSelectorViewController<T> { _ in }
}, onDismiss: { vc in
_ = vc.navigationController?.popViewController(animated: true)
})
}
}
Here are the errors for the custom row:
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:78:29:
Generic type 'SelectorRow' specialized with too many type parameters
(got 2, but expected 1)
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:85:9:
'super' members cannot be referenced in a root class
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:86:9:
Use of unresolved identifier 'cellProvider'
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:88:9:
Use of unresolved identifier 'presentationMode'
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:98:20:
Type 'StackedPushRow' does not conform to protocol 'BaseRowType'
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:98:20:
Type 'StackedPushRow' does not conform to protocol 'RowType'
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:98:20:
Candidate has non-matching type '(String?, (Self) -> Void)'
(Eureka.RowType)
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:98:20:
Type 'StackedPushRow' does not conform to protocol 'Taggable'
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:98:20:
Type 'StackedPushRow' does not conform to protocol 'TypedRowType'
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:111:9:
Use of unresolved identifier 'validationOptions'
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomRows/StackedPushRow.swift:141:9:
'StackedPushRow' is not a subtype of 'BaseRow'
Here are the errors for the custom selector view controller:
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomSelectorViewController.swift:12:64:
Type 'T' does not conform to protocol 'OptionsProviderRow'
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomSelectorViewController.swift:14:24:
Method does not override any method from its superclass
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomSelectorViewController.swift:15:9:
'super' members cannot be referenced in a root class
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomSelectorViewController.swift:17:9:
Use of unresolved identifier 'form'
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomSelectorViewController.swift:17:80:
Use of unresolved identifier 'row'
/Users/rod/Documents/Development/Caliber/CaliberiOS/H2O/_iOS/H2O/UI/Common/CustomSelectorViewController.swift:22:52:
Argument passed to call that takes no arguments
I've read the issues section on Github and seen examples of others running into this, but every time I try to put the examples in to practice, I run into other problems and I just keep running in circles. I could really use some help.
Thanks.
SelectorRow now only takes a generic Cell type but no view controller. The SelectorViewController is defined by the presentationMode. You should declare your row like:
open class _StackedPushRow: SelectorRow<StackedPushCell>
For your CustomSelectorViewController you need to pass the rowType you are going to use as generic type. That row type must conform to OptionsProviderRow, like ListCheckRow for example.

Issues with Contentful SDK code after migration

See the code below I am having issues with. I have added most of the function even tho I am only getting the error in line 3. Just to give a better understanding of what I am trying to do.
func getTopArticles(_ vc: ArticleListViewController, subCatId: String) {
var articleDict = [String: Article]()
Constants.CLIENT.fetchEntries(["content_type":Constants.CONTENT_TYPE_ARTICLE,
"fields.top10Listing.sys.id":subCatId, "order":Constants.SORT_CREATED_AT_DESCENDING]) { //Getting error here
switch $0 {
case let .success(articleResult):
if articleResult.items.isEmpty {
vc.noTopArticlePresent()
}
else{
for articleEntry in articleResult.items {
let article = Article (entry:articleEntry)
vc.art.append(article)
// store into search cache
Constants.ARTICLE_CACHE.fetch(key: "articles").onSuccess({ (result) in
if let dictValue = result as? [String:Article]
{
articleDict = dictValue
articleDict[article.articleId] = article
}
Constants.ARTICLE_CACHE.set(value: articleDict, key: "articles")
}).onFailure({ (error) in
Constants.ARTICLE_CACHE.set(value: articleDict, key: "articles")
})
}
Constants.CACHE.set(value: NSKeyedArchiver.archivedData(withRootObject: vc.art), key: subCatId)
DispatchQueue.main.async {
vc.dothis()
}
}
}
}
Getting error in line 3. See error below
Argument labels '(__:,_:)' do not match any available overloads
you are missing the argument label matching for the method call.
The function signature is fetchEntries(matching:completion)
Taking your example above, and adding the our call would look like the following:
Constants.CLIENT.fetchEntries(matching:
["content_type": Constants.CONTENT_TYPE_ARTICLE,
"fields.top10Listing.sys.id":subCatId, "order":Constants.SORT_CREATED_AT_DESCENDING]) { (result: Result<ArrayResponse<Entry>>) in // Or anonymous argument $0 as you were using in your example.
Generally, if you see an error telling you argument labels don't match, you can find the declaration in the source and compare to see if you have a mismatch with the naming of your arguments being passed in. See more about argument labels and parameter names in Swift here.

Cast between Oracle Table field and Entity framework fails

Within a WCF web service I make a query on a ORACLE 11g database and I use entity framework as model. The target field is of type Numeric, while in the entity framework is Int64.
When I try to update the field I get the following exception: The specified cast from a materialized 'System.Decimal' type to the 'System.Int64' type is not valid.
The method generating the error is below, in particular for the line within the else statement: result = _context.ExecuteStoreQuery(query).FirstOrDefault();
public string GetDatabaseTimestamp(Type timestampFieldType, string query)
{
object result;
if (timestampFieldType == typeof(string))
{
result = _context.ExecuteStoreQuery<string>(query).FirstOrDefault();
}
else
{
result = _context.ExecuteStoreQuery<long>(query).FirstOrDefault();
}
return result.ToString();
}
Would it be possible to define at the EF level a converter or something similar? The option of changing the Database is not feasible, therefore I have to edit code.
In The EF I already changed the type into decimal. Problem is that the query was executed directly on the Oracle database and this was generating the exception.
I solved the issue by using attributes for the target entity and changed the method into:
public string GetDatabaseTimestamp(Type timestampFieldType, string query)
{
object result;
if (timestampFieldType == typeof(string))
{
result = _context.ExecuteStoreQuery<string>(query).FirstOrDefault();
}
else if (timestampFieldType == typeof(decimal))
{
result = _context.ExecuteStoreQuery<decimal>(query).FirstOrDefault();
}
else
{
result = _context.ExecuteStoreQuery<long>(query).FirstOrDefault();
}
return result.ToString();
}
In this way the passed timestampFieldType is of type decimal and the proper cast is selected. This issue is due to different data types used for similar fields (as example Update fields) in the Oracle DB (legacy database).

Resources