@@ -200,19 +200,7 @@ private static boolean saveSinglePage(Connection conn, GroupData g, String pageI
200200
201201
202202 // ---------- tag_table ----------
203- String tagSql = "REPLACE INTO tag_table (group_uuid, plugin_name, page_id, user_tag) VALUES (?, ?, ?, ?)" ;
204- try (PreparedStatement ps = conn .prepareStatement (tagSql )) {
205- if (inv .userTags != null && !inv .userTags .isEmpty ()) {
206- for (String tag : inv .userTags ) {
207- ps .setString (1 , g .groupUUID .toString ());
208- ps .setString (2 , g .ownerPlugin );
209- ps .setString (3 , pageId );
210- ps .setString (4 , tag );
211- ps .addBatch ();
212- }
213- ps .executeBatch ();
214- }
215- }
203+ syncTagsForPage (conn , g , pageId , inv );
216204
217205 return true ;
218206 }
@@ -376,29 +364,103 @@ public static boolean saveInventoryOnly(GroupData g, StorageData storageData, St
376364 return false ;
377365 }
378366 }
379- /*
380- private static void saveTags(Connection conn, GroupData g) throws SQLException {
381- String sql = "REPLACE INTO tag_table (group_uuid, plugin_name, page_id, user_tag) VALUES (?, ?, ?, ?)";
382- try (PreparedStatement ps = conn.prepareStatement(sql)) {
383- for (Map.Entry<String, InventoryData> entry : g.storageData.storageInventory.entrySet()) {
384- String pageId = entry.getKey();
385- List<String> tags = entry.getValue().userTags;
386-
387- if (tags != null && !tags.isEmpty()) {
388- for (String tag : tags) {
389- ps.setString(1, g.groupUUID.toString());
390- ps.setString(2, g.ownerPlugin);
391- ps.setString(3, pageId);
392- ps.setString(4, tag);
393- ps.addBatch();
394- }
395- }
367+
368+ /** タグの差分同期(tag_tableを現在の集合に合わせてDELETE/INSERT)+ diff_log_tags 追記 */
369+ private static void syncTagsForPage (Connection conn , GroupData g , String pageId , InventoryData inv ) throws SQLException {
370+ // 1) 入力クレンジング&重複排除(順序保持)
371+ java .util .Set <String > newTags = (inv .userTags == null ) ? java .util .Collections .emptySet ()
372+ : inv .userTags .stream ()
373+ .filter (Objects ::nonNull )
374+ .map (String ::trim )
375+ .filter (s -> !s .isEmpty ())
376+ .collect (java .util .stream .Collectors .toCollection (java .util .LinkedHashSet ::new ));
377+
378+ // 2) 既存タグを取得(現在の実データ)
379+ java .util .Set <String > existing = new java .util .LinkedHashSet <>();
380+ final String sel = "SELECT user_tag FROM tag_table WHERE group_uuid = ? AND plugin_name = ? AND page_id = ?" ;
381+ try (PreparedStatement ps = conn .prepareStatement (sel )) {
382+ ps .setString (1 , g .groupUUID .toString ());
383+ ps .setString (2 , g .ownerPlugin );
384+ ps .setString (3 , pageId );
385+ try (ResultSet rs = ps .executeQuery ()) {
386+ while (rs .next ()) existing .add (rs .getString (1 ));
387+ }
388+ }
389+
390+ // 3) 差分計算
391+ java .util .Set <String > toInsert = newTags .stream ().filter (t -> !existing .contains (t ))
392+ .collect (java .util .stream .Collectors .toCollection (java .util .LinkedHashSet ::new ));
393+ java .util .Set <String > toDelete = existing .stream ().filter (t -> !newTags .contains (t ))
394+ .collect (java .util .stream .Collectors .toCollection (java .util .LinkedHashSet ::new ));
395+
396+ // 4) 削除
397+ if (!toDelete .isEmpty ()) {
398+ String del = "DELETE FROM tag_table WHERE group_uuid = ? AND plugin_name = ? AND page_id = ? AND user_tag = ?" ;
399+ try (PreparedStatement ps = conn .prepareStatement (del )) {
400+ for (String t : toDelete ) {
401+ ps .setString (1 , g .groupUUID .toString ());
402+ ps .setString (2 , g .ownerPlugin );
403+ ps .setString (3 , pageId );
404+ ps .setString (4 , t );
405+ ps .addBatch ();
396406 }
397407 ps .executeBatch ();
398408 }
399409 }
400- */
401410
411+ // 5) 追加
412+ if (!toInsert .isEmpty ()) {
413+ String ins = "INSERT INTO tag_table (group_uuid, plugin_name, page_id, user_tag) VALUES (?, ?, ?, ?)" ;
414+ try (PreparedStatement ps = conn .prepareStatement (ins )) {
415+ for (String t : toInsert ) {
416+ ps .setString (1 , g .groupUUID .toString ());
417+ ps .setString (2 , g .ownerPlugin );
418+ ps .setString (3 , pageId );
419+ ps .setString (4 , t );
420+ ps .addBatch ();
421+ }
422+ ps .executeBatch ();
423+ }
424+ }
425+
426+ // 6) メモリ上の inv.userTags も正規化済み集合に合わせて整える
427+ inv .userTags .clear ();
428+ inv .userTags .addAll (newTags );
429+
430+ // 7) diff_log_tags に ADD/REMOVE を記録
431+ UnifiedLogManager .logTagDiffsForPage (conn , g , inv , pageId );
432+ }
433+
434+ /** タグだけ全ページ分を保存(差分同期+diff追記) */
435+ public static boolean saveTagsOnly (GroupData g ) {
436+ if (g == null || g .storageData == null ) return true ;
437+ try (Connection conn = db .getConnection ()) {
438+ for (Map .Entry <String , InventoryData > e : g .storageData .storageInventory .entrySet ()) {
439+ String pageId = e .getKey ();
440+ InventoryData inv = e .getValue ();
441+ if (inv == null ) continue ;
442+ syncTagsForPage (conn , g , pageId , inv );
443+ }
444+ return true ;
445+ } catch (SQLException ex ) {
446+ Bukkit .getLogger ().warning ("[BetterStorage] タグ保存に失敗: " + ex .getMessage ());
447+ return false ;
448+ }
449+ }
450+
451+ /** タグだけ特定ページ分を保存(差分同期+diff追記) */
452+ public static boolean saveTagsOnly (GroupData g , String pageId ) {
453+ if (g == null || g .storageData == null ) return true ;
454+ InventoryData inv = g .storageData .storageInventory .get (pageId );
455+ if (inv == null ) return true ;
456+ try (Connection conn = db .getConnection ()) {
457+ syncTagsForPage (conn , g , pageId , inv );
458+ return true ;
459+ } catch (SQLException ex ) {
460+ Bukkit .getLogger ().warning ("[BetterStorage] タグ保存に失敗(pageId=" + pageId + "): " + ex .getMessage ());
461+ return false ;
462+ }
463+ }
402464
403465 // ===========================================================
404466 // ===== 2. LOAD ============================================
0 commit comments