sequel 中不同型号的相同 dataset-/filter-logic(干)

Same dataset-/filter-logic on different models in sequel (DRY)

我正在构建一个带有 sequel 数据库后端的 sinatra 网络应用程序。这个应用程序的主要任务是收集来自不同机器人的状态消息,将它们存储在数据库中并提供各种查看它们的方法。这些消息的一个共同点是,它们在 lat/lon 中提供 WGS84 位置。

现在我想提供各种过滤器来根据消息的位置查询消息,但我只想编写这些过滤器一次,只测试一次但在所有模型中重复使用它们-classes lat/lon 个条目。

将其归结为一个非常简单的示例:

Sequel.migration do
  up do
    create_table(:auvmessages) do
        primary_key :id
        Float       :lat
        Float       :lon
        String      :message
    end

    create_table(:asvmessages) do
        primary_key :id
        Float       :lat
        Float       :lon
        Integer     :chargestate
    end
  end
end

class Auvessage < Sequel::Model
  dataset_module do
    def north_of(lat)
        self.where{ latitude > lat}
    end
  end
end

class Asvessage < Sequel::Model
  dataset_module do
    def north_of(lat)
        self.where{ latitude > lat}
    end
  end
end

在两个模型中,classes 都具有 north_of(lat) 来过滤来自给定纬度以北的消息。这个函数比较简单,重复两三遍就可以了,但是复杂一点的情况呢?

我在 dataset_module 之外尝试了一些模块,但似乎没有什么是对的。

有没有更好的方法可以在不同的模型上重复使用过滤器?我搜索了很多,但没有找到满意的答案。

编辑:

为了让我的问题更精确一点:我想将所有功能如 north_of(lat)(还有 lot)移动到服务 class.我现在想知道的是将该服务 class 集成到 sequel 模型中的最佳方式:

这是 Bob 叔叔 Screaming Architecture 博客 post 的 link,可能会有帮助。

现在,回答您的问题,似乎 north_of 以及许多其他方法实际上是您的域逻辑的一部分。此逻辑不应进入持久性抽象、控制器或视图等。

为一组对象设计、构建和编写测试,以使用您问题领域的语言解决您的问题。然后,您将拥有一组丰富的功能,您可以简单地在 Models、Controllers、CLI 等

上使用

我通常将我的服务对象放在 lib/ 目录中并编写简单的单元测试,没有任何设置测试数据库的持久性样板。他们通常 运行 也非常快。

您可以将现有模块传递给 dataset_module:

module NorthOf
  def north_of(lat)
    where{latitude > lat}
  end
end
Auvessage.dataset_module NorthOf
Asvessage.dataset_module NorthOf

作为后续行动:我采用了@jeremy-evans 并通过模块的参数化方案对其进行了扩展。所以从现在开始,我可以通过模拟来测试我的过滤器,我的模型 类 在它们的 dataset_module.

中只有一个包含列表

我喜欢

作为解释,我稍微修改了示例:

Sequel.migration do
  up do
    create_table(:auvmessages) do
        primary_key :id
        Float       :lat
        Float       :lon
        String      :message
    end

    create_table(:asvmessages) do
        primary_key :id
        Float       :gps_lat
        Float       :gps_lon
        Integer     :chargestate
    end
  end
end

module GPSFilter
    def self.create(lat_name, lon_name)
        Module.new do
            include GPS

            define_method :lat_col_name do
                lat_name
            end

            define_method :lon_col_name do
                lon_name
            end
       end
    end

    def north_of(lat)
        where( "#{lat_col_name} > #{lat}" )
    end

    ##### default parameters #####
    def lon_col_name
        "lon"
    end

    def lat_col_name
        "lat"
    end
end

class Auvmessage < Sequel::Model
  dataset_module do
     include GPSFilter
  end
end

class Asvmessage < Sequel::Model
  dataset_module do
     include GPSFilter.create :gps_lat, :gps_lon
  end
end