Bukan bahasa pemrograman lain. Bagian 3: Fisika



Bagian ketiga dan terakhir dari serangkaian artikel tentang bahasa lsFusion (tautan ke bagian pertama dan kedua )

Ini akan fokus pada model fisik: segala sesuatu yang tidak terhubung dengan fungsionalitas sistem, tetapi terkait dengan pengembangan dan optimalisasi kinerjanya, ketika ada terlalu banyak data.

Artikel ini, seperti yang sebelumnya, sangat tidak cocok untuk membaca yang menghibur, tetapi, tidak seperti yang lain, akan ada lebih banyak rincian teknis dan "panas" topik (seperti mengetik atau metaprogramming), ditambah artikel ini akan memberikan sebagian dari jawaban untuk pertanyaan, bagaimana semuanya bekerja di dalam.

Dalam artikel ini, kami akan melakukan tanpa gambar (tidak ada tumpukan seperti ini), tetapi kami akan melakukan daftar isi, seperti yang diminta dalam artikel sebelumnya:


Identifikasi Barang


Jika proyek terdiri dari beberapa file kecil, maka masalah dengan penamaan elemen biasanya tidak muncul. Semua nama sudah terlihat, dan cukup mudah untuk memastikan bahwa mereka tidak tumpang tindih. Jika proyek, sebaliknya, terdiri dari banyak modul yang dikembangkan oleh sejumlah besar orang yang berbeda, dan abstraksi dalam modul-modul ini dari satu domain domain, konflik nama menjadi jauh lebih mungkin. LsFusion memiliki dua mekanisme untuk menyelesaikan masalah ini:

  • Namespaces - pemisahan nama menjadi penuh dan pendek, dan kemampuan untuk menggunakan hanya nama pendek saat mengakses suatu elemen
  • Pengetikan eksplisit (lebih tepatnya, kelebihan fungsi) - kemampuan untuk menamai properti (dan tindakan) dengan cara yang sama, dan kemudian, ketika mengaksesnya, tergantung pada kelas argumen, secara otomatis menentukan properti mana yang dituju oleh panggilan tersebut.

Ruang nama


Setiap proyek kompleks biasanya terdiri dari sejumlah besar elemen yang harus dinamai. Dan, jika domain domain bersinggungan, sangat sering ada kebutuhan untuk menggunakan nama yang sama dalam konteks yang berbeda. Misalnya, kami memiliki nama kelas atau formulir Faktur (faktur), dan kami ingin menggunakan nama ini di berbagai blok fungsi, misalnya: Pembelian (Pembelian), Penjualan (Sale), Pengembalian pembelian (PurchaseReturn), Pengembalian penjualan (SaleReturn). Jelas bahwa kelas / formulir dapat disebut PurchaseInvoice, SaleInvoice, dan sebagainya. Tapi, pertama-tama, nama-nama seperti itu dalam diri mereka akan terlalu besar. Dan kedua, dalam satu blok fungsional, panggilan, sebagai aturan, pergi ke elemen-elemen dari blok fungsional yang sama, yang berarti bahwa ketika mengembangkan, misalnya, blok fungsi Pembelian dari pengulangan konstan kata Pembelian, itu hanya akan riak di mata Anda. Untuk mencegah hal ini terjadi, platform memiliki konsep seperti namespace. Ia bekerja sebagai berikut:

  • setiap elemen dalam platform dibuat di beberapa namespace
  • jika dalam proses membuat elemen, elemen lain direferensikan, elemen yang dibuat dalam namespace yang sama diutamakan
MODULE PurchaseInvoice;
NAMESPACE Purchase;
CLASS Invoice ' ()' ;
MODULE SaleInvoice;
NAMESPACE Sale;
CLASS Invoice ' ()' ;
MODULE PurchaseShipment;
REQUIRE PurchaseInvoice, SaleInvoice;
NAMESPACE Purchase;
// Invoice Purchase.Invoice, Sale.invoice
// namespace Purchase namespace Purchase
shipment(Invoice invoice) = AGGR ShipmentInvoce WHERE createShipment(invoice);
Ruang nama dalam versi bahasa saat ini ditetapkan untuk seluruh modul segera di header modul. Secara default, jika tidak ada namespace yang ditentukan, itu dibuat secara implisit dengan nama yang sama dengan nama modul. Jika Anda perlu mengakses elemen dari namespace non-prioritas, Anda dapat melakukan ini dengan menentukan nama lengkap elemen (misalnya, Sale.Invoice).

Pengetikan eksplisit


Ruang nama itu penting, tetapi bukan satu-satunya cara untuk membuat kode lebih pendek dan lebih mudah dibaca. Selain mereka, saat mencari properti (dan tindakan), dimungkinkan juga untuk memperhitungkan kelas argumen yang diteruskan kepada mereka di input. Jadi misalnya:
sum = DATA NUMERIC [ 10 , 2 ] (OrderDetail);
sum = GROUP SUM sum(OrderDetail od) BY order(od);
// , Order
// OrderDetail
CONSTRAINT sum(Order o) < 0 MESSAGE ' ' ;
Di sini, tentu saja, pertanyaan mungkin timbul: apa yang akan terjadi jika namespace properti yang diinginkan bukan prioritas, tetapi lebih cocok untuk kelas? Faktanya, algoritma pencarian umum cukup rumit (uraian lengkapnya ada di sini ) dan ada banyak kasus "ambigu" seperti itu, jadi jika terjadi ketidakpastian, disarankan untuk menentukan ruang nama / kelas properti yang diinginkan secara eksplisit, atau memeriksa ulang pada IDE (menggunakan Go to Declaration - CTRL + B) yang ditemukan oleh properti persis seperti yang dimaksudkan.

Juga, perlu dicatat bahwa mengetik secara eksplisit di lsFusion umumnya tidak diperlukan. Kelas parameter dapat dihilangkan, dan jika platform memiliki informasi yang cukup untuk menemukan properti yang diinginkan, itu akan melakukannya. Di sisi lain, dalam proyek yang sangat kompleks, masih disarankan untuk mengatur kelas parameter secara eksplisit, tidak hanya dari sudut pandang singkatnya kode, tetapi juga dari sudut pandang berbagai fitur tambahan, seperti: diagnosis kesalahan awal, penyelesaian otomatis pintar dari IDE dan sebagainya. Kami memiliki pengalaman luas bekerja baik dengan pengetikan implisit (5 tahun pertama) dan dengan eksplisit (sisa waktu), dan saya harus mengatakan bahwa waktu pengetikan implisit sekarang diingat dengan gemetar (walaupun mungkin saja “kami tidak tahu cara memasaknya”).

Modularitas


Modularitas adalah salah satu sifat paling penting dari sistem, memungkinkan untuk memastikan ekstensibilitasnya, penggunaan kembali kode, serta interaksi yang efektif dari tim pengembangan.

LsFusion menyediakan modularitas dengan dua mekanisme berikut:

  • Extensions - kemampuan untuk memperluas (mengubah) elemen-elemen sistem setelah mereka dibuat.
  • Modul - kemampuan untuk mengelompokkan beberapa fungsionalitas bersama untuk digunakan kembali lebih lanjut.

Ekstensi


lsFusion mendukung kemampuan untuk memperluas kelas dan bentuk, serta properti dan tindakan, melalui mekanisme polimorfisme yang dijelaskan dalam artikel pertama.
sum = DATA NUMERIC [ 10 , 2 ] (OrderDetail);
sum = GROUP SUM sum(OrderDetail od) BY order(od);
// , Order
// OrderDetail
CONSTRAINT sum(Order o) < 0 MESSAGE ' ' ;
CLASS ABSTRACT Shape;
CLASS Box : Shape;

CLASS Quadrilateral;
EXTEND CLASS Box : Quadrilateral; //

CLASS ShapeType {
point '' ,
segment ''
}

EXTEND CLASS ShapeType { //
circle ''
}

CLASS ItemGroup;
name = DATA ISTRING [ 100 ] (ItemGroup);

itemGroup = DATA ItemGroup (Item);

EXTEND FORM items
PROPERTIES (i) NEWSESSION DELETE //

OBJECTS g = ItemGroup BEFORE i //
PROPERTIES (g) READONLY name
FILTERS itemGroup(i) == g // , ,
;
Juga, kami mencatat bahwa hampir semua desain platform lainnya (misalnya, navigator, desain formulir) dapat diperpanjang menurut definisi, oleh karena itu tidak ada logika ekstensi terpisah untuknya.

Modul


Modul adalah beberapa bagian yang berfungsi secara fungsional dari suatu proyek. Dalam versi lsFusion saat ini, modul adalah file terpisah yang terdiri dari header dan badan modul. Judul modul, pada gilirannya, terdiri dari: nama modul, serta, jika perlu, daftar modul yang digunakan dan nama namespace dari modul ini. Badan modul terdiri dari deklarasi dan / atau ekstensi elemen sistem: properti, tindakan, batasan, bentuk, metacode, dan sebagainya.

Biasanya, modul menggunakan elemen dari modul lain untuk mendeklarasikan sendiri / memperluas elemen yang ada. Dengan demikian, jika modul B menggunakan elemen dari modul A, maka perlu untuk menunjukkan dalam modul B bahwa itu tergantung pada A.

Berdasarkan dependensinya, semua modul dalam proyek diatur dalam urutan tertentu di mana mereka diinisialisasi (urutan ini memainkan peran penting ketika menggunakan mekanisme ekstensi yang disebutkan sebelumnya). Dijamin bahwa jika modul B tergantung pada modul A, maka inisialisasi modul A akan terjadi lebih awal dari inisialisasi modul B. Ketergantungan siklik antara modul dalam proyek tidak diperbolehkan.

Ketergantungan antar modul bersifat transitif. Yaitu, jika modul C tergantung pada modul B, dan modul B tergantung pada modul A, maka dianggap bahwa modul C juga tergantung pada modul A.

Setiap modul selalu secara otomatis tergantung pada modul sistem Sistem, terlepas dari apakah itu ditunjukkan secara eksplisit atau tidak.
MODULE EmployeeExample; //

REQUIRE Authentication, Utils; // , Employee
NAMESPACE Employee; //

CLASS Employee '' ; //
CLASS Position '' ; //

employeePosition(employee) = DATA Position (Employee); //

Metaprogramming


Metaprogramming adalah jenis pemrograman yang terkait dengan penulisan kode program, yang sebagai hasilnya menghasilkan kode program lain. LsFusion menggunakan apa yang disebut metacode untuk metaprogramming.

Metacode terdiri dari:

  • nama metacode
  • parameter metacode
  • badan metacode - blok kode yang terdiri dari deklarasi dan / atau ekstensi elemen sistem (properti, tindakan, peristiwa, metacode lain, dll.)

Dengan demikian, sebelum memulai pemrosesan utama kode, platform menyiapkannya - menggantikan semua penggunaan metacode dengan badan metacode ini. Dalam kasus ini, semua parameter metacode yang digunakan dalam pengenal / string literal diganti dengan argumen yang diteruskan ke metacode ini:

Pengumuman:
META addActions(formName)
EXTEND FORM formName
PROPERTIES () showMessage, closeForm
;
END
Penggunaan:
@addActions (documentForm);
@addActions (orderForm);
Kode yang dihasilkan:
EXTEND FORM documentForm
PROPERTIES () showMessage, closeForm
;
EXTEND FORM orderForm
PROPERTIES () showMessage, closeForm
;
Selain hanya mengganti parameter metacode, platform ini juga memungkinkan Anda untuk menggabungkan parameter ini dengan pengidentifikasi / string string yang ada (atau dengan satu sama lain), misalnya:

Pengumuman:
META objectProperties(object, caption)
object ## Name ' ' ## caption = DATA BPSTRING [ 100 ](object);
object ## Type ' ' ## caption = DATA Type (object);
object ## Value ' ' ## caption = DATA INTEGER (object);
END
Penggunaan:
@objectProperties (document, '' );
Kode yang dihasilkan:
DocumentName ' ' = DATA BPSTRING [ 100 ](Document);
DocumentType ' ' = DATA Type (Document);
DocumentValue ' ' = DATA INTEGER (Document);
Metacode sangat mirip dengan makro di C, tetapi, tidak seperti yang terakhir, mereka tidak bekerja di tingkat teks (mereka tidak bisa, misalnya, meneruskan kata kunci dalam parameter), tetapi hanya pada tingkat pengidentifikasi / string literal (pembatasan ini, khususnya, memungkinkan parsing badan metacode di IDE).

Dalam lsFusion, metacode memecahkan masalah yang mirip dengan generik di Jawa (melewati kelas sebagai parameter) dan lambda di FP (melewati fungsi sebagai parameter), namun, mereka tidak melakukannya dengan sangat indah. Tetapi, di sisi lain, mereka melakukan ini dalam kasus yang jauh lebih umum (yaitu, misalnya, dengan kemungkinan menggabungkan pengidentifikasi, digunakan dalam konstruksi sintaksis apa pun - bentuk, desain, navigator, dll.)

Perhatikan bahwa "penyebaran" metacode didukung tidak hanya di platform itu sendiri, tetapi juga di IDE. Jadi, dalam IDE ada mode khusus Aktifkan meta, yang menghasilkan kode yang dihasilkan langsung di sumber dan dengan demikian memungkinkan kode yang dihasilkan ini untuk berpartisipasi dalam pencarian penggunaan, pelengkapan otomatis, dll. Dalam hal ini, jika badan metacode berubah, IDE secara otomatis memperbarui semua penggunaan metacode ini.



Juga, metacode dapat digunakan tidak hanya untuk otomatis, tetapi juga untuk pembuatan kode manual (sebagai templat). Untuk melakukan ini, cukup menulis @@ alih-alih satu @ dan segera setelah string penggunaan metacode dimasukkan sepenuhnya (hingga titik koma), IDE akan mengganti penggunaan metacode ini dengan kode yang dihasilkan oleh metacode ini:



Integrasi


Integrasi mencakup segala sesuatu yang berkaitan dengan interaksi sistem lsFusion dengan sistem lain. Dari sudut pandang arah interaksi ini, integrasi dapat dibagi menjadi:

  • Mengakses sistem lsFusion dari sistem lain.
  • Akses dari sistem lsFusion ke sistem lain.

Dari sudut pandang model fisik, integrasi dapat dibagi menjadi:

  • Interaksi dengan sistem yang berjalan di "lingkungan yang sama" dengan sistem lsFusion (yaitu, di Java Virtual Machine (JVM) dari server lsFusion dan / atau menggunakan server SQL yang sama dengan sistem lsFusion).
  • Interaksi dengan sistem jarak jauh melalui protokol jaringan.

Dengan demikian, sistem yang pertama akan disebut internal, yang kedua - eksternal.

Dengan demikian, ada empat jenis integrasi dalam platform:

  • Banding ke sistem eksternal
  • Banding dari sistem eksternal
  • Banding ke sistem internal
  • Banding dari sistem internal

Banding ke sistem eksternal


Akses ke sistem eksternal di lsFusion dalam banyak kasus diimplementasikan menggunakan operator EKSTERNAL khusus. Operator ini mengeksekusi kode yang diberikan dalam bahasa / dalam paradigma sistem eksternal yang diberikan. Selain itu, operator ini memungkinkan Anda untuk mentransfer objek tipe primitif sebagai parameter panggilan tersebut, serta menulis hasil panggilan ke properti yang ditentukan (tanpa parameter).

Saat ini, platform mendukung jenis interaksi / sistem eksternal berikut:

HTTP - Melakukan permintaan http dari server web.

Untuk jenis interaksi ini, Anda harus menentukan string kueri (URL), yang secara bersamaan menentukan alamat server dan permintaan yang perlu dijalankan. Parameter dapat ditransfer baik di baris permintaan (untuk mengakses parameter, karakter khusus $ dan jumlah parameter ini, mulai dari 1) digunakan, serta dalam tubuhnya (BODY). Diasumsikan bahwa semua parameter yang tidak digunakan dalam string kueri diteruskan ke BODY. Jika ada lebih dari satu parameter dalam BODY, tipe konten BODY selama transmisi diatur ke multipart / campuran, dan parameter ditransfer sebagai komponen dari BODY ini.

Saat memproses parameter kelas file (FILE, PDFFILE, dll.) Di BODY, tipe konten dari parameter ditentukan tergantung pada ekstensi file (sesuai dengan tabel berikut). Jika ekstensi file tidak ada dalam tabel ini, tipe konten diatur ke aplikasi / <ekstensi file>.

Jika perlu, menggunakan opsi khusus (HEADERS), Anda dapat mengatur header dari permintaan yang dieksekusi. Untuk melakukan ini, Anda perlu menentukan properti dengan tepat satu parameter dari kelas string di mana judul akan disimpan, dan nilai kelas string di mana nilai header ini akan disimpan.

Hasil dari permintaan http diproses dengan cara yang sama seperti parameternya, hanya dalam arah yang berlawanan: misalnya, jika tipe konten dari hasil ditampilkan dalam tabel berikut atau sama dengan aplikasi / *, maka dianggap bahwa hasil yang diperoleh adalah file dan harus ditulis ke properti dengan nilai FILE . Header dari hasil permintaan-http diproses secara analogi dengan header dari permintaan ini sendiri (dengan satu-satunya perbedaan adalah bahwa opsi tersebut disebut HEADERSTO, bukan HEADERS).
EXTERNAL HTTP GET 'https://www.cs.cmu.edu/~chuck/lennapg/len_std.jpg' TO exportFile;
open(exportFile());

LOCAL headers = STRING ( STRING );
headers( 'Authentication : Bearer' ) <- 'd43ks43ds343dd233' ';
EXTERNAL HTTP 'http://tryonline.lsfusion.org/exec?action=getExamples'
HEADERS headers
HEADERSTO headers
PARAMS JSONFILE ( '\{"mode"=1\}' )
TO exportFile;

IMPORT FROM exportFile() FIELDS () STRING caption, STRING code DO
MESSAGE 'Example : ' + caption + ', code : ' + code;
FOR v = headers( STRING s) DO
MESSAGE 'Result Header is : Key - ' + s + ', Value - ' + v;
SQL - mengeksekusi perintah SQL server.

Untuk jenis interaksi ini, string koneksi dan perintah SQL yang akan dieksekusi ditentukan. Parameter dapat dilewatkan dalam string koneksi dan dalam perintah SQL. Untuk mengakses parameter, karakter khusus $ dan jumlah parameter ini digunakan (mulai dari 1).

Parameter kelas file (FILE, PDFFILE, dll.) Hanya dapat digunakan dalam perintah SQL. Selain itu, jika salah satu parameter selama eksekusi adalah file TABLE (TABLEFILE atau FILE dengan ekstensi tabel), maka parameter ini dianggap sebagai tabel dalam kasus ini juga:

  • sebelum menjalankan perintah SQL, nilai setiap parameter tersebut dimuat ke server dalam tabel sementara
  • saat mengganti parameter, bukan nilai parameter itu sendiri yang diganti, tetapi nama tabel sementara yang dibuat

Hasil eksekusi adalah: untuk kueri DML - angka sama dengan jumlah catatan yang diproses, untuk kueri SELECT - File format TABEL (FILE dengan ekstensi tabel) yang berisi hasil kueri ini. Urutan hasil ini bertepatan dengan urutan pelaksanaan kueri yang sesuai dalam perintah SQL.
externalSQL () {
EXPORT TABLE FROM bc=barcode(Article a) WHERE name(a) LIKE '%%' ; // -
EXTERNAL SQL 'jdbc:mysql://$1/test?user=root&password='
EXEC 'select price AS pc, articles.barcode AS brc from $2 x JOIN articles ON x.bc=articles.barcode'
PARAMS 'localhost' ,exportFile()
TO exportFile; // -

// -
LOCAL price = INTEGER ( INTEGER );
LOCAL barcode = STRING [ 30 ] ( INTEGER );
IMPORT FROM exportFile() TO price=pc,barcode=brc;
FOR barcode(Article a) = barcode( INTEGER i) DO
price(a) <- price(i);
}
LSF - panggilan aksi dari server lsFusion lain.

Untuk jenis interaksi ini, string koneksi ke server lsFusion (atau server webnya, jika ada) diatur, tindakan yang akan dilakukan, serta daftar properti (tanpa parameter), dalam nilai yang akan dituliskan hasil panggilan. Parameter yang akan ditransfer harus bertepatan dalam jumlah dan kelas dengan parameter tindakan yang dilakukan.

Metode pengaturan aksi dalam jenis interaksi ini sepenuhnya konsisten dengan metode pengaturan aksi ketika mengakses dari sistem eksternal (tentang jenis akses ini di bagian selanjutnya).
externalLSF() {
EXTERNAL LSF 'http://localhost:7651' EXEC 'System.testAction[]' ;
}
Secara default, jenis interaksi ini diimplementasikan menggunakan protokol HTTP menggunakan antarmuka yang sesuai untuk mengakses ke / dari sistem eksternal.

Jika Anda perlu mengakses sistem menggunakan protokol yang berbeda dari yang di atas, Anda selalu dapat melakukan ini dengan membuat tindakan di Jawa dan menerapkan panggilan ini di sana (tetapi lebih lanjut di bagian “Mengakses Sistem Internal”)

Banding dari sistem eksternal


Platform ini memungkinkan sistem eksternal untuk mengakses sistem yang dikembangkan di lsFusion menggunakan protokol jaringan HTTP. Antarmuka interaksi ini adalah untuk memanggil beberapa tindakan dengan parameter yang diberikan dan, jika perlu, mengembalikan nilai beberapa properti (tanpa parameter) sebagai hasilnya. Diasumsikan bahwa semua objek parameter dan hasil adalah objek tipe primitif.

Tindakan yang disebut dapat diatur dalam salah satu dari tiga cara:

  • / exec? action = <action name> - mengatur nama aksi yang dipanggil.
  • / eval? script = <code> - mengatur kode dalam lsFusion. Diasumsikan bahwa dalam kode ini ada pernyataan tindakan dengan nama run, tindakan inilah yang akan dipanggil. Jika parameter skrip tidak ditentukan, diasumsikan kode dilewatkan sebagai parameter BODY pertama.
  • / eval / action? script = <action code> - mengatur kode aksi di lsFusion. Untuk mengakses parameter, Anda dapat menggunakan karakter khusus $ dan nomor parameter (mulai dari 1).

Dalam kasus kedua dan ketiga, jika parameter skrip tidak ditentukan, maka diasumsikan kode dilewatkan oleh parameter BODY pertama.

Pemrosesan parameter dan hasil simetris untuk mengakses sistem eksternal menggunakan protokol HTTP (dengan satu-satunya perbedaan adalah bahwa parameter diproses sebagai hasil, dan, sebaliknya, hasilnya diproses sebagai parameter), sehingga kami tidak akan mengulangi banyak hal.

Misalnya, jika kita memiliki tindakan:
importOrder( INTEGER no, DATE date, FILE detail) {
NEW o = FOrder {
no(o) <- no;
date(o) <- date;
LOCAL detailId = INTEGER ( INTEGER );
LOCAL detailQuantity = INTEGER ( INTEGER );
IMPORT FROM detail TO detailId, detailQuantity;
FOR imported( INTEGER i) DO {
NEW od = FOrderDetail {
id(od) <- detailId(i);
quantity(od) <- detailQuantity(i);
price(od) <- 5 ;
order(od) <- o;
}
}
APPLY ;
EXPORT JSON FROM price = price(FOrderDetail od), id = id(od) WHERE order(od) = o;
EXPORT FROM orderPrice(o), exportFile();
}
}
Kemudian Anda dapat mengaksesnya menggunakan permintaan POST yang:
  • URL - http: // server_address / exec? Action = importOrder & p = 123 & p = 2019-01-01
  • BODY - file json dengan string kueri

Contoh panggilan python
 import json import requests from requests_toolbelt.multipart import decoder lsfCode = ("run(INTEGER no, DATE date, FILE detail) {\n" " NEW o = FOrder {\n" " no(o) <- no;\n" " date(o) <- date;\n" " LOCAL detailId = INTEGER (INTEGER);\n" " LOCAL detailQuantity = INTEGER (INTEGER);\n" " IMPORT JSON FROM detail TO detailId, detailQuantity;\n" " FOR imported(INTEGER i) DO {\n" " NEW od = FOrderDetail {\n" " id(od) <- detailId(i);\n" " quantity(od) <- detailQuantity(i);\n" " price(od) <- 5;\n" " order(od) <- o;\n" " }\n" " }\n" " APPLY;\n" " EXPORT JSON FROM price = price(FOrderDetail od), id = id(od) WHERE order(od) == o;\n" " EXPORT FROM orderPrice(o), exportFile();\n" " }\n" "}") order_no = 354 order_date = '10.10.2017' order_details = [dict(id=1, quantity=10), dict(id=2, quantity=15), dict(id=5, quantity=4), dict(id=10, quantity=18), dict(id=11, quantity=1), dict(id=12, quantity=3)] order_json = json.dumps(order_details) url = 'http://localhost:7651/eval' payload = {'script': lsfCode, 'no': str(order_no), 'date': order_date, 'detail': ('order.json', order_json, 'text/json')} response = requests.post(url, files=payload) multipart_data = decoder.MultipartDecoder.from_response(response) sum_part, json_part = multipart_data.parts sum = int(sum_part.text) data = json.loads(json_part.text) ############################################################## print(sum) for item in data: print('{0:3}: price {1}'.format(int(item['id']), int(item['price']))) ############################################################## # 205 # 4: price 5 # 18: price 5 # 3: price 5 # 1: price 5 # 10: price 5 # 15: price 5 

Banding ke sistem internal


Ada dua jenis interaksi internal:

Interoperabilitas Java

Jenis interaksi ini memungkinkan Anda untuk memanggil kode Java di dalam server lsFusion JVM. Untuk melakukan ini, Anda harus:

  • memastikan bahwa kelas Java yang dikompilasi dapat diakses di classpath dari server aplikasi. Juga diperlukan bahwa kelas ini mewarisi lsfusion.server.physics.dev.integration.internal.to.InternalAction.
    Contoh kelas Java
     import lsfusion.server.data.sql.exception.SQLHandledException; import lsfusion.server.language.ScriptingErrorLog; import lsfusion.server.language.ScriptingLogicsModule; import lsfusion.server.logics.action.controller.context.ExecutionContext; import lsfusion.server.logics.classes.ValueClass; import lsfusion.server.logics.property.classes.ClassPropertyInterface; import lsfusion.server.physics.dev.integration.internal.to.InternalAction; import java.math.BigInteger; import java.sql.SQLException; public class CalculateGCD extends InternalAction { public CalculateGCD(ScriptingLogicsModule LM, ValueClass... classes) { super(LM, classes); } @Override protected void executeInternal(ExecutionContext<ClassPropertyInterface> context) throws SQLException, SQLHandledException { BigInteger b1 = BigInteger.valueOf((Integer)getParam(0, context)); BigInteger b2 = BigInteger.valueOf((Integer)getParam(1, context)); BigInteger gcd = b1.gcd(b2); try { findProperty("gcd[]").change(gcd.intValue(), context); } catch (ScriptingErrorLog.SemanticErrorException ignored) { } } } 
  • mendaftarkan suatu tindakan menggunakan operator panggilan internal khusus (INTERNAL)
    calculateGCD ' ' INTERNAL 'CalculateGCD' ( INTEGER , INTEGER );
  • tindakan terdaftar, seperti yang lainnya, dapat dipanggil menggunakan operator panggilan. Dalam hal ini, metode executeInternal (lsfusion.server.logics.action.controller.context.ExecutionContext konteks) dari kelas Java yang ditentukan akan dieksekusi.
    //
    FORM gcd ''
    OBJECTS (a = INTEGER , b = INTEGER ) PANEL
    PROPERTIES 'A' = VALUE (a), 'B' = VALUE (b)

    PROPERTIES gcd(), calculateGCD(a, b)
    ;

    //
    run() {
    calculateGCD( 100 , 200 );
    }
Interaksi SQL

Jenis interaksi ini memungkinkan Anda untuk mengakses objek / konstruksi sintaks dari server SQL yang digunakan oleh sistem lsFusion yang dikembangkan. Untuk menerapkan jenis interaksi ini di platform, operator khusus digunakan - FORMULA. Operator ini memungkinkan Anda untuk membuat properti yang mengevaluasi beberapa rumus dalam bahasa SQL. Rumus diatur dalam bentuk string di mana karakter khusus $ dan jumlah parameter ini digunakan untuk mengakses parameter (mulai dari 1). Dengan demikian, jumlah parameter dari properti yang diperoleh akan sama dengan maksimum dari jumlah parameter yang digunakan.
round(number, digits) = FORMULA 'round(CAST(($1) as numeric),$2)' ; // :
jumpWorkdays = FORMULA NULL DATE PG 'jumpWorkdays($1, $2, $3)' , MS 'dbo.jumpWorkdays($1, $2, $3)' ; // SQL
Disarankan untuk menggunakan operator ini hanya dalam kasus di mana masalah tidak dapat diselesaikan dengan bantuan operator lain, dan juga jika dijamin bahwa server SQL tertentu dapat digunakan, atau konstruksi sintaks yang digunakan mematuhi salah satu standar SQL terbaru.

Banding dari sistem internal


Semuanya simetris dengan daya tarik ke sistem internal. Ada dua jenis interaksi:

Interoperabilitas Java

Dalam kerangka interaksi jenis ini, sistem internal dapat secara langsung mengakses elemen Java dari sistem lsFusion (seperti objek Java biasa). Dengan demikian, Anda dapat melakukan semua operasi yang sama seperti menggunakan protokol jaringan, tetapi pada saat yang sama menghindari overhead yang signifikan dari interaksi tersebut (misalnya, serialisasi parameter / deserialisasi hasil, dll.). Selain itu, metode komunikasi ini jauh lebih nyaman dan efisien jika interaksi sangat dekat (yaitu, selama pelaksanaan satu operasi, kontak konstan diperlukan di kedua arah - dari sistem lsFusion ke sistem lain dan sebaliknya) dan / atau memerlukan akses ke node platform tertentu.

Untuk mengakses elemen Java dari sistem lsFusion secara langsung, Anda harus terlebih dahulu mendapatkan tautan ke beberapa objek yang akan memiliki antarmuka untuk menemukan elemen Java ini. Ini biasanya dilakukan dengan satu dari dua cara:

  • Jika pada awalnya panggilan tersebut berasal dari sistem lsFusion (melalui mekanisme yang dijelaskan di atas), maka sebagai "objek pencarian" Anda dapat menggunakan objek aksi "melalui mana" panggilan ini berjalan (kelas tindakan ini harus diwarisi dari lsfusion.server.physics.dev.integration. internal.to.InternalAction, yang, pada gilirannya, memiliki semua antarmuka yang diperlukan).
  • Jika objek dari metode yang perlu untuk mengakses sistem lsFusion adalah kacang Spring, maka tautan ke objek logika bisnis dapat diperoleh dengan menggunakan injeksi dependensi (masing-masing kacang disebut businessLogics).

Contoh kelas Java
 import lsfusion.server.data.sql.exception.SQLHandledException; import lsfusion.server.data.value.DataObject; import lsfusion.server.language.ScriptingErrorLog; import lsfusion.server.language.ScriptingLogicsModule; import lsfusion.server.logics.action.controller.context.ExecutionContext; import lsfusion.server.logics.classes.ValueClass; import lsfusion.server.logics.property.classes.ClassPropertyInterface; import lsfusion.server.physics.dev.integration.internal.to.InternalAction; import java.math.BigInteger; import java.sql.SQLException; public class CalculateGCDObject extends InternalAction { public CalculateGCDObject(ScriptingLogicsModule LM, ValueClass... classes) { super(LM, classes); } @Override protected void executeInternal(ExecutionContext<ClassPropertyInterface> context) throws SQLException, SQLHandledException { try { DataObject calculation = (DataObject)getParamValue(0, context); BigInteger a = BigInteger.valueOf((Integer)findProperty("a").read(context, calculation)); BigInteger b = BigInteger.valueOf((Integer)findProperty("b").read(context, calculation)); BigInteger gcd = a.gcd(b); findProperty("gcd[Calculation]").change(gcd.intValue(), context, calculation); } catch (ScriptingErrorLog.SemanticErrorException ignored) { } } } 

Interaksi SQL

Sistem yang memiliki akses ke server SQL dari sistem lsFusion (salah satu dari sistem tersebut, misalnya, adalah server SQL itu sendiri), dapat langsung mengakses tabel dan bidang yang dibuat oleh sistem lsFusion menggunakan alat server SQL. Harus diingat bahwa jika membaca data relatif aman (kecuali untuk kemungkinan penghapusan / modifikasi tabel dan bidangnya), maka tidak ada peristiwa yang akan dipicu ketika data ditulis (dan, karenanya, semua elemen menggunakannya - pembatasan, agregasi, dll. n.), dan juga tidak ada materialisasi yang akan dihitung ulang. Oleh karena itu, menulis data langsung ke tabel sistem lsFusion sangat tidak disarankan, dan jika memang perlu, penting untuk mempertimbangkan semua fitur di atas.

Perhatikan bahwa interaksi langsung semacam itu (tetapi hanya untuk membaca) terutama nyaman untuk integrasi dengan berbagai sistem OLAP, di mana seluruh proses harus terjadi dengan overhead yang minimal.

Migrasi


Dalam praktiknya, situasi sering muncul ketika karena berbagai alasan perlu untuk mengubah nama elemen sistem yang ada. Jika elemen yang akan diganti namanya tidak terkait dengan data primer apa pun, ini dapat dilakukan tanpa gerakan yang tidak perlu. Tetapi jika elemen ini adalah properti atau kelas utama, maka penggantian nama yang "sepi" akan mengarah pada fakta bahwa data properti atau kelas utama ini akan hilang begitu saja. Untuk mencegah hal ini, pengembang dapat membuat file migrasi.script migrasi khusus, letakkan di server classpath, dan tunjukkan di dalamnya bagaimana nama elemen lama sesuai dengan nama baru. Semuanya bekerja sebagai berikut:

Migrasi terdiri dari blok yang menjelaskan perubahan yang dibuat dalam versi tertentu dari struktur database. Saat memulai server, semua perubahan dari file migrasi yang memiliki versi lebih tinggi dari versi yang disimpan dalam database diterapkan. Perubahan diterapkan sesuai dengan versi, dari versi yang lebih kecil ke versi yang lebih besar. Jika struktur database berhasil diubah, maka versi maksimum dari semua blok yang diterapkan ditulis ke database sebagai yang sekarang. Sintaks untuk deskripsi setiap blok adalah sebagai berikut:

 V< > { 1 ... N } 

Perubahan, pada gilirannya, adalah dari jenis berikut:
DATA PROPERTY oldNS.oldName[class1,...,classN] -> newNS.newName[class1,...,classN]
CLASS oldNS.oldName -> newNS.newName
OBJECT oldNS.oldClassName.oldName -> newNS.newClassName.newName

TABLE oldNS.oldName -> newNS.newName
PROPERTY oldNS.oldName[class1,...,classN] -> newNS.newName[class1,...,classN]
FORM PROPERTY oldNS.oldFormName.oldName(object1,...,objectN) -> newNS.newFormName.newName(object1,...,objectN)
NAVIGATOR oldNS.oldName -> newNS.newName
Untuk migrasi data pengguna, hanya tiga jenis perubahan pertama yang relevan (perubahan properti primer, kelas, objek statis). Empat jenis perubahan yang tersisa diperlukan:

  • untuk migrasi metadata (kebijakan keamanan, pengaturan tabel, dll.)
  • untuk mengoptimalkan migrasi data pengguna (agar tidak menghitung ulang agregasi dan tidak mentransfer data antar tabel sekali lagi).

Dengan demikian, jika migrasi metadata tidak diperlukan atau tidak ada banyak data, perubahan dalam skrip migrasi tersebut dapat dihilangkan.

Contoh migrasi
V0. 3.1 {
DATA PROPERTY Item.gender[Item.Article] -> Item.dataGender[Item.Article] // DATA
PROPERTY System.SIDProperty[Reflection.Property] -> Reflection.dbNameProperty[Reflection.Property] //
FORM PROPERTY Item.itemForm.name(i) -> Item.itemForm.itemName(i)
}

V0. 4 {
FORM PROPERTY Document.documentForm.name(i) -> Document.itemForm.itemName(i)
FORM PROPERTY Item.itemForm.itemName(i) -> Item.itemForm.iname // : iname = itemName(i)
CLASS Date.DateInterval -> Date.Interval
OBJECT Geo.Direction.North -> Geo.Direction.north
TABLE User.oldTable -> User.newTable
}


Perlu dicatat bahwa biasanya sebagian besar pekerjaan pembuatan skrip migrasi dilakukan menggunakan IDE. Jadi, ketika mengganti nama sebagian besar elemen, Anda dapat menentukan kotak centang khusus Ubah file migrasi (diaktifkan secara default), dan IDE akan menghasilkan semua skrip yang diperlukan secara otomatis.

Internasionalisasi


Dalam praktiknya, kadang-kadang muncul situasi ketika perlu untuk dapat menggunakan satu aplikasi dalam bahasa yang berbeda. Tugas ini biasanya turun untuk melokalkan semua data string yang dilihat pengguna, yaitu: pesan teks, header properti, tindakan, formulir, dll. Semua data ini di lsFusion diatur menggunakan string literal (string dalam tanda kutip tunggal, misalnya 'abc'), masing-masing, lokalisasi mereka dilakukan sebagai berikut:
  • alih-alih teks yang akan dilokalisasi, string mengidentifikasi data string, terlampir dalam kurung kurawal (misalnya, '{button.cancel}').
  • ketika string ini dikirim ke klien di server, itu mencari semua pengidentifikasi yang ditemukan dalam string, kemudian mencari masing-masing di semua file proyek ResourceBundle di lokal yang diinginkan (yaitu, klien lokal), dan ketika opsi yang tepat ditemukan, pengidentifikasi di kurung diganti dengan teks yang sesuai.
script '{scheduler.script.scheduled.task.detail}' = DATA TEXT (ScheduledTaskDetail);
CONSTRAINT script(ScheduledTaskDetail d) AND action(d) MESSAGE '{scheduler.constraint.script.and.action}' ;
FORM scheduledTask '{scheduler.form.scheduled.task}' ;
ServerResourceBundle.properties:
 scheduler.script.scheduled.task.detail=Script scheduler.constraint.script.and.action=In the scheduler task property and script cannot be selected at the same time scheduler.form.scheduled.task=Tasks 

ServerResourceBundle_ru.properties
 scheduler.script.scheduled.task.detail= scheduler.constraint.script.and.action=           scheduler.form.scheduled.task= 

Mengoptimalkan kinerja proyek data besar


Jika sistemnya kecil dan relatif sedikit data di dalamnya, sebagai aturan, ia bekerja cukup efisien tanpa optimasi tambahan. Jika logika menjadi sangat rumit, dan jumlah data meningkat secara signifikan, kadang-kadang masuk akal untuk memberi tahu platform cara terbaik untuk menyimpan dan memproses semua data ini.

Platform ini memiliki dua mekanisme utama untuk bekerja dengan data: properti dan tindakan. Yang pertama bertanggung jawab untuk menyimpan dan menghitung data, yang kedua adalah untuk mentransfer sistem dari satu negara ke negara lain. Dan jika pekerjaan tindakan dapat dioptimalkan secara terbatas (termasuk karena efek sampingnya), maka untuk properti ada serangkaian fitur yang memungkinkan mengurangi waktu respons operasi spesifik dan meningkatkan kinerja sistem secara keseluruhan:

  • . ( , ), , , .
  • . , , .
  • . / , . «» .


Hampir semua properti teragregasi dalam platform dapat terwujud. Dalam hal ini, properti akan disimpan dalam database secara terus-menerus dan secara otomatis diperbarui ketika data yang bergantung pada properti ini diubah. Selain itu, ketika membaca nilai-nilai properti terwujud, nilai-nilai ini akan dibaca langsung dari database, seolah-olah properti itu primer (dan tidak dihitung setiap kali). Oleh karena itu, semua properti primer diwujudkan dengan definisi.

Properti dapat terwujud jika dan hanya jika untuk itu ada sejumlah terbatas set objek yang nilai properti ini bukan NULL.

Umumnya, topik materialisasi diperiksa secara cukup rinci dalam artikel terbaru. tentang keseimbangan penulisan dan membaca dalam basis data, sehingga untuk membahasnya secara rinci di sini, menurut pendapat saya, tidak masuk akal.

Indeks


Membangun indeks dengan properti memungkinkan Anda untuk menyimpan dalam semua nilai-nilai properti ini dalam urutan. Dengan demikian, indeks diperbarui setiap kali nilai properti yang diindeks berubah. Berkat indeks, jika, misalnya, pemfilteran oleh properti yang diindeks sedang berlangsung, Anda dapat dengan cepat menemukan objek yang diperlukan, daripada melihat semua objek yang ada dalam sistem.

Hanya properti terwujud yang dapat diindeks (dari bagian di atas).

Indeks juga dapat dibangun di atas beberapa properti sekaligus (ini efektif jika, misalnya, penyaringan dilakukan segera pada beberapa properti ini). Selain itu, parameter properti dapat dimasukkan dalam indeks komposit. Jika properti yang ditentukan disimpan dalam tabel yang berbeda, maka upaya untuk membangun indeks akan menghasilkan kesalahan yang sesuai.
INDEX customer(Order o);

date = DATA DATE (Order);
INDEX date(Order o), o;

INDEX name(Sku s), price(s, DATE d), d;

Tabel


LsFusion menggunakan database relasional untuk menyimpan dan menghitung nilai properti. Semua properti utama, serta semua properti teragregasi yang ditandai sebagai terwujud, disimpan di bidang tabel database. Untuk setiap tabel, ada seperangkat bidang kunci dengan nama key0, key1, ..., keyN, di mana nilai-nilai objek disimpan (misalnya, untuk kelas kustom, pengidentifikasi objek-objek ini). Semua bidang lainnya menyimpan nilai properti sedemikian rupa sehingga dalam bidang yang sesuai dari setiap baris adalah nilai properti untuk objek dari bidang kunci.

Saat membuat tabel, Anda harus menentukan daftar kelas objek yang akan menjadi kunci dalam tabel ini.
TABLE book (Book);

in = DATA BOOLEAN (Sku, Stock);
TABLE skuStock (Sku, Stock); // in

price = DATA NUMERIC [ 10 , 2 ] (Sku, DATE );
TABLE skuDate (Sku, DATE ); // Sku

TABLE sku (Sku);
Untuk setiap properti, Anda dapat menentukan di tabel mana ia harus disimpan. Dalam hal ini, jumlah kunci tabel harus cocok dengan jumlah parameter properti, dan kelas parameter harus cocok dengan kelas kunci tabel ini. Jika tabel di mana ia akan disimpan tidak diatur secara eksplisit untuk properti, properti akan secara otomatis ditempatkan di tabel "terdekat" yang ada dalam sistem (yaitu, jumlah kunci yang bertepatan dengan jumlah parameter properti, dan yang kelas kuncinya paling dekat dengan kelas parameter )

Nama-nama tabel dan bidang di mana properti disimpan dalam DBMS dibentuk sesuai dengan kebijakan penamaan yang ditentukan. Saat ini, platform mendukung tiga kebijakan penamaan standar.
PolitikNama tabelNama bidang
Penuh dengan tanda tangan (default)Space Name_NameTables__1
_2..._N
__
Jika perlu, untuk setiap properti, pengembang dapat secara eksplisit menentukan nama bidang di mana properti ini akan disimpan. Selain itu, dimungkinkan untuk membuat kebijakan Anda sendiri untuk penamaan bidang properti jika alasan di atas karena tidak cocok.

Ketika memilih kebijakan penamaan, penting untuk diingat bahwa menggunakan kebijakan penamaan properti yang terlalu singkat, jika jumlah properti terwujud cukup besar, dapat sangat menyulitkan penamaan properti ini (sehingga unik), atau, oleh karena itu, menyebabkan terlalu sering kebutuhan untuk menyebutkan nama secara eksplisit. Kolom tempat properti ini akan disimpan.

Kesimpulan


Seperti yang mereka katakan dalam satu film animasi terkenal: "kami membangun, membangun, dan akhirnya membangun." Tentu saja, ini mungkin sedikit dangkal, tapi saya pikir Anda bisa mengetahui fitur dasar dari bahasa / platform lsFusion untuk tiga artikel ini. Saatnya beralih ke bagian yang paling menarik - membandingkan dengan teknologi lain.

Seperti yang ditunjukkan oleh pengalaman dan format Habr, melakukan ini lebih efektif dengan bermain bukan sendirian, tetapi di lapangan asing. Yaitu, untuk pergi bukan dari peluang, tetapi dari masalah dan, dengan demikian, untuk berbicara bukan tentang keuntungan mereka, tetapi tentang kelemahan teknologi alternatif, dan dalam terminologi mereka sendiri. Pendekatan ini biasanya lebih baik dirasakan di pasar konservatif, dan menurut pendapat saya, pasar seperti itu adalah pasar untuk pengembangan sistem informasi, dalam hal apa pun, di ruang pasca-Soviet.

Jadi segera akan ada beberapa artikel dengan gaya: "Mengapa tidak ...?", Dan saya yakin mereka akan jauh lebih menarik daripada tutorial yang sangat membosankan ini.

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


All Articles