365 lines
13 KiB
Plaintext
365 lines
13 KiB
Plaintext
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Data.SqlClient;
|
|
using System.Linq;
|
|
using DTS.Common.Storage;
|
|
using DTS.Common.Utilities.Logging;
|
|
// ReSharper disable InconsistentNaming
|
|
|
|
// ReSharper disable once CheckNamespace
|
|
namespace DTS.Slice.Users
|
|
{
|
|
public class Tags
|
|
{
|
|
|
|
/// <summary>
|
|
/// represents a single tag, which is composed of an ID and a string of text
|
|
/// we don't currently let you obsolete, delete, or edit tags, just add
|
|
/// </summary>
|
|
public class Tag: ICloneable
|
|
{
|
|
public Tag(string tagText, int tagId)
|
|
{
|
|
ID = tagId;
|
|
Text = tagText;
|
|
IsObsolete = false;
|
|
}
|
|
public const int INVALID_ID = -1;
|
|
public int ID { get; set; }
|
|
public string Text { get; set; }
|
|
public bool IsObsolete { get; set; }
|
|
public Tag(Tag copy)
|
|
{
|
|
ID = copy.ID;
|
|
Text = copy.Text;
|
|
IsObsolete = copy.IsObsolete;
|
|
}
|
|
|
|
public Tag(IDataRecord reader)
|
|
{
|
|
try
|
|
{
|
|
ID = Convert.ToInt32(reader[DbOperations.Tags.TagFields.TagId.ToString()]);
|
|
IsObsolete = Convert.ToBoolean(reader[DbOperations.Tags.TagFields.Obsolete.ToString()]);
|
|
Text = Convert.ToString(reader[DbOperations.Tags.TagFields.TagText.ToString()]);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
}
|
|
}
|
|
|
|
public Tag(DataRow dr)
|
|
{
|
|
try
|
|
{
|
|
IsObsolete = Convert.ToBoolean(dr[DbOperations.Tags.TagFields.Obsolete.ToString()]);
|
|
ID = Convert.ToInt32(dr[DbOperations.Tags.TagFields.TagId.ToString()]);
|
|
Text = Convert.ToString(dr[DbOperations.Tags.TagFields.TagText.ToString()]);
|
|
}
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
|
}
|
|
public object Clone()
|
|
{
|
|
return new Tag(this);
|
|
}
|
|
}
|
|
private static Tags _tagsInstance;
|
|
public static Tags TagsInstance
|
|
{
|
|
get
|
|
{
|
|
if (null == _tagsInstance) { _tagsInstance = new Tags(); }
|
|
return _tagsInstance;
|
|
}
|
|
}
|
|
private static readonly object LOCK_OBJECT = new object();
|
|
public Tags()
|
|
{
|
|
_tagsLookup = new Dictionary<string, Tag>();
|
|
UpdateList();
|
|
}
|
|
/// <summary>
|
|
/// holds a cached collection of tags. This collection however is currently only populated on startup
|
|
/// and not updated except explicitly when a user adds a tag
|
|
/// </summary>
|
|
// ReSharper disable once RedundantDefaultMemberInitializer
|
|
private readonly Dictionary<string, Tag> _tagsLookup = null;
|
|
|
|
/// <summary>
|
|
/// Adds a tag if not present in memory cache to db
|
|
/// </summary>
|
|
/// <param name="tagText"></param>
|
|
/// <returns></returns>
|
|
public static bool AddTag(string tagText)
|
|
{
|
|
if (string.IsNullOrEmpty(tagText)) { return false; }
|
|
|
|
// is it already in the dictionary?
|
|
if (TagsInstance.ContainsTag(tagText)) return false;
|
|
TagsInstance.Commit(new Tag(tagText, Tag.INVALID_ID));
|
|
return true;
|
|
}
|
|
/// <summary>
|
|
/// Changes the ID of a tag during database migration
|
|
/// </summary>
|
|
/// <param name="tagText"></param>
|
|
/// <returns></returns>
|
|
public static bool MigrateTag(string tagText)
|
|
{
|
|
if (string.IsNullOrEmpty(tagText)) { return false; }
|
|
|
|
TagsInstance.Commit(new Tag(tagText, Tag.INVALID_ID));
|
|
return true;
|
|
}
|
|
/// <summary>
|
|
/// commits a tag to db if doesn't already exist in db
|
|
/// </summary>
|
|
/// <param name="tag"></param>
|
|
private void Commit(Tag tag)
|
|
{
|
|
try
|
|
{
|
|
if (-1 == GetIDFromTagText(tag.Text))
|
|
{
|
|
Insert(tag);
|
|
}
|
|
else { UpdateAll(tag); }
|
|
|
|
lock (LOCK_OBJECT)
|
|
{
|
|
_tagsLookup[tag.Text] = tag;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log(ex);
|
|
}
|
|
}
|
|
private void UpdateAll(Tag tag)
|
|
{
|
|
//nothing to do currently? (we don't let you rename or edit, or obsolete, or delete ...)
|
|
tag.ID = GetTagIdFromText(tag.Text);
|
|
}
|
|
/// <summary>
|
|
/// inserts a tag into the db
|
|
/// </summary>
|
|
/// <param name="tag"></param>
|
|
private void Insert(Tag tag)
|
|
{
|
|
using (var cmd = DbOperations.GetSQLCommand(true))
|
|
{
|
|
try
|
|
{
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_TagsInsert.ToString();
|
|
|
|
#region params
|
|
|
|
cmd.Parameters.Add(new SqlParameter("@TagText", SqlDbType.NVarChar, 255) {Value = tag.Text});
|
|
cmd.Parameters.Add(new SqlParameter("@Obsolete", SqlDbType.Bit) {Value = tag.IsObsolete});
|
|
var newIdParam = new SqlParameter("@new_id", SqlDbType.Int) {Direction = ParameterDirection.Output};
|
|
cmd.Parameters.Add(newIdParam);
|
|
var errorNumberParam =
|
|
new SqlParameter("@errorNumber", SqlDbType.Int) {Direction = ParameterDirection.Output};
|
|
cmd.Parameters.Add(errorNumberParam);
|
|
var errorMessageParam =
|
|
new SqlParameter("@errorMessage", SqlDbType.NVarChar, 250)
|
|
{
|
|
Direction = ParameterDirection.Output
|
|
};
|
|
cmd.Parameters.Add(errorMessageParam);
|
|
|
|
#endregion params
|
|
|
|
cmd.ExecuteNonQuery();
|
|
if (int.Parse(errorNumberParam.Value.ToString()) != 0)
|
|
{
|
|
//errorMessageParam.Value
|
|
}
|
|
|
|
|
|
tag.ID = int.Parse(newIdParam.Value.ToString());
|
|
}
|
|
finally
|
|
{
|
|
cmd.Connection.Dispose();
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// retrieves a string text associated with an ID FROM CACHED copies
|
|
/// </summary>
|
|
/// <param name="id"></param>
|
|
/// <returns></returns>
|
|
private string GetTagTextFromId(int id)
|
|
{
|
|
lock (LOCK_OBJECT)
|
|
{
|
|
if (_tagsLookup == null) return null;
|
|
var e = _tagsLookup.GetEnumerator();
|
|
while (e.MoveNext())
|
|
{
|
|
if (e.Current.Value.ID != id) continue;
|
|
var returnText = e.Current.Value.Text;
|
|
e.Dispose();
|
|
return returnText;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
/// <summary>
|
|
/// Gets an ID for a given tag text FROM DB
|
|
/// returns InvalidID if not found
|
|
/// </summary>
|
|
/// <param name="text"></param>
|
|
/// <returns></returns>
|
|
private int GetTagIdFromText(string text)
|
|
{
|
|
using (var cmd = DbOperations.GetSQLCommand(true))
|
|
{
|
|
try
|
|
{
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_TagsGetId.ToString();
|
|
|
|
#region params
|
|
|
|
cmd.Parameters.Add(new SqlParameter("@TagText", SqlDbType.NVarChar, 255) {Value = text});
|
|
var tagIdParam = new SqlParameter("@TagId", SqlDbType.Int) {Direction = ParameterDirection.Output};
|
|
cmd.Parameters.Add(tagIdParam);
|
|
|
|
#endregion params
|
|
|
|
cmd.ExecuteNonQuery();
|
|
|
|
if (DBNull.Value.Equals(tagIdParam.Value))
|
|
{
|
|
return Tag.INVALID_ID;
|
|
}
|
|
var tagIdtemp = int.Parse(tagIdParam.Value.ToString());
|
|
return tagIdtemp == 0 ? Tag.INVALID_ID : tagIdtemp;
|
|
}
|
|
finally
|
|
{
|
|
cmd.Connection.Dispose();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// returns true if a given tag text is contained in cached in memory tags
|
|
/// </summary>
|
|
/// <param name="text"></param>
|
|
/// <returns></returns>
|
|
public bool ContainsTag(string text)
|
|
{
|
|
lock (LOCK_OBJECT)
|
|
{
|
|
return _tagsLookup.ContainsKey(text);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// adds multiple tags at once
|
|
/// note that tags will have their start trimmed before commiting
|
|
/// </summary>
|
|
/// <param name="tagText"></param>
|
|
/// <returns></returns>
|
|
public static bool[] AddRange(string[] tagText)
|
|
{
|
|
List<bool> rv = new List<bool>();
|
|
if (null == tagText || 0 == tagText.Length) { return null; }
|
|
foreach (string s in tagText)
|
|
{
|
|
var tag = s.TrimStart();
|
|
rv.Add(AddTag(tag));
|
|
}
|
|
return rv.ToArray();
|
|
}
|
|
/// <summary>
|
|
/// gets an ID for a given tag text FROM DB
|
|
/// </summary>
|
|
/// <param name="tagText"></param>
|
|
/// <returns></returns>
|
|
public static int GetIDFromTagText(string tagText)
|
|
{
|
|
return TagsInstance.GetTagIdFromText(tagText);
|
|
}
|
|
/// <summary>
|
|
/// gets an array of ids given an array of tag texts
|
|
/// </summary>
|
|
/// <param name="tagText"></param>
|
|
/// <returns></returns>
|
|
public static int[] GetIDsFromTagText(string[] tagText)
|
|
{
|
|
if (null == tagText || 0 == tagText.Length) { return null; }
|
|
|
|
return tagText.Select(s => s.TrimStart()).Select(text => GetIDFromTagText(text)).Where(id => id != Tag.INVALID_ID).ToArray();
|
|
}
|
|
/// <summary>
|
|
/// returns a string for a given id from memory cache
|
|
/// returns null if it doesn't exist or is an invalid id
|
|
/// </summary>
|
|
/// <param name="tagID"></param>
|
|
/// <returns></returns>
|
|
public static string GetTagTextFromID(int tagID)
|
|
{
|
|
if (0 > tagID || tagID == Tag.INVALID_ID)
|
|
{
|
|
// Not a valid ID
|
|
return null;
|
|
}
|
|
return TagsInstance.GetTagTextFromId(tagID);
|
|
}
|
|
|
|
/// <summary>
|
|
/// returns an array of tag text given an array of tag ids.
|
|
/// skips invalid tags or tag text
|
|
/// </summary>
|
|
/// <param name="tagId"></param>
|
|
/// <returns></returns>
|
|
public static string[] GetTagTextFromIDs(int[] tagId)
|
|
{
|
|
if (null == tagId || 0 == tagId.Length) { return new string [0]; }
|
|
|
|
return tagId.Where(i => i != Tag.INVALID_ID).Select(i => GetTagTextFromID(i)).Where(tag => !string.IsNullOrWhiteSpace(tag)).ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// retrieves all tags and updates the cached dictionary of tags
|
|
/// </summary>
|
|
public void UpdateList()
|
|
{
|
|
lock (LOCK_OBJECT)
|
|
{
|
|
_tagsLookup.Clear();
|
|
using (var cmd = DbOperations.GetSQLCommand(true))
|
|
{
|
|
try
|
|
{
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_TagsGet.ToString();
|
|
cmd.Parameters.Add(new SqlParameter("@TagId", SqlDbType.Int) {Value = null});
|
|
|
|
var reader = cmd.ExecuteReader();
|
|
while (reader.Read())
|
|
{
|
|
|
|
var t = new Tag(reader);
|
|
if (t.ID == 0) continue;
|
|
_tagsLookup[t.Text] = t;
|
|
}
|
|
reader.Close();
|
|
}
|
|
finally
|
|
{
|
|
cmd.Connection.Dispose();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|