github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/istructsmem/internal/descr/example_test.go (about)

     1  /*
     2   * Copyright (c) 2021-present Sigma-Soft, Ltd.
     3   * @author: Nikolay Nikitin
     4   */
     5  
     6  package descr_test
     7  
     8  import (
     9  	"encoding/json"
    10  	"fmt"
    11  
    12  	"github.com/stretchr/testify/mock"
    13  	"github.com/voedger/voedger/pkg/appdef"
    14  	"github.com/voedger/voedger/pkg/istructs"
    15  	"github.com/voedger/voedger/pkg/istructsmem/internal/descr"
    16  )
    17  
    18  func Example() {
    19  	appDef := func() appdef.IAppDef {
    20  		adb := appdef.New()
    21  		adb.AddPackage("test", "test/path")
    22  
    23  		numName := appdef.NewQName("test", "number")
    24  		strName := appdef.NewQName("test", "string")
    25  
    26  		sysRecords := appdef.NewQName("sys", "records")
    27  		sysViews := appdef.NewQName("sys", "views")
    28  
    29  		docName, recName := appdef.NewQName("test", "doc"), appdef.NewQName("test", "rec")
    30  
    31  		n := adb.AddData(numName, appdef.DataKind_int64, appdef.NullQName, appdef.MinIncl(1))
    32  		n.SetComment("natural (positive) integer")
    33  
    34  		s := adb.AddData(strName, appdef.DataKind_string, appdef.NullQName)
    35  		s.AddConstraints(appdef.MinLen(1), appdef.MaxLen(100), appdef.Pattern(`^\w+$`, "only word characters allowed"))
    36  
    37  		doc := adb.AddCDoc(docName)
    38  		doc.SetSingleton()
    39  		doc.
    40  			AddField("f1", appdef.DataKind_int64, true).
    41  			SetFieldComment("f1", "field comment").
    42  			AddField("f2", appdef.DataKind_string, false, appdef.MinLen(4), appdef.MaxLen(4), appdef.Pattern(`^\w+$`)).
    43  			AddDataField("numField", numName, false).
    44  			AddRefField("mainChild", false, recName)
    45  		doc.AddContainer("rec", recName, 0, 100, "container comment")
    46  		doc.AddUnique(appdef.UniqueQName(docName, "unique1"), []appdef.FieldName{"f1", "f2"})
    47  		doc.SetComment(`comment 1`, `comment 2`)
    48  
    49  		rec := adb.AddCRecord(recName)
    50  		rec.
    51  			AddField("f1", appdef.DataKind_int64, true).
    52  			AddField("f2", appdef.DataKind_string, false).
    53  			AddField("phone", appdef.DataKind_string, true, appdef.MinLen(1), appdef.MaxLen(25)).
    54  			SetFieldVerify("phone", appdef.VerificationKind_Any...)
    55  		rec.
    56  			SetUniqueField("phone").
    57  			AddUnique(appdef.UniqueQName(recName, "uniq1"), []appdef.FieldName{"f1"})
    58  
    59  		viewName := appdef.NewQName("test", "view")
    60  		view := adb.AddView(viewName)
    61  		view.Key().PartKey().
    62  			AddField("pk_1", appdef.DataKind_int64)
    63  		view.Key().ClustCols().
    64  			AddField("cc_1", appdef.DataKind_string, appdef.MaxLen(100))
    65  		view.Value().
    66  			AddDataField("vv_code", strName, true).
    67  			AddRefField("vv_1", true, docName)
    68  
    69  		objName := appdef.NewQName("test", "obj")
    70  		obj := adb.AddObject(objName)
    71  		obj.AddField("f1", appdef.DataKind_string, true)
    72  
    73  		cmdName := appdef.NewQName("test", "cmd")
    74  		adb.AddCommand(cmdName).
    75  			SetUnloggedParam(objName).
    76  			SetParam(objName).
    77  			SetEngine(appdef.ExtensionEngineKind_WASM)
    78  
    79  		queryName := appdef.NewQName("test", "query")
    80  		adb.AddQuery(queryName).
    81  			SetParam(objName).
    82  			SetResult(appdef.QNameANY)
    83  
    84  		prj := adb.AddProjector(appdef.NewQName("test", "projector"))
    85  		prj.
    86  			SetWantErrors().
    87  			SetEngine(appdef.ExtensionEngineKind_WASM)
    88  		prj.Events().
    89  			Add(recName, appdef.ProjectorEventKind_AnyChanges...).SetComment(recName, "run projector every time when «test.rec» is changed").
    90  			Add(cmdName).SetComment(cmdName, "run projector every time when «test.cmd» command is executed").
    91  			Add(objName).SetComment(objName, "run projector every time when any command with «test.obj» argument is executed")
    92  		prj.States().
    93  			Add(sysRecords, docName, recName).SetComment(sysRecords, "needs to read «test.doc» and «test.rec» from «sys.records» storage")
    94  		prj.Intents().
    95  			Add(sysViews, viewName).SetComment(sysViews, "needs to update «test.view» from «sys.views» storage")
    96  
    97  		reader := adb.AddRole(appdef.NewQName("test", "reader"))
    98  		reader.SetComment("read-only role")
    99  		reader.Grant(
   100  			[]appdef.PrivilegeKind{appdef.PrivilegeKind_Select},
   101  			[]appdef.QName{docName, recName}, []appdef.FieldName{"f1", "f2"},
   102  			"allow reader to select some fields from test.doc and test.rec")
   103  		reader.Grant(
   104  			[]appdef.PrivilegeKind{appdef.PrivilegeKind_Select},
   105  			[]appdef.QName{viewName}, nil,
   106  			"allow reader to select all fields from test.view")
   107  		reader.GrantAll([]appdef.QName{queryName}, "allow reader to execute test.query")
   108  
   109  		writer := adb.AddRole(appdef.NewQName("test", "writer"))
   110  		writer.SetComment("read-write role")
   111  		writer.GrantAll([]appdef.QName{docName, recName, viewName}, "allow writer to do anything with test.doc, test.rec and test.view")
   112  		writer.Revoke(
   113  			[]appdef.PrivilegeKind{appdef.PrivilegeKind_Update},
   114  			[]appdef.QName{docName},
   115  			"disable writer to update test.doc")
   116  		writer.GrantAll([]appdef.QName{cmdName, queryName}, "allow writer to execute all test functions")
   117  
   118  		app, err := adb.Build()
   119  		if err != nil {
   120  			panic(err)
   121  		}
   122  
   123  		return app
   124  	}()
   125  
   126  	res := &mockResources{}
   127  	res.
   128  		On("Resources", mock.AnythingOfType("func(appdef.QName)")).Run(func(args mock.Arguments) {})
   129  
   130  	appStr := &mockedAppStructs{}
   131  	appStr.
   132  		On("AppQName").Return(istructs.AppQName_test1_app1).
   133  		On("AppDef").Return(appDef).
   134  		On("Resources").Return(res)
   135  
   136  	appLimits := map[appdef.QName]map[istructs.RateLimitKind]istructs.RateLimit{}
   137  
   138  	app := descr.Provide(appStr, appLimits)
   139  
   140  	json, err := json.MarshalIndent(app, "", "  ")
   141  
   142  	fmt.Println("error:", err)
   143  	fmt.Println(string(json))
   144  
   145  	//os.WriteFile("C://temp//provide_test.json", json, 0644)
   146  
   147  	// Output:
   148  	// error: <nil>
   149  	// {
   150  	//   "Name": "test1/app1",
   151  	//   "Packages": {
   152  	//     "test": {
   153  	//       "Path": "test/path",
   154  	//       "DataTypes": {
   155  	//         "test.number": {
   156  	//           "Comment": "natural (positive) integer",
   157  	//           "Ancestor": "sys.int64",
   158  	//           "Constraints": {
   159  	//             "MinIncl": 1
   160  	//           }
   161  	//         },
   162  	//         "test.string": {
   163  	//           "Ancestor": "sys.string",
   164  	//           "Constraints": {
   165  	//             "MaxLen": 100,
   166  	//             "MinLen": 1,
   167  	//             "Pattern": "^\\w+$"
   168  	//           }
   169  	//         }
   170  	//       },
   171  	//       "Structures": {
   172  	//         "test.doc": {
   173  	//           "Comment": "comment 1\ncomment 2",
   174  	//           "Kind": "CDoc",
   175  	//           "Fields": [
   176  	//             {
   177  	//               "Name": "sys.QName",
   178  	//               "Data": "sys.QName",
   179  	//               "Required": true
   180  	//             },
   181  	//             {
   182  	//               "Name": "sys.ID",
   183  	//               "Data": "sys.RecordID",
   184  	//               "Required": true
   185  	//             },
   186  	//             {
   187  	//               "Name": "sys.IsActive",
   188  	//               "Data": "sys.bool"
   189  	//             },
   190  	//             {
   191  	//               "Comment": "field comment",
   192  	//               "Name": "f1",
   193  	//               "Data": "sys.int64",
   194  	//               "Required": true
   195  	//             },
   196  	//             {
   197  	//               "Name": "f2",
   198  	//               "DataType": {
   199  	//                 "Ancestor": "sys.string",
   200  	//                 "Constraints": {
   201  	//                   "MaxLen": 4,
   202  	//                   "MinLen": 4,
   203  	//                   "Pattern": "^\\w+$"
   204  	//                 }
   205  	//               }
   206  	//             },
   207  	//             {
   208  	//               "Name": "numField",
   209  	//               "Data": "test.number"
   210  	//             },
   211  	//             {
   212  	//               "Name": "mainChild",
   213  	//               "Data": "sys.RecordID",
   214  	//               "Refs": [
   215  	//                 "test.rec"
   216  	//               ]
   217  	//             }
   218  	//           ],
   219  	//           "Containers": [
   220  	//             {
   221  	//               "Comment": "container comment",
   222  	//               "Name": "rec",
   223  	//               "Type": "test.rec",
   224  	//               "MinOccurs": 0,
   225  	//               "MaxOccurs": 100
   226  	//             }
   227  	//           ],
   228  	//           "Uniques": {
   229  	//             "test.doc$uniques$unique1": {
   230  	//               "Fields": [
   231  	//                 "f1",
   232  	//                 "f2"
   233  	//               ]
   234  	//             }
   235  	//           },
   236  	//           "Singleton": true
   237  	//         },
   238  	//         "test.obj": {
   239  	//           "Kind": "Object",
   240  	//           "Fields": [
   241  	//             {
   242  	//               "Name": "sys.QName",
   243  	//               "Data": "sys.QName",
   244  	//               "Required": true
   245  	//             },
   246  	//             {
   247  	//               "Name": "sys.Container",
   248  	//               "Data": "sys.string"
   249  	//             },
   250  	//             {
   251  	//               "Name": "f1",
   252  	//               "Data": "sys.string",
   253  	//               "Required": true
   254  	//             }
   255  	//           ]
   256  	//         },
   257  	//         "test.rec": {
   258  	//           "Kind": "CRecord",
   259  	//           "Fields": [
   260  	//             {
   261  	//               "Name": "sys.QName",
   262  	//               "Data": "sys.QName",
   263  	//               "Required": true
   264  	//             },
   265  	//             {
   266  	//               "Name": "sys.ID",
   267  	//               "Data": "sys.RecordID",
   268  	//               "Required": true
   269  	//             },
   270  	//             {
   271  	//               "Name": "sys.ParentID",
   272  	//               "Data": "sys.RecordID",
   273  	//               "Required": true
   274  	//             },
   275  	//             {
   276  	//               "Name": "sys.Container",
   277  	//               "Data": "sys.string",
   278  	//               "Required": true
   279  	//             },
   280  	//             {
   281  	//               "Name": "sys.IsActive",
   282  	//               "Data": "sys.bool"
   283  	//             },
   284  	//             {
   285  	//               "Name": "f1",
   286  	//               "Data": "sys.int64",
   287  	//               "Required": true
   288  	//             },
   289  	//             {
   290  	//               "Name": "f2",
   291  	//               "Data": "sys.string"
   292  	//             },
   293  	//             {
   294  	//               "Name": "phone",
   295  	//               "DataType": {
   296  	//                 "Ancestor": "sys.string",
   297  	//                 "Constraints": {
   298  	//                   "MaxLen": 25,
   299  	//                   "MinLen": 1
   300  	//                 }
   301  	//               },
   302  	//               "Required": true,
   303  	//               "Verifiable": true
   304  	//             }
   305  	//           ],
   306  	//           "Uniques": {
   307  	//             "test.rec$uniques$uniq1": {
   308  	//               "Fields": [
   309  	//                 "f1"
   310  	//               ]
   311  	//             }
   312  	//           },
   313  	//           "UniqueField": "phone"
   314  	//         }
   315  	//       },
   316  	//       "Views": {
   317  	//         "test.view": {
   318  	//           "Key": {
   319  	//             "Partition": [
   320  	//               {
   321  	//                 "Name": "pk_1",
   322  	//                 "Data": "sys.int64",
   323  	//                 "Required": true
   324  	//               }
   325  	//             ],
   326  	//             "ClustCols": [
   327  	//               {
   328  	//                 "Name": "cc_1",
   329  	//                 "DataType": {
   330  	//                   "Ancestor": "sys.string",
   331  	//                   "Constraints": {
   332  	//                     "MaxLen": 100
   333  	//                   }
   334  	//                 }
   335  	//               }
   336  	//             ]
   337  	//           },
   338  	//           "Value": [
   339  	//             {
   340  	//               "Name": "sys.QName",
   341  	//               "Data": "sys.QName",
   342  	//               "Required": true
   343  	//             },
   344  	//             {
   345  	//               "Name": "vv_code",
   346  	//               "Data": "test.string",
   347  	//               "Required": true
   348  	//             },
   349  	//             {
   350  	//               "Name": "vv_1",
   351  	//               "Data": "sys.RecordID",
   352  	//               "Required": true,
   353  	//               "Refs": [
   354  	//                 "test.doc"
   355  	//               ]
   356  	//             }
   357  	//           ]
   358  	//         }
   359  	//       },
   360  	//       "Extensions": {
   361  	//         "Commands": {
   362  	//           "test.cmd": {
   363  	//             "Name": "cmd",
   364  	//             "Engine": "WASM",
   365  	//             "Arg": "test.obj",
   366  	//             "UnloggedArg": "test.obj"
   367  	//           }
   368  	//         },
   369  	//         "Queries": {
   370  	//           "test.query": {
   371  	//             "Name": "query",
   372  	//             "Engine": "BuiltIn",
   373  	//             "Arg": "test.obj",
   374  	//             "Result": "sys.ANY"
   375  	//           }
   376  	//         },
   377  	//         "Projectors": {
   378  	//           "test.projector": {
   379  	//             "Name": "projector",
   380  	//             "Engine": "WASM",
   381  	//             "Events": {
   382  	//               "test.cmd": {
   383  	//                 "Comment": "run projector every time when «test.cmd» command is executed",
   384  	//                 "Kind": [
   385  	//                   "Execute"
   386  	//                 ]
   387  	//               },
   388  	//               "test.obj": {
   389  	//                 "Comment": "run projector every time when any command with «test.obj» argument is executed",
   390  	//                 "Kind": [
   391  	//                   "ExecuteWithParam"
   392  	//                 ]
   393  	//               },
   394  	//               "test.rec": {
   395  	//                 "Comment": "run projector every time when «test.rec» is changed",
   396  	//                 "Kind": [
   397  	//                   "Insert",
   398  	//                   "Update",
   399  	//                   "Activate",
   400  	//                   "Deactivate"
   401  	//                 ]
   402  	//               }
   403  	//             },
   404  	//             "WantErrors": true,
   405  	//             "States": {
   406  	//               "sys.records": [
   407  	//                 "test.doc",
   408  	//                 "test.rec"
   409  	//               ]
   410  	//             },
   411  	//             "Intents": {
   412  	//               "sys.views": [
   413  	//                 "test.view"
   414  	//               ]
   415  	//             }
   416  	//           }
   417  	//         }
   418  	//       },
   419  	//       "Roles": {
   420  	//         "test.reader": {
   421  	//           "Comment": "read-only role",
   422  	//           "Privileges": [
   423  	//             {
   424  	//               "Comment": "allow reader to select some fields from test.doc and test.rec",
   425  	//               "Access": "grant",
   426  	//               "Kinds": [
   427  	//                 "Select"
   428  	//               ],
   429  	//               "On": [
   430  	//                 "test.doc",
   431  	//                 "test.rec"
   432  	//               ],
   433  	//               "Fields": [
   434  	//                 "f1",
   435  	//                 "f2"
   436  	//               ]
   437  	//             },
   438  	//             {
   439  	//               "Comment": "allow reader to select all fields from test.view",
   440  	//               "Access": "grant",
   441  	//               "Kinds": [
   442  	//                 "Select"
   443  	//               ],
   444  	//               "On": [
   445  	//                 "test.view"
   446  	//               ]
   447  	//             },
   448  	//             {
   449  	//               "Comment": "allow reader to execute test.query",
   450  	//               "Access": "grant",
   451  	//               "Kinds": [
   452  	//                 "Execute"
   453  	//               ],
   454  	//               "On": [
   455  	//                 "test.query"
   456  	//               ]
   457  	//             }
   458  	//           ]
   459  	//         },
   460  	//         "test.writer": {
   461  	//           "Comment": "read-write role",
   462  	//           "Privileges": [
   463  	//             {
   464  	//               "Comment": "allow writer to do anything with test.doc, test.rec and test.view",
   465  	//               "Access": "grant",
   466  	//               "Kinds": [
   467  	//                 "Insert",
   468  	//                 "Update",
   469  	//                 "Select"
   470  	//               ],
   471  	//               "On": [
   472  	//                 "test.doc",
   473  	//                 "test.rec",
   474  	//                 "test.view"
   475  	//               ]
   476  	//             },
   477  	//             {
   478  	//               "Comment": "disable writer to update test.doc",
   479  	//               "Access": "revoke",
   480  	//               "Kinds": [
   481  	//                 "Update"
   482  	//               ],
   483  	//               "On": [
   484  	//                 "test.doc"
   485  	//               ]
   486  	//             },
   487  	//             {
   488  	//               "Comment": "allow writer to execute all test functions",
   489  	//               "Access": "grant",
   490  	//               "Kinds": [
   491  	//                 "Execute"
   492  	//               ],
   493  	//               "On": [
   494  	//                 "test.cmd",
   495  	//                 "test.query"
   496  	//               ]
   497  	//             }
   498  	//           ]
   499  	//         }
   500  	//       }
   501  	//     }
   502  	//   }
   503  	// }
   504  }
   505  
   506  type mockedAppStructs struct {
   507  	istructs.IAppStructs
   508  	mock.Mock
   509  }
   510  
   511  func (s *mockedAppStructs) AppDef() appdef.IAppDef {
   512  	return s.Called().Get(0).(appdef.IAppDef)
   513  }
   514  
   515  func (s *mockedAppStructs) AppQName() istructs.AppQName {
   516  	return s.Called().Get(0).(istructs.AppQName)
   517  }
   518  
   519  func (s *mockedAppStructs) Resources() istructs.IResources {
   520  	return s.Called().Get(0).(istructs.IResources)
   521  }
   522  
   523  type mockResources struct {
   524  	istructs.IResources
   525  	mock.Mock
   526  }
   527  
   528  func (r *mockResources) Resources(cb func(appdef.QName)) {
   529  	r.Called(cb)
   530  }