column-builder.vala 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. using Invercargill.DataStructures;
  2. using InvercargillSql.Orm;
  3. namespace InvercargillSql.Migrations {
  4. /**
  5. * Column builder for migrations that provides a fluent API for configuring column definitions.
  6. *
  7. * This builder is used within migration operations to configure column properties.
  8. * All configuration methods return this builder for method chaining.
  9. *
  10. * Example usage within a migration:
  11. * {{{
  12. * b.create_table("users")
  13. * .column<int64>("id", c => c.type_int().primary_key().auto_increment())
  14. * .column<string>("email", c => c.type_text().not_null().unique())
  15. * .execute();
  16. * }}}
  17. */
  18. public class MigrationColumnBuilder : Object {
  19. private MigrationBuilder? _migration_parent;
  20. private TableBuilder? _table_parent;
  21. private AlterTableBuilder? _alter_parent;
  22. private ColumnDefinition _column;
  23. private string? _table_name;
  24. // Index support
  25. private bool _should_create_index = false;
  26. private string? _index_name = null;
  27. // Foreign key support
  28. private ForeignKeyBuilder? _fk_builder = null;
  29. /**
  30. * Protected constructor for subclasses like ForeignKeyBuilder.
  31. */
  32. protected MigrationColumnBuilder.for_subclass() {
  33. _column = new ColumnDefinition();
  34. }
  35. /**
  36. * Creates a new MigrationColumnBuilder with a MigrationBuilder parent.
  37. *
  38. * @param parent the parent MigrationBuilder to return to after configuration
  39. * @param table_name the name of the table this column belongs to
  40. * @param column the column definition being configured
  41. */
  42. internal MigrationColumnBuilder(MigrationBuilder parent, string table_name, ColumnDefinition column) {
  43. _migration_parent = parent;
  44. _table_name = table_name;
  45. _column = column;
  46. }
  47. /**
  48. * Creates a new MigrationColumnBuilder with a TableBuilder parent.
  49. *
  50. * @param parent the parent TableBuilder to return to after configuration
  51. * @param column the column definition being configured
  52. */
  53. internal MigrationColumnBuilder.for_table(TableBuilder parent, ColumnDefinition column) {
  54. _table_parent = parent;
  55. _column = column;
  56. }
  57. /**
  58. * Creates a new MigrationColumnBuilder with an AlterTableBuilder parent.
  59. *
  60. * @param parent the parent AlterTableBuilder to return to after configuration
  61. * @param table_name the name of the table this column belongs to
  62. * @param column the column definition being configured
  63. */
  64. internal MigrationColumnBuilder.for_alter(AlterTableBuilder parent, string table_name, ColumnDefinition column) {
  65. _alter_parent = parent;
  66. _table_name = table_name;
  67. _column = column;
  68. }
  69. /**
  70. * Sets the column type to INTEGER.
  71. *
  72. * @return this builder for method chaining
  73. */
  74. public MigrationColumnBuilder type_int() {
  75. _column.column_type = ColumnType.INT_64;
  76. return this;
  77. }
  78. /**
  79. * Sets the column type to TEXT.
  80. *
  81. * @return this builder for method chaining
  82. */
  83. public MigrationColumnBuilder type_text() {
  84. _column.column_type = ColumnType.TEXT;
  85. return this;
  86. }
  87. /**
  88. * Sets the column type to REAL.
  89. *
  90. * @return this builder for method chaining
  91. */
  92. public MigrationColumnBuilder type_real() {
  93. _column.column_type = ColumnType.DECIMAL;
  94. return this;
  95. }
  96. /**
  97. * Sets the column type to BLOB.
  98. *
  99. * @return this builder for method chaining
  100. */
  101. public MigrationColumnBuilder type_blob() {
  102. _column.column_type = ColumnType.BINARY;
  103. return this;
  104. }
  105. /**
  106. * Sets the column type to DATETIME.
  107. *
  108. * @return this builder for method chaining
  109. */
  110. public MigrationColumnBuilder type_datetime() {
  111. _column.column_type = ColumnType.DATETIME;
  112. return this;
  113. }
  114. /**
  115. * Sets the column type to BOOLEAN.
  116. *
  117. * @return this builder for method chaining
  118. */
  119. public MigrationColumnBuilder type_boolean() {
  120. _column.column_type = ColumnType.BOOLEAN;
  121. return this;
  122. }
  123. /**
  124. * Marks this column as the primary key.
  125. *
  126. * Only one column per table should be marked as primary key.
  127. *
  128. * @return this builder for method chaining
  129. */
  130. public MigrationColumnBuilder primary_key() {
  131. _column.is_primary_key = true;
  132. return this;
  133. }
  134. /**
  135. * Marks this column as NOT NULL.
  136. *
  137. * @return this builder for method chaining
  138. */
  139. public MigrationColumnBuilder not_null() {
  140. _column.is_required = true;
  141. return this;
  142. }
  143. /**
  144. * Marks this column as UNIQUE.
  145. *
  146. * @return this builder for method chaining
  147. */
  148. public MigrationColumnBuilder unique() {
  149. _column.is_unique = true;
  150. return this;
  151. }
  152. /**
  153. * Marks this column as auto-incrementing.
  154. *
  155. * Typically used for integer primary keys.
  156. *
  157. * @return this builder for method chaining
  158. */
  159. public MigrationColumnBuilder auto_increment() {
  160. _column.auto_increment = true;
  161. return this;
  162. }
  163. /**
  164. * Sets a default value for this column.
  165. *
  166. * @param value the default value to use when inserting records
  167. * @return this builder for method chaining
  168. */
  169. public MigrationColumnBuilder default_value<T>(T value) {
  170. _column.default_value = new Invercargill.NativeElement<T>(value);
  171. return this;
  172. }
  173. /**
  174. * Marks this column to use the current timestamp as default.
  175. *
  176. * Only applicable to DATETIME columns.
  177. *
  178. * @return this builder for method chaining
  179. */
  180. public MigrationColumnBuilder default_now() {
  181. _column.default_now = true;
  182. return this;
  183. }
  184. /**
  185. * Adds a foreign key reference to another table.
  186. *
  187. * This method creates a ForeignKeyBuilder that allows configuring the FK
  188. * constraint with methods like .name(), .on_delete_cascade(), etc.
  189. * The ForeignKeyBuilder extends MigrationColumnBuilder, so column methods
  190. * can still be called after FK configuration.
  191. *
  192. * Example:
  193. * {{{
  194. * t.column<int64?>("user_id")
  195. * .not_null()
  196. * .references("users", "id")
  197. * .name("fk_orders_users")
  198. * .on_delete_cascade()
  199. * .indexed(); // Can continue with column methods
  200. * }}}
  201. *
  202. * @param table the referenced table name
  203. * @param column the referenced column name in the foreign table
  204. * @return a ForeignKeyBuilder for configuring the FK constraint
  205. */
  206. public ForeignKeyBuilder references(string table, string column) {
  207. _fk_builder = new ForeignKeyBuilder(this, table, column);
  208. return _fk_builder;
  209. }
  210. /**
  211. * Marks this column to have an index created for it.
  212. *
  213. * The index uniqueness is automatically inferred from the column's is_unique property.
  214. * If a custom index name is needed, pass it as the name parameter.
  215. *
  216. * Example:
  217. * {{{
  218. * // Basic index with auto-generated name (idx_{table}_{column})
  219. * t.column<string>("email").not_null().indexed();
  220. *
  221. * // Unique index - uniqueness inferred from column's unique() flag
  222. * t.column<string>("email").unique().indexed();
  223. *
  224. * // Index with custom name
  225. * t.column<string>("email").indexed("idx_users_email_address");
  226. * }}}
  227. *
  228. * @param name optional custom index name; if null, auto-generated as idx_{table}_{column}
  229. * @return this builder for method chaining
  230. */
  231. public MigrationColumnBuilder indexed(string? name = null) {
  232. _should_create_index = true;
  233. _index_name = name;
  234. return this;
  235. }
  236. /**
  237. * Whether an index should be created for this column.
  238. * TableBuilder uses this to determine if an index operation is needed.
  239. */
  240. public bool should_create_index { get { return _should_create_index; } }
  241. /**
  242. * The custom index name, or null if auto-generation should be used.
  243. * Auto-generated format: idx_{table}_{column}
  244. */
  245. public string? index_name { get { return _index_name; } }
  246. /**
  247. * The ForeignKeyBuilder if a foreign key was configured via references().
  248. * TableBuilder uses this to collect FK constraints from column definitions.
  249. */
  250. public ForeignKeyBuilder? fk_builder { get { return _fk_builder; } }
  251. /**
  252. * Returns to the parent MigrationBuilder.
  253. *
  254. * This method navigates through the parent chain to find the MigrationBuilder.
  255. *
  256. * @return the parent MigrationBuilder
  257. */
  258. internal virtual MigrationBuilder return_to_migration() {
  259. if (_migration_parent != null) return _migration_parent;
  260. if (_table_parent != null) return _table_parent.return_to_migration();
  261. if (_alter_parent != null) return _alter_parent.return_to_migration();
  262. assert_not_reached();
  263. }
  264. }
  265. }