No es otro lenguaje de programación. Parte 2: Lógica de representación



La segunda parte de la trilogía de lenguaje y plataforma lsFusion. La primera parte se puede encontrar aquí .

Se centrará en la lógica de las representaciones, es decir, en todo lo relacionado con la combinación de datos y mostrarlos al usuario u otros sistemas de información.

Está claro que muchos pueden no estar tan interesados ​​en mirar la presentación del luchador, y les gustaría ver una pelea real, si es posible con sangre (y lo será, ya que la discusión de los artículos anteriores ayudó a comprender mejor los lugares desprotegidos de competidores potenciales y dónde vencerla) . Pero hay dos cosas a considerar:

a) este es Habr. Es decir, un recurso técnico, no les gustan las bellas imágenes y los lemas publicitarios aquí; para decir algo, necesita detalles sobre cómo va a lograr esto.
b) es un mercado para el desarrollo de sistemas de información, y es muy similar al mercado de productos para perder peso. Aquí, todos dicen que tenemos un rápido y fácil. Pero cuando se trata de detalles, en los que, como saben, el diablo miente, o los CRUD más simples se usan como ejemplos o recurren a varios trucos: muestran algunos fragmentos de código y ocultan la parte principal con las palabras "no importa". "," Hecho en un par de minutos "y todo eso.

En realidad, es por eso que teníamos dos opciones: comenzar con los beneficios y los riesgos de obtener reproches por mentiras de marketing, o comenzar con una descripción técnica y las preguntas "¿por qué necesitamos un idioma más?". Teóricamente, por supuesto, todo esto podría hacerse en un artículo, pero tal artículo sería difícil no solo de leer, sino incluso de desplazarse. En consecuencia, elegimos la segunda opción, aunque si todavía es importante que alguien conozca las razones de la apariencia y las ventajas del idioma en este momento (y no en futuros artículos), bienvenido al sitio . Consta de solo tres páginas: qué, cómo y por qué no, y, en mi opinión, proporciona suficiente información para responder a todas estas preguntas. Además, también puede probar la plataforma en línea allí , incluso para asegurarse de que no haya "piano en los arbustos", y el código de los ejemplos en este artículo es realmente todo el código necesario para ejecutar la aplicación.

Pero suficientes digresiones líricas, volvemos a la presentación de la descripción del luchador de la lógica de las representaciones.

Al igual que la lógica de dominio (primer artículo), todos los conceptos de lógica de presentación en lsFusion forman una pila:



y es en el orden de esta pila que hablaré sobre ellos.


Formas


Un formulario es el concepto más importante (y de hecho prácticamente el único) en la lógica de presentación, que es responsable de todo, tanto de la interacción del usuario como de la impresión, exportación e importación de datos.

El formulario se puede dividir lógicamente en dos partes:

  • La estructura del formulario determina qué datos muestra el formulario.
  • La presentación del formulario determina cómo muestra estos datos.

Estructura de la forma


Comenzamos, naturalmente, con la estructura de la forma.

Los objetos


Al crear un formulario, primero debe determinar qué objetos mostrará. Vale la pena señalar que puede haber una ligera confusión en la terminología entre los objetos del formulario y los objetos que se muestran en estos objetos de formulario. Por lo tanto, en el futuro, si esto no es obvio por el contexto, utilizaremos los términos "objetos de formulario" (para el primer caso) y "objetos en la base de datos" (para el segundo).

Para cada objeto de formulario, debe establecer su clase. Esta clase puede ser primitiva (incorporada) u objeto (personalizada).
FORM currentBalances ' '
OBJECTS s = Stock, i = Item // ,
;
De acuerdo con el orden de agregar objetos al formulario, se forma una lista ordenada de objetos. En consecuencia, el último objeto para un determinado conjunto de objetos se llamará un objeto de este conjunto con el número de serie máximo en esta lista (es decir, el más reciente).

Cada objeto en el formulario en un momento dado tiene un valor actual. Su cambio ocurre dependiendo de la presentación, ya sea como resultado de las acciones correspondientes del usuario en la presentación interactiva, o "virtualmente" en el proceso de lectura de datos en una representación estática.

Propiedades y acciones


Después de definir los objetos en el formulario, puede agregar propiedades y acciones, sustituyendo los objetos descritos anteriormente por ellos como entrada a los argumentos.

Tenga en cuenta que agregar acciones solo es relevante para la presentación interactiva; se ignoran en los informes y las exportaciones. Además, dado que el comportamiento de las propiedades y acciones desde el punto de vista de su visualización en el formulario es exactamente el mismo, en el futuro utilizaremos solo el término propiedad (para acciones, el comportamiento es exactamente el mismo).

Objeto de visualización


Cada propiedad se muestra exactamente en un objeto en el formulario (lo llamaremos el objeto de visualización de esta propiedad). Por defecto, el objeto de visualización es un objeto, este último para el conjunto de objetos que se pasan a la entrada de esta propiedad. Por ejemplo, si tenemos una forma de saldos actuales con dos objetos: un almacén y mercancías, y tres propiedades, nombres del almacén y mercancías y el saldo de mercancías en el almacén:
FORM currentBalances ' '
OBJECTS s = Stock, i = Item // ,
PROPERTIES name(s), name(i), currentBalance(s, i)
;
Luego, para el nombre del almacén, el objeto de visualización será s (almacén), y para el nombre de las mercancías y el saldo, i (mercancías).

Sin embargo, si es necesario, el desarrollador puede especificar el objeto de visualización explícitamente (es decir, en una vista interactiva, mostrar la propiedad con el resto en la tabla de almacenes, no productos).

Filtros y clasificación


Para cada formulario, el desarrollador puede establecer filtros y órdenes que limitarán la lista de objetos disponibles para ver / seleccionar en el formulario, así como el orden en que se muestran.

Para establecer un filtro, debe especificar una propiedad que se utilizará como criterio de filtro. El filtro se aplicará a la tabla de ese objeto, que es el último para el conjunto de objetos pasados ​​a la entrada de esta propiedad (es decir, de manera similar a la definición del objeto de visualización de la propiedad). En este caso, solo se mostrarán aquellos conjuntos de objetos (series) para los que los valores de propiedad no son NULL. Por ejemplo, si agregamos el filtro currentBalance (s, i) OR isActive (i) al formulario anterior:
FORM currentBalances ' '
OBJECTS s = Stock, i = Item // ,
PROPERTIES name(s), name(i), currentBalance(s, i)
FILTERS currentBalance(s, i) OR isActive(i)
;
Captura de pantalla del formulario


al mostrar productos, solo se mostrarán los productos que están en la balanza o marcados como activos.

Los tipos se definen como una lista de propiedades en el formulario en el que se deben mostrar los objetos de orden. De lo contrario, todo es similar a los filtros.

Grupos de objetos


La plataforma también tiene la capacidad de combinar objetos en un grupo de objetos . En este caso, el "producto cartesiano" de estos objetos se mostrará en las tablas / listas (es decir, para dos objetos, todos pares, tres objetos, triples, etc.).
FORM currentBalances ' '
OBJECTS (s = Stock, i = Item) //
PROPERTIES name(s), name(i), currentBalance(s, i)
FILTERS currentBalance(s, i) OR isActive(i)
;
Captura de pantalla del formulario


En consecuencia, en casi todas partes, tanto antes como después, en lugar de objetos individuales del formulario, puede usar grupos de objetos.

En realidad, esto es lo que se hizo en la documentación: el término más general "grupo de objetos" se usa en todas partes, pero para no complicar las cosas en este artículo (y los grupos de objetos que consisten en varios objetos se usan con mucha menos frecuencia), se decidió olvidar y contar sobre grupos de objetos, que un grupo de objetos siempre consiste exactamente en un objeto y, en consecuencia, use el término "objeto" en todas partes en lugar del más complejo "grupo de objetos" y "conjunto de objetos".

Grupos de propiedades


Las propiedades en el formulario, como los objetos, también se pueden combinar en grupos, que, a su vez, se utilizan en las representaciones interactivas (diseño predeterminado) y jerárquicas del formulario (un poco más adelante sobre ellas). De forma predeterminada, el enlace de una propiedad a un grupo es global (es decir, se establece para una propiedad para todos los formularios a la vez), sin embargo, si es necesario, para formularios individuales, este enlace se puede redefinir.

Objetos de columna


Por defecto, una propiedad se muestra exactamente una vez en su objeto de visualización. En este caso, como los valores de los objetos que no sean el objeto de visualización de esta propiedad (los llamamos superiores), se utilizan sus valores actuales. Sin embargo, la plataforma también tiene la capacidad de mostrar una propiedad varias veces para que los valores de algunos objetos superiores no sean utilizados por sus valores actuales, sino todos los objetos en la base de datos que sean adecuados para los filtros. Con este mapeo de propiedades, se forma una especie de "matriz" - (objeto de visualización) x (objetos superiores). Por consiguiente, para crear una matriz de este tipo, al agregar una propiedad al formulario, es necesario indicar qué objetos superiores se deben usar para crear columnas (llamaremos a estos objetos objetos en columnas).
FORM currentBalances ' '
// ,
//
OBJECTS s = Stock, i = Item
//
PROPERTIES name(i), currentBalance(s, i) COLUMNS (s) HEADER name(s)
FILTERS isActive(i), isActive(s)
;
Captura de pantalla del formulario


Entonces, con lo que muestra el formulario, más o menos resuelto, pasemos a cómo puede hacer esto.

Envíos de formularios


Hay tres presentaciones de formularios:



Ver capturas de pantalla
Interactivo:



Impreso:



Estructurado:



  • Interactivo Una vista con la que el usuario puede interactuar es cambiar los datos y los objetos actuales activando varios eventos. En realidad, esta representación generalmente se llama forma.
  • Impreso Por lo general, se denomina informe: cargar todos los datos del formulario y presentarlo en forma gráfica. Incluso con la posibilidad de imprimirlos (de donde obtuvo su nombre).
  • Estructurado: representación del formulario en varios formatos estructurados (JSON, XML, DBF, etc.). Normalmente se usa para una mayor integración con otros sistemas.

Las representaciones interactivas e impresas son gráficas, es decir, muestran los datos recibidos en un espacio bidimensional: papel o la pantalla del dispositivo. En consecuencia, cada una de estas representaciones tiene un diseño que, dependiendo de la representación particular, se puede establecer utilizando los mecanismos apropiados (sobre ellos un poco más adelante).

La presentación impresa y estructurada es estática, es decir, leen todos los datos en el momento en que se abre el formulario (a diferencia del interactivo, que lee los datos según sea necesario).

La descripción de las actuaciones comenzará, quizás, con lo más difícil: la presentación interactiva.

Presentación interactiva


En una vista interactiva, los objetos de formulario se muestran en forma de tabla. Las filas en esta tabla corresponden a los objetos en la base de datos que satisfacen los filtros especificados, las columnas, a su vez, corresponden a las propiedades.

Sin embargo, si es necesario, la propiedad puede mostrarse no como una columna de tabla, es decir, para todas sus filas, sino como un campo separado en el formulario, es decir, solo para el valor actual del objeto de formulario. Por ejemplo:
currentBalance ' ' (Stock s) = GROUP SUM currentBalance(s, Item i);
FORM currentBalances ' '
OBJECTS s = Stock, i = Item
// currentBalance(s) ,
PROPERTIES name(s), currentBalance(s) PANEL ,
name(i), currentBalance(s, i)
FILTERS currentBalance(s, i)
;
Captura de pantalla del formulario


El cambio del valor actual de un objeto de formulario se produce como resultado de que un usuario cambie la fila actual de la tabla o como resultado de una acción creada utilizando un operador de búsqueda especial (SEEK).

Tenga en cuenta que la forma en que se muestra una propiedad en un panel o tabla, como regla, no se establece para cada propiedad por separado, sino como un todo para un objeto de formulario. En consecuencia, si el objeto de formulario se marca como PANEL, todas sus propiedades se muestran en el panel (es decir, para el valor actual), de lo contrario (de forma predeterminada) todas sus propiedades se muestran en la tabla. Las propiedades sin parámetros y acciones predeterminadas se muestran en el panel.

Todas las tablas en la vista interactiva son dinámicas de manera predeterminada, es decir, solo se lee un número limitado de objetos en la base de datos y el resto se lee a medida que cambia el objeto actual en la tabla. El número de objetos mostrados en este caso puede determinarse automáticamente en función de la altura de la parte visible de la tabla, o el desarrollador puede establecerlo explícitamente al crear el formulario.

Además, el formulario en la presentación interactiva es completamente reactivo, es decir, actualiza automáticamente todos los datos en el formulario cuando cambia cualquier dato que los afecte (como Reaccionar, solo en el caso general). Además, todo esto no se realiza mediante un recálculo completo (como en el mismo React), sino de forma incremental, además, en el servidor SQL.

En general, es divertido cuando, al comparar con otras tecnologías, intentas incluir los tres requisitos principales en la tarea, las personas a menudo miran con ojos redondos, como si se les pidiera lanzar a una persona al espacio. Aunque el incumplimiento del segundo requisito por parte de cualquier usuario normal se clasificará como un error, y el primer y tercer requisito es que el formulario desarrollado funcionará normalmente cuando aparezca al menos una pequeña cantidad de datos en la base de datos (varias decenas de miles de registros, por ejemplo).

La presentación interactiva es compatible tanto en modo cliente web (es decir, aplicaciones web en un navegador) como en modo cliente de escritorio (aplicaciones Java). El cliente de escritorio, como cualquier cliente nativo, tiene una capacidad de respuesta ligeramente mejor de la interfaz, pero lo más importante, le permite trabajar con equipos y realizar otras operaciones que no están disponibles en el navegador (principalmente debido a problemas de seguridad).

Árboles de objetos


Además de las tablas, la plataforma también le permite organizar la visualización de objetos en forma de árboles, tanto planos ("anidados" en otras tablas) como recursivos (por ejemplo, objetos "anidados" en la base de datos).

Los árboles planos, de hecho, son una generalización de tablas, cuando varias tablas se "combinan" en una tabla a la vez:
FORM currentBalances ' '
TREE tree s = Stock, i = Item
//
//
PROPERTIES name(s), currentBalance(s),
name(i), currentBalance(s, i)
;
Captura de pantalla del formulario


Este es un mecanismo relativamente complejo y rara vez se usa en la práctica, por lo que no nos detendremos en detalle.

Pero los árboles recursivos, por el contrario, se usan con bastante frecuencia (por ejemplo, para implementar clasificadores). Para mostrar un objeto de formulario en la forma de dicho árbol, es necesario establecer un filtro adicional para él, una propiedad cuyo valor para los objetos inferiores debe ser igual al objeto superior. Inicialmente, el objeto superior se considera NULL.
parent = DATA ItemGroup (ItemGroup) IN base;
group = DATA ItemGroup (Item) IN base;
//
level '' (ItemGroup child, ItemGroup parent) = RECURSION 1 AND child IS ItemGroup AND parent = child STEP 1 IF parent = parent($parent);
currentBalance ' ' (ItemGroup ig, Stock s) = GROUP SUM currentBalance(s, Item i) IF level(ig, group(i));

FORM currentBalances ' '
OBJECTS s=Stock PANEL //
PROPERTIES (s) name
TREE tree ig = ItemGroup PARENT parent, i = Item // /
PROPERTIES name(ig), currentBalance(ig, s)
PROPERTIES name(i), currentBalance(s, i)
FILTERS group(i) = ig
;
Captura de pantalla del formulario


Gestión de formularios de usuario


Para garantizar una mejor ergonomía del sistema (incluso no crear formularios para todos), los propios usuarios pueden realizar parte de las operaciones para configurar la presentación interactiva del formulario. Por ejemplo, tales operaciones son:

  • configuración de tablas (columnas visibles, orden, fuentes, etc.),
  • creando filtros y tipos personalizados,
  • agrupando datos por valores de columna,
  • imprima una tabla y cárguela en Excel.

Además, el desarrollador puede crear los llamados grupos de filtros, que el usuario puede activar / desactivar de forma independiente. Por ejemplo:
EXTEND FORM currentBalances //
FILTERGROUP stockActive // , , /
FILTER '' active(st) 'F11' // , F11
FILTERGROUP bal
FILTER ' ' currentBalance(st, sk) > 0 'F10'
FILTER ' ' currentBalance(st, sk) < 0 'F9'
FILTER ' ' currentBalance(st, sk) 'F8' DEFAULT
FILTER ' ' NOT currentBalance(st, sk) 'F7'
;
Estas no son todas las posibilidades para que el usuario personalice el sistema, pero volveremos a las otras posibilidades en el tercer artículo, ya que la mayoría de ellas aún no tienen una relación directa con la lógica de presentación.

Tenga en cuenta que la funcionalidad descrita anteriormente se refiere más probablemente a la funcionalidad de las plataformas ERP, que ya es completamente discordante con el título del artículo. Por otro lado, como se menciona en el primer artículo, en el futuro, el lenguaje / plataforma pretende reemplazar, incluida esta clase de plataformas, por lo que sería un error no mencionar estas características en absoluto.

Operadores de objetos


Uno de los escenarios más comunes de trabajar con un formulario es agregar / eliminar un objeto, así como editarlo en un nuevo formulario. Para implementar tales escenarios, la plataforma tiene un conjunto predefinido de operadores que le permiten crear las acciones necesarias en una palabra directamente en el operador de creación de formularios:

  • NUEVO: crear un objeto
  • EDITAR - editar un objeto
  • NEWEDIT - crear y editar un objeto
  • BORRAR - eliminar un objeto

Además, dado que a menudo es necesario realizar estas acciones en una nueva sesión (si necesita separar las acciones de creación de objetos de las acciones en la forma en que se crean estos objetos), la plataforma admite el azúcar sintáctico correspondiente: las opciones NEWSESSION y NESTEDSESSION, que funcionan de manera similar a los operadores del mismo nombre crear acciones, pero, al igual que los propios operadores que trabajan con objetos, no requieren que el desarrollador cree y nombre nuevas acciones. Por ejemplo:
FORM teams
OBJECTS t=Team
// /
PROPERTIES (t) NEWSESSION NEW , EDIT , DELETE
OBJECTS p=Player
FILTERS team(p)=t
//
PROPERTIES (p) NEW , DELETE
;
Por defecto, al editar un objeto, se llama al formulario de edición, que se genera automáticamente para la clase del objeto de formulario pasado. Sin embargo, a menudo es necesario redefinir este formulario (por ejemplo, agregar información adicional, cambiar el diseño, etc.) Para hacer esto, es suficiente crear el formulario de edición necesario e indicar que es el formulario predeterminado para editar objetos de una clase dada:
FORM order ''
OBJECTS o = Order PANEL
PROPERTIES (o) date, number

OBJECTS d = OrderDetail
PROPERTIES (d) nameBook, quantity, price, NEW , DELETE
FILTERS order(d) = o

EDIT Order OBJECT o
;
Del mismo modo, las formas para seleccionar objetos de una clase dada se redefinen.

Diseño de la forma


Como con la mayoría de las GUI existentes, el diseño de una presentación interactiva de un formulario es una jerarquía cuyos nodos son componentes. Los componentes, a su vez, pueden ser:

  • contenedores: componentes que contienen otros componentes.
  • componentes básicos: representaciones gráficas de elementos básicos: tablas, paneles de propiedades, grupos de filtros, etc.

El mecanismo para organizar los componentes dentro de los contenedores esencialmente repite el diseño de caja flexible CSS (y se implementa en el cliente web con él), por lo que no nos detendremos en este mecanismo con gran detalle.

Tenga en cuenta que el diseño del formulario generalmente no se crea desde cero (ya que es bastante laborioso). Por lo general, un diseño de formulario se crea automáticamente en función de la estructura del formulario, y luego el desarrollador solo lo modifica un poco: por ejemplo, agrega un nuevo contenedor y le transfiere los componentes existentes:

Ejemplo de diseño de formulario predeterminado
FORM myForm 'myForm'
OBJECTS myObject = myClass
PROPERTIES (myObject) myProperty1, myProperty2 PANEL
FILTERGROUP myFilter
FILTER 'myFilter' myProperty1(myObject)
;
La jerarquía de contenedores y componentes en el diseño predeterminado se verá así:


FORM myForm ' '
OBJECTS u = CustomUser
PROPERTIES (u) name, NEW , DELETE

OBJECTS c = Chat
PROPERTIES (c) message, NEW , DELETE
FILTERS user(c) = u
;

DESIGN myForm {
NEW middle FIRST {
type = CONTAINERH ;
fill = 1 ; //
MOVE BOX (u);
MOVE BOX (c);
}
}
Captura de pantalla del formulario


Diseño de formulario 2.0 (Reaccionar)


Si observa las representaciones interactivas de los formularios en las capturas de pantalla anteriores (o, por ejemplo, en una demostración en línea), puede ver que el diseño actual del formulario en la interfaz de usuario es, digamos, bastante ascético. Esto, por supuesto, nunca ha sido un problema particular para los sistemas de información, donde los principales usuarios son empleados o socios de la empresa propietaria de estos sistemas de información. Además, a pesar del ascetismo, el mecanismo de diseño de formularios actual le permite implementar casos muy difíciles, por ejemplo, POS:

Captura de pantalla del formulario


Pero si se trata de, por ejemplo, SaaS B2B, o incluso B2C (por ejemplo, algunos servicios bancarios por Internet), entonces inmediatamente comienzan a aparecer preguntas sobre cómo hacer que el diseño sea más ergonómico.

En la etapa actual, para resolver este problema, se ha desarrollado una biblioteca javascript especial, cuya tarea principal es crear y actualizar un objeto js especial que contenga datos de formulario. En consecuencia, este objeto se puede usar como estado para el componente Reaccionar y, por lo tanto, crear cualquier diseño y cualquier interactividad adicional de la forma que se está desarrollando. Por ejemplo:

Reaccionar formulario de ejemplo (en codesandbox)

O un ejemplo más complejo: con listas desplegables y utilizando la API REST (o más bien Sin estado) para esto:

Ejemplo de formulario de reacción con listas desplegables (en codesandbox)

Es cierto que el problema con este enfoque es que los formularios de los ejemplos anteriores no se integrarán en la interfaz de la plataforma general ni en el flujo de control general de las acciones. Por lo tanto, una de las tareas más inmediatas en el desarrollo de la plataforma es la traducción del mecanismo de diseño de formularios al esquema utilizado en el diseño del informe (presentación impresa):

  • La plataforma genera automáticamente un diseño de reacción basado en la estructura del formulario como en el ejemplo anterior.
  • Si es necesario, el desarrollador puede guardarlo y editarlo como quiera. En consecuencia, la plataforma utilizará este diseño editado al abrir el formulario.

Además, este enfoque permitirá generar formularios React Native y, por lo tanto, permitirá crear aplicaciones móviles nativas. Aunque este problema (con aplicaciones móviles nativas) aún no hemos resuelto muy profundamente.

Es cierto que observamos que el antiguo mecanismo de diseño también será compatible, ya que, para las mismas aplicaciones comerciales, cumple perfectamente su función.

Eventos de formulario


Los eventos de formulario son el segundo mecanismo clave después de los eventos de dominio, que es responsable de determinar cuándo realizar acciones.

La plataforma tiene un conjunto completo de varios eventos de formulario que surgen como resultado de ciertas acciones del usuario, pero en este artículo consideraremos solo uno, el más utilizado: el evento CHANGE. Este evento ocurre cuando el usuario inició una llamada de acción / cambio de propiedad, por ejemplo, presionando cualquier tecla que no sea del sistema en el teclado, estando en el campo de la propiedad que se está cambiando o haciendo clic en este campo con el mouse.

En cuanto a los eventos del área temática, para los eventos del formulario, puede especificar el procesamiento, la acción que se realizará cuando ocurra el evento especificado. Tenga en cuenta que la mayoría de los eventos de formulario ya tienen un procesamiento predeterminado que implementa el comportamiento más esperado por el usuario (por ejemplo, con el evento CHANGE mencionado anteriormente, solicite la entrada del usuario y cambie la propiedad al valor ingresado). Sin embargo, en la práctica, a veces surgen situaciones cuando para algún evento de formulario es necesario especificar algún procesamiento específico, por ejemplo:
changeQuantity (Order o, Book b) {
INPUT q = INTEGER DO { //
IF lastOrderDetail(o, b) THEN { // ,
IF q THEN //
quantity(OrderDetail d) <- q IF d = lastOrderDetail(o, b) WHERE order(d) = o AND book(d) = b; //
ELSE // -
DELETE OrderDetail d WHERE order(d) == o AND book(d) == b;
} ELSE
IF q THEN
NEW d = OrderDetail { //
order(d) <- o;
book(d) <- b;
quantity(d) <- q;
}
}
}

EXTEND FORM order
OBJECTS b = Book
PROPERTIES name(b) READONLY , quantity(o, b) ON CHANGE changeQuantity(o, b)
;
, – , ( , , , paste , ). . .


, , , , , , , , INPUT.

, , , , , , . Por ejemplo:
FORM order
OBJECTS o = Order
PROPERTIES (o) customer ON CHANGE {
INPUT s = STRING DO {
customer(o) <- s;
IF s THEN
MESSAGE 'Customer changed to ' + s;
ELSE
MESSAGE 'Customer dropped' ;
}
}
;
, , :

  • ,
  • ( ),
  • ,
  • .

, INPUT – . (ASK):
DELETE Order o WHERE selected(o);
ASK ' ' + ( GROUP SUM 1 IF DROPPED (Order o)) + ' . ?' DO {
APPLY ;
}
(DIALOG) , , , , .

.


, . , , . , «» . , A B, A B, A A, B (A, B) B, A B ( «» ).

, , :

  • :
  • , , A B, A ( ).

Por ejemplo:
FORM myForm 'myForm'
OBJECTS A, B SUBREPORT , C, D, E
PROPERTIES f(B, C), g(A, C)
FILTERS c(E) = C, h(B, D)
;


, , , , .


LGPL – JasperReports.

, JasperReports , . , :

  • «» ( , O1, O2, O3,… On, O2 – O1, O3 – O2 ..) ;
  • , .

«» , SUBREPORT ( , -):



:
FORM shipment
OBJECTS s=Shipment //
PROPERTIES (s) date, customer = nameCustomer, stock = nameStock // , ( customer) ( stock)
PROPERTIES total = ( GROUP SUM quantity(ShipmentDetail d)*price(d) IF shipment(d)=s) //
OBJECTS sd=ShipmentDetail //
FILTERS shipment(sd) = s //
PROPERTIES (sd) index, item = nameItem // , ( item)
PROPERTIES (sd) price, quantity // ,
PROPERTIES sum '' = (quantity(sd) * price(sd)) // - * ( sum)
;

run() {
// 12345
PRINT shipment OBJECTS s = ( GROUP MAX Shipment s IF number(s) = '12345' )
XLSX TO exportFile;
}



JasperReports (, lsFusion). , . , JasperSoft Studio.

, lsFusion- IDEA, Eclipse, ( Eclipse JasperReports ). IDEA , language injection, jrxml-, , , , , , . , , Eclipse GrammarKit autocomplete (, ), stub-, lazy chameleon- ( ), , . .


() :

  • (XML, JSON) – , () -.
  • (DBF, CSV, XLS) – - . parent, «» -.

, (- ), , , ( ). . , .


– XML, JSON. , , JSON ( XML ).

/ JSON , : JSON-, – , – . :

JSON
/ , / :

  • / : , .
  • X:
    • X , , . En este caso:
      • X ,
      • ( ) X.

, / :

 JSON  ::= { JSON  ,   /    } JSON  ,   /  ::= JSON  1 | JSON   1 | JSON   1 JSON  2 | JSON   2 | JSON   2 ... JSON  M | JSON   M | JSON   M JSON  ::= "   " :   JSON   ::= "  " : { JSON   ,   /  } JSON   ::= "  " : [ { JSON   ,   /  1 }, { JSON   ,   /  2 }, ... { JSON   ,   /  N }, ] 


:
GROUP money;

FORM shipment
OBJECTS dFrom= DATE , dTo= DATE
OBJECTS s=Shipment //
PROPERTIES (s) date, customer = nameCustomer, stock = nameStock // , ( customer) ( stock)
FILTERS dFrom <= date(s) AND date(s) <= dTo //
OBJECTS sd=ShipmentDetail //
FILTERS shipment(sd) = s //
PROPERTIES (sd) IN money index, item = nameItem, price, quantity // , ( item), , money
;

run() {
EXPORT shipment OBJECTS dFrom = 2019_02_20 , dTo = 2019_04_28 ; //
}
Resultado
 { "s": [ { "date": "21.02.19", "sd": [ { "money": { "item": " 3", "quantity": 1, "price": 5, "index": 1 } } ], "stock": " 2", "customer": " 2" }, { "date": "15.03.19", "sd": [ { "money": { "item": " 1", "quantity": 1, "price": 5, "index": 1 } }, { "money": { "item": " 2", "quantity": 1, "price": 10, "index": 2 } }, { "money": { "item": " 3", "quantity": 1, "price": 15, "index": 3 } }, { "money": { "item": " 4", "quantity": 1, "price": 20, "index": 4 } }, { "money": { "item": "Milk", "quantity": 1, "price": 50, "index": 5 } } ], "stock": " 1", "customer": " 3" }, { "date": "04.03.19", "sd": [ { "money": { "item": " 1", "quantity": 2, "price": 4, "index": 1 } }, { "money": { "item": " 2", "quantity": 3, "price": 4, "index": 2 } }, { "money": { "item": " 1", "quantity": 2, "price": 5, "index": 3 } } ], "stock": " 1", "customer": " 2" }, { "date": "04.03.19", "sd": [ { "money": { "item": " 1", "quantity": 3, "price": 1, "index": 1 } }, { "money": { "item": " 2", "quantity": 2, "price": 1, "index": 2 } } ], "stock": " 1", "customer": " 2" }, { "date": "14.03.19", "sd": [ { "money": { "item": " 2", "quantity": 1, "price": 2, "index": 1 } } ], "stock": " 1", "customer": " 2" }, { "date": "17.04.19", "sd": [ { "money": { "item": " 2", "quantity": 5, "price": 6, "index": 1 } }, { "money": { "item": " 1", "quantity": 2, "price": 6, "index": 2 } } ], "stock": " 1", "customer": " 1" }, { "date": "21.02.19", "sd": [ { "money": { "item": " 3", "quantity": 1, "price": 22, "index": 1 } } ], "stock": " 2", "customer": " 1" }, { "date": "21.02.19", "sd": [ { "money": { "item": " 3", "quantity": 1, "price": 22, "index": 1 } } ], "stock": " 2", "customer": " 1" }, { "date": "20.02.19", "sd": [ { "money": { "item": " 3", "quantity": 1, "price": 22, "index": 1 } } ], "stock": " 2", "customer": " 1" } ] } 


, JSON JSON-. , , IDE JSON , – JSON. , ( , , JSON- ), . / JSON .


, :

  • .
  • – , .

, , , ( ). , , , / :
run() {
EXPORT XLSX FROM item = upper(name(Item i)), currentBalance(i, Stock s),
stock = name(s), barcode(i), salePrice(i)
WHERE (name(i) LIKE '%%' OR salePrice(i) > 10 ) AND currentBalance(i, s);
}
, SELECT SQL. , , , ( , ).

, , , – .


, , , :

  • – .
  • – : .
run(Genre g) {
SHOW booksByGenre OBJECTS g=g;
PRINT booksByGenre OBJECTS g=g;
EXPORT booksByGenre OBJECTS g=g;
}
– ( ) . .

(SHOW, DIALOG)


:

  • (WAIT) – , , , , .
  • (NOWAIT) – .

.

, :

  • (FLOAT) – .
  • (DOCKED) – System.forms.

, – .

, , (DIALOG). (, , ), , , .

, , (INPUT), ( ), , , ( ), , , ( ).
FORM booksByGenre
OBJECTS g = Genre PANEL
PROPERTIES (g) name
OBJECTS b = Book
PROPERTIES (b) name
FILTERS genre(b) = g
;

EXTEND FORM ordersByGenre
PROPERTIES (o) nameBook
ON CHANGE {
DIALOG booksByGenre OBJECTS g = g, b = book(o) INPUT DO
book(o) <- b;
}
;

(PRINT)


( ) , JasperReports : DOC, DOCX, XLS, XLSX, PDF, HTML, RTF , JasperReports. , , , , ( , ).

, - (PREVIEW), , / . , , .

(EXPORT, IMPORT)


, , , : XML, JSON, DBF, CSV, XLS, XLSX. .

, , , – . () , () , .

– , , « », :
  • .
  • ( , , , , , TRUE f(a) = b – f(a) b)

TRUE ( , , 0 , .., , , ).
// ,
inn = DATA LOCAL BPSTRING [ 9 ] (Shipment);
barcode = DATA LOCAL BPSTRING [ 13 ] (ShipmentDetail);

FORM shipments
OBJECTS s=Shipment EXTID 'shipments' // EXTID s, shipments
PROPERTIES (s) number, date, inn
OBJECTS sd=ShipmentDetail EXTID 'detail' // EXTID sd, detail
FILTERS shipment(sd) = s // shipment detail
PROPERTIES (sd) barcode, price, quantity
;

run() {
FOR jsonFile = JSONFILE ( '\{ shipments : [ ' + // jsonFile / run, {} escape'
' \{number : "13423", date : "01.01.2019", inn : "2", detail : [\{ barcode : "141", quantity : 5, price : 10 \}, \{ barcode : "545", quantity : 2, price : 11 \}] \},' +
' \{number : "12445", date : "01.02.2019", inn : "1", detail : [\{ barcode : "13", quantity : 1, price : 22 \}] \} ]\}' )
DO {
IMPORT shipments FROM jsonFile; //
FOR BPSTRING [ 9 ] inn = inn(Shipment s) DO { // inn
customer(s) <- legalEntityINN(inn); // INN
stock(s) <- GROUP MAX st AS Stock; // - ( id)
}
FOR barcode(Item item) = barcode(ShipmentDetail sd) DO //
item(sd) <- item;

APPLY ;
exportString() <- IF canceled() THEN applyMessage() ELSE ' ' ;
}
}


, , . , , , . . ( ), .

- , ( ). , , ( ). .


. , — .

– , . , , . , , .



.



100x100 . , , . , «» . , ( ). , . , .

. , - , , .

:
  • , – , , .
  • – forms, log, status, root, toolbar, tree, (, root, , )
FORM items;
FORM stocks;
FORM legalEntities;
FORM shipments;
hello() { MESSAGE 'Hello world' ; }
hi() { MESSAGE 'Hi' ; }

NAVIGATOR {
NEW FOLDER catalogs '' WINDOW toolbar { // ,
NEW items; // - items,
}
catalogs { //
NEW FORM stocksNavigator '' = stocks; // - stocksNavigator stocls catalogs
NEW legalEntities AFTER items; // - legalEntities catalogs items
NEW shipments;
}
NEW FOLDER documents '' WINDOW toolbar { // ,
// root,
//
NEW ACTION hi; // -
NEW ACTION h=hello; // -
MOVE shipments BEFORE h; // shipments catalogs document hello
}
}


, – , , , , , ERP-. , , « », : ? ? ? , -, lsFusion language-based ( SQL ABAP), library-based ( Java 1C) / . , , – domain-specific , . -, , , , . : , , , . , , , ( ).

. – , :

  • : , , , , , ;
  • : , .

, :

  • . «» : , , / . , , , , , , .
  • . control flow . , – .
  • SQL ( ORM). , , , .

Conclusión


, , (, , , , tutorial, , , ). , , ( ) «», , lsFusion.

, , – . , . , , « . .», , ( - ).

. : « ». , . , , lsFusion SQL-. , , , – , - , . , SQL- ( ). , . , , ( , ), , , . «?», « ...?» «?».

UPD: .

Source: https://habr.com/ru/post/460141/


All Articles