1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef OHOS_MEDIA_PHOTO_ALBUM_DAO_H
16 #define OHOS_MEDIA_PHOTO_ALBUM_DAO_H
17 
18 #include <string>
19 #include <vector>
20 #include <algorithm>
21 #include <cctype>
22 #include <mutex>
23 
24 #include "rdb_store.h"
25 #include "safe_map.h"
26 
27 namespace OHOS::Media {
28 class PhotoAlbumDao {
29 public:
30     struct PhotoAlbumRowData {
31         int32_t albumId;
32         int32_t albumType;
33         int32_t albumSubType;
34         std::string albumName;
35         std::string lPath;
36         std::string bundleName;
37         int32_t priority = 1;
38     };
39 
40 public:
SetMediaLibraryRdb(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)41     void SetMediaLibraryRdb(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
42     {
43         this->mediaLibraryRdb_ = mediaLibraryRdb;
44     }
45     std::vector<PhotoAlbumRowData> GetPhotoAlbums();
46     PhotoAlbumRowData GetPhotoAlbum(const std::string &lPath);
47     PhotoAlbumRowData GetOrCreatePhotoAlbum(const PhotoAlbumRowData &album);
48     int32_t RestoreAlbums(std::vector<PhotoAlbumRowData> &photoAlbums);
49     PhotoAlbumRowData BuildAlbumInfoOfRecorders();
50     std::string ParseSourcePathToLPath(const std::string &sourcePath);
51     PhotoAlbumRowData BuildAlbumInfoByLPath(const std::string &lPath);
ToString(const PhotoAlbumRowData & albumInfo)52     std::string ToString(const PhotoAlbumRowData &albumInfo)
53     {
54         return "albumId: " + std::to_string(albumInfo.albumId) + ", albumType: " + std::to_string(albumInfo.albumType) +
55                ", albumSubType: " + std::to_string(albumInfo.albumSubType) + ", albumName: " + albumInfo.albumName +
56                ", lPath: " + albumInfo.lPath + ", bundleName: " + albumInfo.bundleName;
57     }
58     void LoadPhotoAlbums();
59 
60 private:
61     std::string FindUniqueAlbumName(const PhotoAlbumRowData &photoAlbum);
62     bool CheckAlbumNameUnique(const std::string &albumName, const std::string &lPath);
63     std::string ToString(const std::vector<NativeRdb::ValueObject> &bindArgs);
64     PhotoAlbumRowData BuildAlbumInfoByLPath(
65         const std::string &lPath, const int32_t albumType, const int32_t albumSubType);
66 
67 private:
68     std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb_;
69     OHOS::SafeMap<std::string, PhotoAlbumRowData> photoAlbumCache_;
70     std::mutex cacheLock_;
71     std::mutex photoAlbumCreateLock_;
72 
73 private:
74     const int32_t MAX_ALBUM_NAME_SEQUENCE = 1000;
75     const std::string FIELD_NAME_ALBUM_ID = "album_id";
76     const std::string FIELD_NAME_ALBUM_TYPE = "album_type";
77     const std::string FIELD_NAME_ALBUM_SUBTYPE = "album_subtype";
78     const std::string FIELD_NAME_ALBUM_NAME = "album_name";
79     const std::string FIELD_NAME_BUNDLE_NAME = "bundle_name";
80     const std::string FIELD_NAME_LPATH = "lpath";
81     const std::string FIELD_NAME_PRIORITY = "priority";
82     const std::string SQL_PHOTO_ALBUM_SELECT = "\
83         SELECT album_id, \
84             album_type, \
85             album_subtype, \
86             album_name, \
87             bundle_name, \
88             lpath, \
89             cloud_id, \
90             relative_path, \
91             priority \
92         FROM PhotoAlbum \
93         WHERE album_type != 1024 \
94         ORDER BY album_id \
95         LIMIT ?, ? ;";
96     const std::string SQL_PHOTO_ALBUM_SELECT_BY_LPATH = "\
97         SELECT album_id, \
98             album_type, \
99             album_subtype, \
100             album_name, \
101             bundle_name, \
102             lpath, \
103             cloud_id, \
104             relative_path, \
105             priority \
106         FROM PhotoAlbum \
107         WHERE LOWER(lpath) = LOWER(?) \
108         ORDER BY album_id DESC \
109         LIMIT 1 ;";
110     // The albumName of PhotoAlbum, which is not in album_plugin, should be unique.
111     const std::string SQL_PHOTO_ALBUM_CHECK_ALBUM_NAME_UNIQUE = "\
112         SELECT COUNT(1) AS count \
113         FROM PhotoAlbum \
114             LEFT JOIN album_plugin \
115             ON LOWER(PhotoAlbum.lpath) = (album_plugin.lpath) \
116         WHERE LOWER(PhotoAlbum.album_name) = LOWER(?) AND \
117             LOWER(PhotoAlbum.lpath) != LOWER(?) AND \
118             album_plugin.lpath IS NULL ;";
119     // create PhotoAlbum from albumInfo and album_plugin.
120     // If the lPath is in album_plugin, use the album_plugin info to create.
121     const std::string SQL_PHOTO_ALBUM_INSERT = "\
122         INSERT INTO PhotoAlbum ( \
123             album_type, \
124             album_subtype, \
125             album_name, \
126             bundle_name, \
127             lpath, \
128             priority, \
129             date_modified, \
130             date_added \
131         ) \
132         SELECT \
133             INPUT.album_type, \
134             INPUT.album_subtype, \
135             CASE \
136                 WHEN COALESCE(album_plugin.album_name, '') <> '' THEN album_plugin.album_name \
137                 WHEN NAME.count > 0 THEN INPUT.album_name || ' ' || NAME.count \
138                 ELSE INPUT.album_name \
139             END AS album_name, \
140             CASE \
141                 WHEN COALESCE(album_plugin.bundle_name, '') = '' THEN INPUT.bundle_name \
142                 ELSE album_plugin.bundle_name \
143             END AS bundle_name, \
144             CASE \
145                 WHEN COALESCE(album_plugin.lpath, '') = '' THEN INPUT.lpath \
146                 ELSE album_plugin.lpath \
147             END AS lpath, \
148             CASE \
149                 WHEN album_plugin.priority IS NULL THEN INPUT.priority \
150                 ELSE album_plugin.priority \
151             END AS priority, \
152             strftime('%s000', 'now') AS date_modified, \
153             strftime('%s000', 'now') AS date_added \
154         FROM \
155         ( \
156             SELECT \
157                 ? AS album_type, \
158                 ? AS album_subtype, \
159                 ? AS album_name, \
160                 ? AS bundle_name, \
161                 ? AS lpath, \
162                 ? AS priority \
163         ) AS INPUT \
164         LEFT JOIN album_plugin \
165             ON LOWER(INPUT.lpath)=LOWER(album_plugin.lpath) \
166         LEFT JOIN PhotoAlbum \
167             ON LOWER(INPUT.lpath)=LOWER(PhotoAlbum.lpath) \
168         LEFT JOIN  \
169         ( \
170             SELECT album_name, COUNT(1) AS count \
171             FROM PhotoAlbum \
172             GROUP BY album_name \
173         ) AS NAME \
174             ON INPUT.album_name = NAME.album_name \
175         WHERE PhotoAlbum.lpath IS NULL \
176         LIMIT 1;";
177 };
178 
179 class StringUtils {
180     StringUtils() = delete;
181     ~StringUtils() = delete;
182 
183 public:
184     static std::string ToLower(const std::string &str);
185 };
186 }  // namespace OHOS::Media
187 #endif  // OHOS_MEDIA_PHOTO_ALBUM_DAO_H