using Cysharp.Threading.Tasks;
using SQLite4Unity3d;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UVC.Factory.Playback;
using UVC.Util;
namespace UVC.Factory
{
public class PlaybackSQLiteService
{
// SQLite 데이터베이스 연결 객체
private SQLiteConnection dbConnection;
// 데이터베이스 연결 여부 확인
public bool Connected { get => dbConnection != null; }
private string date;
public string Date { get => date; }
private string sqliteFileName;
public string SqliteFileName { get => sqliteFileName; }
///
/// 데이터베이스 파일에 연결합니다.
/// 예시:
///
/// var service = new PlaybackSQLiteService();
/// service.Connect("2024-07-29", "sample.db");
///
///
/// 폴더명(날짜 등)
/// SQLite 파일명
public void Connect(string date, string sqliteFileName)
{
this.date = date;
this.sqliteFileName = sqliteFileName;
dbConnection = new SQLiteConnection(Path.Combine(PlaybackService.PlaybackFolderPath, date, sqliteFileName));
}
///
/// 데이터베이스 연결을 닫습니다.
/// 예시:
///
/// service.CloseDB();
///
///
public void CloseDB()
{
dbConnection.Close();
dbConnection = null;
}
///
/// realTime 테이블에 데이터를 추가합니다.
/// 예시:
///
/// int rows = service.Insert("센서값", "2024-07-29T12:00:00.000Z", "온도값");
///
///
/// 저장할 데이터(문자열)
/// yyyy-MM-ddTHH:mm:ss.fffZ 형식의 시간
/// 임시 데이터(옵션)
/// 추가된 행 수
public int Insert(string data, string timeStamp, string temp = null)
{
var query = $"INSERT INTO realTime (data, timestamp, temp) VALUES ('{data}', '{timeStamp}', " + (temp == null ? "null" : "'" + temp + "'") + ");";
int changedRowLen = dbConnection.Execute(query);
return changedRowLen;
}
readonly string[] queryParts =
{
"SELECT * FROM realTime WHERE ",
"timestamp >= '",
"' AND timestamp < '",
"timestamp <= '",
"' AND timestamp > '",
" ORDER BY timestamp ",
" LIMIT ",
};
///
/// 특정 시간(selectTime) 기준으로 ±second 범위의 데이터를 조회합니다.
/// 예시:
///
/// // 10초 뒤까지의 데이터 5개를 조회(오름차순)
/// var list = await service.SelectBySecond("2024-07-29T12:00:00.000Z", 10, true, 5);
///
///
/// 기준 시간(yyyy-MM-ddTHH:mm:ss.fffZ)
/// ±초(양수: 미래, 음수: 과거)
/// true: 오래된 시간부터, false: 최근 시간부터
/// 최대 조회 개수(0이면 제한 없음)
/// 조회된 데이터 리스트
public async UniTask> SelectBySecond(string selectTime, int second, bool orderAsc = true, int limit = 0)
{
#if UNITY_WEBGL && !UNITY_EDITOR
DateTime target = DateTimeUtil.UtcParse(selectTime).AddSeconds(second);
string targetTime = DateTimeUtil.FormatTime(target);
queryBuilder.Append(queryParts[0]);
if (second > 0)
{
queryBuilder.Append($"{queryParts[1]}{selectTime}{queryParts[2]}{targetTime}'");
}
else
{
queryBuilder.Append($"{queryParts[3]}{selectTime}{queryParts[4]}{targetTime}'");
}
queryBuilder.Append($"{queryParts[5]}{(orderAsc ? "asc" : "desc")}");
if (limit > 0)
queryBuilder.Append($"{queryParts[6]}{limit}");
queryBuilder.Append(";");
var query = queryBuilder.ToString();
queryBuilder.Clear();
// 동기 실행 (WebGL은 ThreadPool 사용 불가)
var list = dbConnection.Query(query);
return list;
#else
bool isMainThread = PlayerLoopHelper.IsMainThread;
List result = await UniTask.RunOnThreadPool(() =>
{
DateTime date = DateTimeUtil.UtcParse(selectTime).AddSeconds(second);
string targetTime = DateTimeUtil.FormatTime(date);
//Debug.Log($"SelectBySecondBaseInfo {selectTime} {second} {targetTime} {date}");
queryBuilder.Append(queryParts[0]);
//second가 selectTime 보다 더 미래면
if (second > 0)
{
queryBuilder.Append($"{queryParts[1]}{selectTime}{queryParts[2]}{targetTime}'");
}
else
{
//second가 selectTime 보다 더 과거면
queryBuilder.Append($"{queryParts[3]}{selectTime}{queryParts[4]}{targetTime}'");
}
queryBuilder.Append($"{queryParts[5]}{(orderAsc ? "asc" : "desc")}");
if (limit > 0)
queryBuilder.Append($"{queryParts[6]}{limit}");
queryBuilder.Append(";");
//Debug.Log($"SelectBySecond {query}");
var query = queryBuilder.ToString();
queryBuilder.Clear();
// 쿼리 실행 및 결과 반환
return dbConnection.Query(query);
});
if (!isMainThread) await UniTask.SwitchToThreadPool();
return result;
#endif
}
StringBuilder queryBuilder = new();
/// baseInfo 테이블에서 특정 시간(selectTime) 기준으로 ±second 범위의 데이터를 조회합니다.
/// 예시:
///
/// // 5초 전까지의 데이터 1개를 조회(내림차순)
/// var list = await service.SelectBySecondBaseInfo("2024-07-29T12:00:00.000Z", -5);
///
///
/// 기준 시간(yyyy-MM-ddTHH:mm:ss.fffZ)
/// ±초(양수: 미래, 음수: 과거)
/// true: 오래된 시간부터, false: 최근 시간부터
/// 최대 조회 개수
/// 조회된 데이터 리스트
public async UniTask> SelectBySecondBaseInfo(string selectTime, int second, bool orderAsc = false, int limit = 1)
{
#if UNITY_WEBGL && !UNITY_EDITOR
DateTime target = DateTimeUtil.UtcParse(selectTime).AddSeconds(second);
string targetTime = DateTimeUtil.FormatTime(target);
queryBuilder.Append("SELECT * FROM baseInfo WHERE ");
if (second > 0)
{
queryBuilder.Append($"timestamp >= '{selectTime}' AND timestamp < '{targetTime}'");
}
else
{
queryBuilder.Append($"timestamp <= '{selectTime}' AND timestamp > '{targetTime}'");
}
queryBuilder.Append($" ORDER BY timestamp {(orderAsc ? "asc" : "desc")}");
if (limit > 0) queryBuilder.Append($" LIMIT {limit}");
queryBuilder.Append(";");
var query = queryBuilder.ToString();
queryBuilder.Clear();
var list = dbConnection.Query(query);
return list;
#else
bool isMainThread = PlayerLoopHelper.IsMainThread;
List result = await UniTask.RunOnThreadPool(() =>
{
DateTime date = DateTimeUtil.UtcParse(selectTime).AddSeconds(second);
string targetTime = DateTimeUtil.FormatTime(date);
//Debug.Log($"SelectBySecondBaseInfo {selectTime} {second} {targetTime} {date}");
queryBuilder.Append($"SELECT * FROM baseInfo WHERE ");
//second가 selectTime 보다 더 미래면
if (second > 0)
{
queryBuilder.Append($"timestamp >= '{selectTime}' AND timestamp < '{targetTime}'");
}
else
{
//second가 selectTime 보다 더 과거면
queryBuilder.Append($"timestamp <= '{selectTime}' AND timestamp > '{targetTime}'");
}
queryBuilder.Append($" ORDER BY timestamp {(orderAsc ? "asc" : "desc")}");
if (limit > 0) queryBuilder.Append($" LIMIT {limit}");
queryBuilder.Append(";");
//Debug.Log($"SelectBySecondBaseInfo {query}");
var query = queryBuilder.ToString();
queryBuilder.Clear();
// 쿼리 실행 및 결과 반환
return dbConnection.Query(query);
});
if (!isMainThread) await UniTask.SwitchToThreadPool();
return result;
#endif
}
}
///
/// 데이터베이스에서 사용하는 데이터 구조체입니다.
/// 예시:
///
/// var entity = new PlaybackSQLiteDataEntity {
/// data = "센서값",
/// timestamp = "2024-07-29T12:00:00.000Z",
/// temp = "임시값"
/// };
///
///
[System.Serializable]
public class PlaybackSQLiteDataEntity
{
public string data { get; set; }
[PrimaryKey]
public string timestamp { get; set; }
// timestampHungary는 timestamp를 DateTime으로 변환한 값입니다.
public DateTime timestampHungary { get => DateTimeUtil.UtcStringToHungaryDateTime(timestamp); }
public string temp { get; set; }
}
}