Consolidated ASP Classic MVC framework from best components
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

440 lignes
17KB

  1. <%
  2. '=======================================================================================================================
  3. ' MIGRATION SYSTEM
  4. '=======================================================================================================================
  5. ' Provides database migration capabilities for version-controlled schema changes.
  6. '
  7. ' Features:
  8. ' - Sequential migration versioning (timestamp-based)
  9. ' - Up/Down migration support
  10. ' - Migration tracking in schema_migrations table
  11. ' - Transaction support for atomic migrations
  12. ' - Migration status checking
  13. '
  14. ' Usage:
  15. ' Set migrator = Migrator()
  16. ' migrator.ApplyMigration "20260109120000_create_users_table.asp"
  17. ' migrator.RollbackMigration "20260109120000_create_users_table.asp"
  18. ' pending = migrator.GetPendingMigrations()
  19. ' applied = migrator.GetAppliedMigrations()
  20. '
  21. Class Migrator_Class
  22. Private m_db
  23. Private m_migrations_path
  24. Private m_schema_table
  25. '-------------------------------------------------------------------------------------------------------------------
  26. Private Sub Class_Initialize()
  27. Set m_db = DAL()
  28. m_schema_table = "schema_migrations"
  29. m_migrations_path = Server.MapPath("../db/migrations/")
  30. End Sub
  31. '-------------------------------------------------------------------------------------------------------------------
  32. ' Ensure the schema_migrations table exists
  33. '-------------------------------------------------------------------------------------------------------------------
  34. Public Sub EnsureSchemaMigrationsTable()
  35. On Error Resume Next
  36. ' Try to query the table - if it doesn't exist, create it
  37. Dim rs
  38. Set rs = m_db.Query("SELECT TOP 1 version FROM " & m_schema_table, empty)
  39. If Err.Number <> 0 Then
  40. ' Table doesn't exist, create it
  41. Err.Clear
  42. On Error GoTo 0
  43. Dim createSQL
  44. createSQL = "CREATE TABLE " & m_schema_table & " (" & _
  45. "version VARCHAR(14) PRIMARY KEY, " & _
  46. "applied_at DATETIME NOT NULL)"
  47. m_db.Execute createSQL, empty
  48. Else
  49. If Not rs Is Nothing Then
  50. rs.Close
  51. Set rs = Nothing
  52. End If
  53. End If
  54. On Error GoTo 0
  55. End Sub
  56. '-------------------------------------------------------------------------------------------------------------------
  57. ' Get all applied migration versions
  58. '-------------------------------------------------------------------------------------------------------------------
  59. Public Function GetAppliedMigrations()
  60. EnsureSchemaMigrationsTable
  61. Dim rs, versions, version
  62. Set versions = Server.CreateObject("Scripting.Dictionary")
  63. Set rs = m_db.Query("SELECT version FROM " & m_schema_table & " ORDER BY version", empty)
  64. Do While Not rs.EOF
  65. version = Trim(rs("version"))
  66. versions.Add version, True
  67. rs.MoveNext
  68. Loop
  69. rs.Close
  70. Set rs = Nothing
  71. Set GetAppliedMigrations = versions
  72. End Function
  73. '-------------------------------------------------------------------------------------------------------------------
  74. ' Get all available migration files
  75. '-------------------------------------------------------------------------------------------------------------------
  76. Public Function GetAvailableMigrations()
  77. Dim fso, folder, files, file
  78. Set fso = Server.CreateObject("Scripting.FileSystemObject")
  79. If Not fso.FolderExists(m_migrations_path) Then
  80. Set GetAvailableMigrations = Server.CreateObject("Scripting.Dictionary")
  81. Exit Function
  82. End If
  83. Set folder = fso.GetFolder(m_migrations_path)
  84. Set files = folder.Files
  85. Dim migrations
  86. Set migrations = Server.CreateObject("Scripting.Dictionary")
  87. For Each file In files
  88. If LCase(fso.GetExtensionName(file.Name)) = "asp" Then
  89. Dim version
  90. version = GetVersionFromFilename(file.Name)
  91. If version <> "" Then
  92. migrations.Add version, file.Name
  93. End If
  94. End If
  95. Next
  96. Set GetAvailableMigrations = migrations
  97. End Function
  98. '-------------------------------------------------------------------------------------------------------------------
  99. ' Get pending migrations (available but not applied)
  100. '-------------------------------------------------------------------------------------------------------------------
  101. Public Function GetPendingMigrations()
  102. Dim applied, available, pending, version
  103. Set applied = GetAppliedMigrations()
  104. Set available = GetAvailableMigrations()
  105. Set pending = Server.CreateObject("Scripting.Dictionary")
  106. For Each version In available.Keys
  107. If Not applied.Exists(version) Then
  108. pending.Add version, available(version)
  109. End If
  110. Next
  111. Set GetPendingMigrations = pending
  112. End Function
  113. '-------------------------------------------------------------------------------------------------------------------
  114. ' Extract version from migration filename
  115. ' Expected format: YYYYMMDDHHMMSS_description.asp
  116. '-------------------------------------------------------------------------------------------------------------------
  117. Private Function GetVersionFromFilename(filename)
  118. Dim parts
  119. parts = Split(filename, "_")
  120. If UBound(parts) >= 0 Then
  121. Dim version
  122. version = parts(0)
  123. ' Validate it's a 14-digit timestamp
  124. If Len(version) = 14 And IsNumeric(version) Then
  125. GetVersionFromFilename = version
  126. Exit Function
  127. End If
  128. End If
  129. GetVersionFromFilename = ""
  130. End Function
  131. '-------------------------------------------------------------------------------------------------------------------
  132. ' Apply a migration (run the Up method)
  133. '-------------------------------------------------------------------------------------------------------------------
  134. Public Sub ApplyMigration(filename)
  135. Dim version
  136. version = GetVersionFromFilename(filename)
  137. If version = "" Then
  138. Err.Raise vbObjectError + 1, "Migrator", "Invalid migration filename format: " & filename
  139. End If
  140. ' Check if already applied
  141. Dim applied
  142. Set applied = GetAppliedMigrations()
  143. If applied.Exists(version) Then
  144. Response.Write "Migration " & version & " already applied. Skipping." & vbCrLf
  145. Exit Sub
  146. End If
  147. Response.Write "Applying migration: " & filename & "..." & vbCrLf
  148. ' Begin transaction
  149. m_db.BeginTransaction
  150. On Error Resume Next
  151. ' Execute the migration file
  152. ExecuteMigrationFile filename, "Up"
  153. If Err.Number <> 0 Then
  154. Dim errMsg
  155. errMsg = "Migration failed: " & Err.Description
  156. m_db.RollbackTransaction
  157. Err.Raise vbObjectError + 2, "Migrator", errMsg
  158. End If
  159. ' Record the migration
  160. m_db.Execute "INSERT INTO " & m_schema_table & " (version, applied_at) VALUES (?, ?)", _
  161. Array(version, Now())
  162. If Err.Number <> 0 Then
  163. Dim recordErr
  164. recordErr = "Failed to record migration: " & Err.Description
  165. m_db.RollbackTransaction
  166. Err.Raise vbObjectError + 3, "Migrator", recordErr
  167. End If
  168. ' Commit transaction
  169. m_db.CommitTransaction
  170. On Error GoTo 0
  171. Response.Write "Migration " & version & " applied successfully." & vbCrLf
  172. End Sub
  173. '-------------------------------------------------------------------------------------------------------------------
  174. ' Rollback a migration (run the Down method)
  175. '-------------------------------------------------------------------------------------------------------------------
  176. Public Sub RollbackMigration(filename)
  177. Dim version
  178. version = GetVersionFromFilename(filename)
  179. If version = "" Then
  180. Err.Raise vbObjectError + 1, "Migrator", "Invalid migration filename format: " & filename
  181. End If
  182. ' Check if applied
  183. Dim applied
  184. Set applied = GetAppliedMigrations()
  185. If Not applied.Exists(version) Then
  186. Response.Write "Migration " & version & " not applied. Skipping." & vbCrLf
  187. Exit Sub
  188. End If
  189. Response.Write "Rolling back migration: " & filename & "..." & vbCrLf
  190. ' Begin transaction
  191. m_db.BeginTransaction
  192. On Error Resume Next
  193. ' Execute the migration file
  194. ExecuteMigrationFile filename, "Down"
  195. If Err.Number <> 0 Then
  196. Dim errMsg
  197. errMsg = "Rollback failed: " & Err.Description
  198. m_db.RollbackTransaction
  199. Err.Raise vbObjectError + 4, "Migrator", errMsg
  200. End If
  201. ' Remove the migration record
  202. m_db.Execute "DELETE FROM " & m_schema_table & " WHERE version = ?", version
  203. If Err.Number <> 0 Then
  204. Dim recordErr
  205. recordErr = "Failed to remove migration record: " & Err.Description
  206. m_db.RollbackTransaction
  207. Err.Raise vbObjectError + 5, "Migrator", recordErr
  208. End If
  209. ' Commit transaction
  210. m_db.CommitTransaction
  211. On Error GoTo 0
  212. Response.Write "Migration " & version & " rolled back successfully." & vbCrLf
  213. End Sub
  214. '-------------------------------------------------------------------------------------------------------------------
  215. ' Execute a migration file's Up or Down method
  216. '-------------------------------------------------------------------------------------------------------------------
  217. Private Sub ExecuteMigrationFile(filename, direction)
  218. Dim migrationPath
  219. migrationPath = m_migrations_path & filename
  220. Dim fso
  221. Set fso = Server.CreateObject("Scripting.FileSystemObject")
  222. If Not fso.FileExists(migrationPath) Then
  223. Err.Raise vbObjectError + 6, "Migrator", "Migration file not found: " & migrationPath
  224. End If
  225. ' Create a migration context that the file can use
  226. Dim migration
  227. Set migration = New MigrationContext_Class
  228. Set migration.DB = m_db
  229. ' Include and execute the migration file
  230. Server.Execute(migrationPath)
  231. ' Call the appropriate method (Up or Down)
  232. If direction = "Up" Then
  233. Execute "Call Migration_Up(migration)"
  234. ElseIf direction = "Down" Then
  235. Execute "Call Migration_Down(migration)"
  236. End If
  237. End Sub
  238. '-------------------------------------------------------------------------------------------------------------------
  239. ' Apply all pending migrations
  240. '-------------------------------------------------------------------------------------------------------------------
  241. Public Sub ApplyAllPending()
  242. Dim pending, version, versions()
  243. Set pending = GetPendingMigrations()
  244. If pending.Count = 0 Then
  245. Response.Write "No pending migrations." & vbCrLf
  246. Exit Sub
  247. End If
  248. ' Sort versions
  249. ReDim versions(pending.Count - 1)
  250. Dim i : i = 0
  251. For Each version In pending.Keys
  252. versions(i) = version
  253. i = i + 1
  254. Next
  255. ' Simple bubble sort for versions
  256. Dim j, temp
  257. For i = 0 To UBound(versions) - 1
  258. For j = i + 1 To UBound(versions)
  259. If CLng(versions(i)) > CLng(versions(j)) Then
  260. temp = versions(i)
  261. versions(i) = versions(j)
  262. versions(j) = temp
  263. End If
  264. Next
  265. Next
  266. ' Apply in order
  267. For i = 0 To UBound(versions)
  268. ApplyMigration pending(versions(i))
  269. Next
  270. End Sub
  271. '-------------------------------------------------------------------------------------------------------------------
  272. ' Rollback the last applied migration
  273. '-------------------------------------------------------------------------------------------------------------------
  274. Public Sub RollbackLast()
  275. Dim applied, version, lastVersion
  276. Set applied = GetAppliedMigrations()
  277. If applied.Count = 0 Then
  278. Response.Write "No migrations to rollback." & vbCrLf
  279. Exit Sub
  280. End If
  281. ' Find the last version
  282. lastVersion = ""
  283. For Each version In applied.Keys
  284. If lastVersion = "" Or CLng(version) > CLng(lastVersion) Then
  285. lastVersion = version
  286. End If
  287. Next
  288. ' Find the filename
  289. Dim available
  290. Set available = GetAvailableMigrations()
  291. If available.Exists(lastVersion) Then
  292. RollbackMigration available(lastVersion)
  293. Else
  294. Err.Raise vbObjectError + 7, "Migrator", "Migration file not found for version: " & lastVersion
  295. End If
  296. End Sub
  297. End Class
  298. '=======================================================================================================================
  299. ' MIGRATION CONTEXT
  300. '=======================================================================================================================
  301. ' Provides helper methods for use within migration files
  302. '
  303. Class MigrationContext_Class
  304. Public DB ' Reference to DAL
  305. '-------------------------------------------------------------------------------------------------------------------
  306. ' Execute raw SQL
  307. '-------------------------------------------------------------------------------------------------------------------
  308. Public Sub ExecuteSQL(sql)
  309. DB.Execute sql, empty
  310. End Sub
  311. '-------------------------------------------------------------------------------------------------------------------
  312. ' Create a table
  313. '-------------------------------------------------------------------------------------------------------------------
  314. Public Sub CreateTable(tableName, columns)
  315. Dim sql
  316. sql = "CREATE TABLE " & tableName & " (" & columns & ")"
  317. ExecuteSQL sql
  318. End Sub
  319. '-------------------------------------------------------------------------------------------------------------------
  320. ' Drop a table
  321. '-------------------------------------------------------------------------------------------------------------------
  322. Public Sub DropTable(tableName)
  323. ExecuteSQL "DROP TABLE " & tableName
  324. End Sub
  325. '-------------------------------------------------------------------------------------------------------------------
  326. ' Add a column to a table
  327. '-------------------------------------------------------------------------------------------------------------------
  328. Public Sub AddColumn(tableName, columnName, columnType)
  329. ExecuteSQL "ALTER TABLE " & tableName & " ADD COLUMN " & columnName & " " & columnType
  330. End Sub
  331. '-------------------------------------------------------------------------------------------------------------------
  332. ' Drop a column from a table
  333. '-------------------------------------------------------------------------------------------------------------------
  334. Public Sub DropColumn(tableName, columnName)
  335. ExecuteSQL "ALTER TABLE " & tableName & " DROP COLUMN " & columnName
  336. End Sub
  337. '-------------------------------------------------------------------------------------------------------------------
  338. ' Create an index
  339. '-------------------------------------------------------------------------------------------------------------------
  340. Public Sub CreateIndex(indexName, tableName, columns)
  341. ExecuteSQL "CREATE INDEX " & indexName & " ON " & tableName & " (" & columns & ")"
  342. End Sub
  343. '-------------------------------------------------------------------------------------------------------------------
  344. ' Drop an index
  345. '-------------------------------------------------------------------------------------------------------------------
  346. Public Sub DropIndex(indexName, tableName)
  347. ExecuteSQL "DROP INDEX " & indexName & " ON " & tableName
  348. End Sub
  349. End Class
  350. '=======================================================================================================================
  351. ' SINGLETON
  352. '=======================================================================================================================
  353. Dim Migrator__Singleton : Set Migrator__Singleton = Nothing
  354. Function Migrator()
  355. If Migrator__Singleton Is Nothing Then
  356. Set Migrator__Singleton = New Migrator_Class
  357. End If
  358. Set Migrator = Migrator__Singleton
  359. End Function
  360. %>

Powered by TurnKey Linux.