├── COSQuickRef.md ├── LICENSE └── README.md /COSQuickRef.md: -------------------------------------------------------------------------------- 1 | # Caché ObjectScript Quick Reference 2 | A list of some common ObjectScript expressions 3 | 4 | ## Object/SQL Basics 5 | 6 | | Action | Code | 7 | |----------------------------------------------|-----------------------------------------------------------------------------------| 8 | | Call a class method | `Do ##class(package.class).method(arguments)`
`Set variable = ##class(package.class).method(arguments)`
Note: place a . before each pass-by-reference argument | 9 | | Call an instance method | `Do object.method(arguments)`
`Set variable = object.method(arguments)`
Note: place a . before each pass-by-reference argument | 10 | | Create a new object | `Set object = ##class(package.class).%New()` | 11 | | Open an existing object | `Set object = ##class(package.class).%OpenId(id, concurrency, .status)` | 12 | | Open an existing object by unique index value| `Set object = ##class(package.class).IndexNameOpen(value, concurrency, .status)` | 13 | | Save an object | `Set status = object.%Save()` | 14 | | Retrieve the ID of a saved object | `Set id = object.%Id()` | 15 | | Retrieve the OID of a saved object | `Set oid = object.%Oid()` | 16 | | Retrieve property of a saved object | `Set variable = ##class(package.class).GetStoredPropertyName(id)` | 17 | | Determine if an object was modified | `Set variable = object.%IsModified()` | 18 | | Validate an object without saving | `Set status = object.%ValidateObject()` | 19 | | Validate a property without saving | `Set status = ##class(package.class).PropertyIsValid(object.Property)` | 20 | | Print status after error | `Do $system.Status.DisplayError(status)`
`Write $system.Status.GetErrorText(status)` | 21 | | Obtain status details after error | `Do $system.Status.DecomposeStatus(status, .err)` | 22 | | Remove an object from process memory | `Set object = ""` | 23 | | Delete an existing object of a class | `Set status = ##class(package.class).%DeleteId(id)` | 24 | | Delete all saved objects of a class | `Do ##class(package.class).%DeleteExtent()`
`Do ##class(package.class).%KillExtent()` | 25 | | Reload properties of a saved object | `Do object.%Reload()` | 26 | | Clone an object | `Set clonedObject = object.%ConstructClone()` | 27 | | Write a property | `Write object.property` | 28 | | Set a property | `Set object.property = value` | 29 | | Write a class parameter | `Write ##class(package.class).#PARAMETER` | 30 | | Set a serial (embedded) property | `Set object.property.embeddedProperty = value` | 31 | | Link two objects | `Set object1.referenceProperty = object2` | 32 | | Populate a class | `Do ##class(package.class).Populate(count, verbose)` | 33 | | Remove all objects in process memory | `Kill` | 34 | | List all objects in process memory | `Do $system.OBJ.ShowObjects()` | 35 | | Display all properties of an object | `Do $system.OBJ.Dump(object)`
`Zwrite object` (v2012.2+) | 36 | | Determine If variable is an object reference | `If $isobject(variable) ; 1=yes, 0=no` | 37 | | Find classname of an object | `Write $classname(oref)` | 38 | | Start the SQL shell | `Do $system.SQL.Shell()` | 39 | | Test a class query | `Do ##class(%ResultSet).RunQuery(class, query)` | 40 | | Declare a variable's type for Studio Assist | `#dim object as package.class` | 41 | 42 | ## ObjectScript Commands 43 | 44 | | Command | Description | 45 | |-------------------------------|-------------------------------------------------------------------------------------| 46 | | `Write` | Display text strings, value of variable or expression | 47 | | `Zwrite` | Display array, list string, bit string | 48 | | `Set` | Set value of variable | 49 | | `Do` | Execute method, procedure, or routine | 50 | | `Quit` or `Return` (v2013.1) | Terminate method, procedure, or routine. Optionally return value to calling method | 51 | | `Continue` | Stop current loop iteration, and continue looping | 52 | | `Halt` | Stop Caché process and close Terminal | 53 | | `Kill` | Destroy variable(s) | 54 | | `If {} ElseIf {} Else {}` | Evaluate conditions and branch | 55 | | `For {}`, `While {}`, `Do {} While` | Execute block of code repeatedly | 56 | | `Try {} Catch {}`, `Throw` | Handle errors | 57 | 58 | ## ObjectScript Date/Time Functions and Special Variables 59 | 60 | | Action | Code | 61 | |--------------------------------------------------|-------------------------------------------------------------| 62 | | Date conversion (external → internal) | `Set variable = $zdh("mm/dd/yyyy")` | 63 | | Date conversion (internal → external) | `Set variable = $zd(internalDate, format)` | 64 | | Time conversion (external → internal) | `Set variable = $zth("hh:mm:ss")` | 65 | | Time conversion (internal → external) | `Set variable = $zt(internalTime, format)` | 66 | | Display current internal date/time string | `Write $horolog` | 67 | | Display UTC date/time string | `Write $ztimestamp` | 68 | | Get the date relative to other date (any type) | `Write $system.SQL.DATEADD("hh", -4, "yyyy-mm-dd hh:mm:ss")` | 69 | | Get the difference between two dates (any type) | `Write $system.SQL.DATEDIFF("hh", horolog-or-ztimestamp, horolog-or-ztimestamp)`| 70 | 71 | ## ObjectScript Branching Functions 72 | 73 | | Action | Code | 74 | |--------------------------------------------------|------------------------------------------------------------------------| 75 | | Display result for value of expression | `Write $case(expression, value1:result1, value2:result2, …, :resultN)` | 76 | | Display result for first true condition | `Write $select(condition1:result1, condition2:result2, …, 1:resultN)` | 77 | 78 | ## ObjectScript String Functions 79 | 80 | | Action | Code | 81 | |----------------------------------------------------------|---------------------------------------------------------------| 82 | | Display substring extracted from string | `Write $extract(string, start, end)` | 83 | | Display right-justified string within width characters | `Write $justify(string, width)` | 84 | | Display length of string | `Write $length(string)` | 85 | | Display number of delimited pieces in string | `Write $length(string, delimiter)` | 86 | | Display piece from delimited string | `Write $piece(string, delimiter, pieceNumber)` | 87 | | Set piece into delimited string | `Set $piece(string, delimiter, pieceNumber) = piece` | 88 | | Display string after replacing substring | `Write $replace(string, subString, replaceString)` | 89 | | Display reversed string | `Write $reverse(string)` | 90 | | Display string after replacing characters | `Write $translate(string, searchChars, replaceChars)` | 91 | | Build a list | `Set listString = $listbuild(list items, separated by comma)` | 92 | | Retrieve an item from a list | `Set variable = $list(listString, position)` | 93 | | Retrieves elements sequentially from a list | `Set pointerToNextElement = 0`
`While = $ListNext(listString, pointerToNextElement, value) {}` | 94 | | Put item into list string | `Set $list(listString, position) = substring` | 95 | | Display the length of a list | `Write $listlength(listString)` | 96 | | Search a value in a list | `Write $listfind(listString, value)` | 97 | | Build a list from a string | `Set listString = $listFromString(string, delimiter)` | 98 | 99 | ## ObjectScript Existence Functions 100 | 101 | | Action | Code | 102 | |--------------------------------------------------|-------------------------------------------------------------| 103 | | Check if variable exists | `Write $data(variable)` | 104 | | Return value of variable, or default If undefined | `Write $get(variable, default)` | 105 | | Return next valid subscript in array | `Write $order(array(subscript))` | 106 | 107 | ## Additional ObjectScript Functions 108 | 109 | | Action | Code | 110 | |--------------------------------------------------|---------------------------------------------------------------------| 111 | | Increment ^global by increment | `$increment(^global, increment)`
`$sequence(^global)` | 112 | | Match a regular expression | `Set matches = $match(string, regularexpression)` | 113 | | Display random integer from start to start+count | `Write $random(count) + start` | 114 | 115 | ## ObjectScript Special Variables 116 | 117 | | Action | Code | 118 | |-----------------------------------|---------------------------------------| 119 | | Display process ID | `Write $job` | 120 | | Display current namespace | `Write $namespace` | 121 | | Change current namespace | `Set $namespace = newnamespace` | 122 | | Display username | `Write $username` | 123 | | Display roles | `Write $roles` | 124 | 125 | ## Utilities 126 | 127 | | Action | Code | 128 | |-----------------------------------|---------------------------------------| 129 | | Change current namespace | `Do ^%CD`
`zn "newnamespace"` | 130 | | Display a ^global | `Do ^%G`
`zwrite ^global` | 131 | 132 | ## Collections 133 | 134 | | Action | Code | 135 | |--------------------------------------------------------------|------------------------------------------------------------------------------------------------------------| 136 | | Create a new standalone list
Work with a list property | `Set listObject=##class(%ListOfDataTypes).%New()`
Use methods below on a list collection property | 137 | | Insert an element at the end of a list | `Do listObject.Insert(value)`
`Do object.listProperty.Insert(value)` | 138 | | Insert an element into a list | `Do listObject.SetAt(value, position)`
`Do object.listProperty.SetAt(value, position)` | 139 | | Remove an element from a list | `Do listObject.RemoveAt(position)`
`Do object.listProperty.RemoveAt(position)` | 140 | | Display an element of a list | `Write listObject.GetAt(position)`
`Write object.listProperty.GetAt(position)` | 141 | | Display the size of a list | `Write listObject.Count()`
`Write object.listProperty.Count()` | 142 | | Clear all the elements of a list | `Do listObject.Clear()`
`Do object.listProperty.Clear()` | 143 | | Create a new standalone array
Work with an array property | `Set arrayObject=##class(%ArrayOfDataTypes).%New()`
Use methods below on an array collection property | 144 | | Insert an element into an array | `Do arrayObject.SetAt(value, key)`
`Do object.arrayProperty.SetAt(value, key)` | 145 | | Remove an element from an array | `Do arrayObject.RemoveAt(key)`
`Do object.arrayProperty.RemoveAt(key)` | 146 | | Display an element of an array | `Write arrayObject.GetAt(key)`
`Do object.arrayProperty.GetAt(key)` | 147 | | Display the size of an array | `Write arrayObject.Count()`
`Do object.arrayProperty.Count()` | 148 | | Clear all elements of an array | `Do arrayObject.Clear()`
`Do object.arrayProperty.Clear()` | 149 | 150 | ## Relationships 151 | 152 | | Action | Code | 153 | |-----------------------------------------|--------------------------------------------------------------------------------------------------------------| 154 | | Parent-to-children object linking | `Do parentObject.childRefProperty.Insert(chilDobject)`
`Set chilDobject.parentRefProperty = parentObject` | 155 | | One-to-many object linking | `Do oneObject.manyRefProperty.Insert(manyObject)`
`Set manyObject.OneRefProperty = OneObject` | 156 | | Write a property of a child object | `Write parentObject.childRefProperty.GetAt(position).property` | 157 | | Write a property of a many object | `Write oneObject.manyRefProperty.GetAt(position).property` | 158 | | Display the count of child/many objects | `Write parentObject.childRefProperty.Count()`
`Write oneObject.manyRefProperty.Count()` | 159 | | Open a many/child object directly | `Set object = ##class(package.class).IDKEYOpen(parentID, childsub)` | 160 | | Retrieve the id of a child object | `Set status = ##class(package.class).IDKEYExists(parentID, childsub, .childID)` | 161 | | Clear the child/many objects | `Do parentObject.childRefProperty.Clear()
Do oneObject.manyRefProperty.Clear()` | 162 | 163 | ## Streams 164 | 165 | | Action | Code | 166 | |-------------------------------------------|---------------------------------------------------------------------------------------| 167 | | Create a new stream | `Set streamObject=##class(%Stream.GlobalCharacter).%New()`
`Set streamObject=##class(%Stream.GlobalBinary).%New()`
Use methods below on a stream property | 168 | | Add text to a stream | `Do streamObject.Write(text)`
`Do object.streamProperty.Write(text)` | 169 | | Add a line of text to a stream | `Do streamObject.WriteLine(text)`
`Do object.streamProperty.WriteLine(text)` | 170 | | Read len characters of text from a stream | `Write streamObject.Read(len)`
`Write object.streamProperty.Read(len)` | 171 | | Read a line of text from a stream | `Write streamObject.ReadLine(len)`
`Write object.streamProperty.ReadLine(len)` | 172 | | Go to the beginning of a stream | `Do streamObject.Rewind()`
`Do object.streamProperty.Rewind()` | 173 | | Go to the end of a stream, for appending | `Do streamObject.MoveToEnd()`
`Do object.streamProperty.MoveToEnd()` | 174 | | Clear a stream | `Do streamObject.Clear()`
`Do object.streamProperty.Clear()` | 175 | | Display the length of a stream | `Write streamObject.Size`
`Write object.streamProperty.Size` | 176 | 177 | ## Unit Testing Macros 178 | 179 | | Action | Code | 180 | |-----------------------------|--------------------------------------------------| 181 | | Assert equality | `Do $$$AssertEquals(value1, value2, message)` | 182 | | Assert inequality | `Do $$$AssertNotEquals(value1, value2, message)` | 183 | | Assert status is OK | `Do $$$AssertStatusOK(status, message)` | 184 | | Assert status isn't OK | `Do $$$AssertStatusNotOK(status, message)` | 185 | | Assert condition is true | `Do $$$AssertTrue(condition, message)` | 186 | | Assert condition isn't true | `Do $$$AssertNotTrue(condition, message)` | 187 | | Log message | `Do $$$LogMessage(message)` | 188 | 189 | ## Other Macros 190 | 191 | | Action | Code | 192 | |----------------------------------|-------------------------------------------| 193 | | Return a good status | `Quit $$$OK` | 194 | | Return an error status | `Quit $$$ERROR($$$GeneralError, message)` | 195 | | Throw exception on error | `$$$ThrowOnError(status, code)` or `$$$TOE(status, code)` | 196 | | Check if status is good | `If $$$ISOK(status)` | 197 | | Check if status is an error | `If $$$ISERR(status)` | 198 | | Return a null object reference | `Quit $$$NULLOREF` | 199 | | Place a new line within a string | `Write string1_$$$NL_string2` | 200 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 InterSystems Corp. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Caché ObjectScript Code Guidelines 2 | 3 | This is the first approximation of Caché ObjectScript guidelines we use for github.com/intersystems-ru projects. There are mandatory and recommended parts. 4 | 5 | We do not plan to be very restrictive, but want be rather flexible enough and allow any *reasonable* style. 6 | Here is the general advice: use common sense and try to *be consistent* wherever you write code. 7 | If there is some style already established in the class or utility being modified then we recommend 8 | to continue use that same style, than introducing yet another one, which may be more recommended 9 | but which will be introducing some unnecessary inconsistency. 10 | 11 | ## Quick Reference Guide 12 | 13 | For Caché ObjectScript quick reference guide see [here](COSQuickRef.md). 14 | 15 | ## Mandatory Part 16 | 17 | * Only "modern" syntax permitted, dotted syntax is not generally allowed (with few exceptions); 18 | * No short name for statements keywords or built-in functions allowed - use fully expanded names; 19 | * Comment your code appropriately, use English in comments to make your code easy to understand by your international colleagues. Same English-based rule applies to global, local, and type names. 20 | 21 | ## Recommended Part 22 | * We recommend to use fully expanded keyword or function name in lower case or capitalized. Whatever you'll select should be consistent across class or utility, i.e. 23 | ``` 24 | If (expression) { 25 | Do ##class(Sample).%New(initexpresion) 26 | For i=1:1:10 { 27 | Write something, $ZVersion, ! 28 | } 29 | } 30 | ``` 31 | or 32 | 33 | ``` 34 | if (expression) { 35 | do ##class(Sample).%New(initexpresion) 36 | for i=1:1:10 { 37 | write something, $zversion, ! 38 | } 39 | } 40 | ``` 41 | * We recommend to use fully qualified package name of a class (except `%Library` package) 42 | ``` 43 | Set obj = ##class(Sample.Person).%New(initexpresion) 44 | ``` 45 | instead of 46 | ``` 47 | Set obj = ##class(Person).%New(initexpresion) 48 | ``` 49 | * In general, use the reasonable name convention consistently across whole hierarchy. We recommend to use CamelCase for classes, methods and properties (e.g. `Sample.Person`, `OpenFile`, `LastIndex`, etc.), but smallCamelCase for local variables (e.g. `startDate`, `endDate`), but please be consistent and use local schema if it's different than current recommendation. 50 | * We recommend to use `#dim` statement for declaration of local variables types, e.g. 51 | ``` 52 | #dim array as %ArrayOfDataTypes = ##class(%ArrayOfDataTypes).%New() 53 | do array.SetAt(id, "id") 54 | #dim status As %Status = $$$OK 55 | ``` 56 | This will help editor to provide better auto-complete, and eventually will be used by static checker for type information extraction. 57 | * Please indent blocks reasonably. We recommend to use 8, 4 or 2 spaces indentations. Pick your level, and apply consistently. 58 | ``` 59 | if (expression) { 60 | do ..Method(args...) 61 | set i = j + 1 62 | } else { 63 | while (condition) { 64 | write arg1, arg2, ! 65 | } 66 | } 67 | ``` 68 | * For better readability please insert spaces after comma in functions/methods argument list, i.e. 69 | ``` 70 | Write 1, 2, 3 71 | Do ..Method(arg1, arg2, argN) 72 | ``` 73 | For obvious reasons this recommendation not applies to arguments in `$$$macro`-call, where such extra spaces will break final result. 74 | * For better readability please insert spaces around assignment. You may align several neighbour assignments according to your tastes, i.e. 75 | ``` 76 | #dim index As %Integer = 0 77 | #dim countOfItems As %Integer = ..Count() 78 | set j = k + 1 79 | set iN = jN \ l 80 | ``` 81 | 82 | ## Related discussion 83 | [Standards document for Objectscript developers](https://community.intersystems.com/post/standards-document-objectscript-developers) 84 | --------------------------------------------------------------------------------