PluginStore クラスに `get_like` メソッドを追加

PluginStore に get_like メソッドを追加する PR を提出したいと考えています。

get_like は、指定されたプラグインに関連するレコードのうち、キーが特定の単語で始まるものをすべて取得します。

ユースケース
あるプラグインが、りんごとオレンジなど、2 つ以上のエンティティを保存したい場合、プラグイン名を「fruits」として、データを apple_1, apple_2… や orange_1, orange_2 のように保存するとします。

すべての「オレンジ」を取得するには、PluginStore.get_like('fruits', 'orange') のように呼び出すだけで済みます。

チームメンバーやプラグイン開発者の皆さんはどうお考えでしょうか?

個人的には、このパターンを使う必要はなかったと思います。公開されているプラグインで見たことはありますか?それとも、あなたが作成しているものだけでしょうか?

また、入力する文字数はそれほど長くはありません。

PluginStoreRow.where("plugin_name = 'fruits' AND key LIKE 'orange%')

もし頻繁にこの処理を行うのであれば、プラグインにヘルパー関数やクラスを追加することをお勧めします。また、これらのクエリに対して適切なインデックスが設定されていることも確認してください。

custom-wizards プラグインのこの機能の開発に取り組んでおり、すべてのウィザードを取得したかったのです。
使用されるキーは、ウィザードごとに一意の文字列です。このケースは、プラグインのすべての行を取得し、value に対してフィルタリングすることで処理されていました。これはレコード数が少ない場合は問題ありませんが、大規模なプラグインには最適ではありません。plugin_store_rows は、プラグインの「設定のような」データを格納するために設計されているようです。

個人的には、これにより plugin_store_rows テーブルに「設定ではない」データを格納するというアイデアが広がると思います。

(もし奇妙に聞こえるようでしたら、お詫びいたします)

一般的に、PluginStoreRow を希望する方法でクエリできない場合は、マイグレーションを通じて独自のテーブルを作成することをお勧めします。これは現在、複数のプラグインで一般的に行われており、非常にうまく機能しています!

ああ、それは知りませんでした。ありがとうございます。

一般的なパターンは、plugin_store_rows テーブルの key フィールドを使用して、名前空間と一意の識別子の両方を保存することです。つまり、以下の形式です:

<namespace>_<id>

このパターンは、最近のコア Discourse プラグインではあまり見られなくなっています。PluginStore の使用が全体的に減少しているためです。例えば:

  • OAuth2 Basic プラグインは、user_associated_accounts へ移行するまで、関連するアカウントデータの保存にこれを使用していました 参照

  • Poll プラグインも、独自のテーブルへ移行する前にこれを使用していました 参照

ただし、コア Discourse コードベース自体を含むいくつかの場所では、まだ使用されています。例えば Reviewables モデル などです。

私も複数のプラグインでこのパターンを使用しています。

このパターンが使用される主な理由は、plugin_store_rows テーブルが複数のプラグイン(およびいくつかのコアサービス)によって使用されるため、識別列である idplugin_name を、PluginStore を使用する各システム内部での識別に使用できないからです。そのため、代わりに key 列で文字列ベースのシステムが使用されています。

プラグインからデータベース構造を変更することについては、@gdpelican が良い投稿をしています:

個人的には、これを行うことにはまだ非常に慎重です。なぜなら、サードパーティのプラグインを扱う場合、名前空間の制御、プラグインの削除、コア Discourse への潜在的な競合する変更などについて、コントロールがないからです。

@gdpelican が指摘しているように、プラグインをアンインストールする際にユーザーがデータベースの変更を削除できるようにする仕組みを提供する必要があります。

プラグインが不要になったユーザーがデータベースの変更をクリーンアップできる方法を提供してください。私はこれを rake タスクで行いました。

これは、ほとんどのプラグインユーザーにとっては詳細すぎる内容であり、この点に気づいていない場合、リスクとなります。

さらに、私は PluginStore や CustomFields の範囲外に出る真の必要性を感じていません。

以上を踏まえて、個人的には、このパターンが有用であるため、PluginStore にこのような新しいメソッドが追加されることに賛成です。

@david にも、上記についてのご意見をお聞かせいただければ幸いです。

@evitrout が述べているように、現在、複数のプラグインでマイグレーションと専用テーブルを採用しており、大きな成功を収めています。データベース制約を強制できる機能により、パフォーマンス(任意の列でのルックアップ)とデータの整合性(ユニークインデックスによる)の向上が実現されました。これら 2 つの点は、一部のホスト顧客の規模において特に重要であることが証明されています。チームに参加する前は、このようなことをあまり考慮していませんでした。

私が最初に本格的に取り組んだプラグインは chat-integration で、プラグインストアに依存する非常に煩雑な「擬似 ActiveRecord」を実装しました。振り返ってみると、専用テーブルを採用していた方がはるかに良い選択だったでしょう。将来的には、このプラグインを専用テーブル方式に移行する可能性もあります。

コアテーブルを変更する場合については、同意します。既存テーブルへの列の追加や変更は、後々予期せぬ結果を招く可能性があり、プラグインをアンインストールしても残ってしまいます。これについては強く推奨しません。

一方、専用テーブルは比較的リスクが低いです。プラグインをアンインストールしても、それらは単に残るだけで、負の副作用はありません(外部キー制約を導入しない限り)。データを置き去りにすることは、「プラグインストアを使用する」ことよりも悪いわけではありません。

クリーンアップの観点では、プラグインマイグレーションを「逆転」させて整理する rake タスクの提供を検討することもできます。しかし、正直なところ、これはあまり利用されないと思います。私の仮説では、人々はプラグインをアンインストールすることは稀であり、仮にアンインストールする場合でも、再インストールする可能性に備えてデータを残しておきたいと考えているだろうということです。

そのコードの作成者として、少し補足させていただきます。優先度 ID は定数であり、リレーショナルデータではありません。ID が事前にわからない場合、something_id を使用するのは絶対に避けるべきです。この場合、各優先度はシングルトンとして扱われており、私が作成するテーブルは結局 PluginStore のクローンになってしまうだろうと考えたからです。