classname:methodname
20 | Property call As %String(MAXLEN = 255, XMLPROJECTION = "attribute");
21 |
22 | /// The class query to wrap. May just be the query name if the query is in the current class, or classname:queryname
if in a different class.
23 | Property query As %String(MAXLEN = 255, XMLPROJECTION = "attribute");
24 |
25 | /// The method to use for the action. Defaults to POST, as this will be most common.
26 | Property method As %String(VALUELIST = ",GET,POST,PUT,DELETE", XMLPROJECTION = "attribute") [ InitialExpression = "POST", Required ];
27 |
28 | /// For queries, the model class of result instances (if different from the source class)
29 | Property modelClass As %Dictionary.CacheClassname(XMLPROJECTION = "attribute");
30 |
31 | /// This callback method is invoked by the If this method returns an error then
If this method returns an error then
36 | /// The input argument is either JSON as a string or stream, or a subclass of %DynamicAbstractObject.
37 | Method JSONImport(input) As %Status
38 | {
39 | Quit ..%JSONImport(.input, ..#JSONMAPPING)
40 | }
41 |
42 | /// Serialize a JSON enabled class as a JSON document and write it to the current device.
43 | Method JSONExport() As %Status
44 | {
45 | Quit ..%JSONExport(..#JSONMAPPING)
46 | }
47 |
48 | /// Serialize a JSON enabled class as a JSON document and write it to a stream.
49 | Method JSONExportToStream(ByRef export As %Stream.Object) As %Status
50 | {
51 | Quit ..%JSONExportToStream(.export, ..#JSONMAPPING)
52 | }
53 |
54 | /// Serialize a JSON enabled class as a JSON document and return it as a string.
55 | Method JSONExportToString(ByRef %export As %String) As %Status
56 | {
57 | Quit ..%JSONExportToString(.%export, ..#JSONMAPPING)
58 | }
59 |
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/cls/AppS/REST/Model/DBMappedResource.cls:
--------------------------------------------------------------------------------
1 | /// Base class for all models that directly correspond to data from the database (e.g., AppS.REST.Model.Proxy and AppS.REST.Model.Adaptor)
2 | Class AppS.REST.Model.DBMappedResource Extends (AppS.REST.Model.Resource, %JSON.Adaptor) [ Abstract, System = 3 ]
3 | {
4 |
5 | /// The class to which this class provides REST access. It must extend %Persistent and have its %JSONENABLED class parameter set to 1 (e.g., by extending %JSON.Adaptor).
6 | /// Subclasses must override this parameter.
7 | Parameter SOURCECLASS As STRING [ Abstract ];
8 |
9 | /// The JSON mapping of the related JSON-enabled class to use.
10 | /// Defaults to empty (the default mapping for the associated class).
11 | Parameter JSONMAPPING As STRING [ Abstract ];
12 |
13 | /// Override to use an alternative JSON generator
14 | Parameter JSONGENERATOR As CLASSNAME = "%JSON.Generator";
15 |
16 | /// Override to use an alternative unique index name
17 | Parameter IndexToUse As STRING = "ID";
18 |
19 | /// If true, the whole SQL result row is passed to GetModelInstance rather than just the ID.
20 | /// If true,
54 | /// The object argument is a %Persistent object of whatever class is specified by
56 | /// This method should instantiate an instance of this model with ..%New(), populate its properties
57 | /// using object, and then return the model. For example, a subclass implementation might look something like:
58 | /// set myModel = ..%New() 59 | /// set myModel.name = object.DisplayName 60 | /// set myModel.alive = 'object.isDead() 61 | /// set myModel.age = object.age 62 | /// return myModel 63 | ///64 | /// This method must be overwritten by subclasses. 65 | ClassMethod GetModelFromObject(object As %Persistent) As AppS.REST.Model.DBMappedResource [ Abstract ] 66 | { 67 | } 68 | 69 | /// Saves the model instance 70 | Method SaveModelInstance(pUserContext As %RegisteredObject) [ Abstract ] 71 | { 72 | } 73 | 74 | /// Deletes an instance of this model, based on the identifier pID 75 | ClassMethod DeleteModelInstance(pID As %String) As %Boolean [ Abstract ] 76 | { 77 | } 78 | 79 | /// Since a proxy connects directly to a %persistent class, getting a collection constitutes 80 | /// building and running a query, and then printing out the result set in a json format. 81 | ClassMethod GetCollection(ByRef URLParams) 82 | { 83 | Set resultSet = ..ConstructAndRunQuery(.URLParams) 84 | Write "[" 85 | 86 | Set useResultRow = ..#ConstructFromResultRow 87 | While resultSet.%Next(.sc) { 88 | $$$ThrowOnError(sc) 89 | Set tProxy = ..GetModelInstance($Select(useResultRow:resultSet, 90 | 1:resultSet.%Get(..#IndexToUse))) 91 | If ($Increment(count) > 1) { 92 | Write "," 93 | } 94 | Do tProxy.JSONExport() 95 | } 96 | $$$ThrowOnError(sc) 97 | 98 | Write "]" 99 | } 100 | 101 | ClassMethod ConstructAndRunQuery(ByRef URLParams) [ Internal, Private ] 102 | { 103 | Set query = ##class(AppS.REST.QueryGenerator).GetQuery(..#SOURCECLASS, ..GetProxyColumnList(), ..#IndexToUse, .URLParams, .queryParams) 104 | 105 | Set tStatement = ##class(%SQL.Statement).%New() 106 | Set qStatus = tStatement.%Prepare(query) 107 | $$$ThrowOnError(qStatus) 108 | 109 | Set rset = tStatement.%Execute(queryParams...) 110 | If (rset.%SQLCODE < 0) { 111 | Throw ##class(%Exception.SQL).CreateFromSQLCODE(rset.%SQLCODE,rset.%Message) 112 | } 113 | Return rset 114 | } 115 | 116 | /// JSONImport imports JSON or dynamic object input into this object.
3 | /// zpm
4 | /// apps.rest test -only -DUnitTest.Case=UnitTest.AppS.REST.DriveSample -DUnitTest.UserParam.KeepApplication=1 -verbose
5 | ///
6 | Class UnitTest.AppS.REST.DriveSample Extends %UnitTest.TestCase
7 | {
8 |
9 | Property ForgeryInstalled As %Boolean [ InitialExpression = {$$$comClassDefined("Forgery.Agent")} ];
10 |
11 | Property WebAppName As %String [ InitialExpression = {"/csp/"_$ZConvert($Namespace,"L")_"/unit-test/sample"} ];
12 |
13 | Property Agent As %RegisteredObject;
14 |
15 | Property Person As %DynamicAbstractObject;
16 |
17 | Property Vendor As %DynamicAbstractObject;
18 |
19 | Method OnBeforeAllTests() As %Status
20 | {
21 | Set sc = $$$OK
22 | Set oldNamespace = $Namespace
23 | Try {
24 | // Generate data for tests
25 | Do ##class(UnitTest.AppS.REST.Sample.Data.Utils).Generate()
26 |
27 | New $Namespace
28 | Set $Namespace = "%SYS"
29 | Set props("NameSpace") = oldNamespace
30 | Set props("DispatchClass") = "UnitTest.AppS.REST.Sample.Handler"
31 | Set props("CookiePath") = ..WebAppName_"/"
32 | Set props("Recurse") = 1
33 | Set props("IsNameSpaceDefault") = 0
34 | Set props("AutheEnabled") = 32 // Password
35 | If ##class(Security.Applications).Exists(..WebAppName) {
36 | $$$ThrowOnError(##class(Security.Applications).Modify(..WebAppName, .props))
37 | } Else {
38 | $$$ThrowOnError(##class(Security.Applications).Create(..WebAppName, .props))
39 | }
40 | } Catch e {
41 | Set sc = e.AsStatus()
42 | }
43 | Quit sc
44 | }
45 |
46 | Method OnBeforeOneTest(testname As %String) As %Status
47 | {
48 | Set ..SkipTest = (testname '= "TestCompiling") && '..ForgeryInstalled
49 | If ..SkipTest {
50 | Do $$$AssertSkipped("Must install the Forgery project from the Open Exchange to support running certain REST tests.")
51 | } Else {
52 | Set ..Agent = ##class(Forgery.Agent).%New(..WebAppName_"/", {
53 | "Content-Type": "application/json; charset=utf-8",
54 | "Accept": "application/json"
55 | })
56 | }
57 | Quit $$$OK
58 | }
59 |
60 | Method OnAfterAllTests() As %Status
61 | {
62 | Set sc = $$$OK
63 | Set oldNamespace = $Namespace
64 | Try {
65 | If '..Manager.UserFields.GetAt("KeepApplication") {
66 | New $Namespace
67 | Set $Namespace = "%SYS"
68 | $$$ThrowOnError(##class(Security.Applications).Delete(..WebAppName))
69 | }
70 | } Catch e {
71 | Set sc = e.AsStatus()
72 | }
73 | Quit sc
74 | }
75 |
76 | Method TestAuthStatus()
77 | {
78 | Do $$$AssertStatusOK(..Agent.Get({"url": "auth/status"}, .jsonStream))
79 | Set response = ..Agent.GetLastResponse()
80 | Do $$$AssertEquals(response.Status, "200 OK")
81 | Do $$$AssertEquals(response.ContentType, "application/json")
82 | Set object = {}.%FromJSON(jsonStream)
83 | Do $$$AssertEquals(object.Username,$Username)
84 | Do $$$AssertEquals(object.IsAdmin,(","_$Roles_",") [ ",%All,")
85 | }
86 |
87 | Method TestCompiling()
88 | {
89 | Do $$$AssertStatusOK($System.OBJ.CompilePackage("UnitTest.AppS.REST.Sample", "ck/nomulticompile"))
90 | }
91 |
92 | Method TestPerson01Query()
93 | {
94 | Do $$$AssertStatusOK(..Agent.Get({"url": "person?$orderBy=name"}, .jsonStream))
95 | Set response = ..Agent.GetLastResponse()
96 | Do $$$AssertEquals(response.Status, "200 OK")
97 | Do $$$AssertEquals(response.ContentType, "application/json")
98 | Set object = {}.%FromJSON(jsonStream)
99 | If '$$$AssertEquals(object.%Size(), 200) {
100 | Do $$$LogMessage("Response: "_object.%ToJSON())
101 | }
102 | }
103 |
104 | Method TestPerson02Get()
105 | {
106 | Do $$$AssertStatusOK(..Agent.Get({"url": "person/1"}, .jsonStream))
107 | Set response = ..Agent.GetLastResponse()
108 | Do $$$AssertEquals(response.Status, "200 OK")
109 | Do $$$AssertEquals(response.ContentType, "application/json")
110 | Set object = {}.%FromJSON(jsonStream)
111 | Set ..Person = object
112 | }
113 |
114 | Method TestPerson03Put()
115 | {
116 | Set ..Person.name = "Rubble, Barney"
117 | Do $$$AssertStatusOK(..Agent.Put({"url": "person/1", "data": (..Person)}, .jsonStream))
118 | Set response = ..Agent.GetLastResponse()
119 | Do $$$AssertEquals(response.Status, "200 OK")
120 | Do $$$AssertEquals(response.ContentType, "application/json")
121 | Set object = {}.%FromJSON(jsonStream)
122 | Do $$$AssertEquals(object.name, "Rubble, Barney")
123 | }
124 |
125 | Method TestPerson04Post()
126 | {
127 | Do $$$AssertStatusOK(..Agent.Post({"url": "person", "data": {"name": "Flintstone, Fred"}}, .jsonStream))
128 | Set response = ..Agent.GetLastResponse()
129 | Do $$$AssertEquals(response.Status, "200 OK")
130 | Do $$$AssertEquals(response.ContentType, "application/json")
131 | Set object = {}.%FromJSON(jsonStream)
132 | Do $$$AssertEquals(object.name, "Flintstone, Fred")
133 | }
134 |
135 | Method TestPerson05ListByName()
136 | {
137 | Do $$$AssertStatusOK(..Agent.Get({"url": "person/$list-by-name?name=Flintstone"}, .jsonStream))
138 | Set response = ..Agent.GetLastResponse()
139 | Do $$$AssertEquals(response.Status, "200 OK")
140 | Set object = {}.%FromJSON(jsonStream)
141 | Do $$$LogMessage("Response: "_object.%ToJSON())
142 | Do $$$AssertEquals(object.%Size(), 1)
143 | }
144 |
145 | Method TestPerson06UpdateHomeAddress()
146 | {
147 | Do $$$AssertStatusOK(..Agent.Put({"url": "person/201/$update-home-address","data":{"Zip":"12345"}}, .jsonStream))
148 | Set response = ..Agent.GetLastResponse()
149 | Do $$$AssertEquals(response.Status, "200 OK")
150 | Set object = {}.%FromJSON(jsonStream)
151 | Do $$$LogMessage("Response: "_object.%ToJSON())
152 | Do $$$AssertEquals(object.Zip,"12345")
153 | }
154 |
155 | Method TestPerson07UpdateOfficeAddress()
156 | {
157 | Do $$$AssertStatusOK(..Agent.Post({"url": "person/201/$update-office-address","data":{"Zip":"12345"}}, .jsonStream))
158 | Set response = ..Agent.GetLastResponse()
159 | Do $$$AssertEquals(response.Status, "200 OK")
160 | Set object = {}.%FromJSON(jsonStream)
161 | Do $$$LogMessage("Response: "_object.%ToJSON())
162 | Do $$$AssertEquals(object.name, "Flintstone, Fred")
163 | Do $$$AssertEquals(object."office_address".Zip, "12345")
164 | }
165 |
166 | Method TestPerson08Ping()
167 | {
168 | Do $$$AssertStatusOK(..Agent.Post({"url": "person/$ping", "data": {"foo":"bar"}}, .jsonStream))
169 | Set response = ..Agent.GetLastResponse()
170 | Do $$$AssertEquals(response.Status, "200 OK")
171 | Set object = {}.%FromJSON(jsonStream)
172 | Do $$$LogMessage("Response: "_object.%ToJSON())
173 | Do $$$AssertEquals(object.foo, "bar")
174 | }
175 |
176 | Method TestPerson09Delete()
177 | {
178 | Do $$$AssertStatusOK(..Agent.Delete({"url": "person/201"}, .jsonStream))
179 | Set response = ..Agent.GetLastResponse()
180 | Do $$$AssertEquals(response.Status, "204 No Content")
181 | Do $$$AssertStatusOK(..Agent.Delete({"url": "person/201"}, .jsonStream))
182 | Set response = ..Agent.GetLastResponse()
183 | Do $$$AssertEquals(response.Status, "404 Not Found")
184 | }
185 |
186 | Method TestVendor1Query()
187 | {
188 | Do $$$AssertStatusOK(..Agent.Get({"url": "vendor"}, .jsonStream))
189 | Set response = ..Agent.GetLastResponse()
190 | Do $$$AssertEquals(response.Status, "200 OK")
191 | Do $$$AssertEquals(response.ContentType, "application/json")
192 | Set object = {}.%FromJSON(jsonStream)
193 | Do $$$AssertEquals(object.%Size(), 100)
194 | }
195 |
196 | Method TestVendor2Get()
197 | {
198 | Do $$$AssertStatusOK(..Agent.Get({"url": "vendor/1"}, .jsonStream))
199 | Set response = ..Agent.GetLastResponse()
200 | Do $$$AssertEquals(response.Status, "200 OK")
201 | Do $$$AssertEquals(response.ContentType, "application/json")
202 | Set object = {}.%FromJSON(jsonStream)
203 | Set ..Vendor = object
204 | }
205 |
206 | Method TestVendor3Put()
207 | {
208 | Set ..Vendor.Name = "Acme Pharmaceuticals"
209 | Do $$$AssertStatusOK(..Agent.Put({"url": "vendor/1", "data": (..Vendor)}, .jsonStream))
210 | Set response = ..Agent.GetLastResponse()
211 | Do $$$AssertEquals(response.Status, "200 OK")
212 | Do $$$AssertEquals(response.ContentType, "application/json")
213 | Set object = {}.%FromJSON(jsonStream)
214 | Do $$$AssertEquals(object.Name, "Acme Pharmaceuticals")
215 | }
216 |
217 | Method TestVendor4Post()
218 | {
219 | Set ..Vendor.Name = "Acme Robotics"
220 | Do $$$AssertStatusOK(..Agent.Post({"url": "vendor", "data": (..Vendor)}, .jsonStream))
221 | Set response = ..Agent.GetLastResponse()
222 | Do $$$AssertEquals(response.Status, "200 OK")
223 | Do $$$AssertEquals(response.ContentType, "application/json")
224 | Set object = {}.%FromJSON(jsonStream)
225 | Do $$$AssertEquals(object.Name, "Acme Robotics")
226 | }
227 |
228 | Method TestVendor5Delete()
229 | {
230 | Do $$$AssertStatusOK(..Agent.Delete({"url": "vendor/101"}, .jsonStream))
231 | Set response = ..Agent.GetLastResponse()
232 | Do $$$AssertEquals(response.Status, "204 No Content")
233 | Do $$$AssertStatusOK(..Agent.Delete({"url": "vendor/101"}, .jsonStream))
234 | Set response = ..Agent.GetLastResponse()
235 | Do $$$AssertEquals(response.Status, "404 Not Found")
236 | }
237 |
238 | Method TestVendor6Construct()
239 | {
240 | Do $$$AssertStatusOK(..Agent.Get({"url": "vendor/$new"}, .jsonStream))
241 | Set response = ..Agent.GetLastResponse()
242 | Do $$$AssertEquals(response.Status, "200 OK")
243 | Set object = {}.%FromJSON(jsonStream)
244 | Do $$$LogMessage("Response: "_object.%ToJSON())
245 | Do $$$AssertEquals(object.%Size(),1)
246 | }
247 |
248 | Method TestBad01InvalidOrderBy()
249 | {
250 | Do $$$AssertStatusOK(..Agent.Get({"url": "person?$orderBy=-SSN"}, .jsonStream))
251 | Set response = ..Agent.GetLastResponse()
252 | Do $$$AssertEquals(response.Status, "403 Unauthorized")
253 | Do $$$AssertEquals(response.ContentType, "application/json")
254 | Set object = {}.%FromJSON(jsonStream)
255 | Do $$$LogMessage("Response: "_object.%ToJSON())
256 | Do $$$AssertEquals(object.errors.%Get(0).params.%Get(0), "Invalid query. Access to column 'SSN' is not permitted.")
257 | }
258 |
259 | Method TestBad02MalformedFilter()
260 | {
261 | Do $$$AssertStatusOK(..Agent.Get({"url": "person?name[foo]=Fred"}, .jsonStream))
262 | Set response = ..Agent.GetLastResponse()
263 | Do $$$AssertEquals(response.Status, "400 Bad Request")
264 | Do $$$AssertEquals(response.ContentType, "application/json")
265 | Set object = {}.%FromJSON(jsonStream)
266 | Do $$$LogMessage("Response: "_object.%ToJSON())
267 | Do $$$AssertEquals(object.errors.%Get(0).params.%Get(0), "Invalid query. The parameter value 'name[foo]=Fred' could not be parsed.")
268 | }
269 |
270 | Method TestBad03NoResource()
271 | {
272 | Do $$$AssertStatusOK(..Agent.Get({"url": "vehicle"}, .jsonStream))
273 | Set response = ..Agent.GetLastResponse()
274 | Do $$$AssertEquals(response.Status, "406 Not Acceptable")
275 | Do $$$AssertEquals(response.ContentType, "application/json")
276 |
277 | Do $$$AssertStatusOK(..Agent.Get({"url": "vehicle/1"}, .jsonStream))
278 | Set response = ..Agent.GetLastResponse()
279 | Do $$$AssertEquals(response.Status, "406 Not Acceptable")
280 | Do $$$AssertEquals(response.ContentType, "application/json")
281 |
282 | Do $$$AssertStatusOK(..Agent.Put({"url": "vehicle/1", "data":{}}, .jsonStream))
283 | Set response = ..Agent.GetLastResponse()
284 | Do $$$AssertEquals(response.Status, "415 Unsupported Media Type")
285 | Do $$$AssertEquals(response.ContentType, "application/json")
286 |
287 | Do $$$AssertStatusOK(..Agent.Post({"url": "vehicle", "data":{}}, .jsonStream))
288 | Set response = ..Agent.GetLastResponse()
289 | Do $$$AssertEquals(response.Status, "415 Unsupported Media Type")
290 | Do $$$AssertEquals(response.ContentType, "application/json")
291 |
292 | Do $$$AssertStatusOK(..Agent.Delete({"url": "vehicle/1"}, .jsonStream))
293 | Set response = ..Agent.GetLastResponse()
294 | Do $$$AssertEquals(response.Status, "415 Unsupported Media Type")
295 | Do $$$AssertEquals(response.ContentType, "application/json")
296 | }
297 |
298 | Method TestBad04NoAction()
299 | {
300 | Do $$$AssertStatusOK(..Agent.Get({"url": "person/1/$promote"}, .jsonStream))
301 | Set response = ..Agent.GetLastResponse()
302 | Do $$$AssertEquals(response.Status, "406 Not Acceptable")
303 | }
304 |
305 | Method TestBad05WrongActionMethod()
306 | {
307 | Do $$$AssertStatusOK(..Agent.Post({"url": "person/1/$update-home-address","data":{"Zip":"12345"}}, .jsonStream))
308 | Set response = ..Agent.GetLastResponse()
309 | Do $$$AssertEquals(response.Status, "405 Method Not Allowed")
310 | }
311 |
312 | Method TestBad06MalformedJSON()
313 | {
314 | // No "data"
315 | Do $$$AssertStatusNotOK(..Agent.Put({"url": "person/1"}, .jsonStream))
316 | Set response = ..Agent.GetLastResponse()
317 | Do $$$AssertEquals(response.Status, "400 Bad Request")
318 | }
319 |
320 | Method TestBad07NoObject()
321 | {
322 | // No person with this ID
323 | Do $$$AssertStatusNotOK(..Agent.Get({"url": "person/42000"}, .jsonStream))
324 | Set response = ..Agent.GetLastResponse()
325 | Do $$$AssertEquals(response.Status, "404 Not Found")
326 |
327 | // For a PUT it should be 409 Conflict
328 | Do $$$AssertStatusNotOK(..Agent.Put({"url": "person/42000", "data":{}}, .jsonStream))
329 | Set response = ..Agent.GetLastResponse()
330 | Do $$$AssertEquals(response.Status, "409 Conflict")
331 | }
332 |
333 | Method TestBad08NonJSONTypes()
334 | {
335 | Do $$$AssertStatusOK(..Agent.Get({"url": "person/1", "headers":{"Accept":"application/xml"}}, .jsonStream))
336 | Set response = ..Agent.GetLastResponse()
337 | Do $$$AssertEquals(response.Status, "406 Not Acceptable")
338 |
339 | Do $$$AssertStatusOK(..Agent.Put({"url": "person/1/$update-home-address", "headers":{"Content-Type":"application/xml"}, "data":(##class(%Stream.FileCharacter).%New())}, .jsonStream))
340 | Set response = ..Agent.GetLastResponse()
341 | Do $$$AssertEquals(response.Status, "415 Unsupported Media Type")
342 |
343 | Do $$$AssertStatusOK(..Agent.Put({"url": "person/1/$update-home-address", "headers":{"Accept":"application/xml"}, "data":{}}, .jsonStream))
344 | Set response = ..Agent.GetLastResponse()
345 | Do $$$AssertEquals(response.Status, "406 Not Acceptable")
346 | }
347 |
348 | }
349 |
--------------------------------------------------------------------------------
/internal/testing/unit_tests/UnitTest/AppS/REST/QueryBuilder.cls:
--------------------------------------------------------------------------------
1 | Class UnitTest.AppS.REST.QueryBuilder Extends %UnitTest.TestCase
2 | {
3 |
4 | Method TestCompiling()
5 | {
6 | Do $$$AssertStatusOK($System.OBJ.Compile("UnitTest.AppS.REST.SamplePersistentAdapted","ck/nomulticompile"))
7 | }
8 |
9 | Method TestValidEverything()
10 | {
11 | Set p("someField[noteq]",1) = 2 // someField is the JSON alias for 'Foo'
12 | Set p("Bar[isnull]",1) = ""
13 | Do ..GetQueryWrapper(.p,.query,.params,.prepareStatus,.exception)
14 | If $$$AssertEquals($Data(exception),0) {
15 | Do $$$AssertEquals(query,"select ID from UnitTest_AppS_REST.SamplePersistentAdapted where 1=1 and Bar is null and not FOO_NAME = ?")
16 | Do $$$AssertEquals(params,1)
17 | Do $$$AssertEquals(params(1),2)
18 | Do $$$AssertStatusOK(prepareStatus)
19 | } Else {
20 | Do $$$AssertFailure("Exception occured: "_exception.DisplayString())
21 | }
22 | }
23 |
24 | Method TestIllegalColumnExpression()
25 | {
26 | Set p("Baz union all select 1 -- [eq]",1) = "42"
27 | Do ..GetQueryWrapper(.p,.query,.params,.prepareStatus,.exception)
28 | If $$$AssertEquals($Data(exception),1) {
29 | Do $$$AssertEquals($classname(exception),"AppS.REST.Exception.InvalidColumnException")
30 | } Else {
31 | Do $$$AssertFailure("Exception should have been thrown.")
32 | }
33 | }
34 |
35 | Method TestInvalidColumnName()
36 | {
37 | // For now, a runtime error preparing the query.
38 | Set p("Qux[eq]",1) = "42"
39 | Do ..GetQueryWrapper(.p,.query,.params,.prepareStatus,.exception)
40 | If $$$AssertEquals($Data(exception),1) {
41 | Do $$$AssertEquals($classname(exception),"AppS.REST.Exception.InvalidColumnException")
42 | } Else {
43 | Do $$$AssertFailure("Exception should have been thrown.")
44 | }
45 | }
46 |
47 | Method TestInvalidOrderBy()
48 | {
49 | Set p("$orderBy",1) = "baz union all select 1"
50 | Do ..GetQueryWrapper(.p,.query,.params,.prepareStatus,.exception)
51 | If $$$AssertEquals($Data(exception),1) {
52 | Do $$$AssertEquals($classname(exception),"AppS.REST.Exception.InvalidColumnException")
53 | } Else {
54 | Do $$$AssertFailure("Exception should have been thrown.")
55 | }
56 | }
57 |
58 | Method GetQueryWrapper(ByRef URLParams, Output query As %String, Output queryParams, Output prepareStatus As %Status, Output exception As %Exception.AbstractException)
59 | {
60 | Kill query, queryParams, prepareStatus, exception
61 | Try {
62 | Set query = ##class(AppS.REST.QueryGenerator).GetQuery(
63 | "UnitTest.AppS.REST.SamplePersistentAdapted",
64 | ##class(UnitTest.AppS.REST.SamplePersistentAdapted).GetProxyColumnList(),
65 | ##class(UnitTest.AppS.REST.SamplePersistentAdapted).#IndexToUse,
66 | .URLParams,
67 | .queryParams)
68 | } Catch exception {
69 | Return
70 | }
71 |
72 | Set tStatement = ##class(%SQL.Statement).%New()
73 | Set prepareStatus = tStatement.%Prepare(query)
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/internal/testing/unit_tests/UnitTest/AppS/REST/Sample/Data/Address.cls:
--------------------------------------------------------------------------------
1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code.
2 | /// This is a sample embeddable class representing an address.
3 | Class UnitTest.AppS.REST.Sample.Data.Address Extends (%SerialObject, %Populate, %XML.Adaptor, %JSON.Adaptor)
4 | {
5 |
6 | /// The street address.
7 | Property Street As %String(MAXLEN = 80, POPSPEC = "Street()");
8 |
9 | /// The city name.
10 | Property City As %String(MAXLEN = 80, POPSPEC = "City()");
11 |
12 | /// The 2-letter state abbreviation.
13 | Property State As %String(MAXLEN = 2, POPSPEC = "USState()");
14 |
15 | /// The 5-digit U.S. Zone Improvement Plan (ZIP) code.
16 | Property Zip As %String(MAXLEN = 5, POPSPEC = "USZip()");
17 |
18 | Storage Default
19 | {
20 |
21 |