Code Monkey home page Code Monkey logo

fullstack-lang / gong Goto Github PK

View Code? Open in Web Editor NEW
11.0 2.0 0.0 96.72 MB

Gong (go+ng) is a go sub-language that compiles to go and angular. All valid go is valid gong and vice versa. Gong enables fast development of web applications. Gong is model centric and by default, a UML diagram editor of the model is embedded in each application.

License: MIT License

Go 86.41% CSS 0.03% TypeScript 13.18% HTML 0.37% Dart 0.02%
golang angular2 fullstack full-stack gin gorm material go typescript swagger angular orm

gong's Introduction

1. Gong

gong logo

With gong, a web application is a set of stacks. Each stack is based on go and angular. Each stack has its own data model.

Gong is a work in progress. API of the framework is not yet stabilized/baselined

1.1. About Gong

Gong (go + ng) is a framework for rapid web application development (a.k.a. full stack development) based on go and angular. The go back-end uses gin, gorm and sqlite (a pure go sqlite, no cgo needed). The angular front-end uses angular material.

The unit of development in gong is the gong stack (a "stack" in the rest of this document). A stack can import other stacks (both the front end and the back end of a stack are integrated as a whole). The granularity of a stack is similar to an angular components.

Gong includes gongc, a go data model compiler to generate front-end and back-end code. Gongc compiles gong code, a go sub-langage, to go and angular.

1.2. Gong aims low complexity

Gong fullstack approach was inspired by the idea that complexity facing the programmer should be carefuly managed (for the idea, see conceptual compression concept or Rob Pike's design of Go regarding complexity.

1.3. Prerequisite

1.3.1. Go

go version equal or above 1.21. See https://golang.org for installation.

Gong uses sqlite3 in a cgo free configuration by default.

1.3.2. go-swagger (optional)

go-swagger is a go program that is used (as an option) after each gongc compilation to generate the project API in a yml file. gongc is robust to the absence of go-swagger but it is recommanded to use it if you need to document the back-end API with yaml.

1.3.3. npm

Gong uses npm version >= 8 (see https://nodejs.org)

1.3.4. Angular

Gong uses angular version 16 (see https://angular.io for installation)

1.3.5. Vscode (optional)

Vscode is usefull & handy because the tasks definitions and debug configuration related to gong are provided in the repository.

2. Gong is a Go sub language

Gong is a langage with a compiler and a library.

Gong is also a go sub language because it is not autonomous. It must be developped within a go envionment and it needs the tools of the go toolchains. A gong program is a go program.

2.1. Gong specification

Gong specification is the go specification with additional constraints. If a go construct does not meet those contraints, it is transparant to the gong compiler.

There are three objects in gong.

2.1.1. package nomenclature

A gong program is a go program (go > 1.20) developped with a go module. The gong code is developed in only one package "go/models"

package models

No particular inmport is necessary.

2.1.2. Gongstruct

// Hello is a gongstruct
type Hello struct { // it is exported
  Name string // it has an exported "Name" field
}

// foo is not a gongstruct
type foo struct { // it is not exported
  Name string
}

// Bar is not a gongstruct
type Bar struct { // it is exported
  name string // it has no exported "Name" field
}

// Zong is not a gongstruct
//
// gong:ignore it has a "ignore" magic code
type Zong struct { // it is exported
  Name string // it has an exported "Name" field
}

2.1.3. Gongenum

// Gongenums can be of type tring or int.

type AEnumType string // It is exported

const (
	ENUM_VAL1 AEnumType = "ENUM_VAL1_NOT_THE_SAME"
	ENUM_VAL2 AEnumType = "ENUM_VAL2"
)

type CEnumTypeInt int

// values for EnumType
const (
	CENUM_VAL1 CEnumTypeInt = iota
	CENUM_VAL2
)

2.1.4. Gongfields

Gongfields are fields within a gongstruct.

// Hello is a gongstruct
type Hello struct { // it is exported
  Name string // it has an exported "Name" field

  // Those are gongfields. They are exported fields of type int, int64, float, float64 bool, string
  Floatfield float64
  Intfield int
  Booleanfield bool

  // Those are gongfields. They are exported fields of type time.Duration or time.Time
  Duration1 time.Duration
  Date time.Time

  // HelloP is a gongfield. It is an exported pointer to a gongstruct within the same package
  HelloP *Hello 

  // HellosP is a gongfield. It is an exported slice of pointers to a gongstruct within the same package
  HellosP []*Hello 

  // AEnum is a gongfield. It is an exported field of a gongenum type within the same pakage  
  AEnum AEnumType

  // CEnum is gongfield
  CEnum CEnumTypeInt
  
}

2.1.5. Gongnote

// A gongnote is a string const with a comment
// that starts with the GONGDOC keyword
// It follows the "Note" defined in the [go doc](https://pkg.go.dev/go/doc) and 
// [go doc comment]([]https://pkg.go.dev/go/doc/comment) defined in the
// standard go library
//
// > A Note represents a marked comment starting with "MARKER(uid): note body".

// GONGDOC(NoteExample): Note example
// It can reference Gongstructs
// [models.Bstruct],
// [models.Astruct],
// Gongenums
// [models.AEnumType]
// Gongfields
// [models.Astruct.Associationtob], 
// having the following const exported identifier allows for
// referencing the note from the UML note and allows for
// renaming
//
// # This is heading 1
//
// ## This is heading 1.1
//
//	-
const NoteExample = ""

2.2. Gong library

The gongc compilers generates code within the "go/models" package and within other packages.

3. Using gong

3.1. Running the gong test application

the test directory contains a stack wit the generated code.

cd test/ng
npm i; ng build
cd ..
go run main.go

Then, browse to localhost:8080

test web application Example of a generated application with gong

3.2. Testing the generation of the code

Installing The gong compiler.

From the root directory.

cd go/gongc; go install; cd ../..

Generating the code

cd test; gongc go/models

3.3. Reusable stacks

A gong application is a stack that can integrate other stacks. Below is a list of stacks that can be reused.

https://github.com/fullstack-lang/gongdoc, a UML editor (based on jointjs) for documenting a gong model. gongdoc uses the gong stack.

https://github.com/fullstack-lang/gongsim, a stack for developping simulations

https://github.com/fullstack-lang/gongleaflet, a stack for developping application with leaflet carto components

https://github.com/fullstack-lang/gongsvg, a stack for developping application with svg graphical components

https://github.com/fullstack-lang/gongjointjs, a stack for developping application with jointjs interactive graphical component

3.4. Examples

https://github.com/fullstack-lang/helloworld is a recommanded starting point for understanding gong.

https://github.com/fullstack-lang/bookstore is a little more sophisticated example than helloworld.

https://github.com/fullstack-lang/laundromat, is a more sophisticated example. It is a simulation stack that reuses 3 other stacks (gong, gongsim, gongdoc)

https://github.com/fullstack-lang/gongfly, an airplane simulation that reuses 4 stacks (gong, gongsim, gongdoc, gongleaflet)

https://github.com/fullstack-lang/gongproject, a project management application that reuses 3 stacks (gong, gongjointjs, gongdoc)

4. Gong's Features

4.1. Gong is a go sub langage for generating a full stack

Gong is a sublangage of go (stereotyped go). It is comprised of one or many gongstruct and gongenum. The gongc compiler is based on the go compiler.

A gong project is a go module with a unique name (for instance github.com/fullstack-lang/gongdoc). gongstruct and gongenum have to be present in the go/models sub package.

A gongstruct is a go struct with a Name field.

package models
type Hello struct {
  Name string
}

A gongenum is a go string with some const values. The string type must be commented with // swagger:enum

package models

// swagger:enum AEnumType
type AEnumType string

// values for EnumType
const (
	ENUM_VAL1 AEnumType = "ENUM_VAL1"
	ENUM_VAL2 AEnumType = "ENUM_VAL2"
)

A gongstruct can have gongfield. A gongfield is an exported fields (starts with an Upperscase) with type as int, float64, bool, time.Time, time.Duration, pointer to another gongstruct in the same package and slice of pointers to another gongstruct in the same package (for ONE-MANY associations). MANY-MANY associations are also implemented (if the target of the ONE-MANY association ends with the Use).

// Astruct demonstrate basic gong features
type Astruct struct {

	// a "Name" field is necessary to generate a GongStruct
	Name string

	// string a is a supported type of gong
	Description string

	// bool is a supported type of gong
	Booleanfield bool

	// enums is a supported type of gong (if they are string)
	Aenum AEnumType

	// an embedded struct is supported if it is not a gongstruct (i.e. it is without a field `Name`)
	Cstruct

	// float64 is a supported type of gong
	Floatfield float64

	// int is a supported type of gong
	Intfield int

	// time.Time is a supported type of gong
	Date time.Time

	// time.Duration is a supported type of gong
	Duration time.Duration

	// ONE-ZERO/ONE association is a supported type of gong
	Associationtob *Bstruct

	// ONE-MANY association is a supported type of gong
	Sliceofb []*Bstruct

	// MANY-MANY association, 
	// because AclassBclassUse ends with "Use", it will implement a ONE/ONE assocation to the Bstruct)
	AnarrayofbUse  []*AstructBstructUse
}

4.2. Back end SQL and go code from gong code

The gorm framework is a go API for ORM (Object Realtionship Management). This means you do not need to code SQL to configure/migrate the database. gorm acts as a conceptual compression since you do not need to know SQL code to program the database, you only need to master the go API.

However, gorm is still a concept you need to know to program the database in go. gong allows to ignore this conceptual layer since the gorm code is generated. Indeed, the gongc compiler compiles the models (the go/models package) to generate the appropriate gorm code (in the go/orm package). Therefore, gong is another conceptual compression to avoid programming gorm code.

4.3. Controler go code from gong code

The gin framework is an API for programming the controllers that implement the REST web service of the application. gin acts as a conceptual compression since it provides a high level concept to program the REST api.

However, you need to know to program gin for implementing the REST api. gong allows to ignore this conceptual layer since the gin code is generated by gong. The gongc compiles compiles the models (the go/models package) to generate the appropriate gin code (in the go/controllers package)

4.4. Front end angular code from gong code

Angular framework is an API for programming front-end of the application.

gongc compiles the models (the go/models package) to generate the appropriate angular code (in the ng/projects/<name of the package> angular workspace). This code provides an API to the front end code that follows the data models of the the go/models package.

Each gongstruct/gongenum is compiled into an appropriate typescript code.

4.5. Angular material code from gong code

Angular Material is a set of front-end Angular components.

gongc compiles the models (the go/models package) to generate the appropriate angular material code, in the ng/projects/<name of the package> angular workspace :

  • navigation tree between all gongstruct of the go/models package
  • table for each gongstruct of the go/models package
  • form for each gongstruct of the go/models package

4.6. Front stage, back stage and repository programming model

Putting data to the database and retrieving data from the database (CRUD operations) is performed via an API that is generated for each gongstruct.

The API follows loosely the repository pattern.

The generated API comprises Stage(), Unstage(), Commit(), Delete() for each gongstruct.

4.7. UML Code documentation as go code

see gongcode.

4.8. Integrated Stack configuration management

The configuration of both back-end and front-end code of a stack is a single configuration item.

This is done thank the go module. For the go code, it is the standard way of managing dependencies. For the angular/typescript/js code, it is done in four steps.

First, gong uses the go embed fearure that allows, by using four lines of go in a file stored in the angular workspace to directory,

package ng
import "embed"
//go:embed projects
var Projects embed.FS

that the code in the angular workspace projects directory is stored into the go module.

The second step is to import the created ng package in the project that will use the stack. For instance, the following line makes avaible the Project directory to the project.

	_ "github.com/fullstack-lang/gongjointjs/ng"

The third step is another go feature, the go mod vendor command, that makes available the source code of all dependencies in a vendor directory simply by issuing the command. Then, the angular code is now in the directory vendor/github.com/fullstack-lang/gongjointjs/ng.

The four step is to define your front-end dependency by using the tsconfig.json file and point it the to import path into the vendor directory (instead of using the installation by npm install of the imported front code module). you are therefore assured that your back-end code and front-end code belong to the same configuration. (see the https://github.com/fullstack-lang/gongproject/blob/master/ng/tsconfig.json for an example of tsconfig.json configuration).

4.9. Persistance as go code for enabling fast refactoring

Gong's goal is to speed up development of full stack applications. Gong's goal is therefore to allow fast iterations of the database model and content/database.

An iteration of the data model can include an addition or removal of a concept (a go´struct') or the addition or removal of a field of a concept. In this case, the 'gorm' tool takes care of the content/database migration.

An iteration can also include a renaming of a field or the renaming of a struct. In this case, the code can be automatically changed by the use of the refactoring function of the "go please" langage server for the backend and the typescript language server for the front end.

Wihout gong, if one needs to refactor the name of a gongstruct or the name of a field of a gongstruct, the content/database of the application must be refactored by hand.

For instance :

  • via a json file
  • via the sqlite table/column renaming
  • via gorm

With gong, data refactoring is automatic. Gong API provides a Marshall() function of the staged objects that generates an Unmarshall() function in go code (a persistance of the repository data as go code)

when refactoring the code, the generated go code is refactored. Therefore, no need to manualy refactor the data.

4.10. Further documentation

See gong back-end API for API details.

See gong back-end implementation for implementation details.

5. A "hello world" stack in 5 minutes

If prerequisite and gongc are installed, it is possible to generate a functionning stack in 5 minutes.

5.1. Generating the code with the gongc command

In a terminal, below commands :

  • mkdir creates a helloworld directory
  • mkdir generates a sub directory go/models
  • echo commands generates 2 go structs in this subdirectory
    • Hello which stores a way to say hello
    • Country which stores a country and an association to the way to say hello in this country
  • gongc go/models compiles the models
  • ./helloworld run the server
mkdir helloworld
cd helloworld
mkdir go
mkdir go/models
echo "package models
type Hello struct {
Name string
}" > go/models/hello.go
echo "package models
type Country struct {
Name string
Hello *Hello
AlternateHellos []*Hello
}" > go/models/country.go
gongc go/models
cd go/cmd/helloworld
./helloworld -unmarshallFromCode=stage.go -marshallOnCommit=stage 

Then, browse to localhost:8080 and add data manualy.

With the option -marshallOnCommit=stage, a stage.go file is generated as each save operation (along the default sqlite database test.db). When the application is restarted with the --unmarshall=stage , the data is injected from the stage.go file, not from the database.

5.2. Timing of the gongc command

gongc go/models takes a few minutes the first time it is executed. gongc can be long the first time it is executed for a stack because it perfoms npm i which can be long if it is the first time (3'37'' on a macbook pro with a 2,6 GHz 6-Core Intel Core i7).

If gongc is performed again, it will take a few tens seconds (32'' on a macbook pro with a 2,6 GHz 6-Core Intel Core i7, 1'16'' on a Core I7 windows PC).

5.3. Injecting Data via REST

The backend of a gong application is a REST server (thanks to gin). You can interact with the server via REST calls.

For instance, if you start from an empty database, the following commands will inject proprer data.

curl --request POST \
  --url http://localhost:8080/api/helloworld/go/v1/hellos \
  --header 'content-type: application/json' \
  --data '{"Name": "Bonjour"}'

curl --request POST \
  --url http://localhost:8080/api/helloworld/go/v1/hellos \
  --header 'content-type: application/json' \
  --data '{"Name": "Bonjorno"}'

curl --request POST \
  --url http://localhost:8080/api/helloworld/go/v1/countrys \
  --header 'content-type: application/json' \
  --data '{"Name": "France","HelloID":{"Int64":1,"Valid":true}}'

curl --request POST \
  --url http://localhost:8080/api/helloworld/go/v1/countrys \
  --header 'content-type: application/json' \
  --data '{"Name": "Italy","HelloID":{"Int64":2,"Valid":true}}'

gong's People

Contributors

thomaspeugeot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

gong's Issues

Example fails with ng 12

Steps:

npm install --save angular-split material-design-icons typeface-open-sans typeface-roboto @angular-material-components/datetime-picker
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: [email protected]
npm ERR! Found: @angular/[email protected]
npm ERR! node_modules/@angular/cdk
npm ERR!   @angular/cdk@"^12.2.13" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer @angular/cdk@"^13.0.1" from @angular-material-components/[email protected]
npm ERR! node_modules/@angular-material-components/datetime-picker
npm ERR!   @angular-material-components/datetime-picker@"*" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! See /Users/thomaspeugeot/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/thomaspeugeot/.npm/_logs/2022-01-05T13_08_14_204Z-debug.log

It seems 7.0.1 from datetime-picker requests 13.0.1

Export basic fields to XL

This features uses xlsx WriteStruct API.

This translates into the need to have go struct in the orm domain that is

type AclassWOP struct {

   // basic fields
  // encoded pointers
}

func CopyFieldsFromAClassDBToAclassAOP {
}
func CopyFieldsFromAClassAOPToAclassDB {
}

Steps:

  • manual
    • test
    • gong.go
    • backRepo.go
    • aclass.go
  • genereted
    • gong.go
    • backRepo.go
    • aclass.go

Solve adder with association set

Findngs:

  • setEditorSpecialRouterOutlet is call from the sidebar
node.associatedStructName.toLowerCase() + "-adder", node.id, node.structName + "_" + node.name

Finding n1: the detail class is not reintialized when called

  • Make it not reusable

Finding n2 : when detail is called, id == 1 (the id of the bclass) and association == "Aclass_(Bclass) Anarrayofb". Initialisation of BClass is not performed correctly

  •  compute a variable mode with values CREATE_INSTANCE, UPDATE_INSTANCE, CREATE_INSTANCE_WITH_ASSOCIATION_<>_SET
  • set the asociation in the init

Code refactoring is necessary to go forward:

  •  in the sidebar, add "AssociationField" variable to the node
  • in the routing change "assocation" into "orginStruct" and "originAssociationField"
  • in the detail, update the code accordingly

Generate a frontRepo that is a mirror of the backRepo

Situation

Gong back-end architecture and the repository pattern

Rationale

Gong is a programming language that is a subset of the go language. When compiled, a gong program generates additional go code. The original go code and the generated go code coexist in the back-end and are arranged in a software architecture.

Program written in gong can invoke functions on gong object (Stage() for instance) that are later generated by the gong compiler. This can be a problem when this generated code is not yet present (the go compiler will fails and the go language server will pinpoint error). However, the gong compiler is robust to this kind of go compiler errors.

The Gong back-end architecture is close to the repository design pattern (which includes the unit of work, another design pattern). Thanks to this architecture, a set of object (the "unit of work") can be persisted to a database (the "repository") with a single "check in" operation. Conversely, objects can be retrieved from the database with a single "check out" operation. Moreover, once persisted, objects can be CRUD via a REST API.

This architecture presents two advantages:

  • since gong generates the code implementing the repository pattern, it insulates the programmer from the the complexity of database management (pointer encoding, instances management, null values, ...) and of REST API implementation.
  • It leverages a mental model that is familiar to all programmer. Indeed, "Stage", "Unstage", "Check in", "Check out" are not trivial operation to understand but there are part of the knowledge of all programmers because they use it with git, the de facto standard tool of configuration management.

To implement the repository pattern, Gong divides programming objects into three sets (memory, stage and backRepo) that falls in two packages (models and orm). A third package, controllers, provides a REST API to the back repo objects.

Staging gongstruct instances

The first set of go instance is the memory set. It lives in the models package. With gong, the models package is where manual coding takes places. The rest of the backend code is generated by gongc, the gong compiler.

The second set is the stage set, a subset of the memory set (this is where it follows the repository design pattern). As with git, the programmer stages instances (or unstages them) of the memory set.

To be staged, go instances have to be instances of a special kind of go struct called gongstruct. A gongstruct is an a exported go struct with a Name field.

package models

// Aclass is an example of gongstruct
// It has two association to Bclass, another gong struct
// - a pointer (a 0..1 relationship), 
// - an array of pointers (a 0..N relationship)
type Aclass struct {
	Name string
	Associationtob *Bclass
	Anarrayofb []*Bclass
}

type Bclass struct {
	Name string
}

// Stage puts aclass to the model stage
func (aclass *Aclass) Stage() *Aclass {
        ....
	return aclass
}

// Unstage removes aclass off the model stage
func (aclass *Aclass) Unstage() *Aclass {
	....
        return aclass
}
        // stage two instances
	bclass1 := (&models.Bclass{Name: "B1"}).Stage()

	aclass1 := (&models.Aclass{
		Name:                "A1",
		Associationtob:      bclass1,
		Anarrayofb: []*models.Bclass{
			bclass1,
		},
	}).Stage()

       // aclass1 and bclass1 form a "unit of work"

Only gongstruct instances can be staged or unstaged. It is interesting to stage a gongstruct instance for different reasons:

  • if the instance need to be persisted in a database
  • if the instance need to be seen in the front end

Commiting a unit of work of the stage

needs to call the Commit on a Stage object (a generated singloton in the models package).

The stage object can also serves as a in-memory datastore in the model package.

// for a set implementation in  golang
type __void struct{}
var __member __void

type StageStruct struct { 
	Aclasss           map[*Aclass]struct{} // set of Aclass instances
	Aclasss_mapString map[string]*Aclass // map of Aclass by their Name
	....
}

// Stage puts aclass to the model stage
func (aclass *Aclass) Stage() *Aclass {
	Stage.Aclasss[aclass] = __member
	Stage.Aclasss_mapString[aclass.Name] = aclass

	return aclass
}

// Unstage puts aclass off the model stage
func (aclass *Aclass) Unstage() *Aclass {
	delete(Stage.Aclasss, aclass)
	delete(Stage.Aclasss_mapString, aclass.Name)
	return aclass
}

func (stage *StageStruct) Commit() {
	....
}

func (stage *StageStruct) Checkout() {
	....
}

var Stage StageStruct = StageStruct{ 
	....
}

The third set is the backRepo, it contains sister instances of instances of the stage set. The sister instances in the backRepo differ from the staged instance in two ways that make them fit for storage in a database:

  • basic field are of type sql
  • pointer fields are encoded into basic fields. Therefore, they are without pointers (acronym WOP).

The sister instances of the backRepo are instances in the ormpackage.

package orm

type AclassDB struct {
	gorm.Model

	Name_Data sql.NullString

	// encoding of pointers
	AclassPointersEnconding
}

type AclassPointersEnconding struct {
	// field Associationtob is a pointer to another Struct (optional or 0..1)
	// This field is generated into another field to enable AS ONE association
	AssociationtobID sql.NullInt64
}

Notice that the stage can be checked-out from the backRepo.

When a commit is performed, the WOP sister is created and it is persisted in the database.

Problem & resolution

For the frontRepo, the architecture is not as clean:

  • There is only one library that mixes WOP instances, memory instances and angular material components

Implementation

Additions:

  • uses test2
  • at compil, generates, if absent, an angular library for material (ng generate library test2-mat --skip-install true --skip-package-json true )
  • at compil, generates, if absent, an angular library for models (ng generate library test2-models --skip-install true --skip-package-json true )
  • at compil, generates, if absent, an angular library for orm (ng generate library test2-orm --skip-install true --skip-package-json true )

Port to gorm.io

Interest:

  • follow latest gorm.io, including cgo free sqlite driver
  • mulit DB

set up test2 example with inclusion of test

  • problem with router path that are not dependant on the stack path
  • manualy setup router paths depdendant on the stack path
  • generate router paths depdendant on the stack path

port to gorm.io

  • port to gorm.io

unique package path

  • reproduce issue with 2 DB that have a name collision
  • solve issue with schema generation based on the package path

multiple DB (one in memory, the other in DB)

  • reproduce issue in test & test2 (eventually, creates a test3)
  • reproduce issue in atmsim
  • solve issue

generate embed.go in root and ng and generate the main.go in cmd/<packagName>

Problems:

  • main.go in root directory makes it a main package, disalowing the export of embed variables from this directory
  • embed of n/dist/ng can fails in import (not a problem), embed of ng/projects must not fails at import. Therefore both can be in the same package

Steps:

  • generate embed.go in root with NgDistNg var
  • generate embed.go in ng with Projects var
  • optional generation of main.go cmd/

MANY MANY association

Situation:

  • a 'MANY MANY' association between A and B with gong is implemented with a ONE-MANY association between A and a BUse and a a ONE-ONE/ZERO association between BUse and B
  • the "BUse" struct is the the MANY MANY association table

Issue:

  • This is is cumbersome since for the user in the interaction with the table component when it is in the "association" mode

Solution:

  • define struct with Name that ends with "Use" as MANY-MANY association struct (MMAS)
  • when working with the table component between A and "AClassBClassUse" in the "association" mode for struct
    • gather all relevant "AClassBClassUse" instances, indicate the "selected" for each of those instance
    • when saving, compute the difference that create/delete AClassBClassUse instances

Implementation:

  • Create a AClassBClassUse struct
  • Manual work on the association A->AClassBClassUse
    • Add a button to deal directly with MANY-MANY association (MM)
    • Implement a different setRouterOutlet...
    • Take into account in the table component
  • Generation
    • Front Repo
    • table component ts
    • detail component html
    • detail component ts

issue 48

The idea is that when this menu is invoked,

  • all Bclass instances have to be displayed (with ID and Name, ....), like when you invoke a ONE-MANY selector to Bclass
  • selected are is list of Aclass array of AclassBclassUse that have the Aclass
  • at the save delete removed instance and create added ones

Implementation:

  •  refactor table component in order to be explicit about the mode ( DISPLAY_MODE, ONE_MANY_ASSOCIATION_MODE, MANY_MANY_ASSOCIATION_MODE)
  • Implement the MANY_MANY_ASSOCIATION_MODE
  • generation

Finding:

  • dialogData is not null when invoked from the Aclass detail (ONE_MANY_ASSOCIATION_MODE)
  • There are already 3 modes:
  • display mode
  • select mode

the dialogData contains the reverse field.

  • in the bclass-table component, set up of the correct selection of item to be selected
  • one needs to performs a double loop:
  • get all the AclassBclassUse instances of aclass. for each instance, get the bclass instance that is referenced and push it to the selection

IT works, but with hard coded variables

image

          let aclass = this.frontRepo.Aclasss.get(this.dialogData.ID)

          if (aclass.AnarrayofbUse) {
            for (let AclassBclassUse of aclass.AnarrayofbUse) {
              let bclass = AclassBclassUse.Bclass
              this.initialSelection.push(bclass)
            }  
          }

Let's try to have soft coded variable for aclass.

2 ways to do it.
1/ use soft typing of typescript

        if (this.mode == TableComponentMode.MANY_MANY_ASSOCIATION_MODE) {

          let mapOfSourceInstances = this.frontRepo[this.dialogData.SourceStruct + "s"]
          let sourceInstance = mapOfSourceInstances.get(this.dialogData.ID)

          if (sourceInstance[this.dialogData.SourceField]) {
            for (let associationInstance of sourceInstance[this.dialogData.SourceField]) {
              let bclass = associationInstance[this.dialogData.IntermediateStructField]
              this.initialSelection.push(bclass)
            }
          }
          this.selection = new SelectionModel<BclassDB>(allowMultiSelect, this.initialSelection);
        }

OK. Hard coded deletion/creation works.

    private reverseAclassBclassUseService: AclassBclassUseService,

and

            this.reverseAclassBclassUseService.deleteAclassBclassUse(associationInstance.ID).subscribe(
              aclassBclassUse => {
                this.reverseAclassBclassUseService.AclassBclassUseServiceChanged.next("delete")
              }
            );

...
              this.reverseAclassBclassUseService.postAclassBclassUse(aclassBclassUse).subscribe(
                aclassBclassUse => {
                  this.reverseAclassBclassUseService.AclassBclassUseServiceChanged.next("post")
                }
              );

Remove presentation component

Remove presentation component

Steps:

  • manually
    • remove the route to the presenter component, and replace it with a route to the editor
    • remove the router-outlet
  • automatic
  • remove unused code

With ng 12, ng add needs --skip-confirmation

$ ng add @angular/material --defaults=true
ℹ Using package manager: npm
✔ Found compatible package version: @angular/[email protected].
✔ Package information loaded.

The package @angular/[email protected] will be installed and executed.
Would you like to proceed? (Y/n)
$ ng add @angular/material --defaults=true --skip-confirmation
ℹ Using package manager: npm
✔ Found compatible package version: @angular/[email protected].
✔ Package information loaded.
✔ Package successfully installed.
UPDATE package.json (1159 bytes)
⠦ Installing packages (npm)...

Capture items order for "zero/one-many" association

Expected:

  • in detail, a button beside the selector of the "zero/one-many" for sorting
  • this start a dialog with the list of assoicated instances
  • the end user can sort elements
  • the end user can save the ordered items
  • in the stage, the slice order is restaured during checkout
  • in the stage, the slice order is captured during chekin

Steps:

manualy

  • add a button in a grid beside the access to the selector
  • in the front, creates a new component for implementing the sort function between the associated IDs
  • in the front and backrepo, add a generated "order" field with each reverse association pointer.
  • creates a test to inspect the database and manipulate the order
  • in the stage, implement checkout
  • in the stage, implement checkin

Generated (front)

  • add the field Index to API class
  • add set Valid=true in the save
  • add the field OrderingMode to DialogData in frontrepo
  • Generate the sorting component
  • add sorting component to module
  • add sorting component to map of component
  • impact the detail component for the new sorting button

Generated (back)

  • add Index field
  • add Index field management
  • add commit checkout for the zero/one side

Provide backend & restore API for the Stage

Feature:

// backup generates backup files in the dirPath
func (stage *StageStruct) Backup(dirPath string) {
	if stage.BackRepo != nil {
		stage.BackRepo.Backup(stage, dirPath)
	}
}

// Restore resets Stage & BackRepo and restores their content from the restore files in dirPath
func (stage *StageStruct) Restore(dirPath string) {
	if stage.BackRepo != nil {
		stage.BackRepo.Restore(stage, dirPath)
	}
}

Steps:

  • Implement a AclassDB without pointers

    • gong
    • backRepo
    • AclassDB
  • generate

    • gong
    • backRepo
    • AclassDB
    • AclassCRUD
  • manual implementation in test with backup files as json files

    • Stage
    • Backup
    • BackupAclass
    • BackupBclass
  • generated code

Perform reindexing at restauration

Index of instances can be different at creation (for instance aclass1 is 1 and aclass2 is 3).

Perform reindexing:

  •  ResotePhase1 : unmarshall, create in databse store ID at backup in a dedicated field ID_atBckp in aclassDB
  •  ResotePhase2 : - reindex the Pointer to Struct and Slice of Pointer to Struct

Port to ng 12

generated tsconfig.json add a strict:true parameter

Problem with the Create if association is set

				this.{{structname}}.{{AssocStructName}}_{{FieldName}}DBID_Index = new NullInt64 // !!
				this.{{structname}}.{{AssocStructName}}_{{FieldName}}DBID_Index.Valid = true
				this.{{structname}}.{{AssocStructName}}_{{FieldName}}_reverse = undefined // very important, otherwise, circular JSON

Add index to fields

Problem:

  • field is an interface
  • field index is unknown

Resolution:

  • add field index to the interface

port to ng 13

updated to node 16

thomaspeugeot@MacBook-Pro-de-Thomas ng % node --version
v16.13.0

npm cache clean --force

is good

npx @angular/cli@13 update @angular/core@13 @angular/cli@13 --allow-dirty

--allow-dirty for it does not compute git properly

RESULT : Can't do it, datetimepicker is not compatible with angular 13

Error: node_modules/@angular-material-components/datetime-picker/lib/datetime-picker.component.d.ts:12:20 - error TS2305: Module '"@angular/material/core"' has no exported member 'CanColorCtor'.

12 import { CanColor, CanColorCtor, ThemePalette } from '@angular/material/core';
                      ~~~~~~~~~~~~

h2qutc/angular-material-components#226

Issue with use of Enum in generated template

Compilation of gongsvg

Error: ../../gong/ng/projects/gong/src/lib/gongstruct-detail/gongstruct-detail.component.html:26:121 - error TS2345: Argument of type '"ONE_MANY_ASSOCIATION_MODE"' is not assignable to parameter of type 'SelectionMode'.

26             <button mat-raised-button (click)="openReverseSelection('GongBasicField', 'GongStruct_GongBasicFieldsDBID', 'ONE_MANY_ASSOCIATION_MODE', '', '', '')">GongBasicFields</button>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.