The IMiFileSystem
object is one of the most likely object to replace if you're implementing your own storage mechanism. It is used to read and write files.
#r "nuget: Migrondi.Core, 1.0.0-beta-010"
open System
open Migrondi.Core.FileSystem
open Migrondi.Core.Serialization
open Microsoft.Extensions.Logging
let logger =
// create a sample logger, you can provide your own
LoggerFactory.Create(fun builder -> builder.AddConsole() |> ignore)
|> fun x -> x.CreateLogger("FileSystem")
let serializer = MigrondiSerializer()
let rootDir = Uri("https://my-storage.com/project-a/", UriKind.Absolute)
let migrationsDir = Uri("./migrations/", UriKind.Relative)
NOTE: Please keep in mind that URI objects treat trailing shashes differently, since we're using them to represent directories. The
Uri
object must contain the trailing slash from therootDir
andmigrationsDir
objects. If you fail to ensure the trailing slash is there, the library will not work as expected.
let fs: IMiFileSystem =
MiFileSystem(logger, serializer, serializer, rootDir, migrationsDir)
In order to list the migrations in the file system, you can call the ListMigrations(targetDirectory)
method.
fs.ListMigrations("./")
Internally this will build the URI from the rootDir
and migrationsDir
objects, and then list the files in the directory.
So you have to keep into consideration how will you take external paths and convert them into URIs to be used by the library.
This is mainly an implementation detail, but it's important to keep in mind when you're implementing your own IMiFileSystem
object.
A simplified way to list the migrations internally that we currently do is similar to the following:
// usually "readFrom" is the content of config.migrationsDir
let listMigrations (readFrom: string) =
let path = Uri(rootDir, readFrom)
let dir = IO.DirectoryInfo(path.LocalPath)
// list all files in the directory
// filter out the ones that are migrations (we have a specific schema for the file name)
// for each found file, decode the text and return migration object otherwise return an error
[]
When you read a migration file specifically you can call the ReadMigration(readFrom)
method.
This readFrom is the relative path to the migrationsDir
objects including the name of the file.
e.g.
fs.ReadMigration("initial-tables_1708216610033.sql")
This will build the URI from the rootDir
and migrationsDir
objects, and then read the file. Internally it looks like this:
let readMigration (readFrom: string) =
let path = Uri(rootDir, Uri(migrationsDir, readFrom))
let file = IO.File.ReadAllText(path.LocalPath)
let migration = (serializer :> IMiMigrationSerializer).DecodeText(file)
migration
Writing a migration is similar, and usually we don't write migrations directly, but we do it through the serializers.
fs.WriteMigration(
{
name = "initial-tables_1708216610033"
timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds()
upContent = "CREATE TABLE users (id INT, name VARCHAR(255));"
downContent = "DROP TABLE users;"
manualTransaction = false
},
"initial-tables_1708216610033.sql"
)
In this case it just means that you need to know how you will want to store the migrations in your own backing store.
type LoggerFactory = interface ILoggerFactory interface IDisposable new: unit -> unit + 5 overloads member AddProvider: provider: ILoggerProvider -> unit member CreateLogger: categoryName: string -> ILogger member Dispose: unit -> unit static member Create: configure: Action<ILoggingBuilder> -> ILoggerFactory
<summary> Produces instances of <see cref="T:Microsoft.Extensions.Logging.ILogger" /> classes based on the given providers. </summary>
--------------------
LoggerFactory() : LoggerFactory
LoggerFactory(providers: Collections.Generic.IEnumerable<ILoggerProvider>) : LoggerFactory
LoggerFactory(providers: Collections.Generic.IEnumerable<ILoggerProvider>, filterOptions: LoggerFilterOptions) : LoggerFactory
LoggerFactory(providers: Collections.Generic.IEnumerable<ILoggerProvider>, filterOption: Extensions.Options.IOptionsMonitor<LoggerFilterOptions>) : LoggerFactory
LoggerFactory(providers: Collections.Generic.IEnumerable<ILoggerProvider>, filterOption: Extensions.Options.IOptionsMonitor<LoggerFilterOptions>, options: Extensions.Options.IOptions<LoggerFactoryOptions>) : LoggerFactory
LoggerFactory(providers: Collections.Generic.IEnumerable<ILoggerProvider>, filterOption: Extensions.Options.IOptionsMonitor<LoggerFilterOptions>, ?options: Extensions.Options.IOptions<LoggerFactoryOptions>, ?scopeProvider: IExternalScopeProvider) : LoggerFactory
(extension) ILoggingBuilder.AddConsole(configure: Action<Console.ConsoleLoggerOptions>) : ILoggingBuilder
(extension) ILoggerFactory.CreateLogger(``type`` : Type) : ILogger
ILoggerFactory.CreateLogger(categoryName: string) : ILogger
type MigrondiSerializer = interface IMiConfigurationSerializer interface IMiMigrationSerializer new: unit -> MigrondiSerializer
--------------------
new: unit -> MigrondiSerializer
type Uri = interface ISpanFormattable interface IFormattable interface ISerializable new: uriString: string -> unit + 6 overloads member Equals: comparand: obj -> bool member GetComponents: components: UriComponents * format: UriFormat -> string member GetHashCode: unit -> int member GetLeftPart: part: UriPartial -> string member IsBaseOf: uri: Uri -> bool member IsWellFormedOriginalString: unit -> bool ...
<summary>Provides an object representation of a uniform resource identifier (URI) and easy access to the parts of the URI.</summary>
--------------------
Uri(uriString: string) : Uri
Uri(uriString: string, creationOptions: inref<UriCreationOptions>) : Uri
Uri(uriString: string, uriKind: UriKind) : Uri
Uri(baseUri: Uri, relativeUri: string) : Uri
Uri(baseUri: Uri, relativeUri: Uri) : Uri
<summary>Defines the different kinds of URIs.</summary>
<summary> This is an abstraction to the file system, it allows for custom implementations to either use a physical file system or even a virtual one. It provides both sync and async methods to read and write migrondi specific files. </summary>
type MiFileSystem = interface IMiFileSystem new: logger: ILogger * configurationSerializer: IMiConfigurationSerializer * migrationSerializer: IMiMigrationSerializer * projectRootUri: Uri * migrationsRootUri: Uri -> MiFileSystem
--------------------
new: logger: ILogger * configurationSerializer: IMiConfigurationSerializer * migrationSerializer: IMiMigrationSerializer * projectRootUri: Uri * migrationsRootUri: Uri -> MiFileSystem
val string: value: 'T -> string
--------------------
type string = String
type DirectoryInfo = inherit FileSystemInfo new: path: string -> unit member Create: unit -> unit member CreateSubdirectory: path: string -> DirectoryInfo member Delete: unit -> unit + 1 overload member EnumerateDirectories: unit -> IEnumerable<DirectoryInfo> + 3 overloads member EnumerateFileSystemInfos: unit -> IEnumerable<FileSystemInfo> + 3 overloads member EnumerateFiles: unit -> IEnumerable<FileInfo> + 3 overloads member GetDirectories: unit -> DirectoryInfo array + 3 overloads member GetFileSystemInfos: unit -> FileSystemInfo array + 3 overloads ...
<summary>Exposes instance methods for creating, moving, and enumerating through directories and subdirectories. This class cannot be inherited.</summary>
--------------------
IO.DirectoryInfo(path: string) : IO.DirectoryInfo
<summary>Gets a local operating-system representation of a file name.</summary>
<exception cref="T:System.InvalidOperationException">This instance represents a relative URI, and this property is valid only for absolute URIs.</exception>
<returns>The local operating-system representation of a file name.</returns>
<summary>Provides static methods for the creation, copying, deletion, moving, and opening of a single file, and aids in the creation of <see cref="T:System.IO.FileStream" /> objects.</summary>
IO.File.ReadAllText(path: string, encoding: Text.Encoding) : string
<summary> This service is responsible for serializing and deserializing the migration files. The default implementation coordinates between the v0.x and the v1.x formats to provide backwards compatibility. </summary>
[<Struct>] type DateTimeOffset = new: dateTime: DateTime -> unit + 8 overloads member Add: timeSpan: TimeSpan -> DateTimeOffset member AddDays: days: float -> DateTimeOffset member AddHours: hours: float -> DateTimeOffset member AddMicroseconds: microseconds: float -> DateTimeOffset member AddMilliseconds: milliseconds: float -> DateTimeOffset member AddMinutes: minutes: float -> DateTimeOffset member AddMonths: months: int -> DateTimeOffset member AddSeconds: seconds: float -> DateTimeOffset member AddTicks: ticks: int64 -> DateTimeOffset ...
<summary>Represents a point in time, typically expressed as a date and time of day, relative to Coordinated Universal Time (UTC).</summary>
--------------------
DateTimeOffset ()
DateTimeOffset(dateTime: DateTime) : DateTimeOffset
DateTimeOffset(dateTime: DateTime, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(ticks: int64, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(date: DateOnly, time: TimeOnly, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, microsecond: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, microsecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : DateTimeOffset
<summary>Gets a <see cref="T:System.DateTimeOffset" /> object that is set to the current date and time on the current computer, with the offset set to the local time's offset from Coordinated Universal Time (UTC).</summary>
<returns>A <see cref="T:System.DateTimeOffset" /> object whose date and time is the current local time and whose offset is the local time zone's offset from Coordinated Universal Time (UTC).</returns>