Modern Database Techniques with the Postrelational DBMS Caché

Total Page:16

File Type:pdf, Size:1020Kb

Modern Database Techniques with the Postrelational DBMS Caché

Modern Database Techniques I Exercises

Modern Database Techniques with the Postrelational DBMS Caché Exercises Document Conventions 1. Some exercises don't show every necessary step. Be aware that there might be more tasks necessary to complete a given step. 2. When specifying attributes and parameters for class definitions, remember that these values may be entered directly in the code window, or by using the inspector. These exercises show these values as they would appear in the code window, so some strings are contained within quotes. If you choose to enter the values in the inspector, remove the outer pair of quotes. Note: the PATTERN parameter may itself contain quotes, which must be doubled inside quotes. To enter the pattern in the inspector, remove the outer pair of quotes, and un-double any inner quotes. 3. This folder contains .txt files containing predefined test code, and .xml files containing predefined classes. 4. Instructor note: There are notes in the slides that refer to related exercises.

1 Modern Database Techniques I Exercises

E-13: Develop UML class diagram for FCE application. 1. Homework: For the example scenario "Foreign Cash Exchange" develop an UML class diagram 2. See description in chapter 2 3. Work in groups of two (or three) 4. Explain your solution to the class 5. Discuss the presented solution

E-14: Exercise: Create OOP unit test for FCE.Branch class. Create the FCE.Branch class. 6. These are possible specifications for objects of class Branch.  A Branch must have a name.  A Branch must have a phone number.  The phone number must only contain numbers and the characters + or -, + only as first character.  The phone number must be unique  The opening time cannot be before 5:00 am.  The closing time cannot be after 10:00 pm.  If either Opens or Closes is present the other time must be set, too (not in actual test code, will be investigated later).  Opens must be before Closes (not in actual test code, will be investigated later). 7. As a class, transfer specifications into test steps. Write them on board: 8. Demonstration: Follow the steps of your teacher: 9. Start Studio. Click File  Change Namespace to switch to the FCE namespace. 10.Click File  New. On the General tab, double-click Caché Class Definition. Enter a package name: FCE.Tests Enter a class name: BasicTests. Click Next. For Class Type, click Extends, and enter %UnitTest.TestCase in the text box. Click Finish. 11.Save the class. 12.Inside the class {}, enter the following code, which sets up some parameters and calls RunTest() to run the tests for this class: /// Helper method ClassMethod Run() { set classname = ..%ClassName(1) // "this" classname set spec = "Foundation:" _ classname set quals = "/noload/norecursive" do ##class(%UnitTest.Manager).RunTest(spec, quals) quit } 13.Inside the class {}, enter the following code: /// Basic tests for FCE.Branch Method TestBranch() { }

2 Modern Database Techniques I Exercises

14.As a class, write unit test assertions on board. Solution in branchtestcode.txt. 15.Copy code from branchtestcode.txt. Compile the class. 16.Start Terminal. Run the tests (unit test code fails because class doesn't exist): FCE>do ##class(FCE.Tests.BasicTests).Run() 17.Click File  New. On the General tab, double-click Caché Class Definition. Enter a package name: FCE. Enter a class name: Branch. Click Next. Accept default Persistent for Class Type. Click Next. Click XML and Automatic Data Population options. Click Finish. 18.Save the class. 19.Click the New Property toolbar button (a yellow house): Enter a name: Name. Click Next. A single value of type: %String. Click Finish. 20.Click the New Property toolbar button: Enter a name: Phone. Click Next. A single value of type: %String. Click Next. Click Required and Unique options. Click Next. Click in the box to the right of the PATTERN parameter, and enter: 0.1"+"1. (1n,1"-",1" "). This means 0 to 1 times the character "+", then at least once or arbitrarily often one of the following: one digit or one hyphen or one blank For the MAXLEN parameter, enter 20. Click Finish. 21.Enter the following code in the Code Window, anywhere inside main pair of {}. This defines the properties Opens and Closes: /// Time branch opens Property Opens As %Time;

/// Time branch closes Property Closes As %Time; 22.Note contents of Code Window: Class statement. Class extends (inherits from) 3 classes: %Persistent, %XML.Adaptor, %Populate. 4 Property statements. Note Required attribute and PATTERN parameter for Phone property. Note %Time datatype represents seconds since midnight. 1 Index statement. Note Unique attribute for Phone index. 23.Note contents of Class Inspector: Class definition. 4 Property definitions. 1 Index definition. 24.Using the Class Inspector, in the left-hand dropdown list, click Property. Double-click the Opens property. Scroll down to MAXVAL and MINVAL in the Parameters section. For MINVAL parameter, enter: 18000 (5 am). 25.Repeat previous step for the Closes property. For MAXVAL parameter, enter: 79200 (10pm). 3 Modern Database Techniques I Exercises

26.Compile the class. 27.Run the tests (all assertions pass): FCE>do ##class(FCE.Tests.BasicTests).Run() 28.Run tests again (all assertions pass).

E-15: Add OOP unit test for FCE.RealEstate. Create the FCE.RealEstate class. Update FCE.Branch definition to use new FCE.RealEstate class. 1. Add the following code to the FCE.Tests.BasicTests class (you can find the code in realestatetestcode.txt): /// Basic tests for FCE.RealEstate Method TestRealEstate() { /* Only banks in the USA are considered. Address structure corresponds to addresses in the USA. */ // assertion 1 set realestate = ##class(FCE.RealEstate).%New() set status = realestate.%Save() do $$$AssertStatusNotOK(status, "Real Estate requires all 4 properties") // assertion 2 set realestate.Street = "10 Wall St." set status = realestate.%Save() do $$$AssertStatusNotOK(status, "Real Estate requires all 4 properties") // assertion 3 set realestate.City = "New York" set status = realestate.%Save() do $$$AssertStatusNotOK(status, "Real Estate requires all 4 properties") // assertion 4 set realestate.State = "ny" set status = realestate.%Save() do $$$AssertStatusNotOK(status, "State must be 2 uppercase letters") // assertion 5 set realestate.State = "NY" set status = realestate.%Save() do $$$AssertStatusNotOK(status, "Real Estate requires all 4 properties") // assertion 6 set realestate.Zip = "123" set status = realestate.%Save() do $$$AssertStatusNotOK(status, "ZipCode must be ##### or #####-####") // assertion 7 set realestate.Zip = "12345-1" set status = realestate.%Save() do $$$AssertStatusNotOK(status, "ZipCode must be ##### or #####-####") // assertion 8 set realestate.Zip = "10011-4567" set status = realestate.%Save() set realestateid = realestate.%Id() do $$$AssertStatusOK(status, "Real Estate saved") // assertion 9 set branch = ##class(FCE.Branch).%New() set branch.Phone = "212-999-9999" set branch.Address = realestate set status = branch.%Save() set branchid = branch.%Id() do $$$AssertStatusOK(status, "Branch saved") 4 Modern Database Techniques I Exercises

// assertion 10 set (branch, realestate) = "" do $$$AssertStatusOK(1, "All objects closed") // assertion 11 set branch = ##class(FCE.Branch).%OpenId(branchid) set realestate = ##class(FCE.RealEstate).%OpenId(realestateid) do $$$AssertEquals(branch.Address.City, realestate.City, "Branch references Real Estate") // assertion 12 set (branch, realestate) = "" do $$$AssertStatusOK(1, "All objects closed") // assertion 13 set status = ##class(FCE.Branch).%DeleteId(branchid) do $$$AssertStatusOK(status, "Branch deleted") // assertion 14 set realestate = ##class(FCE.RealEstate).%OpenId(realestateid) do $$$AssertNotEquals(realestate, "", "Real Estate not automatically deleted") // assertion 15 set status = ##class(FCE.RealEstate).%DeleteId(realestateid) do $$$AssertStatusOK(status, "Real Estate deleted") } 2. Compile the class. 3. Run tests (unit test code fails). 4. Create the FCE.RealEstate class. Accept default Persistent for Class Type. Click XML and Automatic Data Population options. Add Properties according to the specification:  Real Estate requires all 4 properties: Street, City, State, and Zip  State must be 2 uppercase letters  ZipCode must be ##### or #####-#### For the ZIP-code, add PATTERN parameter: 5n.1(1"-"4n) and for State, add PATTERN parameter: 2u (2 uppercase characters A … Z) 5. Add Property Address of type FCE.RealEstate to FCE.Branch 6. Re-compile FCE.Branch.

E-16: Add SQL unit tests for FCE. Branch and FCE. RealEstate. Use data population method to add data to the FCE.Branch and the FCE.RealEstate class/table. Since there are two ways to access data in the database, by objects or by SQL, also test insert, update and delete operations 1. Add the following code to the FCE.Tests.BasicTests class: /// SQL tests for FCE.Branch table Method TestBranchSQL() { }

/// SQL tests for FCE.RealEstate Method TestRealEstateSQL() { }

5 Modern Database Techniques I Exercises

2. Copy the code in the branchSQLtestcode.txt file into the new method TestBranchSQL (this file contains predefined SQL test code) and the realestateSQLtestcode.txt code into the method TestRealEstateSQL. 3. Ensure that you understand SQL code and assertions. TestBranchSQL() is the SQL version of TestBranch(). 4. Compile the class. 5. Run tests. All assertions pass. 1. Using Terminal, enter this line of code to add 30 new real estate addresses. FCE>do ##class(FCE.RealEstate).Populate(30) 2. Using Terminal, enter this line of code to add 5 new branches. FCE>do ##class(FCE.Branch).Populate(5) 3. Use the SQL section of the Portal to see the new data.

E-17: Create the FCE.ATM class. Add OOP unit tests for FCE.ATM.CurrencyBalances. Add CurrencyBalances property to FCE.ATM. Add SQL unit tests for FCE.ATM_CurrencyBalances. 4. Define (informal) test steps for FCE.ATM and for FCE.ATM.CurrencyBalances.  An ATM belongs to exactly one Branch. It can't exist without a branch.  An ATM requires a serial number.  An ATM may have a manufacturer stored as Brand  Each ATM has a real estate as an Address  Test, if the number of ATMs of a branch equals the number of ATMs you have assigned to this branch.  If an ATM has currency balances, no balance may be negative.  An ATM must not have two entries for the same currency. (This is automatically true if you choose array of %Numeric as data type for CurrencyBalances.)  If the branch is deleted, all ATMs belonging to the branch have to be deleted, too. 5. Compare your test steps with the test code provided in the files atmtestcode.txt and atmSQLtestcode.txt. 6. In Studio, create the FCE.ATM class according to the specification in the test code add the CurrencyBalances property. A collection of type: array, containing elements of type: %Numeric. For the MINVAL parameter, enter 0. 7. Demonstration: Follow the steps of your teacher: Since an ATM cannot exist without a branch, define ATM as dependent class of FCE.Branch. In Caché use a parent-children relationship to do so. 8. Compile the class. 9. Add the methods TestATM and TestATMSQL provided in the files atmtestcode.txt and atmSQLtestcode.txt to the FCE.Tests.BasicTests class. 10.Compile the test class, run tests, and correct your FCE.ATM class until all assertions pass.

6 Modern Database Techniques I Exercises

E-18: Use Portal to write query which uses -> operator. 1. In Portal, click SQL  Execute SQL Statement. Enter the queries you developed in "Practice: Query with -> Operator" in Part 1, Chapter 4.3. Click Execute Query.

E-19: View storage definition for FCE.Branch and FCE.ATM. 1. Using the Portal, look for the globals that store Branches and ATMs. If your system stores Branches and ATMs in the same global, goto step 5. Otherwise, follow the next steps, which will change the storage definitions so that Branches and ATMs are stored in the same global. 2. Delete ^FCE.Branch* and ^FCE.ATM* globals. 3. Using the Inspector, for both FCE.Branch and FCE.ATM classes, locate their Default storage definition, right-click and click Delete. Save both classes, and click Build  Rebuild All to recompile all classes in your project. 4. Look at ^FCE.BranchD to confirm that Branch and ATM data is stored in this global. 5. View the object ids of branches and ATMs. 6. Try to change an object id using SQL. 7. Each object has an Id and an Oid. What is the difference? To find out run the following commands: FCE>set br = ##class(FCE.Branch).%OpenId(Id of an existing branch) FCE>write br.%Id() FCE>write br.%Oid()

E-20: Import the FCE.Person class. 1. Include the Person class into the FCE project, as it has been defined in Part 1, 4.1. To do so, open the menu Tools in Studio, click Import local, and open the file FCE.Person.xml.

E-21: Create subclasses FCE.Employee and FCE.Customer of FCE.Person. Create FCE.Account. Don't implement Companies as Customers because they do not change money at ATMs. Therefore they are not considered in this application. 1. Define class FCE.Employee as subclass of FCE.Person as described in "Sample Scenario" in Part 1, 1: Like Persons, additionally Task, Salary, SSN, Branch, Supervisor, … 2. Define class FCE.Customer as subclass of FCE.Person as described in "Sample Scenario" in Part 1, 1: Like Persons, additionally CustomerNr, CostomerSince, Credit Rating 3. Define class FCE.Account as a limited version of real accounts only suitable for cash exchange. Do not consider transactions and interests. Description: A customer may have many accounts, but each account belongs to one customer. Accounts have a Nr, a balance and a currency.

E-22: Create the FCE.Address abstract class. View inherited members of FCE.RealEstate class. 1. Now there are two similar address classes in the project: RealEstate and AddressCl. The difference is, that in AddressCl you may also have mailing addresses and international

7 Modern Database Techniques I Exercises

addresses whereas in RealEstate there are only US Addresses. Define an abstract super class for AddressCl and RealEstate. 2. Create the FCE.Address class. Specify Abstract for Class Type. Click Finish. 3. Add %Populate, %XML.Adaptor as superclasses. 4. Move (don't copy) all properties and methods from FCE.RealEstate and FCE.AddressCl to FCE.Address, which are identical in both classes. 5. Change superclasses of FCE.RealEstate and FCE.AddressCl to (%Persistent, FCE. Address). 6. Build your project. Run FCE.Tests.BasicTests to verify everything still works. 7. Using the Inspector, in left-hand dropdown list, click Method (no methods listed). Right-click anywhere in Inspector and click Show Inherited Members (many inherited methods listed).

E-23: Implement the M:N relation: Employees advise Customers. 1. Many employees advise many customers in different subject areas like loans, investments, or online banking. 2. Import the test class FCE.Tests.PersonTests in File FCE.Tests.PersonTests.xml. Look at the test cases and implement additional constraints in FCE.Employee and FCE.Customer, e. g. SSN required for an employee. 3. Run the tests and correct your person classes until all tests pass.

E-24: Generalize ATM and Branch classes to a CashLocation superclass 1. ATMs and Branches have two things in common: They have real estate addresses and they store different currencies. Therefore they can be generalized to a superclass. The advantage is that the methods to deal with currency balances only have to be implemented once. 2. Create the FCE.CashLocation class. Specify Abstract for Class Type. Click Finish. 3. Add %Populate as superclass. 4. Move (don't copy) the property Address from FCE.ATM and FCE.Branch to FCE.CashLocation. 5. Move (don't copy) the property CurrencyBalances from FCE.ATM to FCE.CashLocation. 6. Add FCE.CashLocation to list of superclasses of FCE.Branch and FCE.ATM. 7. Build your project. Run FCE.Tests.BasicTests to verify everything still works.

E-25: Add a class query to FCE.ATM to sum balances and count ATMs by currency. Test class queries using ODBC. 1. Define a SQL query that calculates the sum of the currency amounts of all ATMs for every currency available in any ATM. Additionally this query should calculate the number of ATMs that provide a currency. Show only those currencies with a sum greater or equal than the minimum parameter. (Use group by and having.) 2. Add the following class query code to the FCE.ATM class: /// Sum currency amounts and count ATMs, by currency Query CurrencySummary(minimum = 0) As %SQLQuery { Insert your query from step 1 here 8 Modern Database Techniques I Exercises

} 3. Test the class query after when the classes are populated with data.

E-26: Add Code to populate CurrencyBalances for ATMs. 1. Define a class FCE.Currency that serves as a look up table for currencies and exchange rates. The code is also provided in FCE.Currency.txt. Class FCE.Currency Extends (%Persistent, %XML.Adaptor) { Property Name As %String [ Required ]; Index NameIndex On Name [ Unique ]; Property IsBaseCurrency As %Boolean [ Required ]; // BaseCurrency = ExchangeRateToBase * Currency Property ExchangeRateToBase As %Numeric(MINVAL = 0);

/// Randomly select a currency name for use as collection key in an ATM's CurrencyBalance ClassMethod RandCurrency() As %String { set rs = ##class(%ScrollableResultSet).%New("FCE.Currency:Extent") set status = rs.Execute() if '(status = $$$OK) quit "" set randomItem = $random(rs.Count()) + 1 set row = rs.CurrRowSet(randomItem) set cid = $get(rs.Data("ID")) set c = ##class(FCE.Currency).%OpenId(cid) do rs.Close() quit c.Name } } 2. Insert at least 8 currencies of your choice, e. g. "US Dollars", "Euros", "Indian Rupees", "Venezuelan Bolivares", "Japanese Yen", "Mexican Pesos", "South African Rands", "Brazilian Reais", "Canadian Dollars", "Russian Rubles" 3. Go to the class definition of FCE.CashLocation. Using the Class Inspector, in the left-hand dropdown list, click Property. Double-click the CurrencyBalances property. Scroll down to POPSPEC in the Parameters section. Click in the box to the right of the POPSPEC parameter, and enter: :5:##class(FCE.Currency).RandCurrency() 4. Using Terminal, enter: FCE>do ##class(FCE.ATM).Populate(15) 5. Use the Portal to view the FCE.ATM_CurrencyBalances table. Note Currency_Balances column contains positive numeric values. Note element_key column contains generated currency name from FCE.Currency table.

E-27: Create the FCE.Tests.Utilities class, and add DestroyAll() and CreateAll() methods. 1. Create the FCE.Tests.Utilitiies class. For Class Type, click Extends, but don’t enter anything in the text box. Click Finish. Save the class. 2. Inside the class {}, enter the following code or copy it from FCE.Tests.Utilities.txt: /// Delete all data and run tests ClassMethod DestroyAll() { 9 Modern Database Techniques I Exercises

do ##class(FCE.Branch).%KillExtent() do ##class(FCE.RealEstate).%KillExtent() do ##class(FCE.Customer).%KillExtent() do ##class(FCE.Employee).%KillExtent() read !, "Data Deleted. Press to run tests.", x do ##class(FCE.Tests.BasicTests).Run() read !, "Press to continue.", x do ##class(FCE.Tests.PersonTests).Run() read !, "Press to continue.", x } 3. Inside the class {}, enter the following code: /// Create data and run tests ClassMethod CreateAll() { do ##class(FCE.RealEstate).Populate(20) do ##class(FCE.Branch).Populate(5) do ##class(FCE.ATM).Populate(15) do ##class(FCE.Customer).Populate(15) do ##class(FCE.Employee).Populate(15) read !, "Data added. Press to run tests.", x do ##class(FCE.Tests.BasicTests).Run() read !, "Press to continue.", x do ##class(FCE.Tests.PersonTests).Run() read !, "Press to continue.", x } 4. Using Portal, clean up old globals. Select all FCE* globals except FCE.CurrencyD and FCE.CurrencyI. Click Delete. 5. Run the DestroyAll() and CreateAll() methods (all assertions pass, both times). Note: in some cases, DestroyAll() won’t destroy the ATMs of a Branch, causing some assertion failures. If this happens, add the following line to DestroyAll() to destroy them explicitly: do ##class(FCE.ATM).%KillExtent() This may happen if the FCE.ATM class is compiled separately without and before the FCE.Branch class is compiled. In this case delete the storage definition of FCE.ATM using studios' inspector, too. Then recompile FCE.Branch. 6. Use the Portal to see the data from all tables.

10 Modern Database Techniques I Exercises

E-28: View a ResultSet. Test class queries using ODBC. 1. Using Terminal, enter this code to test the new query, and the Extent query. FCE>set class = "FCE.ATM" FCE>set query = "CurrencySummary" FCE>do ##class(%ResultSet).RunQuery(class,query) FCE>do ##class(%ResultSet).RunQuery(class,query,10000) FCE>set query = "Extent" FCE>do ##class(%ResultSet).RunQuery(class,query) 2. Start WinSQL or DbVisualizer. Connect to the FCE (or your DAPROxx) namespace. Specify User ID and Password in the ODBC Data Source dialog in WinSQL if necessary. 3. Click the Query tab. Enter: call FCE.ATM_CurrencySummary. Click the button to run the statement. 4. Enter and run: call FCE.ATM_CurrencySummary(20000). 5. Enter and run: call FCE.ATM_Extent.

E-29: Add FCE.CurrencyOrder class and related items. Note: Do exercise using pair programming. One student is the driver, and the other student is the navigator, while writing the unit tests (steps 1-6). Students switch roles to develop the class (steps 7-9). 1. Look carefully at the definition of the FCE.CurrencyOrder persistent class, and the Create() method signature, in steps 5-7 below. This will prepare you to write the tester for this method now. 2. Create a new unit testing class: FCE.Tests.CurrencyOrderTests. Use the FCE.Tests.BasicTests class as a guide. Make sure to include the Run() method in the new class. 3. In the FCE.Tests.CurrencyOrderTests class, add the TestCurrencyOrderCreate() method. Signature: Method TestCurrencyOrderCreate() Specification:  Set a variable for each argument of the Create() method of the FCE.CurrencyOrder class to some value, except for the exchangeRate argument.  Set the variables for requestedAmount and suppliedAmount to prohibited values, call Create(), and assert that the method failed (use $$$AssertNotEquals and $IsObject).  Set the requestedAmount and suppliedAmount variables to valid values, call Create() again, and assert that the method succeeded (use $$$AssertEquals and $IsObject).  Delete the order, and assert that the order was deleted (use $$$AssertStatusOK). 4. Compile the class. Run the tests from Terminal (all assertions fail). do ##class(FCE.Tests.CurrencyOrderTests).Run() 5. Add the FCE.CurrencyOrder persistent class. Property Type Attributes/Parameters  Requestor %String  RequestorEmail %String  RequestedAmount %Numeric MINVAL = .01  RequestedCurrency %String POPSPEC = "##class(FCE.Currency).RandCurrency()"  SuppliedAmount %Numeric MINVAL = .01  SuppliedCurrency %String POPSPEC = "##class(FCE.Currency).RandCurrency()" 11 Modern Database Techniques I Exercises

 ExchangeRate %Float MINVAL = 0  Fee %Numeric  DateStamp %Date MAXVAL = "+$system.SYS.TimeStamp()"  TimeStamp %Time  Status %String VALUELIST = ",Requested,Pending,Rejected,Paid, Completed,Problem,Canceled" Note: RequestedCurrency and SuppliedCurrency are of type %String and not FCE.Currency because older CurrencyOrders need not refer to actual currencies in FCE.Currency. 6. Enter this Status property description in the Code Window: /// Requested: initial request /// Pending: only if awaiting approval /// Rejected: not enough stock, or not approved by bank /// Paid: supplied currency received, requested currency to be picked up /// Completed: requested currency paid to customer /// Problem: problem in system /// Canceled: canceled by customer 7. In the FCE.CurrencyOrder class, add a Create() method. This is a user defined constructor method. Signature: ClassMethod Create(requestor As %String, requestorEmail As %String, requestedCurrency As %String, requestedAmount As %Numeric, suppliedCurrency As %String, suppliedAmount As %Numeric, exchangeRate As %Float = 1, fee As %Numeric) As FCE.CurrencyOrder Specification:  Create a new FCE.CurrencyOrder, assign "Requested" status, and assign the properties to the arguments.  Save the object. If successful (use $$$OK), return the object; otherwise, return a null object (use $$ $NULLOREF). 8. Create a one-to-many relationship between FCE.ATM and FCE.CurrencyOrder. Property Type  FCE.ATM.Orders FCE.CurrencyOrder  FCE.CurrencyOrder.ATM FCE.ATM 9. Add a new argument to the Create method of FCE.CurencyOrder: ATM as FCE.ATM. Alter the TestCurrencyOrderCreate method in FCE.Tests.CurrencyOrderTests accordingly. 10.Run the tests from Terminal (all assertions pass).

E-30: Add methods to FCE.ATM and FCE.RealEstate classes. 1. Look carefully at the Update() method signature, in step 4 below. This will prepare you to understand the tester for this method now. 2. In the FCE.Tests.CurrencyOrderTests class, add a TestATMUpdate() method by copying the code from FCE.TestATMUpdate.txt. Here is the specification of the test method for easier reading:  Create a branch and an ATM, and link them.  Assign amounts to ATM's Euros and US Dollars currencies (use SetAt()).  Set a variable for each argument of the Update() method of FCE.ATM class, setting a very large requestedAmount.  Call Update(), and assert that the method failed (use $$$AssertStatusNotOK).  Set a valid requestedAmount, call Update(), and assert that the method succeeded (use $$ $AssertStatusOK).  Retrieve the updated currency values (GetAt()), and assert that they match predicted values (use $$ $AssertEquals).  Delete the branch. 12 Modern Database Techniques I Exercises

3. Run the tests from Terminal (all new assertions fail). 4. In the FCE.ATM class, add an Update() method. Signature: Method Update(requestedCurrency As %String, requestedAmount As %Numeric, suppliedCurrency As %String, suppliedAmount As %Numeric) As %Status Specification:  Debit the requested currency by the requested amount. If the result would be less than 0, return a general error with the message "ATM out of stock" (use $$$ERROR($$$GeneralError,"ATM out of stock")), and don't save.  If supplied amount isn't positive, return $$$OK, skipping the following step (this handles non-cash payments for a later exercise).  Credit the supplied currency by the supplied amount.  Return $$$OK. 5. Run the tests from Terminal (all new assertions pass). Export changed classes and move to the other student's machine. 6. In the FCE.Tests.Utilities class, update methods DestroyAll() and CreateAll(). Add code to destroy/create currency orders, and to run the currency order tests. Place a "Press to continue" line before running each test case. Run both methods, and ensure that they work. 7. In the FCE.RealEstate class, add a Print() method. Signature: Method Print() Specification:  Print the address in mailing label format (2 lines). 8. Using Terminal, open a Branch or ATM object and test the Print() method.

E-31: Add business logic to the FCE.ATM class and create related items. This is the standard process flow for a currency exchange:  User comes to an ATM  User requests an exchange  User provides all information: requested currency, supplied currency, supplied amount, name, …  ATM sends information to Server as arguments of a method ProcessRequest.  ProcessRequest creates a currency order, and tests whether there is enough money of requested currency in ATM  If all tests pass, supplied amount is calculated  The Server sends all order data back to ATM  User accepts data, hits OK button, and supplies money. If supplied money is ok, ATM gives requested amount.  ATM calls ProcessOrder  In a transaction ProcessOrder reflects all actions of the real ATM: decrease balance of requested currency and increase balance of supplied currency. 1. In the FCE.Tests.CurrencyOrderTests class, add the TestProcessRequest() and TestProcessOrder() methods. Signatures: Method TestProcessRequest() Method TestProcessOrder() 2. Retrieve the method code for both methods from FCE.Tests.ordertestcode1.txt, and paste it in. 3. Work in pairs to verbalize what each test method does. 13 Modern Database Techniques I Exercises

4. Run the tests from Terminal (all assertions fail). 5. In the class FCE.Currency add the classmethod GetExchangeRate /// Calculate Exchange Rate ClassMethod GetExchangeRate(requestedCurrency As %String, suppliedCurrency As %String) As %Float { &sql(select ExchangeRateToBase into :ERreq from FCE.Currency where Name = :requestedCurrency) &sql(select ExchangeRateToBase into :ERsup from FCE.Currency where Name = :suppliedCurrency) set rate = ERreq/ERsup quit rate } 6. Define two methods, ProcessRequest and ProcessOrder, and the classmethod SendConfirmation in FCE.ATM. You can copy the code from FCE.ProcessRequest.txt. Don't forget to define the parameter 'FEERATE'. Compare the code to your solution of Practice: Develop Method(s) to Process a Request. The method ProcessRequest() accepts an exchange request and creates a new CurrencyOrder object. The method ProcessOrder() then processes the request stored in the CurrencyOrder object. Both methods are called from a client which in this application is an ATM or a computer program simulating an ATM. 7. Do this step only if the classroom has access to an SMTP server, and you have access to your email account (business or personal): In the FCE. ATM class, enable the SendConfirmation() method. In the FCE.Tests.CurrencyOrderTests class, edit the TestProcessOrder() method, and specify your email address in the requestorEmail variable. 8. Run the tests from Terminal (all assertions pass).

E-32: Create FCE.Payment, FCE.Cash, FCE.CreditCard, and FCE.AccountPayment classes. Import related unit test class. The cash exchange model is enhanced: Users can not only provide money as cash but also by credit card or by an account. Therefore an abstract payment class is created with three subclasses, one for each payment type. Every currency order has one related payment object. The payment classes store the appropriate information for the payment, e. g. the account number. The classes also provide a method, that produce a string which is returned to the user of the ATM. 9. Create a new persistent class: FCE.Payment. It should extend %Persistent, %Populate, and %XML.Adaptor. After you finish creating the class using the wizard, change the Abstract attribute to True. 10.Define subclasses FCE.CashPayment, FCE.CreditCardPayment, and FCE.AccountPayment 11.Create a parent-to-children relationship from FCE.CurrencyOrder to the FCE.Payment class, with property: Property Type Attributes/Parameters  Payment FCE.Payment Cardinality = children, Inverse = CurrencyOrder Simulate a one-to-one relationship between these classes by making one additional change in the FCE.Payment class (see slide "Caché: Simulate One-to-One Relationship" in 1.4 Object Oriented Databases). 12.Add a CreatePaymentString() method. Signature: Method CreatePaymentString() As %String 14 Modern Database Techniques I Exercises

This method should create the following strings: For every payment: "Your request of: RequestedAmount RequestedCurrency" For a cash payment additionally: "Cash payment of SuppliedAmount SuppliedCurrency verified." For a credit card payment additionally: "CardType transaction for SuppliedAmount SuppliedCurrency completed." For a account payment additionally: "Thank you CustomerName for your payment of SuppliedAmount SuppliedCurrency by account AccountNumber." 13.Save all classes. Compile FCE.Payment, which will compile its subclasses. 14.Import and compile a new unit testing class: FCE.Tests.PaymentTests, from FCE.Tests.PaymentTests.xml. 15.Work in pairs to verbalize what each test method does. Note: there are no SQL test methods in this class. 16.Add properties to the FCE.Payment class and its subclasses according to the specification in the tests. 17.Run the tests from Terminal until all assertions pass. 18.In the FCE.Tests.Utilities class, update methods DestroyAll() and CreateAll(). Add code to destroy all payments, to create different types of payments, and to run the new payment tests. Run both methods, and ensure that they work. To create different types of payments, use this code: for i = 1:1:50 { set random = $random(3) if (random = 0) { do ##class(FCE.CashPayment).Populate(1) } elseif (random = 1) { do ##class(FCE.CreditCardPayment).Populate(1)} elseif (random = 2) { do ##class(FCE.AccountPayment).Populate(1)} } 19.Use the SQL section of the Portal to look at the four new payment tables. Use the Globals section of the Portal to look at the payment data global.

E-33: Add PrintName computed property to FCE.NameCl. Create two new always-computed properties. 1. In FCE.NameCl add an always computed PrintName property. 2. In FCE.ATM, change the SerialNumber property to an always computed property. Enter the line of code below into the SqlComputeCode attribute. Discuss this code with your partner. Remove the Required parameter because it doesn't make sense for a computed property. set {SerialNumber} = ($p({ID},"||",1)*1000)+$p({ID},"||",2) 3. In FCE.Branch create an always computed property OpenTime that calculates how long a Branch is open, using Opens and Closes properties. 4. Add this parameter to FCE.ATM to include the column SerialNumber into the Extent query: Parameter EXTENTQUERYSPEC = "SerialNumber"; 5. Using Terminal, enter this code to test your Extent query again. FCE>set class = "FCE.ATM" FCE>set query = "Extent" FCE>do ##class(%ResultSet).RunQuery(class,query)

15 Modern Database Techniques I Exercises

E-34: Triggers and callback methods 1. Implement the callback method of Practice: Write Callback Method to enforce Opens < Closes for branches. 2. Implement the trigger of Practice: Write Trigger to enforce Opens < Closes for branches. 3. Write trigger and callback method that assert: If either Opens or Closes is set the other property must be set, too.

E-35: Add a RepairNotes property to FCE.ATM. 1. In FCE.ATM, add a new property, RepairNotes, of type %Stream.GlobalCharacter. Compile the class. 2. Using Terminal, experiment with the new property. Add repair notes to a new ATM and save. Append to the notes. Reset the notes. 3. Enter this code to create an 80 KB note: FCE>set atm = ##class(FCE.ATM).%New() FCE>for i=1:1:1000 { set text = ##class(%PopulateUtils).Mission() w !, text do atm.RepairNotes.Write(text) } FCE>write atm.RepairNotes.Size 4. Create a file with a few lines of text (for example, c:\Foundations\notes.txt). 5. Enter this code to access the file for reading, copy it into RepairNotes property, and display it: FCE>set atm = ##class(FCE.ATM).%New() FCE>set filename = "c:\Foundations\notes.txt" FCE>set file = ##class(%File).%New(filename) FCE>do file.Open("R") FCE>do atm.RepairNotes.CopyFrom(file) FCE>write atm.RepairNotes.Read(1000)

16

Recommended publications