diff --git a/docs/API/BlobClass.md b/docs/API/BlobClass.md
index 22262b92458de5..d566062e79e41b 100644
--- a/docs/API/BlobClass.md
+++ b/docs/API/BlobClass.md
@@ -5,6 +5,12 @@ title: Blob
The Blob class lets you create and manipulate [blob objects](../Concepts/dt_blob.md#blob-types) (`4D.Blob`).
+:::info
+
+This class is [**streamable**](../Concepts/dt_object.md#binary-streaming-variable-to-blob) in binary.
+
+:::
+
### Summary
||
diff --git a/docs/API/CollectionClass.md b/docs/API/CollectionClass.md
index 2fa45e7517e794..9c1e02fa5ddcbb 100644
--- a/docs/API/CollectionClass.md
+++ b/docs/API/CollectionClass.md
@@ -9,6 +9,11 @@ The Collection class manages [Collection](Concepts/dt_collection.md) type expres
A collection is initialized with the [`New collection`](../commands/new-collection) or [`New shared collection`](../commands/new-shared-collection) commands.
+:::info
+
+This class is [**streamable**](../Concepts/dt_object.md#binary-streaming-variable-to-blob) in binary.
+
+:::
### Example
diff --git a/docs/API/EmailObjectClass.md b/docs/API/EmailObjectClass.md
index 6181d150547830..e7d4a6297ebaa7 100644
--- a/docs/API/EmailObjectClass.md
+++ b/docs/API/EmailObjectClass.md
@@ -16,6 +16,13 @@ You send `Email` objects using the SMTP [`.send()`](SMTPTransporterClass.md#send
[`MAIL Convert from MIME`](../commands/mail-convert-from-mime) and [`MAIL Convert to MIME`](../commands/mail-convert-to-mime) commands can be used to convert `Email` objects to and from MIME contents.
+:::info
+
+This class is [**streamable**](../Concepts/dt_object.md#binary-streaming-variable-to-blob) in binary.
+
+:::
+
+
### Email Object
Email objects provide the following properties:
diff --git a/docs/API/FileClass.md b/docs/API/FileClass.md
index b5bbde2d330e9a..ac8ef5a0e60f46 100644
--- a/docs/API/FileClass.md
+++ b/docs/API/FileClass.md
@@ -5,6 +5,14 @@ title: File
`File` objects are created with the [`File`](../commands/file) command. They contain references to disk files that may or may not actually exist on disk. For example, when you execute the `File` command to create a new file, a valid `File` object is created but nothing is actually stored on disk until you call the [`file.create( )`](#create) function.
+
+:::info
+
+This class is [**streamable**](../Concepts/dt_object.md#binary-streaming-variable-to-blob) in binary.
+
+:::
+
+
### Example
The following example creates a preferences file in the project folder:
diff --git a/docs/API/FileHandleClass.md b/docs/API/FileHandleClass.md
index f66157df84c0be..8de8f41b394a7a 100644
--- a/docs/API/FileHandleClass.md
+++ b/docs/API/FileHandleClass.md
@@ -17,7 +17,6 @@ Object resources, such as documents, are released when no more references exist
:::
-
### Example
```code4d
@@ -57,6 +56,7 @@ End while
```
+
### FileHandle object
File handle objects cannot be shared.
diff --git a/docs/API/FolderClass.md b/docs/API/FolderClass.md
index 417f6c5dd687b7..4c949b0d93a25e 100644
--- a/docs/API/FolderClass.md
+++ b/docs/API/FolderClass.md
@@ -7,6 +7,14 @@ title: Folder
`Folder` objects are created with the [`Folder`](../commands/folder) command. They contain references to folders that may or may not actually exist on disk. For example, when you execute the `Folder` command to create a new folder, a valid `Folder` object is created but nothing is actually stored on disk until you call the [`folder.create()`](#create) function.
+
+:::info
+
+This class is [**streamable**](../Concepts/dt_object.md#binary-streaming-variable-to-blob) in binary.
+
+:::
+
+
### Example
The following example creates a "JohnSmith" folder:
diff --git a/docs/API/FormulaClass.md b/docs/API/FormulaClass.md
index b8494a9407c9e9..836e36c673f64c 100644
--- a/docs/API/FormulaClass.md
+++ b/docs/API/FormulaClass.md
@@ -13,6 +13,12 @@ title: Formula
See examples in the [Executing code in Function objects](../API/FunctionClass.md#executing-code-in-function-objects) paragraph.
+:::info
+
+This class is [**streamable**](../Concepts/dt_object.md#binary-streaming-variable-to-blob) in binary.
+
+:::
+
### Passing parameters to formulas
diff --git a/docs/API/MailAttachmentClass.md b/docs/API/MailAttachmentClass.md
index 3049a31be4f620..2a0a4fd0362514 100644
--- a/docs/API/MailAttachmentClass.md
+++ b/docs/API/MailAttachmentClass.md
@@ -5,6 +5,12 @@ title: MailAttachment
Attachment objects allow referencing files within a [`Email`](EmailObjectClass.md) object. Attachment objects are created using the [`MAIL New attachment`](../commands/mail-new-attachment) command.
+:::info
+
+This class is [**streamable**](../Concepts/dt_object.md#binary-streaming-variable-to-blob) in binary.
+
+:::
+
### Attachment Object
diff --git a/docs/API/MethodClass.md b/docs/API/MethodClass.md
index 759994eb2b48cc..b2771ef01eccc8 100644
--- a/docs/API/MethodClass.md
+++ b/docs/API/MethodClass.md
@@ -21,6 +21,12 @@ See examples in the [Executing code in Function objects](../API/FunctionClass.md
:::
+:::info
+
+This class is [**streamable**](../Concepts/dt_object.md#binary-streaming-variable-to-blob) in binary.
+
+:::
+
### Examples
diff --git a/docs/API/SessionClass.md b/docs/API/SessionClass.md
index 9c98a6ead3bfa0..55d3c5f064a98b 100644
--- a/docs/API/SessionClass.md
+++ b/docs/API/SessionClass.md
@@ -12,7 +12,7 @@ Session objects are returned by the [`Session`](../commands/session) command. Th
- [Scalable sessions for advanced web applications](https://blog.4d.com/scalable-sessions-for-advanced-web-applications/)
- [Permissions: Inspect Session Privileges for Easy Debugging](https://blog.4d.com/permissions-inspect-session-privileges-for-easy-debugging/)
- [Generate, share and use web sessions One-Time Passcodes (OTP)](https://blog.4d.com/connect-your-web-apps-to-third-party-systems/)
-- [Client / server – Handle a session when working on a 4D client](https://blog.4d.com/client-server-handle-a-session-when-working-on-a-4d-client)
+- [Forget server-side wrappers, use 4D Sessions from the client](https://blog.4d.com/forget-server-side-wrappers-use-4d-sessions-from-the-client)
:::
diff --git a/docs/API/VectorClass.md b/docs/API/VectorClass.md
index 7a9965b582de13..2181018c84adc0 100644
--- a/docs/API/VectorClass.md
+++ b/docs/API/VectorClass.md
@@ -10,7 +10,11 @@ The `Vector` class allows you to handle **vectors** and to execute distance and
In the world of AIs, a vector is a sequence of numbers that enables a machine to understand and manipulate complex data. For a detailed overview of the role of vectors with AIs, you can refer to [this page](https://aiforsocialgood.ca/blog/understanding-the-role-of-vectors-in-artificial-intelligence-a-comprehensive-guide).
+:::info
+
+This class is [**streamable**](../Concepts/dt_object.md#binary-streaming-variable-to-blob) in binary.
+:::
### Understanding the different vector computations
diff --git a/docs/API/WebServerClass.md b/docs/API/WebServerClass.md
index 785b2366d46eb4..62c22e5283db3d 100644
--- a/docs/API/WebServerClass.md
+++ b/docs/API/WebServerClass.md
@@ -6,14 +6,17 @@ title: WebServer
The `WebServer` class API allows you to start and monitor a web server for the main (host) application as well as each hosted component (see the [Web Server object](WebServer/webServerObject.md) overview). This class is available from the `4D` class store.
+### Properties
+
+- **Streamable**: no
+- **Sharable**: no
+
### Web Server object
Web server objects are instantiated with the [`WEB Server`](../commands/web-server) command.
They provide the following properties and functions:
-### Summary
-
||
|---|
|[](#accesskeydefined)
|
diff --git a/docs/Concepts/classes.md b/docs/Concepts/classes.md
index 445bbc197405cc..c3bf9f7d57d8cf 100644
--- a/docs/Concepts/classes.md
+++ b/docs/Concepts/classes.md
@@ -41,6 +41,13 @@ $hello:=$person.sayHello() //"Hello John Doe"
Class files are managed through the 4D Explorer (see [Creating classes](../Project/code-overview.md#creating-classes)).
+#### Deleting a class
+
+To delete an existing class, select it in the Explorer and click  or choose **Move to Trash** from the contextual menu.
+
+You can also remove the .4dm class file from the "Classes" folder on your disk.
+
+
## Class stores
Available classes are accessible from their class stores. Two class stores are available:
@@ -49,7 +56,7 @@ Available classes are accessible from their class stores. Two class stores are a
- [`4D`](../commands/4d) for built-in class store
-### `cs`
+#### `cs`
**cs** : Object
@@ -74,7 +81,7 @@ You want to create a new instance of an object of `myClass`:
$instance:=cs.myClass.new()
```
-### `4D`
+#### `4D`
**4D** : Object
@@ -100,7 +107,7 @@ $key:=4D.CryptoKey.new(New object("type";"ECDSA";"curve";"prime256v1"))
You want to list 4D built-in classes:
```4d
- var $keys : collection
+ var $keys : Collection
$keys:=OB Keys(4D)
ALERT("There are "+String($keys.length)+" built-in classes.")
```
@@ -144,7 +151,7 @@ Specific 4D keywords can be used in class definitions:
#### Syntax
```4d
-{shared} Function ({$parameterName : type; ...}){->$parameterName : type}
+{local | server} {shared} Function ({$parameterName : type; ...}){->$parameterName : type}
// code
```
@@ -158,6 +165,9 @@ Class functions are specific properties of the class. They are objects of the [4
If the function is declared in a [shared class](#shared-classes), you can use the `shared` keyword so that the function could be called without [`Use...End use` structure](shared.md#useend-use). For more information, refer to the [Shared functions](#shared-functions) paragraph below.
+In the context of a client/server application, the `local` or `server` keyword allows you to specify on which machine the function must be executed. These keywords can only be used with ORDA data model functions and shared/session singleton functions. For more information, refer to the [local and server functions](#local-and-server) paragraph below.
+
+
The function name must be compliant with [object naming rules](Concepts/identifiers.md#object-properties).
:::note
@@ -465,12 +475,12 @@ $o.age:="Smith" //error with check syntax
#### Syntax
```4d
-{shared} Function get ()->$result : type
+{local | server} {shared} Function get ()->$result : type
// code
```
```4d
-{shared} Function set ($parameterName : type)
+{local | server} {shared} Function set ($parameterName : type)
// code
```
@@ -497,6 +507,9 @@ When both functions are defined, the computed property is **read-write**. If onl
If the functions are declared in a [shared class](#shared-classes), you can use the `shared` keyword with them so that they could be called without [`Use...End use` structure](shared.md#useend-use). For more information, refer to the [Shared functions](#shared-functions) paragraph below.
+In the context of a client/server application, the `local` or `server` keyword allows you to specify on which machine the function must be executed. These keywords can only be used with ORDA data model functions and shared/session singleton functions. For more information, refer to the [local and server functions](#local-and-server) paragraph below.
+
+
The type of the computed property is defined by the `$return` type declaration of the *getter*. It can be of any [valid property type](dt_object.md).
> Assigning *undefined* to an object property clears its value while preserving its type. In order to do that, the `Function get` is first called to retrieve the value type, then the `Function set` is called with an empty value of that type.
@@ -632,13 +645,6 @@ $val:=$o.f() //8
For more details, see the [`This`](../commands/this) command description.
-
-
-## Class commands
-
-
-Several commands of the 4D language allows you to handle class features.
-
### `OB Class`
#### `OB Class ( object ) -> Object | Null`
@@ -867,7 +873,193 @@ $myList := cs.ItemInventory.me.itemList
-#### See also
+:::tip Related blog posts
+
+[Singletons in 4D](https://blog.4d.com/singletons-in-4d)
+[Session Singletons](https://blog.4d.com/introducing-session-singletons)
+
+:::
+
+
+
+## `local` and `server`
+
+In [client/server architecture](../Desktop/clientServer.md), `local` and `server` keywords allow you to specify where you want the function to be executed: client-side, or server-side. Controlling the execution location is useful for performance reasons or to implement business logic features.
+
+The formal syntax is:
+
+```4d
+// declare a function to execute on a client in client/server
+local Function
+```
+```4d
+// declare a function to execute on the server in client/server
+server Function
+```
+
+`local` and `server` keywords are only available for the functions of the following classes:
+- [ORDA data model](../ORDA/ordaClasses.md) classes
+- [shared or session singleton](#singleton-classes) classes.
+
+
+:::tip Related blog post
+
+[A new way to execute business logic on the server](https://blog.4d.com/a-new-way-to-execute-business-logic-on-the-server)
+
+:::
+
+### Overview
+
+Supported functions have a **default execution location** when no location keyword is used. You can nevertheless insert a `local` or `server` keyword to modify the execution location, or to make the code more explicit.
+
+|Supported functions|Default execution|with `local` keyword|with `server` keyword|
+|---|---|---|---|
+|[ORDA data model](../ORDA/ordaClasses.md)|on Server|The function is executed on the client if called on the client||
+|[Shared or session singleton](#singleton-classes)|Local||The function is executed on the server on the server instance of the singleton.
If there is no instance of the singleton on the server, it is created. |
+
+If `local` and `server` keywords are used in another context, an error is returned.
+
+
+:::note
+
+For a overall description of where code is actually executed in client/server, please refer to [this section](../Desktop/clientServer.md#code-execution-location).
+
+::::
-[Singletons in 4D](https://blog.4d.com/singletons-in-4d) (blog post)
[Session Singletons](https://blog.4d.com/introducing-session-singletons) (blog post).
+### `local`
+
+In a [client/server architecture](../Desktop/clientServer.md), the `local` keyword specifies that the function must be executed **on the machine from where it is called**.
+
+:::note Reminder
+
+The `local` keyword is useless for [shared or session singleton functions](#singleton-classes), which are executed locally by default.
+
+:::
+
+By default, [ORDA data model functions](../ORDA/ordaClasses.md) are executed on the server. It usually provides the best performance since only the function request and the result are sent over the network. However, [for optimization reasons](../ORDA/client-server-optimization.md#using-the-local-keyword), you could want to execute a data model function on client. You can then use the `local` keyword.
+
+
+
+#### Example: Calculating age
+
+Given an entity with a *birthDate* attribute, we want to define an `age()` function that would be called in a list box. This function can be executed on the client, which avoids triggering a request to the server for each line of the list box.
+
+On the *StudentsEntity* class:
+
+```4d
+Class extends Entity
+
+local Function age() -> $age: Variant
+
+If (This.birthDate#!00-00-00!)
+ $age:=Year of(Current date)-Year of(This.birthDate)
+Else
+ $age:=Null
+End if
+```
+
+
+
+### `server`
+
+In a [client/server architecture](../Desktop/clientServer.md), the `server` keyword specifies that the function must be executed **on the server side**.
+
+
+:::note Reminder
+
+The `server` keyword is useless for [ORDA data model functions](../ORDA/ordaClasses.md), which are executed on the server by default.
+
+:::
+
+
+`server` function parameters and result must be [**streamable**](./dt_object.md#streaming-support). For example, [4D.Datastore](../API/DataStoreClass.md), [File handle](../API/FileHandleClass.md), or [WebServer](../API/WebServerClass.md) are non-streamable classes but [4D.File](../API/FileClass.md) is streamable.
+
+This feature is particularly useful in the context of [remote user sessions](../Desktop/sessions.md#remote-user-sessions), allowing you to implement the business logic in a [session singleton](#shared-or-session-singleton-functions) to share it accross all the processes of the session, thus extending the functionalities of the [`Session`](../commands/session) command. In this case, you might want the relevant business logic to be executed **on the server** so that all the session information is gathered on the server.
+
+
+By default, shared or session singleton functions are executed locally. Adding the `server` keyword in the class function definition makes 4D use the singleton instance on the server. Note that this can result of an instantiation of the singleton on the server if no instance exists yet.
+
+For [sessions singletons](#singleton-classes), the function is executed on the server in the corresponding singleton instance, i.e. the instance of the singleton for the current session.
+
+:::note
+
+If you declare a `server Function` in a shared singleton, then:
+
+- you instantiate a singleton *S1* on the client (named *s1*),
+- you run *s1.function()* on the client.
+
+If no instance of *S1* exists on the server at that moment, *S1* is instantiated on the server (the constructor is executed), and *function()* runs on that server instance. As a result, two instances of *S1* can coexist (client-side and server-side), with distinct property values. In this case, *s1.property* is always accessed locally. It cannot be accessed on the server, for example from server-side code using direct dot notation (an error is returned).
+
+:::
+
+#### Example: Administration singleton
+
+The *Administration* shared singleton has a "server" function running the [`Process activity`](../commands/process-activity) command. This singleton is instantiated on a remote 4D but the function returns the server activity on the server.
+
+```4d
+ // Administration class
+
+shared singleton Class constructor
+
+ // This function is executed on the server
+server Function processActivity() : Object
+ return Process activity
+
+
+Function localProcessActivity() : Object
+ return Process activity
+```
+
+Code running on the client:
+
+```4d
+var $localActivity; $serverActivity : Object
+var $administration : cs.Administration
+
+// The Administration singleton is instantiated on the 4D Client
+$administration:=cs.Administration.me
+
+// Get processes running on the remote 4D
+$localActivity:=$administration.localProcessActivity()
+
+// Get processes and sessions running on 4D Server
+$serverActivity:=$administration.processActivity()
+
+```
+
+
+
+#### Example: Session singleton
+
+You store your users in a Users table and handle a custom authentication. You use a session singleton for the authentication:
+
+```4d
+// UserSession session singleton class
+
+server Function checkUser($credentials : Object) : Boolean
+
+var $user : cs.UsersEntity
+var $result:=False
+
+If ($credentials#Null)
+ $user:=ds.Users.query("Email === :1"; $credentials.identifier).first()
+
+ If (($user#Null) && (Verify password hash($credentials.password; $user.Password)))
+ Use (Session.storage)
+ Session.storage.userInfo:=New shared object("userId"; $user.ID)
+ End use
+
+ $result:=True
+ End if
+End if
+
+return $result
+```
+
+To provide the current user to 4D clients, the singleton exposes a user computed property got from the server:
+
+```4d
+server Function get user() : cs.UsersEntity
+ return ds.Users.get(Session.storage.userInfo.userId)
+```
diff --git a/docs/Concepts/dt_object.md b/docs/Concepts/dt_object.md
index 21f6f7067c8b5c..13e3e68512db76 100644
--- a/docs/Concepts/dt_object.md
+++ b/docs/Concepts/dt_object.md
@@ -18,7 +18,7 @@ Variables, fields or expressions of the Object type can contain various types of
- picture(2)
- collection
-(1) **Non-streamable objects** such as ORDA objects ([entities](ORDA/dsMapping.md#entity), [entity selections](ORDA/dsMapping.md#entity-selection), etc.), [file handles](../API/FileHandleClass.md), [web server](../API/WebServerClass.md)... cannot be stored in **object fields**. An error is returned if you try to do it; however, they are fully supported in **object variables** in memory.
+(1) [**Non-streamable objects**](#streaming-support) such as ORDA objects ([entities](ORDA/dsMapping.md#entity), [entity selections](ORDA/dsMapping.md#entity-selection), etc.), [file handles](../API/FileHandleClass.md), [web server](../API/WebServerClass.md)... cannot be stored in **object fields**. An error is returned if you try to do it; however, they are fully supported in **object variables** in memory.
(2) When exposed as text in the debugger or exported to JSON, picture object properties print "[object Picture]".
@@ -272,6 +272,40 @@ $doc:=Null // free resources occupied by $doc
```
+## Classes
+
+Objects can belong to classes. Using a class allows to predefine an object behaviour and structure with associated properties and functions.
+
+The 4D language proposes several [native classes](../category/class-API-reference/) that you can use to handle objects. You can also define and use your own [user classes](./classes.md) to organize your code.
+
+
+
+## Streaming support
+
+A streamable class (or *serializable* class) is a class whose objects can be converted into a sequence of bytes (text or binary) in order to write them in a file, to send them as parameters, or to be able to store and rebuild them afterwards.
+
+### Text streaming (`JSON Stringify`)
+
+JSON commands that stringify contents such as [`JSON Stringify`](../commands/json-stringify) and the [`Execute on server`](../commands/execute-on-server) command allow you to convert objects to json (text). They support objects, collections, and user classes.
+
+However, text streaming of objects has the following limitations:
+
+- circular references (i.e. objects containing themselves as a property) are not supported and return an error,
+- a class object loses its class when it is stringified,
+- native 4D class objects such as [Entity](../API/EntityClass.md) cannot be represented as JSON and are returned as "[object \]", for example "[object Entity]".
+
+### Binary streaming (`VARIABLE TO BLOB`)
+
+4D also implements a built-in binary streaming feature through the [`VARIABLE TO BLOB`](../commands/variable-to-blob) command. This feature allows you to get rid of most of text streaming limitations regarding objects (see above):
+
+- circular references are supported,
+- objects keep their class,
+- an extended range of objects are streamable: [4D Write Pro](../WritePro/user-legacy/presentation.md) documents, pictures as objects, [blobs as objects](dt_blob.md#blob-types), and pointers as objects,
+- several native 4D class objects can be streamed, for example [`File`](../API/FileClass.md), [`Folder`](../API/FolderClass.md), or [`Vector`](../API/VectorClass.md). However, only a few native 4D classes are streamable. Unless explicitely stated that "This class is **streamable** in binary", consider that a native 4D class is NOT streamable.
+
+
+
+
## Examples
Using object notation simplifies the 4D code while handling objects. Note however that the command-based notation is still fully supported.
diff --git a/docs/Desktop/clientServer.md b/docs/Desktop/clientServer.md
index 5e02cfc9cef10d..fd25b4d95b2b80 100644
--- a/docs/Desktop/clientServer.md
+++ b/docs/Desktop/clientServer.md
@@ -128,3 +128,28 @@ This feature is designed for small-size development teams who are used to work o
[Developing Concurrently on 4D Server in Project Mode](https://blog.4d.com/developing-concurrently-on-4d-server-in-project-mode/)
:::
+
+
+## Code execution location
+
+In a client/server application, it is important to know where your code will be actually executed: **server-side** or **client-side**. Execution location is crucial when you want to implement user session-related code, share information between processes, access data, etc.
+
+The following table summarizes where the code is executed by default and how to switch its execution location (if allowed). Note that **local** means that the code will be executed on the machine from where it is actually called.
+
+|Code|Default execution|How to switch|
+|---|---|---|
+|[ORDA data model functions](../ORDA/ordaClasses.md)|server|use `local` keyword in function definition|
+|ORDA computed attribute functions [`get()`](../ORDA/ordaClasses.md#function-get-attributename), [`set()`](../ORDA/ordaClasses.md#function-set-attributename)|server|use `local` keyword in function definition|
+|ORDA computed attribute functions [`query()`](../ORDA/ordaClasses.md#function-query-attributename), [`orderBy()`](../ORDA/ordaClasses.md#function-orderby-attributename)|server|n/a|
+|ORDA event functions [(general)](../ORDA/orda-events.md)|server|n/a|
+|ORDA event function [`constructor()`](../ORDA/ordaClasses.md#class-constructor-1)|local|n/a|
+|ORDA event function [`event touched()`](../ORDA/orda-events.md#function-event-touched)|server|use `local` keyword in function definition|
+|[User class functions](../Concepts/classes.md#function)|local|n/a|
+|[Shared or session singleton function](../Concepts/classes.md#singleton-classes)|local|use `server` keyword in function definition|
+|Trigger|server|n/a|
+|Project method called from a client|client|check [**Execute on server** option](../Project/project-method-properties.md#execute-on-server). The code is executed in the twin process of the [user session process](./sessions.md#remote-user-sessions-remote-user-sessions)|
+|||call [`Execute on server`](../commands/execute-on-server) command. The code is executed in the [Stored procedures session](./sessions.md#stored-procedure-sessions-stored-procedure-sessions) |
+|Project method called from a stored procedure on the server|server|call [`EXECUTE ON CLIENT`](../commands/execute-on-client) command. The target client must have been [registered](../commands/register-client) |
+|Object method|local|n/a|
+|Database methods:- On Backup Shutdown
- On Backup Startup
- On Server Close Connection
- On Server Open Connection
- On Server Shutdown
- On Server Startup
- On SQL Authentication
- On Web Authentication
- On Web Connection
|server|n/a|
+|Database methods:|client|n/a|
\ No newline at end of file
diff --git a/docs/Desktop/sessions.md b/docs/Desktop/sessions.md
index 821f59e67cc8ee..bb572fa20be8de 100644
--- a/docs/Desktop/sessions.md
+++ b/docs/Desktop/sessions.md
@@ -71,7 +71,7 @@ On the client side, two distinct local storage objects are available:
:::tip Related blog posts
- [4D remote session object with Client/Server connection and Stored procedure](https://blog.4d.com/new-4D-remote-session-object-with-client-server-connection-and-stored-procedure).
-- [Client / server – Handle a session when working on a 4D client](https://blog.4d.com/client-server-handle-a-session-when-working-on-a-4d-client).
+- [Forget server-side wrappers, use 4D Sessions from the client](https://blog.4d.com/forget-server-side-wrappers-use-4d-sessions-from-the-client).
:::
diff --git a/docs/Notes/updates.md b/docs/Notes/updates.md
index 4db614a79e8c8a..b8e63799a0ae12 100644
--- a/docs/Notes/updates.md
+++ b/docs/Notes/updates.md
@@ -13,6 +13,7 @@ title: Release Notes
- New [`4D.Method` class](../API/MethodClass.md) to create and execute a 4D method code from text source. [`METHOD Get path`](../commands/method-get-path) and [`METHOD RESOLVE PATH`](../commands/method-resolve-path) commands support a new `path volatile method` constant (128).
- IMAP transporter now supports mailbox event notifications using the IDLE protocol through a [notifier object](../API/IMAPTransporterClass.md#notifier) of the [4D.IMAPNotifier](../API/IMAPNotifier.md) class, configurable via the `listener` property of [IMAP New transporter](../commands/imap-new-transporter).
- Remote [session](../API/SessionClass.md) objects are now [available client-side](../Desktop/sessions.md#availability).
+- Support of [`server` keyword](../Concepts/classes.md#server) for ORDA data model functions and shared/session singleton functions.
- Dependencies: support of [components stored on GitLab repositories](../Project/components.md#configuring-a-gitlab-repository).
diff --git a/docs/ORDA/client-server-optimization.md b/docs/ORDA/client-server-optimization.md
index 4c02de52577fc8..3c7d23d02bbf1f 100644
--- a/docs/ORDA/client-server-optimization.md
+++ b/docs/ORDA/client-server-optimization.md
@@ -147,3 +147,55 @@ By default, the ORDA cache is transparently handled by 4D. However, you can cont
* [dataClass.getRemoteCache()](../API/DataClassClass.md#getremotecache)
* [dataClass.clearRemoteCache()](../API/DataClassClass.md#clearremotecache)
+### Using the `local` keyword
+
+By default, [ORDA data model functions](../ORDA/ordaClasses.md) are executed on the server, which usually provides the best performance since only the function request and the result are sent over the network. However, it could happen that a function processes data that's already in the local cache and is fully executable on the client side. In this case, you can save requests to the server and thus, enhance the application performance by [using the `local` keyword in the function definition](../Concepts/classes.md#local).
+
+Note that the function will work even if it eventually requires to access the server (for example if the ORDA cache is expired). However, it is highly recommended to make sure that the local function does not access data on the server, otherwise the local execution could not bring any performance benefit. A local function that generates many requests to the server is less efficient than a function executed on the server that would only return the resulting values. For example, consider the following function on the Schools entity class:
+
+```4d
+// Get the youngest students
+// Inappropriate use of local keyword
+local Function getYoungest() : Object
+ return This.students.query("birthDate >= :1"; !2000-01-01!).orderBy("birthDate desc").slice(0; 5)
+```
+- **without** the `local` keyword, the result is given using a single request
+- **with** the `local` keyword, 4 requests are necessary: one to get the Schools entity students, one for the `query()`, one for the `orderBy()`, and one for the `slice()`. In this example, using the `local` keyword is inappropriate.
+
+
+#### Example: Checking attributes
+
+We want to check the consistency of the attributes of an entity loaded on the client and updated by the user before requesting the server to save them.
+
+On the *StudentsEntity* class, the local `checkData()` function checks the Student's age:
+
+```4d
+Class extends Entity
+
+local Function checkData() -> $status : Object
+
+$status:=New object("success"; True)
+Case of
+ : (This.age()=Null)
+ $status.success:=False
+ $status.statusText:="The birthdate is missing"
+
+ :((This.age() <15) | (This.age()>30) )
+ $status.success:=False
+ $status.statusText:="The student must be between 15 and 30 - This one is "+String(This.age())
+End case
+```
+
+Calling code:
+
+```4d
+var $status : Object
+
+//Form.student is loaded with all its attributes and updated on a Form
+$status:=Form.student.checkData()
+If ($status.success)
+ $status:=Form.student.save() // call the server
+End if
+```
+
+
diff --git a/docs/ORDA/orda-events.md b/docs/ORDA/orda-events.md
index 06a73f3c95956e..245737a6bb5b75 100644
--- a/docs/ORDA/orda-events.md
+++ b/docs/ORDA/orda-events.md
@@ -52,11 +52,11 @@ You can also define the same event at both attribute and entity levels. The attr
Usually, ORDA events are executed on the server.
-In client/server configuration however, the `touched()` event function can be executed on the **server or the client**, depending on the use of [`local`](./ordaClasses.md#local-functions) keyword. A specific implementation on the client side allows the triggering of the event on the client.
+In client/server configuration however, the `touched()` event function can be executed on the **server or the client**, depending on the use of [`local`](../Concepts/classes.md#local) keyword. A specific implementation on the client side allows the triggering of the event on the client.
:::note
-ORDA [`constructor()`](./ordaClasses.md#class-constructor) functions are always executed on the client.
+ORDA [`constructor()`](./ordaClasses.md#class-constructor) functions are always executed locally.
:::
@@ -67,11 +67,11 @@ With other remote configurations (i.e. [Qodly applications](https://developer.4d
The following table lists ORDA events along with their rules.
-| Event | Level | Function name | (C/S) Executed on |Can stop action by returning an error
+| Event | Level | Function name | (C/S) Execution |Can stop action by returning an error
| :------- |:------- | :----- | :-----: |---|
-| Entity instantiation | Entity | [`constructor()`](./ordaClasses.md#class-constructor-1) | client | no|
-| Attribute touched | Attribute | `event touched ()` | Depends on [`local`](../ORDA/ordaClasses.md#local-functions) keyword | no|
-| | Entity | `event touched()` | Depends on [`local`](../ORDA/ordaClasses.md#local-functions) keyword | no|
+| Entity instantiation | Entity | [`constructor()`](./ordaClasses.md#class-constructor-1) | local | no|
+| Attribute touched | Attribute | `event touched ()` | Depends on [`local`](../Concepts/classes.md#local) keyword | no|
+| | Entity | `event touched()` | Depends on [`local`](../Concepts/classes.md#local) keyword | no|
|Before saving an entity|Attribute|`validateSave ()`|server|yes|
||Entity|`validateSave()`|server|yes|
|When saving an entity|Attribute|`saving ()`|server|yes|
diff --git a/docs/ORDA/ordaClasses.md b/docs/ORDA/ordaClasses.md
index 8e762d5efe8163..b76af78426d75d 100644
--- a/docs/ORDA/ordaClasses.md
+++ b/docs/ORDA/ordaClasses.md
@@ -66,6 +66,7 @@ Also, object instances from ORDA data model user classes benefit from their pare
|Release|Changes|
|---|---|
+|21 R3|Support for the `server` keyword.
|19 R4|Alias attributes in the Entity Class
|19 R3|Computed attributes in the Entity Class
|18 R5|Data model class functions are not exposed to REST by default. New `exposed` and `local` keywords.
@@ -303,7 +304,7 @@ When creating or editing data model classes, you must pay attention to the follo
When compiled, data model class functions are executed:
- in **preemptive or cooperative processes** (depending on the calling process) in single-user applications,
-- in **preemptive processes** in client/server applications (except if the [`local`](#local-functions) keyword is used, in which case it depends on the calling process like in single-user).
+- in **preemptive processes** in client/server applications (except if the [`local`](../Concepts/classes.md#local) keyword is used, in which case it depends on the calling process like in single-user).
If your project is designed to run in client/server, make sure your data model class function code is thread-safe. If thread-unsafe code is called, an error will be thrown at runtime (no error will be thrown at compilation time since cooperative execution is supported in single-user applications).
@@ -369,9 +370,7 @@ The `Class constructor` function is triggered by the following commands and feat
#### Remote configurations
-When using a remote configurations, you need to pay attention to the following principles:
-
-- In **client/server** the function can be called on the client or on the server, depending on the location of the calling code. When it is called on the client, it is not triggered again when the client attempts to save the new entity and sends an update request to the server to create in memory on the server.
+When using a remote configurations, you need to pay attention to the following principle: in **client/server** the function can be called on the client or on the server, depending on the location of the calling code. When it is called on the client, it is not triggered again when the client attempts to save the new entity and sends an update request to the server to create in memory on the server.
:::warning
@@ -499,7 +498,7 @@ Within computed attribute functions, [`This`](Concepts/classes.md#this) designat
> ORDA computed attributes are not [**exposed**](#exposed-vs-non-exposed-functions) by default. You expose a computed attribute by adding the `exposed` keyword to the **get function** definition.
-> **get and set functions** can have the [**local**](#local-functions) property to optimize client/server processing.
+> **get and set functions** can have the [`local`](../Concepts/classes.md#local) property to optimize client/server processing.
### `Function get `
@@ -507,7 +506,7 @@ Within computed attribute functions, [`This`](Concepts/classes.md#this) designat
#### Syntax
```4d
-{local} {exposed} Function get ({$event : Object}) -> $result : type
+{local | server} {exposed} Function get ({$event : Object}) -> $result : type
// code
```
The *getter* function is mandatory to declare the *attributeName* computed attribute. Whenever the *attributeName* is accessed, 4D evaluates the `Function get` code and returns the *$result* value.
@@ -532,6 +531,12 @@ The *$event* parameter contains the following properties:
|kind|Text|"get"|
|result|Variant|Optional. Add this property with Null value if you want a scalar attribute to return Null|
+:::note
+
+For more information about the `local` and `server` keywords, please refer to the [local and server](../Concepts/classes.md#local-and-server) section.
+
+:::
+
#### Examples
@@ -578,7 +583,7 @@ Function get coWorkers($event : Object)-> $result: cs.EmployeeSelection
```4d
-{local} Function set ($value : type {; $event : Object})
+{local | server} Function set ($value : type {; $event : Object})
// code
```
@@ -595,6 +600,12 @@ The *$event* parameter contains the following properties:
|kind|Text|"set"|
|value|Variant|Value to be handled by the computed attribute|
+:::note
+
+For more information about the `local` and `server` keywords, please refer to the [local and server](../Concepts/classes.md#local-and-server) section.
+
+:::
+
#### Example
```4d
@@ -1131,138 +1142,3 @@ It can be called by the following HTTP GET request:
IP:port/rest/Products/getThumbnail?$params='["Yellow Pack",200,200]'
```
-
-## Local functions
-
-By default in client/server architecture, ORDA data model functions are executed **on the server**. It usually provides the best performance since only the function request and the result are sent over the network.
-
-However, it could happen that a function is fully executable on the client side (e.g., when it processes data that's already in the local cache). In this case, you can save requests to the server and thus, enhance the application performance by inserting the `local` keyword. The formal syntax is:
-
-```4d
-// declare a function to execute locally in client/server
-local Function
-```
-
-With this keyword, the function will always be executed on the client side.
-
-> The `local` keyword can only be used with data model class functions. If used with a [regular user class](Concepts/classes.md) function, it is ignored and an error is returned by the compiler.
-
-Note that the function will work even if it eventually requires to access the server (for example if the ORDA cache is expired). However, it is highly recommended to make sure that the local function does not access data on the server, otherwise the local execution could not bring any performance benefit. A local function that generates many requests to the server is less efficient than a function executed on the server that would only return the resulting values. For example, consider the following function on the Schools entity class:
-
-```4d
-// Get the youngest students
-// Inappropriate use of local keyword
-local Function getYoungest
- var $0 : Object
- $0:=This.students.query("birthDate >= :1"; !2000-01-01!).orderBy("birthDate desc").slice(0; 5)
-```
-- **without** the `local` keyword, the result is given using a single request
-- **with** the `local` keyword, 4 requests are necessary: one to get the Schools entity students, one for the `query()`, one for the `orderBy()`, and one for the `slice()`. In this example, using the `local` keyword is inappropriate.
-
-
-### Examples
-
-#### Calculating age
-
-Given an entity with a *birthDate* attribute, we want to define an `age()` function that would be called in a list box. This function can be executed on the client, which avoids triggering a request to the server for each line of the list box.
-
-On the *StudentsEntity* class:
-
-```4d
-Class extends Entity
-
-local Function age() -> $age: Variant
-
-If (This.birthDate#!00-00-00!)
- $age:=Year of(Current date)-Year of(This.birthDate)
-Else
- $age:=Null
-End if
-```
-
-#### Checking attributes
-
-We want to check the consistency of the attributes of an entity loaded on the client and updated by the user before requesting the server to save them.
-
-On the *StudentsEntity* class, the local `checkData()` function checks the Student's age:
-
-```4d
-Class extends Entity
-
-local Function checkData() -> $status : Object
-
-$status:=New object("success"; True)
-Case of
- : (This.age()=Null)
- $status.success:=False
- $status.statusText:="The birthdate is missing"
-
- :((This.age() <15) | (This.age()>30) )
- $status.success:=False
- $status.statusText:="The student must be between 15 and 30 - This one is "+String(This.age())
-End case
-```
-
-Calling code:
-
-```4d
-var $status : Object
-
-//Form.student is loaded with all its attributes and updated on a Form
-$status:=Form.student.checkData()
-If ($status.success)
- $status:=Form.student.save() // call the server
-End if
-```
-
-
-
-## Support in 4D IDE
-
-
-### Class files
-
-An ORDA data model user class is defined by adding, at the [same location as regular class files](../Concepts/classes.md#class-definition) (*i.e.* in the `/Sources/Classes` folder of the project folder), a .4dm file with the name of the class. For example, an entity class for the `Utilities` dataclass will be defined through a `UtilitiesEntity.4dm` file.
-
-
-### Creating classes
-
-4D automatically pre-creates empty classes in memory for each available data model object.
-
-
-
-
-> By default, empty ORDA classes are not displayed in the Explorer. To show them you need to select **Show all data classes** from the Explorer's options menu:
-
-
-ORDA user classes have a different icon from regular classes. Empty classes are dimmed:
-
-
-
-
-To create an ORDA class file, you just need to double-click on the corresponding predefined class in the Explorer. 4D creates the class file and add the `extends` code. For example, for an Entity class:
-
-```
-Class extends Entity
-```
-
-Once a class is defined, its name is no longer dimmed in the Explorer.
-
-
-### Editing classes
-
-To open a defined ORDA class in the 4D Code Editor, select or double-click on an ORDA class name and use **Edit...** from the contextual menu/options menu of the Explorer window:
-
-
-
-For ORDA classes based upon the local datastore (`ds`), you can directly access the class code from the 4D Structure window:
-
-
-
-
-### Code Editor
-
-In the 4D Code Editor, variables typed as an ORDA class automatically benefit from autocompletion features. Example with an Entity class variable:
-
-
-
diff --git a/docs/language-legacy/BLOB/variable-to-blob.md b/docs/language-legacy/BLOB/variable-to-blob.md
index 073d7fc4368113..d108862982628b 100644
--- a/docs/language-legacy/BLOB/variable-to-blob.md
+++ b/docs/language-legacy/BLOB/variable-to-blob.md
@@ -42,10 +42,7 @@ If you pass the *offset* variable parameter, the variable is written at the offs
After the call, the *offset* variable parameter is returned, incremented by the number of bytes that have been written. Therefore, you can reuse that same variable with another BLOB writing command to write another variable or list.
-VARIABLE TO BLOB accepts any type of variable (including other BLOBs), except the following:
-
-* Pointer
-* Array of pointers
+VARIABLE TO BLOB accepts any type of variable, including other BLOBs and [**streamable objects**](../../Concepts/dt_object.md#streaming-support).
Note that:
@@ -54,17 +51,15 @@ Note that:
**WARNING:** If you use a BLOB for storing variables, you must later use the command [BLOB TO VARIABLE](../commands/blob-to-variable) for reading back the contents of the BLOB, because variables are stored in BLOBs using a 4D internal format.
-After the call, if the variable has been successfully stored, the OK variable is set to 1\. If the operation could not be performed, the OK variable is set to 0; for example, there was not enough memory.
-
**Note regarding Platform Independence:** VARIABLE TO BLOB and [BLOB TO VARIABLE](../commands/blob-to-variable) use a 4D internal format for handling variables stored in BLOBs. As a benefit, you do not need to worry about byte swapping between platforms while using these two commands. In other words, a BLOB created on Windows using either of these commands can be reused on Macintosh, and vice-versa.
### Note
-**Compatiblity note:** Since this command alters the blob passed as a parameter, it does not support blob objects (4D.Blob type). See [Passing blobs and blob objects to 4D commands](../../Concepts/dt_blob.md#passing-blobs-and-blob-objects-to-4d-commands).
+**Compatibility note:** Since this command alters the blob passed as a parameter, it does not support blob objects (4D.Blob type). See [Passing blobs and blob objects to 4D commands](../../Concepts/dt_blob.md#passing-blobs-and-blob-objects-to-4d-commands).
## System variables and sets
-The OK variable is set to 1 if the variable has been successfully stored, otherwise it is set to 0.
+The OK variable is set to 1 if the variable has been successfully stored, otherwise it is set to 0, for example if there was not enough memory.
## Example 1
diff --git a/docs/language-legacy/Processes/session.md b/docs/language-legacy/Processes/session.md
index ea551463022f66..540214e6309334 100644
--- a/docs/language-legacy/Processes/session.md
+++ b/docs/language-legacy/Processes/session.md
@@ -62,7 +62,7 @@ The `Session` object of a remote user session is available:
- On the server, from code running in the user context, such as project methods that have the [Execute on Server](../../Project/project-method-properties.md#execute-on-server) attribute (they are executed in the "twinned" process of the client process) or ORDA [data model functions](../../ORDA/ordaClasses.md).
- On the client, from code running locally, such as in project methods or ORDA data model functions with the *local* property.
-For more information, see [the "Availability" paragraph](../../Desktop/sessions.md#availability).
+For more information, see the ["Remote user sessions" paragraph in the Desktop sessions](../../Desktop/sessions.md#remote-user-sessions) page.
diff --git a/i18n/en/docusaurus-plugin-content-docs/current.json b/i18n/en/docusaurus-plugin-content-docs/current.json
index 45e0497d631443..3a1cdf5afc2bcd 100644
--- a/i18n/en/docusaurus-plugin-content-docs/current.json
+++ b/i18n/en/docusaurus-plugin-content-docs/current.json
@@ -348,7 +348,7 @@
"description": "The label for category Classes in sidebar docs"
},
"sidebar.docs.category.Classes.link.generated-index.title": {
- "message": "Class Functions",
+ "message": "Classes",
"description": "The generated-index page title for category Classes in sidebar docs"
},
"sidebar.docs.category.Classes.link.generated-index.description": {