demo.vala 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. using Invercargill.DataStructures;
  2. using InvercargillSql;
  3. using InvercargillSql.Orm;
  4. using InvercargillSql.Orm.Projections;
  5. using InvercargillSql.Migrations;
  6. using InvercargillSql.Dialects;
  7. /**
  8. * Invercargill-Sql ORM Demo Application
  9. *
  10. * This demo showcases the main features of the Invercargill-Sql ORM:
  11. * - Database migrations
  12. * - Entity mapping and CRUD operations
  13. * - Projection queries (simple, join, aggregate)
  14. */
  15. public int main(string[] args) {
  16. print("=== Invercargill-Sql ORM Demo ===\n\n");
  17. // Allow optional connection string argument
  18. string connection_string = args.length > 1
  19. ? args[1]
  20. : "sqlite::memory:";
  21. try {
  22. // Create and open database connection
  23. var conn = ConnectionFactory.create_and_open(connection_string);
  24. var dialect = new SqliteDialect();
  25. var session = new OrmSession(conn, dialect);
  26. // --- Running Migrations ---
  27. print("--- Running Migrations ---\n");
  28. run_migrations(conn, dialect);
  29. // --- Registering Entity Mappers ---
  30. print("\n--- Registering Entity Mappers ---\n");
  31. register_entities(session);
  32. // --- Registering Projection Definitions ---
  33. print("Registering projection definitions...\n");
  34. register_projections(session);
  35. // --- Inserting Data ---
  36. print("\n--- Inserting Data ---\n");
  37. insert_sample_data(session);
  38. // --- Querying Entities ---
  39. print("\n--- Querying Entities ---\n");
  40. demonstrate_entity_queries(session);
  41. // --- Updating Data ---
  42. print("\n--- Updating Data ---\n");
  43. demonstrate_update(session);
  44. // --- Deleting Data ---
  45. print("\n--- Deleting Data ---\n");
  46. demonstrate_delete(session);
  47. // --- Querying Projections ---
  48. print("\n--- Querying Projections ---\n");
  49. demonstrate_projection_queries(session);
  50. print("\n=== Demo Complete ===\n");
  51. conn.close();
  52. return 0;
  53. } catch (Error e) {
  54. printerr("\n=== Demo failed: %s ===\n", e.message);
  55. return 1;
  56. }
  57. }
  58. void run_migrations(Connection conn, SqlDialect dialect) throws SqlError {
  59. var runner = new MigrationRunner(conn, dialect);
  60. // Register migrations
  61. runner.register_migration(new V001_CreateUsers());
  62. runner.register_migration(new V002_CreateProducts());
  63. runner.register_migration(new V003_CreateOrders());
  64. // Run all pending migrations
  65. runner.migrate_to_latest();
  66. // Get applied migrations count
  67. var applied = runner.get_applied_migrations();
  68. print("Applied %d migrations\n", (int)applied.length);
  69. }
  70. void register_entities(OrmSession session) throws SqlError {
  71. // Register User entity using static configure_mapper method
  72. session.register_with_schema<User>("users", User.configure_mapper);
  73. print("Registered User entity\n");
  74. // Register Product entity
  75. session.register_with_schema<Product>("products", Product.configure_mapper);
  76. print("Registered Product entity\n");
  77. // Register Order entity
  78. session.register_with_schema<Order>("orders", Order.configure_mapper);
  79. print("Registered Order entity\n");
  80. }
  81. void register_projections(OrmSession session) throws ProjectionError {
  82. // Register projections using static configure_projection methods
  83. session.register_projection<UserSummary>(UserSummary.configure_projection);
  84. session.register_projection<OrderDetail>(OrderDetail.configure_projection);
  85. session.register_projection<SalesReport>(SalesReport.configure_projection);
  86. }
  87. void insert_sample_data(OrmSession session) throws SqlError {
  88. // Insert users
  89. var alice = new User();
  90. alice.name = "Alice";
  91. alice.email = "alice@example.com";
  92. alice.age = 30;
  93. alice.is_active = true;
  94. session.insert(alice);
  95. print("Inserted user: %s (ID: %lld)\n", alice.name, alice.id);
  96. var bob = new User();
  97. bob.name = "Bob";
  98. bob.email = "bob@example.com";
  99. bob.age = 22;
  100. bob.is_active = true;
  101. session.insert(bob);
  102. print("Inserted user: %s (ID: %lld)\n", bob.name, bob.id);
  103. var charlie = new User();
  104. charlie.name = "Charlie";
  105. charlie.email = "charlie@example.com";
  106. charlie.age = 35;
  107. charlie.is_active = false;
  108. session.insert(charlie);
  109. print("Inserted user: %s (ID: %lld)\n", charlie.name, charlie.id);
  110. // Insert products
  111. var widget = new Product();
  112. widget.name = "Widget";
  113. widget.category = "Electronics";
  114. widget.price = 29.99;
  115. widget.stock = 100;
  116. session.insert(widget);
  117. print("Inserted product: %s (ID: %lld)\n", widget.name, widget.id);
  118. var gadget = new Product();
  119. gadget.name = "Gadget";
  120. gadget.category = "Electronics";
  121. gadget.price = 49.99;
  122. gadget.stock = 50;
  123. session.insert(gadget);
  124. print("Inserted product: %s (ID: %lld)\n", gadget.name, gadget.id);
  125. var doohickey = new Product();
  126. doohickey.name = "Doohickey";
  127. doohickey.category = "Accessories";
  128. doohickey.price = 9.99;
  129. doohickey.stock = 200;
  130. session.insert(doohickey);
  131. print("Inserted product: %s (ID: %lld)\n", doohickey.name, doohickey.id);
  132. // Insert orders
  133. int order_count = 0;
  134. // Alice orders 2 Widgets
  135. var order1 = create_order(alice.id, widget.id, 2, 59.98, "completed");
  136. session.insert(order1);
  137. order_count++;
  138. // Alice orders 1 Gadget
  139. var order2 = create_order(alice.id, gadget.id, 1, 49.99, "completed");
  140. session.insert(order2);
  141. order_count++;
  142. // Bob orders 3 Doohickeys
  143. var order3 = create_order(bob.id, doohickey.id, 3, 29.97, "pending");
  144. session.insert(order3);
  145. order_count++;
  146. // Charlie orders 1 Widget and 2 Gadgets
  147. var order4 = create_order(charlie.id, widget.id, 1, 29.99, "completed");
  148. session.insert(order4);
  149. order_count++;
  150. var order5 = create_order(charlie.id, gadget.id, 2, 99.98, "completed");
  151. session.insert(order5);
  152. order_count++;
  153. print("Inserted %d orders\n", order_count);
  154. }
  155. Order create_order(int64 user_id, int64 product_id, int64 quantity, double total, string status) {
  156. var order = new Order();
  157. order.user_id = user_id;
  158. order.product_id = product_id;
  159. order.quantity = quantity;
  160. order.total = total;
  161. order.status = status;
  162. order.created_at = new DateTime.now_utc();
  163. return order;
  164. }
  165. void demonstrate_entity_queries(OrmSession session) throws SqlError {
  166. // Query all users
  167. var all_users = session.query<User>().materialise();
  168. print("All users: %d\n", (int)all_users.length);
  169. // Query users over 25
  170. var users_over_25 = session.query<User>()
  171. .where("age > 25")
  172. .materialise();
  173. print("Users over 25: %d\n", (int)users_over_25.length);
  174. // Query active users ordered by age
  175. var active_users = session.query<User>()
  176. .where("is_active == 1")
  177. .order_by("age")
  178. .materialise();
  179. print("Active users ordered by age: ");
  180. var first = true;
  181. foreach (var user in active_users) {
  182. if (!first) print(", ");
  183. print("%s(%lld)", user.name, user.age);
  184. first = false;
  185. }
  186. print("\n");
  187. // Query with pagination
  188. var paged_users = session.query<User>()
  189. .order_by("id")
  190. .limit(2)
  191. .offset(1)
  192. .materialise();
  193. print("Users (page 2, size 2): %d\n", (int)paged_users.length);
  194. }
  195. void demonstrate_update(OrmSession session) throws SqlError {
  196. // Find Alice by ID
  197. var alice = session.query<User>()
  198. .where("id == 1")
  199. .first();
  200. if (alice != null) {
  201. // Update Alice's age
  202. alice.age = 31;
  203. session.update(alice);
  204. print("Updated %s's age to %lld\n", alice.name, alice.age);
  205. // Verify the update
  206. var verified = session.query<User>()
  207. .where("id == 1")
  208. .first();
  209. print("Verified update: %s is now %lld\n", verified.name, verified.age);
  210. }
  211. }
  212. void demonstrate_delete(OrmSession session) throws SqlError {
  213. // Find Bob by name (using age as a proxy since string comparison in expressions may not work)
  214. var bob = session.query<User>()
  215. .where("age == 22")
  216. .first();
  217. if (bob != null) {
  218. print("Deleted user: %s\n", bob.name);
  219. session.delete(bob);
  220. // Verify deletion
  221. var remaining = session.query<User>().materialise();
  222. print("Remaining users: %d\n", (int)remaining.length);
  223. }
  224. }
  225. void demonstrate_projection_queries(OrmSession session) throws SqlError, ProjectionError {
  226. // Simple projection - User summaries
  227. print("\n--- User Summaries ---\n");
  228. var user_summaries = session.query_projection<UserSummary>()
  229. .order_by("user_name")
  230. .materialise();
  231. foreach (var summary in user_summaries) {
  232. print(" [%lld] %s <%s>\n", summary.user_id, summary.user_name, summary.email);
  233. }
  234. print("Total user summaries: %d\n", (int)user_summaries.length);
  235. // Join projection - Order details
  236. print("\n--- Order Details ---\n");
  237. var order_details = session.query_projection<OrderDetail>()
  238. .order_by("order_id")
  239. .materialise();
  240. foreach (var detail in order_details) {
  241. print(" [%lld] %s ordered %dx %s ($%.2f) - %s\n",
  242. detail.order_id, detail.user_name, detail.quantity,
  243. detail.product_name, detail.total, detail.status);
  244. }
  245. print("Total order details: %d\n", (int)order_details.length);
  246. // Aggregate projection - Sales by category
  247. print("\n--- Sales by Category ---\n");
  248. var sales_reports = session.query_projection<SalesReport>()
  249. .order_by_desc("total_revenue")
  250. .materialise();
  251. foreach (var report in sales_reports) {
  252. print(" %s: %lld orders, $%.2f revenue, $%.2f avg\n",
  253. report.category, report.total_orders,
  254. report.total_revenue, report.avg_order_value);
  255. }
  256. print("Total categories: %d\n", (int)sales_reports.length);
  257. // Projection with where clause
  258. print("\n--- Completed Orders ---\n");
  259. var completed_orders = session.query_projection<OrderDetail>()
  260. .where("status == 'completed'")
  261. .materialise();
  262. print("Completed orders: %d\n", (int)completed_orders.length);
  263. }