Skip to content
Browse files

Added Beta support for GridFS.

  • Loading branch information...
1 parent d0b10a4 commit feb28a6c35383c265034138f1679bdf9ec3f43bc @atheken committed May 31, 2010
View
65 NoRM.Tests/GridFS/GridFileCollectionTests.cs
@@ -6,15 +6,25 @@
using Norm.Tests;
using Norm;
using Norm.GridFS;
+using System.IO;
namespace NoRM.Tests.GridFS
{
public class GridFileCollectionTests
{
+ public GridFileCollectionTests()
+ {
+ using (var conn = Mongo.Create(TestHelper.ConnectionString("strict=false")))
+ {
+ var files = conn.Database.Files();
+ files.Delete(null);
+ }
+ }
+
[Fact]
public void Extension_Methods_Provide_Access_To_Collections()
{
- using(var conn = Mongo.Create(TestHelper.ConnectionString("strict=false")))
+ using (var conn = Mongo.Create(TestHelper.ConnectionString("strict=false")))
{
var fileColl = conn.Database.Files();
Assert.NotNull(fileColl);
@@ -24,12 +34,63 @@ public void Extension_Methods_Provide_Access_To_Collections()
}
[Fact]
+ public void File_Save_Is_Not_Lossy()
+ {
+ using (var conn = Mongo.Create(TestHelper.ConnectionString()))
+ {
+ var ms = new MemoryStream(8000000);//about 8MB.
+ for (int i = 0; i < 2000000; i++)
+ {
+ ms.Write(BitConverter.GetBytes(i), 0, 4);
+ }
+
+ var gridFS = conn.Database.Files();
+ var file = new GridFile();
+ file.ContentType = "application/unknown";
+ file.FileName = "Random_File_Test" + Guid.NewGuid().ToString();
+ file.Aliases = new String[] { "Alpha", "Bravo", "Delta", "Echo" };
+ file.Content = ms.ToArray();
+ gridFS.Save(file);
+
+ var file2 = gridFS.FindOne(new { _id = file.Id });
+
+
+ Assert.Equal(file.Id, file2.Id);
+ Assert.Equal(file.MD5Checksum, file2.MD5Checksum);
+ Assert.Equal(file.ContentType, file2.ContentType);
+ //Mongo stores dates as long, therefore, we have to use double->long rounding.
+ Assert.Equal((long)((file.UploadDate - DateTime.MinValue)).TotalMilliseconds,
+ (long)(file2.UploadDate - DateTime.MinValue).TotalMilliseconds);
+ Assert.True(file.Aliases.SequenceEqual(file2.Aliases));
+ Assert.True(file.Content.SequenceEqual(file2.Content));
+ }
+ }
+
+ [Fact]
public void File_Delete_Works()
{
- using(var conn = Mongo.Create(TestHelper.ConnectionString("strict=false")))
+ using (var conn = Mongo.Create(TestHelper.ConnectionString()))
{
+ var ms = new MemoryStream(50000);
+ for (int i = 0; i < 2000; i++)
+ {
+ ms.Write(BitConverter.GetBytes(i), 0, 4);
+ }
+ var gridFS = conn.Database.Files();
+ var file = new GridFile();
+ file.ContentType = "application/unknown";
+ file.FileName = "Random_File_Test" + Guid.NewGuid().ToString();
+ file.Aliases = new String[] { "Alpha", "Bravo", "Delta", "Echo" };
+ file.Content = ms.ToArray();
+ gridFS.Save(file);
+ var file2 = gridFS.FindOne(new { _id = file.Id });
+ Assert.NotNull(file2);
+ gridFS.Delete(file2.Id);
+ file2 = gridFS.FindOne(new { _id = file.Id });
+ Assert.Null(file2);
}
}
+
}
}
View
85 NoRM/GridFS/FileSummary.cs
@@ -1,85 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Norm.Configuration;
-
-namespace Norm.GridFS
-{
- /// <summary>
- /// Some metadata about a GridFile.
- /// </summary>
- internal class FileSummary
- {
- static FileSummary()
- {
- MongoConfiguration.Initialize(container => container.For<FileSummary>(y =>
- {
- y.ForProperty(j => j.Length).UseAlias("length");
- y.ForProperty(j => j.ChunkSize).UseAlias("chunkSize");
- y.ForProperty(j => j.UploadDate).UseAlias("uploadDate");
- y.ForProperty(j => j.MD5).UseAlias("md5");
- y.ForProperty(j => j.FileName).UseAlias("filename");
- y.ForProperty(j => j.ContentType).UseAlias("contentType");
- y.ForProperty(j => j.Aliases).UseAlias("aliases");
- }));
- }
-
- public FileSummary()
- {
- this.UploadDate = DateTime.Now.ToUniversalTime();
- this.ChunkSize = (256 * 1024);//the suggested 256kB chunk size.
- this.Id = ObjectId.NewObjectId();
- }
-
- /// <summary>
- /// The unique id associated with this file.
- /// </summary>
- /// <remarks>Required.</remarks>
- public ObjectId Id { get; set; }
-
- /// <summary>
- /// The total size of this file.
- /// </summary>
- /// <remarks>Required.</remarks>
- public long Length { get; set; }
-
- /// <summary>
- /// The size of each chunk in the database, should be no more than 4MB.
- /// </summary>
- /// <remarks>Required.</remarks>
- public int ChunkSize { get; set; }
-
- /// <summary>
- /// When was this file created?
- /// </summary>
- /// <remarks>Required.</remarks>
- public DateTime UploadDate { get; set; }
-
- /// <summary>
- /// The MD5 checksum.
- /// </summary>
- /// <remarks>Required.</remarks>
- public String MD5 { get; set; }
-
- /// <summary>
- /// The original file name for this file.
- /// </summary>
- /// <remarks>Optional.</remarks>
- public String FileName { get; set; }
-
- /// <summary>
- /// The MIME type for this document.
- /// </summary>
- /// <remarks>
- /// Optional.
- /// </remarks>
- public String ContentType { get; set; }
-
- /// <summary>
- /// File Aliases.
- /// </summary>
- /// <remarks>Optional.</remarks>
- public IEnumerable<String> Aliases { get; set; }
- }
-}
View
73 NoRM/GridFS/GridFile.cs
@@ -5,6 +5,8 @@
using Norm.Collections;
using System.IO;
using System.Security.Cryptography;
+using Norm.Attributes;
+using Norm.Configuration;
namespace Norm.GridFS
{
@@ -13,25 +15,54 @@ namespace Norm.GridFS
/// </summary>
public class GridFile
{
- /// <summary>
- /// The GridFS representation of this file.
- /// </summary>
- internal FileSummary Summary { get; set; }
+ static GridFile()
+ {
+ MongoConfiguration.Initialize(container => container.For<GridFile>(y =>
+ {
+ y.ForProperty(j => j.Length).UseAlias("length");
+ y.ForProperty(j => j.ChunkSize).UseAlias("chunkSize");
+ y.ForProperty(j => j.UploadDate).UseAlias("uploadDate");
+ y.ForProperty(j => j.MD5Checksum).UseAlias("md5");
+ y.ForProperty(j => j.FileName).UseAlias("filename");
+ y.ForProperty(j => j.ContentType).UseAlias("contentType");
+ y.ForProperty(j => j.Aliases).UseAlias("aliases");
+ }));
+ }
+
+
+ public GridFile()
+ {
+ this.UploadDate = DateTime.Now.ToUniversalTime();
+ this.ChunkSize = (256 * 1024);//the suggested 256kB chunk size.
+ this.Id = ObjectId.NewObjectId();
+ }
+
+ private int Length { get; set; }
+ private int ChunkSize { get; set; }
/// <summary>
/// The collection in which this file's chunks live.
/// </summary>
+ [MongoIgnore]
internal IQueryable<FileChunk> Chunks { get; set; }
/// <summary>
/// Lazily load the queryable chunks.
/// </summary>
+ [MongoIgnore]
internal List<FileChunk> CachedChunks
{
get
{
if (this._cachedChunks == null)
{
- this._cachedChunks = this.Chunks.ToList();
+ if (this.Chunks != null)
+ {
+ this._cachedChunks = this.Chunks.ToList();
+ }
+ else
+ {
+ this._cachedChunks = new List<FileChunk>(0);
+ }
}
return this._cachedChunks;
}
@@ -40,7 +71,7 @@ private set
this._cachedChunks = value.ToList();
}
}
-
+
private List<FileChunk> _cachedChunks;
/// <summary>
@@ -49,8 +80,8 @@ private set
/// <remarks>Required.</remarks>
public ObjectId Id
{
- get { return this.Summary.Id; }
- set { this.Summary.Id = value; }
+ get;
+ set;
}
/// <summary>
@@ -59,8 +90,8 @@ public ObjectId Id
/// <remarks>Required.</remarks>
public DateTime UploadDate
{
- get { return this.Summary.UploadDate; }
- set { this.Summary.UploadDate = value; }
+ get;
+ set;
}
/// <summary>
@@ -69,8 +100,8 @@ public DateTime UploadDate
/// <remarks>Required.</remarks>
public String MD5Checksum
{
- get { return this.Summary.MD5; }
- set { this.Summary.MD5 = value; }
+ get;
+ set;
}
/// <summary>
@@ -79,9 +110,8 @@ public String MD5Checksum
/// <remarks>Optional.</remarks>
public String FileName
{
-
- get { return this.Summary.FileName; }
- set { this.Summary.FileName = value; }
+ get;
+ set;
}
/// <summary>
@@ -92,8 +122,8 @@ public String FileName
/// </remarks>
public String ContentType
{
- get { return this.Summary.ContentType; }
- set { this.Summary.ContentType = value; }
+ get;
+ set;
}
/// <summary>
@@ -102,14 +132,15 @@ public String ContentType
/// <remarks>Optional.</remarks>
public IEnumerable<String> Aliases
{
- get { return this.Summary.Aliases; }
- set { this.Summary.Aliases = value; }
+ get;
+ set;
}
/// <summary>
/// The content of this file.
/// </summary>
/// <returns></returns>
+ [MongoIgnore]
public IEnumerable<byte> Content
{
get
@@ -126,7 +157,7 @@ public IEnumerable<byte> Content
do
{
var binary = value.Skip(cursor)
- .Take(this.Summary.ChunkSize).ToArray();
+ .Take(this.ChunkSize).ToArray();
takeCount = binary.Length;
cursor += takeCount;
@@ -139,7 +170,7 @@ public IEnumerable<byte> Content
chunkNumber++;
}
} while (takeCount > 0);
- this.Summary.Length = cursor;
+ this.Length = cursor;
var hash = hasher.ComputeHash(this.CachedChunks.SelectMany(y => y.BinaryData).ToArray());
this.MD5Checksum = BitConverter.ToString(hash).Replace("-", "");
}
View
44 NoRM/GridFS/GridFileCollection.cs
@@ -10,40 +10,52 @@ namespace Norm.GridFS
public class GridFileCollection
{
private IMongoCollection<FileChunk> FileChunks { get; set; }
- private IMongoCollection<FileSummary> FileSummaries { get; set; }
+ private IMongoCollection<GridFile> FileSummaries { get; set; }
- internal GridFileCollection(IMongoCollection<FileSummary> fileSummaries, IMongoCollection<FileChunk> fileChunks)
+ internal GridFileCollection(IMongoCollection<GridFile> fileSummaries, IMongoCollection<FileChunk> fileChunks)
{
this.FileChunks = fileChunks;
this.FileSummaries = fileSummaries;
}
public void Save(GridFile file)
{
- this.FileSummaries.Update(new { _id = file.Id }, file.Summary, false, true);
+ this.FileSummaries.Save(file);
this.FileChunks.Delete(new { _id = file.Id });
- this.FileChunks.Insert(file.CachedChunks);
+ if (file.CachedChunks.Any())
+ {
+ this.FileChunks.Insert(file.CachedChunks);
+ }
}
/// <summary>
/// Finds and returns the first file that matches the criteria.
/// </summary>
- /// <param name="matchCriteria"></param>
+ /// <param name="template"></param>
/// <returns></returns>
- public GridFile FindOne(Expression<Func<GridFile, bool>> matchCriteria)
+ public GridFile FindOne<U>(U template)
{
- return null;
+ var retval = this.FileSummaries.FindOne(template);
+ if(retval != null)
+ {
+ retval.Chunks = this.FileChunks.AsQueryable().Where(y => y.FileID == retval.Id).OrderBy(j => j.ChunkNumber);
+ }
+ return retval;
}
/// <summary>
/// Returns all the files that match the criteria.
/// </summary>
/// <param name="matchCriteria"></param>
/// <returns></returns>
- public IEnumerable<GridFile> Find(Expression<Func<GridFile, bool>> matchCriteria)
+ public IEnumerable<GridFile> Find<U>(U template)
{
-
- return Enumerable.Empty<GridFile>();
+ foreach (var f in this.FileSummaries.Find(template))
+ {
+ f.Chunks = this.FileChunks.AsQueryable().Where(y=>y.FileID == f.Id).OrderBy(j => j.ChunkNumber);
+ yield return f;
+ }
+ yield break;
}
@@ -54,8 +66,16 @@ public IEnumerable<GridFile> Find(Expression<Func<GridFile, bool>> matchCriteria
/// <param name="IDofFileToDelete"></param>
public void Delete(ObjectId IDofFileToDelete)
{
- this.FileSummaries.Delete(new { _id = IDofFileToDelete });
- this.FileChunks.Delete(new { _id = IDofFileToDelete });
+ if (IDofFileToDelete != null)
+ {
+ this.FileSummaries.Delete(new { _id = IDofFileToDelete });
+ this.FileChunks.Delete(new { _id = IDofFileToDelete });
+ }
+ else
+ {
+ this.FileSummaries.Delete(new { });
+ this.FileChunks.Delete(new { });
+ }
}
}
}
View
4 NoRM/GridFS/Helpers.cs
@@ -19,7 +19,7 @@ public static class Helpers
/// <returns></returns>
public static GridFileCollection Files<T>(this IMongoCollection<T> rootCollection)
{
- return new GridFileCollection(rootCollection.GetChildCollection<FileSummary>("files"),
+ return new GridFileCollection(rootCollection.GetChildCollection<GridFile>("files"),
rootCollection.GetChildCollection<FileChunk>("chunks"));
}
@@ -30,7 +30,7 @@ public static GridFileCollection Files<T>(this IMongoCollection<T> rootCollectio
/// <returns></returns>
public static GridFileCollection Files(this MongoDatabase database)
{
- return new GridFileCollection(database.GetCollection<FileSummary>("files"),
+ return new GridFileCollection(database.GetCollection<GridFile>("files"),
database.GetCollection<FileChunk>("chunks"));
}
}
View
1 NoRM/NoRM.csproj
@@ -156,7 +156,6 @@
<Compile Include="Connections\Server.cs" />
<Compile Include="Connections\TimedLock.cs" />
<Compile Include="GridFS\FileChunk.cs" />
- <Compile Include="GridFS\FileSummary.cs" />
<Compile Include="GridFS\GridFile.cs" />
<Compile Include="GridFS\GridFileCollection.cs" />
<Compile Include="GridFS\Helpers.cs" />

0 comments on commit feb28a6

Please sign in to comment.
Something went wrong with that request. Please try again.