banshee r2970 - in trunk/banshee: . build src/Core/Banshee.Core/Banshee.Collection src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Database src/Core/Hyena src/Core/Hyena/Hyena.Data
- From: scottp svn gnome org
- To: svn-commits-list gnome org
- Subject: banshee r2970 - in trunk/banshee: . build src/Core/Banshee.Core/Banshee.Collection src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Database src/Core/Hyena src/Core/Hyena/Hyena.Data
- Date: Tue, 15 Jan 2008 18:38:49 +0000 (GMT)
Author: scottp
Date: Tue Jan 15 18:38:49 2008
New Revision: 2970
URL: http://svn.gnome.org/viewvc/banshee?rev=2970&view=rev
Log:
* src/Core/Hyena/Hyena.Data/HyenaDbConnection.cs: An abstraction of
BansheeDbConnection/COmmand
* src/Core/Hyena/Hyena.Data/DatabaseModelProvider.cs: Added.
* src/Core/Hyena/Hyena.Data/CacheableDatabaseModelProvider.cs: Added.
This class functionally inherits from both CacheableModelAdapter
and DatabaseModelProvider.
* src/Core/Hyena/Hyena.Data/CacheableModelAdapter.cs: Added Add()
method.
* src/Core/Banshee.Services/Banshee.Collection.Database/BansheeModelProvider.cs:
Added. This will replace BansheeCacheableModelAdapter.
* src/Core/Banshee.Services/Banshee.Collection.Database/LibraryTrackInfo.cs:
Modified to use new model provider system.
* src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs:
Added Provider inner class which inherits from
BansheeModelProvider. Made to use that inner class.
* src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs:
Abstracted into Hyena.
* src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs: Made MimeType
and FileSize virtual.
* build/build.environment.mk: Added sql-related dependancies to Hyena's
references.
Added:
trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/BansheeModelProvider.cs
trunk/banshee/src/Core/Hyena/Hyena.Data/CacheableDatabaseModelProvider.cs
trunk/banshee/src/Core/Hyena/Hyena.Data/DatabaseModelProvider.cs
trunk/banshee/src/Core/Hyena/Hyena.Data/HyenaDbConnection.cs
Modified:
trunk/banshee/ChangeLog
trunk/banshee/build/build.environment.mk
trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs
trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryTrackInfo.cs
trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs
trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs
trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
trunk/banshee/src/Core/Banshee.Services/Makefile.am
trunk/banshee/src/Core/Hyena/Hyena.Data/CacheableModelAdapter.cs
trunk/banshee/src/Core/Hyena/Hyena.mdp
trunk/banshee/src/Core/Hyena/Makefile.am
Modified: trunk/banshee/build/build.environment.mk
==============================================================================
--- trunk/banshee/build/build.environment.mk (original)
+++ trunk/banshee/build/build.environment.mk Tue Jan 15 18:38:49 2008
@@ -78,7 +78,7 @@
DIR_HYENA = $(DIR_CORE)/Hyena
MONO_BASE_PATH += $(DIR_HYENA)
-REF_HYENA = $(LINK_SYSTEM)
+REF_HYENA = $(LINK_SYSTEM) $(LINK_SQLITE)
LINK_HYENA = -r:$(DIR_HYENA)/Hyena.dll
LINK_HYENA_DEPS = $(REF_HYENA) $(LINK_HYENA)
Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs (original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs Tue Jan 15 18:38:49 2008
@@ -108,12 +108,12 @@
set { more_info_uri = value; }
}
- public string MimeType {
+ public virtual string MimeType {
get { return mimetype; }
set { mimetype = value; }
}
- public long FileSize {
+ public virtual long FileSize {
get { return filesize; }
set { filesize = value; }
}
Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/BansheeModelProvider.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/BansheeModelProvider.cs Tue Jan 15 18:38:49 2008
@@ -0,0 +1,113 @@
+//
+// BansheeModelProvider.cs
+//
+// Author:
+// Scott Peterson <lunchtimemama gmail com>
+//
+// Copyright (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Data;
+
+using Hyena.Data;
+
+using Banshee.Database;
+
+namespace Banshee.Collection.Database
+{
+
+ public abstract class BansheeModelProvider<T> : CacheableDatabaseModelProvider<T>
+ {
+ private IDatabaseModel<T> model; // FIXME do away with this
+
+ public BansheeModelProvider(BansheeDbConnection connection, IDatabaseModel<T> model)
+ : base(connection, model)
+ {
+ this.model = model;
+ }
+
+ protected override sealed int DatabaseVersion {
+ get { return 1; }
+ }
+
+ protected override sealed void CheckVersion()
+ {
+ using(IDataReader reader = Connection.ExecuteReader(String.Format(
+ "SELECT Value FROM CoreConfiguration WHERE Key = '{0}ModelVersion'", TableName))) {
+ if(reader.Read()) {
+ int version = Int32.Parse(reader.GetString(0));
+ if(version < ModelVersion) {
+ MigrateTable(version);
+ Connection.Execute(String.Format(
+ "UPDATE CoreConfiguration SET Value = '{0}' WHERE Key = '{0}ModelVersion'",
+ ModelVersion, TableName));
+ }
+ } else {
+ Connection.Execute(String.Format(
+ "INSERT INTO CoreConfiguration (Key, Value) VALUES ('{0}ModelVersion', '{1}')",
+ TableName, ModelVersion));
+ }
+ }
+ using(IDataReader reader = Connection.ExecuteReader("SELECT Value FROM CoreConfiguration WHERE Key = 'DatabaseVersion'")) {
+ if(reader.Read()) {
+ int version = Int32.Parse(reader.GetString(0));
+ if(version < DatabaseVersion) {
+ MigrateDatabase(version);
+ Connection.Execute(String.Format(
+ "UPDATE CoreConfiguration SET Value = '{0}' WHERE Key = 'DatabaseVersion'",
+ DatabaseVersion));
+ }
+ } else {
+ Connection.Execute(String.Format(
+ "INSERT INTO CoreConfiguration (Key, Value) VALUES ('DatabaseVersion', '{0}')",
+ DatabaseVersion));
+ }
+ }
+ }
+
+
+ protected override string ReloadFragment {
+ get { return model.ReloadFragment; } // FIXME move this elsewhere
+ }
+
+ protected override sealed string CacheTableName {
+ get { return "CoreCache"; }
+ }
+
+ protected override sealed bool Persistent {
+ get { return true; }
+ }
+
+ protected override sealed string CacheModelsTableName {
+ get { return "CoreCacheModels"; }
+ }
+
+ protected override sealed void MigrateDatabase(int old_version)
+ {
+ }
+
+ protected override void MigrateTable(int old_version)
+ {
+ }
+ }
+}
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryTrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryTrackInfo.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryTrackInfo.cs Tue Jan 15 18:38:49 2008
@@ -29,228 +29,195 @@
using System;
using System.Data;
-using Banshee.IO;
+using Hyena.Data;
+
using Banshee.Base;
using Banshee.Database;
using Banshee.ServiceStack;
namespace Banshee.Collection.Database
-{
+{
public class LibraryTrackInfo : TrackInfo
{
- public enum Column : int {
- TrackID,
- ArtistID,
- AlbumID,
- TagSetID,
- MusicBrainzID,
- Uri,
- UriType,
- MimeType,
- FileSize,
- Title,
- TrackNumber,
- TrackCount,
- DiscNumber,
- Duration,
- Year,
- Rating,
- PlayCount,
- SkipCount,
- LastPlayedStamp,
- DateAddedStamp,
-
- // These columns are virtual - they are not actually
- // in CoreTracks and are returned on join selects
- Artist,
- AlbumTitle
- }
-
private enum UriType : int {
AbsolutePath,
RelativePath,
AbsoluteUri
}
- private int dbid;
- private int db_index;
-
- private int artist_id;
- private int album_id;
+ private TrackListDatabaseModel model;
public LibraryTrackInfo () : base ()
{
- dbid = -1;
- }
-
- public LibraryTrackInfo (IDataReader reader, int index) : base ()
- {
- LoadFromReader (reader);
- DbIndex = index;
}
- private void LoadFromReader (IDataReader reader)
+ public LibraryTrackInfo (TrackListDatabaseModel model, int index) : base () // Get rid of model
{
- dbid = ReaderGetInt32 (reader, Column.TrackID);
-
- string uri = ReaderGetString (reader, Column.Uri);
- UriType uri_type = (UriType)ReaderGetInt32 (reader, Column.UriType);
-
- if (uri_type == UriType.RelativePath) {
- uri = System.IO.Path.Combine (Paths.LibraryLocation, uri);
- }
-
- Uri = new SafeUri (uri);
- FileSize = ReaderGetInt64 (reader, Column.FileSize);
-
- ArtistName = ReaderGetString (reader, Column.Artist);
- ArtistId = ReaderGetInt32 (reader, Column.ArtistID);
-
- AlbumTitle = ReaderGetString (reader, Column.AlbumTitle);
- AlbumId = ReaderGetInt32 (reader, Column.AlbumID);
-
- TrackTitle = ReaderGetString (reader, Column.Title);
-
- TrackNumber = ReaderGetInt32 (reader, Column.TrackNumber);
- TrackCount = ReaderGetInt32 (reader, Column.TrackCount);
- Year = ReaderGetInt32 (reader, Column.Year);
- Rating = ReaderGetInt32 (reader, Column.Rating);
-
- Duration = ReaderGetTimeSpan (reader, Column.Duration);
-
- PlayCount = ReaderGetInt32 (reader, Column.PlayCount);
- SkipCount = ReaderGetInt32 (reader, Column.SkipCount);
-
- LastPlayed = ReaderGetDateTime (reader, Column.LastPlayedStamp);
- DateAdded = ReaderGetDateTime (reader, Column.DateAddedStamp);
-
+ this.model = model;
Attributes |= TrackAttributes.CanPlay;
- }
-
- private string ReaderGetString (IDataReader reader, Column column)
- {
- int column_id = (int)column;
- return !reader.IsDBNull (column_id)
- ? String.Intern (reader.GetString (column_id))
- : null;
- }
-
- private int ReaderGetInt32 (IDataReader reader, Column column)
- {
- return reader.GetInt32 ((int)column);
- }
-
- private long ReaderGetInt64 (IDataReader reader, Column column)
- {
- return reader.GetInt64 ((int)column);
- }
-
- private TimeSpan ReaderGetTimeSpan (IDataReader reader, Column column)
- {
- long raw = reader.GetInt64 ((int)column);
- return new TimeSpan (raw * TimeSpan.TicksPerMillisecond);
- }
-
- private DateTime ReaderGetDateTime (IDataReader reader, Column column)
- {
- long raw = reader.GetInt64 ((int)column);
- return DateTimeUtil.ToDateTime (raw);
+ DbIndex = index;
}
public override void Save ()
{
if (DbId < 0) {
- InsertCommit ();
+ DbId = model.Insert(this);
} else {
- UpdateCommit ();
+ model.Update(this);
}
}
- private void InsertCommit ()
- {
- TableSchema.CoreTracks.InsertCommand.ApplyValues (
- null, // TrackID
- ArtistId,
- AlbumId,
- -1, // TagSetID
- null, // MusicBrainzID
- Uri == null ? null :
- (Paths.MakePathRelativeToLibrary (Uri.AbsolutePath)
- ?? Uri.AbsoluteUri),
- UriType.RelativePath,
- MimeType,
- FileSize,
- TrackTitle,
- TrackNumber,
- TrackCount,
- DiscNumber,
- Duration.TotalMilliseconds,
- Year,
- Rating,
- PlayCount,
- SkipCount,
- DateTimeUtil.FromDateTime (LastPlayed),
- DateTimeUtil.FromDateTime (DateAdded)
- );
-
- DbId = ServiceManager.DbConnection.Execute (TableSchema.CoreTracks.InsertCommand);
- }
-
- private void UpdateCommit ()
- {
- TableSchema.CoreTracks.UpdateCommand.ApplyValues (
- DbId, // TrackID
- ArtistId,
- AlbumId,
- -1, // TagSetID
- null, // MusicBrainzID
- Uri == null ? null :
- (Paths.MakePathRelativeToLibrary (Uri.AbsolutePath)
- ?? Uri.AbsoluteUri),
- UriType.RelativePath,
- MimeType,
- FileSize,
- TrackTitle,
- TrackNumber,
- TrackCount,
- DiscNumber,
- Duration.TotalMilliseconds,
- Year,
- Rating,
- PlayCount,
- SkipCount,
- DateTimeUtil.FromDateTime (LastPlayed),
- DateTimeUtil.FromDateTime (DateAdded),
- DbId // TrackID (again, for WHERE clause)
- );
-
- Console.WriteLine ("Updating: {0}", TableSchema.CoreTracks.UpdateCommand.CommandText);
- ServiceManager.DbConnection.Execute (TableSchema.CoreTracks.UpdateCommand);
+ [DatabaseColumn("TrackID", BindingFlags = DatabaseBindingFlags.PrimaryKey)]
+ private int track_id;
+ public int TrackId {
+ get { return track_id; }
+ internal set { track_id = value; }
}
public int DbId {
- get { return dbid; }
- set { dbid = value; }
+ get { return TrackId; }
+ set { TrackId = value; }
}
+ private int db_index;
public int DbIndex {
get { return db_index; }
internal set { db_index = value; }
}
+ [DatabaseColumn("ArtistID", Index = "CoreTracksArtistIndex")]
+ private int artist_id;
public int ArtistId {
get { return artist_id; }
set { artist_id = value; }
}
+ [DatabaseColumn("AlbumID", Index = "CoreTracksAlbumIndex")]
+ private int album_id;
public int AlbumId {
get { return album_id; }
set { album_id = value; }
}
+ [DatabaseVirtualColumn("Name", "CoreArtists", "ArtistID", "ArtistID")]
+ public override string ArtistName {
+ get { return base.ArtistName; }
+ set { base.ArtistName = value; }
+ }
+
+ [DatabaseVirtualColumn("Title", "CoreAlbums", "AlbumID", "AlbumID")]
+ public override string AlbumTitle {
+ get { return base.AlbumTitle; }
+ set { base.AlbumTitle = value; }
+ }
+
+ [DatabaseColumn]
+ private int TagSetID;
+
+ [DatabaseColumn]
+ private string MusicBrainzID;
+
+ [DatabaseColumn("Uri")]
+ private string uri;
+
+ [DatabaseColumn("UriType")]
+ private int uri_type;
+
+ [DatabaseColumn]
+ public override string MimeType {
+ get { return base.MimeType; }
+ set { base.MimeType = value; }
+ }
+
+ [DatabaseColumn]
+ public override long FileSize {
+ get { return base.FileSize; }
+ set { base.FileSize = value; }
+ }
+
+ [DatabaseColumn("Title")]
+ public override string TrackTitle {
+ get { return base.TrackTitle; }
+ set { base.TrackTitle = value; }
+ }
+
+ [DatabaseColumn]
+ public override int TrackNumber {
+ get { return base.TrackNumber; }
+ set { base.TrackNumber = value; }
+ }
+
+ [DatabaseColumn]
+ public override int TrackCount {
+ get { return base.TrackCount; }
+ set { base.TrackCount = value; }
+ }
+
+ [DatabaseColumn]
+ public override int DiscNumber {
+ get { return base.DiscNumber; }
+ set { base.DiscNumber = value; }
+ }
+
+ [DatabaseColumn("Duration")]
+ private long duration {
+ get { return (long)Duration.TotalMilliseconds; }
+ set { Duration = new TimeSpan (value * TimeSpan.TicksPerMillisecond); }
+ }
+
+ [DatabaseColumn]
+ public override int Year {
+ get { return base.Year; }
+ set { base.Year = value; }
+ }
+
+ [DatabaseColumn]
+ public override int Rating {
+ get { return base.Rating; }
+ set { base.Rating = value; }
+ }
+
+ [DatabaseColumn]
+ public override int PlayCount {
+ get { return base.PlayCount; }
+ set { base.PlayCount = value; }
+ }
+
+ [DatabaseColumn]
+ public override int SkipCount {
+ get { return base.SkipCount; }
+ set { base.SkipCount = value; }
+ }
+
+ [DatabaseColumn]
+ private long LastPlayedStamp {
+ get { return DateTimeUtil.FromDateTime(LastPlayed); }
+ set { LastPlayed = DateTimeUtil.ToDateTime(value); }
+ }
+
+ [DatabaseColumn]
+ private long DateAddedStamp {
+ get { return DateTimeUtil.FromDateTime(DateAdded); }
+ set { DateAdded = DateTimeUtil.ToDateTime(value); }
+ }
+
+ private bool set_up;
+ public void SetUp()
+ {
+ if(set_up) {
+ return;
+ }
+ set_up = true;
+
+ if (uri_type == (int)UriType.RelativePath) {
+ uri = System.IO.Path.Combine(Paths.LibraryLocation, uri);
+ }
+ Uri = new SafeUri(uri);
+ }
+
private static BansheeDbCommand check_command = new BansheeDbCommand (
"SELECT COUNT(*) FROM CoreTracks WHERE Uri = ? OR Uri = ?", 2);
-
+
public static bool ContainsUri (SafeUri uri)
{
string relative_path = Paths.MakePathRelativeToLibrary (uri.AbsolutePath) ?? uri.AbsoluteUri;
@@ -258,4 +225,4 @@
check_command.ApplyValues (relative_path, uri.AbsoluteUri))) > 0;
}
}
-}
+}
\ No newline at end of file
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs Tue Jan 15 18:38:49 2008
@@ -42,10 +42,54 @@
namespace Banshee.Collection.Database
{
public class TrackListDatabaseModel : TrackListModel, IExportableModel, ICacheableModel,
- IDatabaseModel<TrackInfo>, IFilterable, ISortable, ICareAboutView
+ IDatabaseModel<LibraryTrackInfo>, IFilterable, ISortable, ICareAboutView
{
+ private sealed class Provider : BansheeModelProvider<LibraryTrackInfo>
+ {
+ private BansheeDbConnection connection;
+ private TrackListDatabaseModel model;
+
+ public Provider(BansheeDbConnection connection, TrackListDatabaseModel model) //FIXME get rid of model
+ : base(connection, model)
+ {
+ this.connection = connection;
+ this.model = model;
+ }
+
+ protected override LibraryTrackInfo MakeNewObject(int offset)
+ {
+ return new LibraryTrackInfo(model, offset);
+ }
+
+ protected override void Add(int key, LibraryTrackInfo value)
+ {
+ base.Add(key, value);
+ value.SetUp();
+ }
+
+ protected override string TableName {
+ get { return "CoreTracks"; }
+ }
+
+ protected override int ModelVersion {
+ get { return 1; }
+ }
+
+ public string FromFragment {
+ get { return From; }
+ }
+
+ public string WhereFragment {
+ get { return Where; }
+ }
+
+ public string SelectFragment {
+ get { return Select; }
+ }
+ }
+
private BansheeDbConnection connection;
- private BansheeCacheableModelAdapter<TrackInfo> cache;
+ private Provider provider;
private int count;
private int unfiltered_count;
@@ -64,7 +108,7 @@
public TrackListDatabaseModel (BansheeDbConnection connection, string uuid)
{
- cache = new BansheeCacheableModelAdapter<TrackInfo> (connection, uuid, this);
+ provider = new Provider(connection, this);
this.connection = connection;
Refilter ();
}
@@ -171,7 +215,7 @@
{
lock(this) {
GenerateFilterQueryPart();
- cache.Clear ();
+ provider.Clear ();
}
}
@@ -187,13 +231,13 @@
sort_column = column;
GenerateSortQueryPart();
- cache.Clear ();
+ provider.Clear ();
}
}
public override void Clear()
{
- cache.Clear ();
+ provider.Clear ();
unfiltered_count = 0;
count = 0;
OnCleared();
@@ -203,8 +247,8 @@
public override void Reload()
{
string unfiltered_query = String.Format (
- "FROM CoreTracks, CoreAlbums, CoreArtists{0} WHERE {1} {2}",
- JoinFragment, FetchCondition, ConditionFragment
+ "FROM {0}{1} WHERE {2} {3}",
+ FetchFrom, JoinFragment, FetchCondition, ConditionFragment
);
unfiltered_count = connection.QueryInt32 (String.Format (
@@ -237,11 +281,11 @@
reload_fragment = qb.ToString ();
- if (!first_reload || !cache.Warm) {
- cache.Reload ();
+ if (!first_reload || !provider.Warm) {
+ provider.Reload ();
}
- count = cache.Count;
+ count = provider.Count;
first_reload = false;
OnReloaded ();
@@ -257,7 +301,7 @@
}
public override TrackInfo this[int index] {
- get { return cache.GetValue (index); }
+ get { return provider.GetValue (index); }
}
public override int Count {
@@ -347,7 +391,7 @@
}
public int CacheId {
- get { return cache.CacheId; }
+ get { return provider.CacheId; }
}
public ISortableColumn SortColumn {
@@ -375,9 +419,19 @@
}
// Implement IDatabaseModel
- public TrackInfo GetItemFromReader (IDataReader reader, int index)
+ public LibraryTrackInfo GetItemFromReader (IDataReader reader, int index)
+ {
+ return new LibraryTrackInfo (this, index);
+ }
+
+ public int Insert(LibraryTrackInfo track)
+ {
+ return provider.Insert(track);
+ }
+
+ public void Update(LibraryTrackInfo track)
{
- return new LibraryTrackInfo (reader, index);
+ provider.Update(track);
}
private const string primary_key = "CoreTracks.TrackID";
@@ -390,15 +444,15 @@
}
public string FetchColumns {
- get { return "CoreTracks.*, CoreArtists.Name, CoreAlbums.Title"; }
+ get { return provider.SelectFragment; }
}
public string FetchFrom {
- get { return "CoreTracks, CoreArtists, CoreAlbums"; }
+ get { return provider.FromFragment; }
}
public string FetchCondition {
- get { return "CoreArtists.ArtistID = CoreTracks.ArtistID AND CoreAlbums.AlbumID = CoreTracks.AlbumID"; }
+ get { return provider.WhereFragment; }
}
public override QueryField ArtistField {
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs Tue Jan 15 18:38:49 2008
@@ -31,40 +31,30 @@
using System.Data;
using Mono.Data.Sqlite;
+using Hyena.Data;
+
using Banshee.Base;
using Banshee.ServiceStack;
namespace Banshee.Database
{
- public class BansheeDbConnection : IService, IDisposable
+ public sealed class BansheeDbConnection : HyenaDbConnection, IService
{
- private SqliteConnection connection;
-
public BansheeDbConnection () : this (true)
{
}
public BansheeDbConnection (bool connect)
+ : base(connect)
{
if (connect) {
- Open ();
- Migrate ();
+ BansheeDbFormatMigrator migrator = new BansheeDbFormatMigrator (Connection);
+ migrator.SlowStarted += OnMigrationSlowStarted;
+ migrator.SlowPulse += OnMigrationSlowPulse;
+ migrator.SlowFinished += OnMigrationSlowFinished;
+ migrator.Migrate ();
}
}
-
- private void Migrate ()
- {
- BansheeDbFormatMigrator migrator = new BansheeDbFormatMigrator (connection);
- migrator.SlowStarted += OnMigrationSlowStarted;
- migrator.SlowPulse += OnMigrationSlowPulse;
- migrator.SlowFinished += OnMigrationSlowFinished;
-
- migrator.Migrate ();
-
- migrator.SlowStarted -= OnMigrationSlowStarted;
- migrator.SlowPulse -= OnMigrationSlowPulse;
- migrator.SlowFinished -= OnMigrationSlowFinished;
- }
//private Gtk.Window slow_window;
//private Gtk.ProgressBar slow_progress;
@@ -134,102 +124,7 @@
}*/
}
- public void Dispose ()
- {
- Close ();
- }
-
- public void Open ()
- {
- lock (this) {
- if (connection != null) {
- return;
- }
-
- string dbfile = DatabaseFile;
- Console.WriteLine ("Opening connection to Banshee Database: {0}", dbfile);
- connection = new SqliteConnection (String.Format ("Version=3,URI=file:{0}", dbfile));
- connection.Open ();
-
- Execute (@"
- PRAGMA synchronous = OFF;
- PRAGMA cache_size = 32768;
- ");
- }
- }
-
- public void Close ()
- {
- lock (this) {
- if (connection != null) {
- connection.Close ();
- connection = null;
- }
- }
- }
-
-#region Convenience methods
-
- public IDataReader ExecuteReader (SqliteCommand command)
- {
- if (command.Connection == null)
- command.Connection = connection;
- return command.ExecuteReader ();
- }
-
- public IDataReader ExecuteReader (BansheeDbCommand command)
- {
- return ExecuteReader (command.Command);
- }
-
- public IDataReader ExecuteReader (object command)
- {
- return ExecuteReader (new SqliteCommand (command.ToString ()));
- }
-
- public object ExecuteScalar (SqliteCommand command)
- {
- if (command.Connection == null)
- command.Connection = connection;
- return command.ExecuteScalar ();
- }
-
- public object ExecuteScalar (BansheeDbCommand command)
- {
- return ExecuteScalar (command.Command);
- }
-
- public object ExecuteScalar (object command)
- {
- return ExecuteScalar (new SqliteCommand (command.ToString ()));
- }
-
- public Int32 QueryInt32 (object command)
- {
- return Convert.ToInt32 (ExecuteScalar (command));
- }
-
- public int Execute (SqliteCommand command)
- {
- if (command.Connection == null)
- command.Connection = connection;
- command.ExecuteNonQuery ();
- return command.LastInsertRowID ();
- }
-
- public int Execute (BansheeDbCommand command)
- {
- return Execute (command.Command);
- }
-
- public int Execute (object command)
- {
- return Execute (new SqliteCommand (command.ToString ()));
- }
-
-#endregion
-
- public string DatabaseFile {
+ public override string DatabaseFile {
get {
if (ApplicationContext.CommandLine.Contains ("db"))
return ApplicationContext.CommandLine["db"];
@@ -254,115 +149,27 @@
return dbfile;
}
}
-
- public IDbConnection Connection {
- get { return connection; }
- }
string IService.ServiceName {
get { return "DbConnection"; }
}
}
- public class BansheeDbCommand
+ public sealed class BansheeDbCommand : HyenaDbCommand
{
- private SqliteCommand command;
-
-#region Properties
-
- public SqliteCommand Command {
- get { return command; }
- }
-
- public SqliteParameterCollection Parameters {
- get { return command.Parameters; }
- }
-
- public string CommandText {
- get { return command.CommandText; }
- }
-
-#endregion
-
public BansheeDbCommand(string command)
+ : base(command)
{
- this.command = new SqliteCommand (command);
}
- public BansheeDbCommand (string command, int num_params) : this (command)
+ public BansheeDbCommand (string command, int num_params)
+ : base(command, num_params)
{
- for (int i = 0; i < num_params; i++) {
- Parameters.Add (new SqliteParameter ());
- }
}
- public BansheeDbCommand (string command, params object [] param_values) : this (command, param_values.Length)
- {
- ApplyValues (param_values);
- }
-
- public BansheeDbCommand ApplyValues (params object [] param_values)
- {
- if (param_values.Length != Parameters.Count) {
- throw new ArgumentException (String.Format (
- "Command has {0} parameters, but {1} values given.", Parameters.Count, param_values.Length
- ));
- }
-
- for (int i = 0; i < param_values.Length; i++) {
- Parameters[i].Value = param_values[i];
- }
-
- return this;
- }
-
- public void AddNamedParameter (string name, object value)
- {
- SqliteParameter param = new SqliteParameter (name, DbType.String);
- param.Value = value;
- Parameters.Add (param);
- }
-
- /*public DbCommand(string command, params object [] parameters) : this(command)
- {
- for(int i = 0; i < parameters.Length;) {
- SqliteParameter param;
-
- if(parameters[i] is SqliteParameter) {
- param = (SqliteParameter)parameters[i];
- if(i < parameters.Length - 1 && !(parameters[i + 1] is SqliteParameter)) {
- param.Value = parameters[i + 1];
- i += 2;
- } else {
- i++;
- }
- } else {
- param = new SqliteParameter();
- param.ParameterName = (string)parameters[i];
- param.Value = parameters[i + 1];
- i += 2;
- }
-
- Parameters.Add(param);
- }
- }
-
- public void AddParameter (object value)
+ public BansheeDbCommand (string command, params object [] param_values)
+ : base(command, param_values.Length)
{
- SqliteParameter param = new SqliteParameter ();
- param.Value = value;
- Parameters.Add (param);
}
-
- public void AddParameter<T>(string name, T value)
- {
- AddParameter<T>(new DbParameter<T>(name), value);
- }
-
- public void AddParameter<T>(DbParameter<T> param, T value)
- {
- param.Value = value;
- Parameters.Add(param);
- }*/
}
}
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp Tue Jan 15 18:38:49 2008
@@ -110,6 +110,7 @@
<File name="Banshee.Metadata.Rhapsody/RhapsodyQueryJob.cs" subtype="Code" buildaction="Compile" />
<File name="Banshee.Networking/NetworkDetect.cs" subtype="Code" buildaction="Compile" />
<File name="Banshee.Networking/NetworkManager.cs" subtype="Code" buildaction="Compile" />
+ <File name="Banshee.Collection.Database/BansheeModelProvider.cs" subtype="Code" buildaction="Compile" />
</Contents>
<References>
<ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
Modified: trunk/banshee/src/Core/Banshee.Services/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Makefile.am (original)
+++ trunk/banshee/src/Core/Banshee.Services/Makefile.am Tue Jan 15 18:38:49 2008
@@ -13,6 +13,7 @@
Banshee.Collection.Database/AlbumListDatabaseModel.cs \
Banshee.Collection.Database/ArtistListDatabaseModel.cs \
Banshee.Collection.Database/BansheeCacheableModelAdapter.cs \
+ Banshee.Collection.Database/BansheeModelProvider.cs \
Banshee.Collection.Database/IDatabaseModel.cs \
Banshee.Collection.Database/LibraryAlbumInfo.cs \
Banshee.Collection.Database/LibraryArtistInfo.cs \
Added: trunk/banshee/src/Core/Hyena/Hyena.Data/CacheableDatabaseModelProvider.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data/CacheableDatabaseModelProvider.cs Tue Jan 15 18:38:49 2008
@@ -0,0 +1,298 @@
+//
+// CacheableDatabaseModelProvider.cs
+//
+// Author:
+// Scott Peterson <lunchtimemama gmail com>
+//
+// Copyright (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Data;
+
+namespace Hyena.Data
+{
+ public sealed class DatabaseCacheTable
+ {
+ public static int ModelCount;
+ }
+
+ public abstract class CacheableDatabaseModelProvider<T> : DatabaseModelProvider<T>
+ {
+ private sealed class DatabaseCacheableModelProvider : CacheableModelAdapter<T>
+ {
+ private CacheableDatabaseModelProvider<T> db;
+
+ public DatabaseCacheableModelProvider(ICacheableModel model, CacheableDatabaseModelProvider<T> db)
+ : base(model)
+ {
+ this.db = db;
+ }
+
+ protected override Dictionary<int, T> Cache {
+ get { return db.Cache; }
+ }
+
+ public Dictionary<int, T> CacheImpl {
+ get { return base.Cache; }
+ }
+
+ public override T GetValue(int index)
+ {
+ return db.GetValue(index);
+ }
+
+ public T GetValueImpl(int index)
+ {
+ return base.GetValue(index);
+ }
+
+ public override void Clear()
+ {
+ db.Clear();
+ }
+
+ public void ClearImpl()
+ {
+ base.Clear();
+ }
+
+ protected override void FetchSet(int offset, int limit)
+ {
+ db.FetchSet(offset, limit);
+ }
+
+ protected override void Add(int key, T value)
+ {
+ db.Add(key, value);
+ }
+
+ public void AddImpl(int key, T value)
+ {
+ base.Add(key, value);
+ }
+
+ public override int Reload ()
+ {
+ return db.Reload();
+ }
+
+ public void InvalidateManagedCacheImpl()
+ {
+ InvalidateManagedCache();
+ }
+ }
+
+ private DatabaseCacheableModelProvider cache;
+ private HyenaDbConnection connection;
+ private HyenaDbCommand select_range_command;
+ private HyenaDbCommand count_command;
+ private string reload_sql;
+ private int uid;
+ private int rows;
+ private bool warm;
+
+ private static bool cache_initialized = false;
+
+ protected abstract string ReloadFragment { get; }
+ protected abstract bool Persistent { get; }
+
+ protected virtual string CacheModelsTableName {
+ get { return "HyenaCacheModels"; }
+ }
+
+ protected virtual string CacheTableName {
+ get { return "HyenaCache"; }
+ }
+
+ public CacheableDatabaseModelProvider(HyenaDbConnection connection, ICacheableModel model)
+ : base(connection)
+ {
+ this.connection = connection;
+ cache = new DatabaseCacheableModelProvider(model, this);
+
+ CheckCacheTable();
+
+ count_command = new HyenaDbCommand(String.Format(
+ "SELECT COUNT(*) FROM {0} WHERE ModelID = ?", CacheTableName), 1);
+
+ if(Persistent) {
+ FindOrCreateCacheModelId(TableName);
+ } else {
+ uid = DatabaseCacheTable.ModelCount++;
+ }
+
+ select_range_command = new HyenaDbCommand(Where.Length > 0
+ ? String.Format(@"
+ SELECT {0} FROM {1}
+ INNER JOIN {2}
+ ON {3} = {2}.ItemID
+ WHERE
+ {2}.ModelID = ? AND
+ {4}
+ LIMIT ?, ?", Select, From, CacheTableName, PrimaryKey, Where)
+ : String.Format(@"
+ SELECT {0} FROM {1}
+ INNER JOIN {2}
+ ON {3} = {2}.ItemID
+ WHERE
+ {2}.ModelID = ?
+ LIMIT ?, ?", Select, From, CacheTableName, PrimaryKey), 3);
+
+ reload_sql = String.Format(@"
+ DELETE FROM {0} WHERE ModelID = {1};
+ INSERT INTO {0} SELECT null, {1}, {2} ", CacheTableName, uid, PrimaryKey);
+
+ if (!cache_initialized && !Persistent) {
+ // Invalidate any old cache
+ connection.Execute(String.Format("DELETE FROM {0}", CacheTableName));
+ }
+ cache_initialized = true;
+ }
+
+ private void CheckCacheTable()
+ {
+ using(IDataReader reader = connection.ExecuteReader(GetSchemaSql(CacheTableName))) {
+ if(!reader.Read()) {
+ connection.Execute(String.Format(@"
+ CREATE TABLE {0} (
+ OrderID INTEGER PRIMARY KEY,
+ ModelID INTEGER,
+ ItemID INTEGER)", CacheTableName));
+ }
+ }
+ }
+
+ protected override void PrepareSelectRangeCommand(int offset, int limit)
+ {
+ SelectRangeCommand.ApplyValues(uid, offset, limit);
+ }
+
+ protected override HyenaDbCommand SelectRangeCommand {
+ get { return select_range_command; }
+ }
+
+ protected virtual Dictionary<int, T> Cache {
+ get { return cache.CacheImpl; }
+ }
+
+ public virtual T GetValue(int index)
+ {
+ return cache.GetValueImpl(index);
+ }
+
+ public virtual void Clear()
+ {
+ cache.ClearImpl();
+ }
+
+ protected void InvalidateManagedCache()
+ {
+ cache.InvalidateManagedCacheImpl();
+ }
+
+ protected virtual void Add(int key, T value)
+ {
+ cache.AddImpl(key, value);
+ }
+
+ protected virtual void FetchSet(int offset, int limit)
+ {
+ int i = offset;
+ foreach(T item in FetchRange(offset, limit)) {
+ if(!Cache.ContainsKey(i)) {
+ Add(i, item);
+ }
+ i++;
+ }
+ }
+
+ public virtual int Reload()
+ {
+ InvalidateManagedCache ();
+ connection.Execute(reload_sql + ReloadFragment);
+ UpdateCount();
+ return rows;
+ }
+
+ protected void UpdateCount()
+ {
+ //using (new Timer (String.Format ("Counting items for {0}", db_model))) {
+ rows = Convert.ToInt32(connection.ExecuteScalar(count_command.ApplyValues(uid)));
+ //}
+ }
+
+ private void FindOrCreateCacheModelId(string id)
+ {
+ using(IDataReader reader = connection.ExecuteReader(GetSchemaSql(CacheModelsTableName))) {
+ if(reader.Read()) {
+ uid = connection.QueryInt32(String.Format(
+ "SELECT CacheID FROM {0} WHERE ModelID = '{1}'",
+ CacheModelsTableName, id
+ ));
+ if(uid == 0) {
+ //Console.WriteLine ("Didn't find existing cache for {0}, creating", id);
+ uid = connection.Execute(new HyenaDbCommand(String.Format(
+ "INSERT INTO {0} (ModelID) VALUES (?)",
+ CacheModelsTableName),
+ id
+ ));
+ } else {
+ //Console.WriteLine ("Found existing cache for {0}: {1}", id, uid);
+ warm = true;
+ InvalidateManagedCache();
+ UpdateCount();
+ }
+ }
+ else {
+ connection.Execute(String.Format(
+ "CREATE TABLE {0} (CacheID INTEGER PRIMARY KEY, ModelID TEXT UNIQUE)",
+ CacheModelsTableName));
+ uid = connection.Execute(new HyenaDbCommand(String.Format(
+ "INSERT INTO {0} (ModelID) VALUES (?)",
+ CacheModelsTableName),
+ id
+ ));
+ }
+ }
+ }
+
+ public bool Warm {
+ //get { return warm; }
+ get { return warm; }
+ }
+
+ public int Count {
+ get { return rows; }
+ }
+
+ public int CacheId {
+ get { return uid; }
+ }
+
+ public static implicit operator CacheableModelAdapter<T> (CacheableDatabaseModelProvider<T> cdmp)
+ {
+ return cdmp.cache;
+ }
+ }
+}
\ No newline at end of file
Modified: trunk/banshee/src/Core/Hyena/Hyena.Data/CacheableModelAdapter.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data/CacheableModelAdapter.cs (original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data/CacheableModelAdapter.cs Tue Jan 15 18:38:49 2008
@@ -57,6 +57,11 @@
return default (T);
}
+
+ protected virtual void Add(int key, T value)
+ {
+ Cache.Add(key, value);
+ }
// Responsible for fetching a set of items and placing them in the cache
protected abstract void FetchSet (int offset, int limit);
Added: trunk/banshee/src/Core/Hyena/Hyena.Data/DatabaseModelProvider.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data/DatabaseModelProvider.cs Tue Jan 15 18:38:49 2008
@@ -0,0 +1,818 @@
+//
+// DatabaseCollection.cs
+//
+// Author:
+// Scott Peterson <lunchtimemama gmail com>
+//
+// Copyright (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Reflection;
+using System.Text;
+
+namespace Hyena.Data
+{
+ [Flags]
+ public enum DatabaseBindingFlags
+ {
+ NotNull = 1,
+ PrimaryKey = 2,
+ Unique = 4
+ }
+
+ public abstract class DatabaseColumnBaseAttribute : Attribute
+ {
+ private string column_name;
+
+ public DatabaseColumnBaseAttribute()
+ {
+ }
+
+ public DatabaseColumnBaseAttribute(string column_name)
+ {
+ this.column_name = column_name;
+ }
+
+ public string ColumnName {
+ get { return column_name; }
+ }
+ }
+
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public sealed class DatabaseColumnAttribute : DatabaseColumnBaseAttribute
+ {
+ private DatabaseBindingFlags binding_flags;
+ private string default_value;
+ private string index;
+
+ public DatabaseColumnAttribute()
+ {
+ }
+
+ public DatabaseColumnAttribute(string column_name)
+ : base(column_name)
+ {
+ }
+
+ public DatabaseBindingFlags BindingFlags {
+ get { return binding_flags; }
+ set { binding_flags = value; }
+ }
+
+ public string DefaultValue {
+ get { return default_value; }
+ set { default_value = value; }
+ }
+
+ public string Index {
+ get { return index; }
+ set { index = value; }
+ }
+ }
+
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public sealed class DatabaseVirtualColumnAttribute : DatabaseColumnBaseAttribute
+ {
+ private string target_table;
+ private string target_column;
+ private string local_key;
+ private string foreign_key;
+
+ public DatabaseVirtualColumnAttribute(string column_name, string target_table, string local_key, string foreign_key)
+ : base(column_name)
+ {
+ this.target_table = target_table;
+ this.local_key = local_key;
+ this.foreign_key = foreign_key;
+ }
+
+ public string TargetTable {
+ get { return target_table; }
+ }
+
+ public string LocalKey {
+ get { return local_key; }
+ }
+
+ public string ForeignKey {
+ get { return foreign_key; }
+ }
+ }
+
+ public abstract class DatabaseModelProvider<T>
+ {
+ private abstract class ColumnBase
+ {
+ private readonly DatabaseColumnBaseAttribute attribute;
+ private readonly FieldInfo field_info;
+ private readonly PropertyInfo property_info;
+ private readonly Type type;
+ private readonly string column_type;
+ private readonly string name;
+
+ public ColumnBase(FieldInfo field_info, DatabaseColumnBaseAttribute attribute)
+ : this(attribute, field_info, field_info.FieldType)
+ {
+ this.field_info = field_info;
+ }
+
+ public ColumnBase(PropertyInfo property_info, DatabaseColumnBaseAttribute attribute) :
+ this(attribute, property_info, property_info.PropertyType)
+ {
+ if(!property_info.CanRead || !property_info.CanWrite) {
+ throw new Exception(String.Format("{0}: The property {1} must have both a get and a set " +
+ "block in order to be bound to a database column.",
+ property_info.DeclaringType,
+ property_info.Name));
+ }
+ this.property_info = property_info;
+ }
+
+ private ColumnBase(DatabaseColumnBaseAttribute attribute, MemberInfo member_info, Type type)
+ {
+ if(type.Equals(typeof(string))) {
+ column_type = "TEXT";
+ } else if(type.Equals(typeof(int)) || type.Equals(typeof(long))) {
+ column_type = "INTEGER";
+ } else {
+ throw new Exception(String.Format("{0}.{1}: The type {2} cannot be bound to a database column.",
+ member_info.DeclaringType,
+ member_info.Name,
+ type.FullName));
+ }
+ this.attribute = attribute;
+ this.name = attribute.ColumnName ?? member_info.Name;
+ this.type = type;
+ }
+
+ public object GetValue(T target)
+ {
+ object result;
+ if(field_info != null) {
+ result = field_info.GetValue(target);
+ } else {
+ result = property_info.GetGetMethod(true).Invoke(target, null);
+ }
+ return GetValue(type, result);
+ }
+
+ protected virtual object GetValue(Type type, object value)
+ {
+ return value;
+ }
+
+ public void SetValue(T target, IDataReader reader, int column)
+ {
+ if(field_info != null) {
+ field_info.SetValue(target, SetValue(type, reader, column));
+ } else {
+ property_info.GetSetMethod(true).Invoke(target, new object[] { SetValue(type, reader, column) });
+ }
+ }
+
+ protected virtual object SetValue(Type type, IDataReader reader, int column)
+ {
+ // FIXME should we insist on nullable types?
+ object result;
+ if(type.Equals(typeof(string))) {
+ result = !reader.IsDBNull(column)
+ ? String.Intern(reader.GetString(column))
+ : null;
+ } else if(type.Equals(typeof(int))) {
+ result = !reader.IsDBNull(column)
+ ? reader.GetInt32(column)
+ : 0;
+ } else {
+ result = !reader.IsDBNull(column)
+ ? reader.GetInt64(column)
+ : 0;
+ }
+ return result;
+ }
+
+ public string Name {
+ get { return name; }
+ }
+
+ public string Type {
+ get { return column_type; }
+ }
+ }
+
+ private sealed class Column : ColumnBase
+ {
+ private DatabaseColumnAttribute attribute;
+
+ public Column(FieldInfo field_info, DatabaseColumnAttribute attribute)
+ : base(field_info, attribute)
+ {
+ this.attribute = attribute;
+ }
+
+ public Column(PropertyInfo property_info, DatabaseColumnAttribute attribute)
+ : base(property_info, attribute)
+ {
+ this.attribute = attribute;
+ }
+
+ public DatabaseBindingFlags BindingFlags {
+ get { return attribute.BindingFlags; }
+ }
+
+ public string DefaultValue {
+ get { return attribute.DefaultValue; }
+ }
+
+ public string Index {
+ get { return attribute.Index; }
+ }
+
+ public string Schema {
+ get {
+ StringBuilder builder = new StringBuilder();
+ builder.Append(Name);
+ builder.Append(' ');
+ builder.Append(Type);
+ if((attribute.BindingFlags & DatabaseBindingFlags.NotNull) > 0) {
+ builder.Append(" NOT NULL");
+ }
+ if((attribute.BindingFlags & DatabaseBindingFlags.Unique) > 0) {
+ builder.Append(" UNIQUE");
+ }
+ if((attribute.BindingFlags & DatabaseBindingFlags.PrimaryKey) > 0) {
+ builder.Append(" PRIMARY KEY");
+ }
+ if(attribute.DefaultValue != null) {
+ builder.Append(" DEFAULT ");
+ builder.Append(attribute.DefaultValue);
+ }
+ return builder.ToString();
+ }
+ }
+
+ public override bool Equals(object o)
+ {
+ Column column = o as Column;
+ return o != null && column.Name.Equals(Name);
+ }
+
+ public override int GetHashCode()
+ {
+ return Name.GetHashCode();
+ }
+ }
+
+ private sealed class VirtualColumn : ColumnBase
+ {
+ private DatabaseVirtualColumnAttribute attribute;
+
+ public VirtualColumn(FieldInfo field_info, DatabaseVirtualColumnAttribute attribute)
+ : base(field_info, attribute)
+ {
+ this.attribute = attribute;
+ }
+
+ public VirtualColumn(PropertyInfo property_info, DatabaseVirtualColumnAttribute attribute)
+ : base(property_info, attribute)
+ {
+ this.attribute = attribute;
+ }
+
+ public string TargetTable {
+ get { return attribute.TargetTable; }
+ }
+
+ public string LocalKey {
+ get { return attribute.LocalKey; }
+ }
+
+ public string ForeignKey {
+ get { return attribute.ForeignKey; }
+ }
+ }
+
+ private readonly List<Column> columns = new List<Column>();
+ private readonly List<VirtualColumn> virtual_columns = new List<VirtualColumn>();
+
+ private Column key;
+ private HyenaDbConnection connection;
+
+ private HyenaDbCommand create_command;
+ private HyenaDbCommand insert_command;
+ private HyenaDbCommand update_command;
+ private HyenaDbCommand select_command;
+ private HyenaDbCommand select_range_command;
+ private HyenaDbCommand select_single_command;
+
+ private string primary_key;
+ private string select;
+ private string from;
+ private string where;
+
+ private const string HYENA_DATABASE_NAME = "hyena_database_master";
+
+ protected abstract string TableName { get; }
+ protected abstract int ModelVersion { get; }
+ protected abstract int DatabaseVersion { get; }
+ protected abstract void MigrateTable(int old_version);
+ protected abstract void MigrateDatabase(int old_version);
+ protected abstract T MakeNewObject(int offset);
+
+ protected virtual string HyenaTableName {
+ get { return "HyenaModelVersions"; }
+ }
+
+ protected HyenaDbConnection Connection {
+ get { return connection; }
+ }
+
+ protected DatabaseModelProvider(HyenaDbConnection connection)
+ {
+ foreach(FieldInfo field in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic)) {
+ foreach(Attribute attribute in field.GetCustomAttributes(true)) {
+ AddColumn(field, attribute);
+ }
+ }
+ foreach(PropertyInfo property in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)) {
+ foreach(Attribute attribute in property.GetCustomAttributes(true)) {
+ AddColumn(property, attribute);
+ }
+ }
+ foreach(PropertyInfo property in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic)) {
+ foreach(Attribute attribute in property.GetCustomAttributes(true)) {
+ AddColumn(property, attribute);
+ }
+ }
+
+ if(key == null) {
+ throw new Exception(String.Format("The {0} table does not have a primary key", TableName));
+ }
+
+ this.connection = connection;
+
+ CheckVersion();
+ CheckTable();
+ }
+
+ private void CheckTable()
+ {
+ using(IDataReader reader = connection.ExecuteReader(GetSchemaSql(TableName))) {
+ if(reader.Read()) {
+ Dictionary<string, string> schema = GetSchema(reader);
+ foreach(Column column in columns) {
+ if(!schema.ContainsKey(column.Name)) {
+ connection.Execute(String.Format(
+ "ALTER TABLE {0} ADD {1}", TableName, column.Schema));
+ }
+ if(column.Index != null) {
+ using(IDataReader index_reader = connection.ExecuteReader(GetSchemaSql(column.Index))) {
+ if(!index_reader.Read()) {
+ connection.Execute(String.Format(
+ "CREATE INDEX {0} ON {1}({2})", column.Index, TableName, column.Name));
+ }
+ }
+ }
+ }
+ } else {
+ CreateTable();
+ }
+ }
+ }
+
+ private static Dictionary<string, string> GetSchema(IDataReader reader)
+ {
+ Dictionary<string, string> schema = new Dictionary<string, string>();
+ string sql = reader.GetString(0);
+ sql = sql.Substring(sql.IndexOf('(') + 1);
+ foreach (string column_def in sql.Split (',')) {
+ string column_def_t = column_def.Trim();
+ int ws_index = column_def_t.IndexOfAny(new char [] { ' ', '\t', '\n', '\r' });
+ schema.Add(column_def_t.Substring (0, ws_index), null);
+ }
+ return schema;
+ }
+
+ protected virtual void CheckVersion()
+ {
+ using(IDataReader reader = connection.ExecuteReader(GetSchemaSql(HyenaTableName))) {
+ if(reader.Read()) {
+ using(IDataReader table_reader = connection.ExecuteReader(String.Format(
+ "SELECT version FROM {0} WHERE name = '{1}'", HyenaTableName, TableName))) {
+ if(table_reader.Read()) {
+ int version = table_reader.GetInt32(0);
+ if(version < ModelVersion) {
+ MigrateTable(version);
+ connection.Execute(String.Format(
+ "UPDATE {0} SET version = {1} WHERE name = '{3}'",
+ HyenaTableName, ModelVersion, TableName));
+ }
+ } else {
+ connection.Execute(String.Format(
+ "INSERT INTO {0} (name, version) VALUES ('{1}', {2})",
+ HyenaTableName, TableName, ModelVersion));
+ }
+ }
+ using(IDataReader db_reader = connection.ExecuteReader(String.Format(
+ "SELECT version FROM {0} WHERE name = '{1}'", HyenaTableName, HYENA_DATABASE_NAME))) {
+ db_reader.Read();
+ int version = db_reader.GetInt32(0);
+ if(version < DatabaseVersion) {
+ MigrateDatabase(version);
+ connection.Execute(String.Format(
+ "UPDATE {0} SET version = {1} WHERE name = '{2}'",
+ HyenaTableName, ModelVersion, HYENA_DATABASE_NAME));
+ }
+ }
+ }
+ else {
+ connection.Execute(String.Format(
+ "CREATE TABLE {0} (id INTEGER PRIMARY KEY, name TEXT UNIQUE, version INTEGER)", HyenaTableName));
+ connection.Execute(String.Format(
+ "INSERT INTO {0} (name, version) VALUES ('{1}', {2})",
+ HyenaTableName, HYENA_DATABASE_NAME, DatabaseVersion));
+ connection.Execute(String.Format(
+ "INSERT INTO {0} (name, version) VALUES ('{1}', {2})",
+ HyenaTableName, TableName, ModelVersion));
+ }
+ }
+ }
+
+ protected static string GetSchemaSql(string table_name)
+ {
+ return String.Format("SELECT sql FROM sqlite_master WHERE name = '{0}'", table_name);
+ }
+
+ private void AddColumn(MemberInfo member, Attribute attribute)
+ {
+ DatabaseColumnAttribute column = attribute as DatabaseColumnAttribute;
+ if(column != null) {
+ Column c = member is FieldInfo
+ ? new Column((FieldInfo)member, column)
+ : new Column((PropertyInfo)member, column);
+
+ foreach(Column col in columns) {
+ if(col.Name == c.Name) {
+ throw new Exception(String.Format("{0} has multiple columns named {1}", TableName, c.Name));
+ }
+ if(col.Index != null && col.Index == c.Index) {
+ throw new Exception(String.Format("{0} has multiple indecies named {1}", TableName, c.Name));
+ }
+ }
+
+ columns.Add(c);
+
+ if((c.BindingFlags & DatabaseBindingFlags.PrimaryKey) > 0) {
+ if(key != null) {
+ throw new Exception(String.Format("Multiple primary keys in the {0} table", TableName));
+ }
+ key = c;
+ }
+ }
+ DatabaseVirtualColumnAttribute virtual_column = attribute as DatabaseVirtualColumnAttribute;
+ if(virtual_column != null) {
+ if(member is FieldInfo) {
+ virtual_columns.Add(new VirtualColumn((FieldInfo)member, virtual_column));
+ } else {
+ virtual_columns.Add(new VirtualColumn((PropertyInfo)member, virtual_column));
+ }
+ }
+ }
+
+ protected virtual void CreateTable()
+ {
+ connection.Execute(CreateCommand);
+ foreach(Column column in columns) {
+ if(column.Index != null) {
+ connection.Execute(String.Format(
+ "CREATE INDEX {0} ON {1}({2})", column.Index, TableName, column.Name));
+ }
+ }
+ }
+
+ protected virtual void PrepareInsertCommand(T target)
+ {
+ for(int i = 0; i < columns.Count; i++) {
+ InsertCommand.Parameters[i].Value = columns[i].GetValue(target);
+ }
+ }
+
+ public int Insert(T target)
+ {
+ PrepareInsertCommand(target);
+ return connection.Execute(InsertCommand);
+ }
+
+ protected virtual void PrepareUpdateCommand(T target)
+ {
+ for(int i = 0; i < columns.Count; i++) {
+ UpdateCommand.Parameters[i].Value = columns[i].GetValue(target);
+ }
+ UpdateCommand.Parameters[columns.Count].Value = key.GetValue(target);
+ }
+
+ public void Update(T target)
+ {
+ PrepareUpdateCommand(target);
+ connection.Execute(UpdateCommand);
+ }
+
+ public void Load(T target, IDataReader reader)
+ {
+ int i = 0;
+
+ foreach(Column column in columns) {
+ column.SetValue(target, reader, i++);
+ }
+
+ foreach(VirtualColumn column in virtual_columns) {
+ column.SetValue(target, reader, i++);
+ }
+ }
+
+ protected virtual void PrepareSelectCommand()
+ {
+ }
+
+ public IEnumerable<T> FetchAll()
+ {
+ PrepareSelectCommand();
+ int i = 1;
+ using(IDataReader reader = connection.ExecuteReader(SelectCommand)) {
+ while(reader.Read()) {
+ T new_object = MakeNewObject(i);
+ Load(new_object, reader);
+ yield return new_object;
+ }
+ }
+ }
+
+ protected virtual void PrepareSelectRangeCommand(int offset, int limit)
+ {
+ SelectRangeCommand.ApplyValues(offset, limit);
+ }
+
+ public IEnumerable<T> FetchRange(int offset, int limit)
+ {
+ PrepareSelectRangeCommand(offset, limit);
+ using(IDataReader reader = connection.ExecuteReader(SelectRangeCommand)) {
+ while(reader.Read()) {
+ T new_object = MakeNewObject(offset++);
+ Load(new_object, reader);
+ yield return new_object;
+ }
+ }
+ }
+
+ protected virtual void PrepareSelectSingleCommand(object id)
+ {
+ SelectSingleCommand.ApplyValues(id);
+ }
+
+ public T FetchSingle(int id)
+ {
+ PrepareSelectSingleCommand(id);
+ using(IDataReader reader = connection.ExecuteReader(SelectSingleCommand)) {
+ if(reader.Read()) {
+ T new_object = MakeNewObject(id);
+ Load(new_object, reader);
+ return new_object;
+ }
+ }
+ return default(T);
+ }
+
+ protected virtual HyenaDbCommand CreateCommand {
+ get {
+ if(create_command == null) {
+ StringBuilder builder = new StringBuilder();
+ builder.Append("CREATE TABLE ");
+ builder.Append(TableName);
+ builder.Append('(');
+ bool first = true;
+ foreach(Column column in columns) {
+ if(first) {
+ first = false;
+ } else {
+ builder.Append(',');
+ }
+ builder.Append(column.Schema);
+ }
+ builder.Append(')');
+ create_command = new HyenaDbCommand(builder.ToString());
+ }
+ return create_command;
+ }
+ }
+
+ protected virtual HyenaDbCommand InsertCommand {
+ get {
+ // FIXME can this string building be done more nicely?
+ if(insert_command == null) {
+ StringBuilder cols = new StringBuilder ();
+ StringBuilder vals = new StringBuilder ();
+ int count = 0;
+ bool first = true;
+ foreach(Column column in columns) {
+ if(first) {
+ first = false;
+ } else {
+ cols.Append(',');
+ vals.Append(',');
+ }
+ cols.Append(column.Name);
+ vals.Append('?');
+ count++;
+ }
+
+ insert_command = new HyenaDbCommand(String.Format(
+ "INSERT INTO {0} ({1}) VALUES ({2})",
+ TableName, cols.ToString(), vals.ToString()), count);
+ }
+ return insert_command;
+ }
+ }
+
+ protected virtual HyenaDbCommand UpdateCommand {
+ get {
+ if(update_command == null) {
+ StringBuilder builder = new StringBuilder();
+ builder.Append("UPDATE ");
+ builder.Append(TableName);
+ builder.Append(" SET ");
+ int count = 0;
+ bool first = true;
+ foreach(Column column in columns) {
+ if(first) {
+ first = false;
+ } else {
+ builder.Append(',');
+ }
+ builder.Append(column.Name);
+ builder.Append(" = ?");
+ count++;
+ }
+ builder.Append(" WHERE ");
+ builder.Append(key.Name);
+ builder.Append(" = ?");
+ count++;
+ update_command = new HyenaDbCommand(builder.ToString(), count);
+ }
+ return update_command;
+ }
+ }
+
+ protected virtual HyenaDbCommand SelectCommand {
+ get {
+ if(select_command == null) {
+ select_command = new HyenaDbCommand(Where.Length > 0
+ ? String.Format("SELECT {0} FROM {1} WHERE {2}", Select, From, Where)
+ : String.Format("SELECT {0} FROM {1}", Select, From));
+ }
+ return select_command;
+ }
+ }
+
+ protected virtual HyenaDbCommand SelectRangeCommand {
+ get {
+ if(select_range_command == null) {
+ select_range_command = new HyenaDbCommand(Where.Length > 0
+ ? String.Format("SELECT {0} FROM {1} WHERE {2} LIMIT ?, ?", Select, From, Where)
+ : String.Format("SELECT {0} FROM {1} LIMIT ?, ?", Select, From), 2);
+ }
+ return select_range_command;
+ }
+ }
+
+ protected virtual HyenaDbCommand SelectSingleCommand {
+ get {
+ if(select_single_command == null) {
+ select_single_command = new HyenaDbCommand(Where.Length > 0
+ ? String.Format("SELECT {0} FROM {1} WHERE {2} AND {3} = ?", Select, From, Where, PrimaryKey)
+ : String.Format("SELECT {0} FROM {1} WHERE {2} = ?", Select, From, PrimaryKey), 1);
+ }
+ return select_single_command;
+ }
+ }
+
+ protected virtual string Select {
+ get {
+ if(select == null) {
+ BuildQuerySql();
+ }
+ return select;
+ }
+ }
+
+ protected virtual string From {
+ get {
+ if(from == null) {
+ BuildQuerySql();
+ }
+ return from;
+ }
+ }
+
+ protected virtual string Where {
+ get {
+ if(where == null) {
+ BuildQuerySql();
+ }
+ return where;
+ }
+ }
+
+ protected string PrimaryKey {
+ get {
+ if(primary_key == null) {
+ primary_key = String.Format("{0}.{1}", TableName, key.Name);
+ }
+ return primary_key;
+ }
+ }
+
+ private void BuildQuerySql()
+ {
+ StringBuilder select_builder = new StringBuilder();
+ bool first = true;
+ foreach(Column column in columns) {
+ if(first) {
+ first = false;
+ } else {
+ select_builder.Append(',');
+ }
+ select_builder.Append(TableName);
+ select_builder.Append('.');
+ select_builder.Append(column.Name);
+ }
+
+ StringBuilder where_builder = new StringBuilder();
+ Dictionary<string, string> tables = new Dictionary<string,string>(virtual_columns.Count + 1);
+ tables.Add(TableName, null);
+ bool first_virtual = true;
+ foreach(VirtualColumn column in virtual_columns) {
+ if(first_virtual) {
+ first_virtual = false;
+ } else {
+ where_builder.Append(" AND ");
+ }
+ if(first) {
+ first = false;
+ } else {
+ select_builder.Append(',');
+ }
+ select_builder.Append(column.TargetTable);
+ select_builder.Append('.');
+ select_builder.Append(column.Name);
+
+ where_builder.Append(column.TargetTable);
+ where_builder.Append('.');
+ where_builder.Append(column.ForeignKey);
+ where_builder.Append(" = ");
+ where_builder.Append(TableName);
+ where_builder.Append('.');
+ where_builder.Append(column.LocalKey);
+
+ if(!tables.ContainsKey(column.TargetTable)) {
+ tables.Add(column.TargetTable, null);
+ }
+ }
+
+ StringBuilder from_builder = new StringBuilder();
+ bool first_tables = true;
+ foreach(KeyValuePair<string, string> pair in tables) {
+ if(first_tables) {
+ first_tables = false;
+ } else {
+ from_builder.Append(',');
+ }
+ from_builder.Append(pair.Key);
+ }
+
+ select = select_builder.ToString();
+ from = from_builder.ToString();
+ where = where_builder.ToString();
+ }
+ }
+}
Added: trunk/banshee/src/Core/Hyena/Hyena.Data/HyenaDbConnection.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data/HyenaDbConnection.cs Tue Jan 15 18:38:49 2008
@@ -0,0 +1,253 @@
+//
+// BansheeDbConnection.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Data;
+using Mono.Data.Sqlite;
+
+namespace Hyena.Data
+{
+ public abstract class HyenaDbConnection : IDisposable
+ {
+ private SqliteConnection connection;
+
+ public HyenaDbConnection() : this(true)
+ {
+ }
+
+ public HyenaDbConnection(bool connect)
+ {
+ if (connect) {
+ Open ();
+ }
+ }
+
+ public void Dispose ()
+ {
+ Close ();
+ }
+
+ public void Open ()
+ {
+ lock (this) {
+ if (connection != null) {
+ return;
+ }
+
+ string dbfile = DatabaseFile;
+ connection = new SqliteConnection (String.Format ("Version=3,URI=file:{0}", dbfile));
+ connection.Open ();
+
+ Execute (@"
+ PRAGMA synchronous = OFF;
+ PRAGMA cache_size = 32768;
+ ");
+ }
+ }
+
+ public void Close ()
+ {
+ lock (this) {
+ if (connection != null) {
+ connection.Close ();
+ connection = null;
+ }
+ }
+ }
+
+#region Convenience methods
+
+ public IDataReader ExecuteReader (SqliteCommand command)
+ {
+ if (command.Connection == null)
+ command.Connection = connection;
+ return command.ExecuteReader ();
+ }
+
+ public IDataReader ExecuteReader (HyenaDbCommand command)
+ {
+ return ExecuteReader (command.Command);
+ }
+
+ public IDataReader ExecuteReader (object command)
+ {
+ return ExecuteReader (new SqliteCommand (command.ToString ()));
+ }
+
+ public object ExecuteScalar (SqliteCommand command)
+ {
+ if (command.Connection == null)
+ command.Connection = connection;
+ return command.ExecuteScalar ();
+ }
+
+ public object ExecuteScalar (HyenaDbCommand command)
+ {
+ return ExecuteScalar (command.Command);
+ }
+
+ public object ExecuteScalar (object command)
+ {
+ return ExecuteScalar (new SqliteCommand (command.ToString ()));
+ }
+
+ public Int32 QueryInt32 (object command)
+ {
+ return Convert.ToInt32 (ExecuteScalar (command));
+ }
+
+ public int Execute (SqliteCommand command)
+ {
+ if (command.Connection == null)
+ command.Connection = connection;
+ command.ExecuteNonQuery ();
+ return command.LastInsertRowID ();
+ }
+
+ public int Execute (HyenaDbCommand command)
+ {
+ return Execute (command.Command);
+ }
+
+ public int Execute (object command)
+ {
+ return Execute (new SqliteCommand (command.ToString ()));
+ }
+
+#endregion
+
+ public abstract string DatabaseFile { get; }
+
+ public IDbConnection Connection {
+ get { return connection; }
+ }
+ }
+
+ public class HyenaDbCommand
+ {
+ private SqliteCommand command;
+
+#region Properties
+
+ public SqliteCommand Command {
+ get { return command; }
+ }
+
+ public SqliteParameterCollection Parameters {
+ get { return command.Parameters; }
+ }
+
+ public string CommandText {
+ get { return command.CommandText; }
+ }
+
+#endregion
+
+ public HyenaDbCommand(string command)
+ {
+ this.command = new SqliteCommand (command);
+ }
+
+ public HyenaDbCommand (string command, int num_params) : this (command)
+ {
+ for (int i = 0; i < num_params; i++) {
+ Parameters.Add (new SqliteParameter ());
+ }
+ }
+
+ public HyenaDbCommand (string command, params object [] param_values) : this (command, param_values.Length)
+ {
+ ApplyValues (param_values);
+ }
+
+ public HyenaDbCommand ApplyValues (params object [] param_values)
+ {
+ if (param_values.Length != Parameters.Count) {
+ throw new ArgumentException (String.Format (
+ "Command has {0} parameters, but {1} values given.", Parameters.Count, param_values.Length
+ ));
+ }
+
+ for (int i = 0; i < param_values.Length; i++) {
+ Parameters[i].Value = param_values[i];
+ }
+
+ return this;
+ }
+
+ public void AddNamedParameter (string name, object value)
+ {
+ SqliteParameter param = new SqliteParameter (name, DbType.String);
+ param.Value = value;
+ Parameters.Add (param);
+ }
+
+ /*public DbCommand(string command, params object [] parameters) : this(command)
+ {
+ for(int i = 0; i < parameters.Length;) {
+ SqliteParameter param;
+
+ if(parameters[i] is SqliteParameter) {
+ param = (SqliteParameter)parameters[i];
+ if(i < parameters.Length - 1 && !(parameters[i + 1] is SqliteParameter)) {
+ param.Value = parameters[i + 1];
+ i += 2;
+ } else {
+ i++;
+ }
+ } else {
+ param = new SqliteParameter();
+ param.ParameterName = (string)parameters[i];
+ param.Value = parameters[i + 1];
+ i += 2;
+ }
+
+ Parameters.Add(param);
+ }
+ }
+
+ public void AddParameter (object value)
+ {
+ SqliteParameter param = new SqliteParameter ();
+ param.Value = value;
+ Parameters.Add (param);
+ }
+
+ public void AddParameter<T>(string name, T value)
+ {
+ AddParameter<T>(new DbParameter<T>(name), value);
+ }
+
+ public void AddParameter<T>(DbParameter<T> param, T value)
+ {
+ param.Value = value;
+ Parameters.Add(param);
+ }*/
+ }
+}
\ No newline at end of file
Modified: trunk/banshee/src/Core/Hyena/Hyena.mdp
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.mdp (original)
+++ trunk/banshee/src/Core/Hyena/Hyena.mdp Tue Jan 15 18:38:49 2008
@@ -40,9 +40,14 @@
<File name="Hyena.Data.Query/QueryField.cs" subtype="Code" buildaction="Compile" />
<File name="Hyena.Data.Query/UserQueryParser.cs" subtype="Code" buildaction="Compile" />
<File name="Hyena.Data.Query/XmlQueryParser.cs" subtype="Code" buildaction="Compile" />
+ <File name="Hyena.Data/HyenaDbConnection.cs" subtype="Code" buildaction="Compile" />
+ <File name="Hyena.Data/DatabaseModelProvider.cs" subtype="Code" buildaction="Compile" />
+ <File name="Hyena.Data/CacheableDatabaseModelProvider.cs" subtype="Code" buildaction="Compile" />
</Contents>
<References>
<ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+ <ProjectReference type="Gac" localcopy="True" refto="Mono.Data.SqliteClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
+ <ProjectReference type="Gac" localcopy="True" refto="System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</References>
<Deployment.LinuxDeployData generateScript="False" />
<MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="Makefile.am">
Modified: trunk/banshee/src/Core/Hyena/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Hyena/Makefile.am (original)
+++ trunk/banshee/src/Core/Hyena/Makefile.am Tue Jan 15 18:38:49 2008
@@ -20,8 +20,11 @@
Hyena.Data.Query/QueryToken.cs \
Hyena.Data.Query/UserQueryParser.cs \
Hyena.Data.Query/XmlQueryParser.cs \
+ Hyena.Data/CacheableDatabaseModelProvider.cs \
Hyena.Data/CacheableModelAdapter.cs \
Hyena.Data/ColumnDescription.cs \
+ Hyena.Data/DatabaseModelProvider.cs \
+ Hyena.Data/HyenaDbConnection.cs \
Hyena.Data/ICacheableModel.cs \
Hyena.Data/ICareAboutView.cs \
Hyena.Data/IFilterable.cs \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]