Swift Vapor - configure.swift 中的“无法使用类型的参数列表调用“添加”...”错误

Posted

技术标签:

【中文标题】Swift Vapor - configure.swift 中的“无法使用类型的参数列表调用“添加”...”错误【英文标题】:Swift Vapor - 'Cannot invoke 'add' with an argument list of type...' errors in configure.swift 【发布时间】:2019-12-20 06:04:26 【问题描述】:

我正在 YouTube 上学习 Paul Hudson 的电子商务教程。我在configure.swift 中遇到以下错误:

import FluentSQLite
import Vapor
import Leaf // added
/// Called before your application initializes.
public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws 
    // Register providers first
    try services.register(FluentSQLiteProvider())

    // Register routes to the router
    let router = EngineRouter.default()
    try routes(router)
    services.register(router, as: Router.self)

    // Register middleware
    var middlewares = MiddlewareConfig() // Create _empty_ middleware config
    // middlewares.use(FileMiddleware.self) // Serves files from `Public/` directory
    middlewares.use(ErrorMiddleware.self) // Catches errors and converts to HTTP response
    services.register(middlewares)

    // Configure a SQLite database
    let sqlite = try SQLiteDatabase(storage: .memory)
    // Register the configured SQLite database to the database config.
    var databases = DatabasesConfig()
    databases.add(database: sqlite, as: .sqlite)
    services.register(databases)

    // Configure migrations
    var migrations = MigrationConfig()
    migrations.add(model: Todo.self, database: .sqlite)
    services.register(migrations)
    let leafProvider = LeafProvider()    // added
    try services.register(leafProvider)  // added
    config.prefer(LeafRenderer.self, for: ViewRenderer.self)// added
      // http://localhost:8080/ already in use so adding new server http://localhost:8080/ below -
    let serverConfigure = NioserverConfig.default(hostname: "0.0.0.0", port: 9090)
    services.register(serverConfigure)

    let directoryConfig = DirectoryConfig.detect()
    services.register(directoryConfig)
    try services.register(FluentSQLiteProvider())
    var databaseConfig = DatabasesConfig()
    let db =    try SQLiteDatabase(storage: .file(path:   "\(directoryConfig.workDir)pizza.db"))
     databaseConfig.add(model: db, database: as .sqlite)
    /**
    The line just above shows errors - 
    errror 1 -> Cannot invoke 'add' with an argument list of type '(model:      
    SQLiteDatabase)'
    error 2 -> Expected expression in list of expressions 
    */       
    services.register(databaseConfig)
    var migrationConfig =  MigrationConfig()
    migrationConfig.add(model: pizza.self,  database: sqlite)
    /**
    The line just above shows error -> Cannot invoke 'add' with an argument list of type     '(model: pizza.Type, database: SQLiteDatabase)'
    */
    services.register(migrationConfig)
 
// configure.swift ends here

我还粘贴了我的 Package.swift 代码以供参考 -

 // swift-tools-version:4.0

import PackageDescription

let package = Package(
name: "vv",
products: [
    .library(name: "vv", targets: ["App"]),
],
dependencies: [
    // ???? A server-side Swift web framework.
    .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),

    // ???? Swift ORM (queries, models, relations, etc) built on SQLite 3.
    .package(url: "https://github.com/vapor/fluent-sqlite.git", from: "3.0.0"),
.package(url: "https://github.com/vapor/leaf.git", from: "3.0.0"),
],
targets: [
    .target(name: "App", dependencies: ["Leaf", "Vapor","FluentSQLite"]),
 .target(name: "Run", dependencies: ["App"]),
    .testTarget(name: "AppTests", dependencies: ["App"])
]
)

pizza.swift 文件 -

 import Foundation
 import Vapor
 import FluentSQLite

 struct pizza: Encodable, Content, Decodable, SQLiteModel 
     var id:  Int?
     var name: String
     var description: String
     var  price: Int
 

我无法弄清楚上述错误是什么意思!谢谢。

routes.swift 文件 -

import Routing
import Vapor
import FluentSQLite

public func routes(_ router: Router) throws 
router.get  req -> Future <View> in
let Newyorker = Pizza(id: 5, name: "statinisland", description: "impracticaljokers", price: 55)
    let Traditional = Pizza(id: 5, name: "rome", description: "pope", price: 55)
    return try req.view().render("welcome",["pizza":[Newyorker,Traditional]])


 router.post(Pizza.self, at: "add")  req, pizza ->
     Future<Response> in
    return Pizza.save(on:req).map(to:Response.self) Pizza
        in
        return req.redirect(to: "/")
    
   
/*Error - Type 'Pizza' has no member 'save'; did you mean 'name'?
 Replace 'save' with 'name' */  
 

【问题讨论】:

【参考方案1】:

这是对我原来的答案的重写,以解决所有问题:

configure.swift

    不要定义MigrationConfig()DatabaseConfig() 的多个实例。 将相关任务(例如添加模型)组合在一起将使您的代码更易于调试和维护。 您已添加两个 .sqlite 数据库实例。 在添加 pizza 模型时,您在 .sqlite 中省略了 .

因此,您的 configure.swift 的相关部分变为:

let directoryConfig = DirectoryConfig.detect()
services.register(directoryConfig)
let sqlite = try SQLiteDatabase(storage: .file(path:   "\(directoryConfig.workDir)pizza.db"))
// Register the configured SQLite database to the database config.
var databases = DatabasesConfig()
databases.add(database: sqlite, as: .sqlite)
services.register(databases)

var migrations = MigrationConfig()
migrations.add(model: Todo.self, database: .sqlite)
migrations.add(model: Pizza.self,  database: .sqlite)
services.register(migrations)

pizza.swift:

    我更喜欢使用 final class 而不是 struct,因为它为您提供了更大的灵活性(例如在您的初始化程序中)。 您需要使其符合Migration

因此,最小的Pizza 模型变为:

final class Pizza:SQLiteModel 
    var id:  Int?
    var name: String
    var description: String
    var  price: Int

    init(id: Int? = nil, name: String, desc:String, price:Int)
    
        self.id = id
        self.description = desc
        self.name = name
        self.price = price
    
 

extension Pizza: Migration  

为了完整起见,您的 configure.swift 变为:

import FluentSQLite
import Vapor
import Leaf // added
public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws 
    // Register providers first
    try services.register(FluentSQLiteProvider())

    // Register routes to the router
    let router = EngineRouter.default()
    try routes(router)
    services.register(router, as: Router.self)

    // Register middleware
    var middlewares = MiddlewareConfig() // Create _empty_ middleware config
    // middlewares.use(FileMiddleware.self) // Serves files from `Public/` directory
    middlewares.use(ErrorMiddleware.self) // Catches errors and converts to HTTP response
    services.register(middlewares)

    let directoryConfig = DirectoryConfig.detect()
    services.register(directoryConfig)
    let sqlite = try SQLiteDatabase(storage: .file(path:"\(directoryConfig.workDir)pizza.db"))
    var databases = DatabasesConfig()
    databases.add(database: sqlite, as: .sqlite)
    services.register(databases)

    var migrations = MigrationConfig()
    migrations.add(model: Todo.self, database: .sqlite)
    migrations.add(model: Pizza.self, database: .sqlite)
    services.register(migrations)

    let leafProvider = LeafProvider()    // added
    try services.register(leafProvider)  // added
    config.prefer(LeafRenderer.self, for: ViewRenderer.self)// added
    let serverConfigure = NIOServerConfig.default(hostname: "0.0.0.0", port: 9090)
    services.register(serverConfigure)

【讨论】:

我按照你的指示做了。前两个错误。没有消失,最后一个错误更改为“表达式类型'()'是不明确的,没有更多的上下文” "编辑 - 刚刚注意到您添加了两个数据库,两个数据库都具有标识符 .sqlite,一个在内存中,另一个在文件中。这不起作用。" - “文件中的另一个” - 我猜它的 configure.swift 文件,“内存中的一个”是什么意思? 还添加了“迁移”,我不小心忘记了,也把它变成了最后一课。所以它现在是“最后一类披萨:Encodable、Content、Decodable、SQLiteModel、Migration ”。现在最后一个错误消失了。前 2 个错误仍然存​​在。 原谅我,但是如何纠正呢? 我在一小时前发布了整个 configure.swift。

以上是关于Swift Vapor - configure.swift 中的“无法使用类型的参数列表调用“添加”...”错误的主要内容,如果未能解决你的问题,请参考以下文章

Vapor 不适用于 xcode 9 和 swift 4

在纯 Swift (Vapor) 项目中拥有 HMAC SHA256

Swift 3 如何使用 Vapor 发送多部分发布请求

无法使用 Vapor 将 swift 包推送到 Heroku

为啥从 Psql 通过 Swift (Vapor) 到通过 Ajax 的 JQuery 的日期落后了 31 年?

国内首个完整的 Swift 服务端开源项目及详解 - 基于 Vapor 3 框架