Consolidated ASP Classic MVC framework from best components
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

440 líneas
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.