github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/parser/impl_test.go (about)

     1  /*
     2  * Copyright (c) 2023-present unTill Pro, Ltd.
     3  * @author Michael Saigachenko
     4   */
     5  package parser
     6  
     7  import (
     8  	"embed"
     9  	"fmt"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/voedger/voedger/pkg/appdef"
    16  	"github.com/voedger/voedger/pkg/istructs"
    17  )
    18  
    19  //go:embed sql_example_app/pmain/*.vsql
    20  var fsMain embed.FS
    21  
    22  //go:embed sql_example_app/airsbp/*.vsql
    23  var fsAir embed.FS
    24  
    25  //go:embed sql_example_app/untill/*.vsql
    26  var fsUntill embed.FS
    27  
    28  //go:embed sql_example_syspkg/*.vsql
    29  var sfs embed.FS
    30  
    31  //go:embed sql_example_app/vrestaurant/*.vsql
    32  var fsvRestaurant embed.FS
    33  
    34  //_go:embed example_app/expectedParsed.schema
    35  // var expectedParsedExampledSchemaStr string
    36  
    37  func getSysPackageAST() *PackageSchemaAST {
    38  	pkgSys, err := ParsePackageDir(appdef.SysPackage, sfs, "sql_example_syspkg")
    39  	if err != nil {
    40  		panic(err)
    41  	}
    42  	return pkgSys
    43  }
    44  
    45  func Test_BasicUsage(t *testing.T) {
    46  
    47  	require := require.New(t)
    48  	mainPkgAST, err := ParsePackageDir("github.com/untillpro/main", fsMain, "sql_example_app/pmain")
    49  	require.NoError(err)
    50  
    51  	airPkgAST, err := ParsePackageDir("github.com/untillpro/airsbp", fsAir, "sql_example_app/airsbp")
    52  	require.NoError(err)
    53  
    54  	untillPkgAST, err := ParsePackageDir("github.com/untillpro/untill", fsUntill, "sql_example_app/untill")
    55  	require.NoError(err)
    56  
    57  	appSchema, err := BuildAppSchema([]*PackageSchemaAST{
    58  		getSysPackageAST(),
    59  		mainPkgAST,
    60  		airPkgAST,
    61  		untillPkgAST,
    62  	})
    63  	require.NoError(err)
    64  
    65  	builder := appdef.New()
    66  	err = BuildAppDefs(appSchema, builder)
    67  	require.NoError(err)
    68  
    69  	app, err := builder.Build()
    70  	require.NoError(err)
    71  
    72  	// table
    73  	cdoc := app.CDoc(appdef.NewQName("main", "TablePlan"))
    74  	require.NotNil(cdoc)
    75  	require.Equal(appdef.TypeKind_CDoc, cdoc.Kind())
    76  	require.Equal(appdef.DataKind_int32, cdoc.Field("FState").DataKind())
    77  	require.Equal("Backoffice Table", cdoc.Comment())
    78  
    79  	// TODO: sf := cdoc.Field("CheckedField").(appdef.IStringField)
    80  	// TODO: require.Equal(uint16(8), sf.Restricts().MaxLen())
    81  	// TODO: require.NotNil(sf.Restricts().Pattern())
    82  
    83  	// container of the table
    84  	container := cdoc.Container("TableItems")
    85  	require.Equal("TableItems", container.Name())
    86  	require.Equal(appdef.NewQName("main", "TablePlanItem"), container.QName())
    87  	require.Equal(appdef.Occurs(0), container.MinOccurs())
    88  	require.Equal(appdef.Occurs(maxNestedTableContainerOccurrences), container.MaxOccurs())
    89  	require.Equal(appdef.TypeKind_CRecord, container.Type().Kind())
    90  	require.Equal(2+5 /* +5 system fields*/, container.Type().(appdef.IFields).FieldCount())
    91  	require.Equal(appdef.DataKind_int32, container.Type().(appdef.IFields).Field("TableNo").DataKind())
    92  	require.Equal(appdef.DataKind_int32, container.Type().(appdef.IFields).Field("Chairs").DataKind())
    93  
    94  	// constraint
    95  	uniques := cdoc.Uniques()
    96  	require.Len(uniques, 2)
    97  
    98  	t.Run("first unique, automatically named", func(t *testing.T) {
    99  		u := uniques[appdef.MustParseQName("main.TablePlan$uniques$01")]
   100  		require.NotNil(u)
   101  		cnt := 0
   102  		for _, f := range u.Fields() {
   103  			cnt++
   104  			switch n := f.Name(); n {
   105  			case "FState":
   106  				require.Equal(appdef.DataKind_int32, f.DataKind())
   107  			case "Name":
   108  				require.Equal(appdef.DataKind_string, f.DataKind())
   109  			default:
   110  				require.Fail("unexpected field name", n)
   111  			}
   112  		}
   113  		require.Equal(2, cnt)
   114  	})
   115  
   116  	t.Run("second unique, named by user", func(t *testing.T) {
   117  		u := uniques[appdef.MustParseQName("main.TablePlan$uniques$UniqueTable")]
   118  		require.NotNil(u)
   119  		cnt := 0
   120  		for _, f := range u.Fields() {
   121  			cnt++
   122  			switch n := f.Name(); n {
   123  			case "TableNumber":
   124  				require.Equal(appdef.DataKind_int32, f.DataKind())
   125  			default:
   126  				require.Fail("unexpected field name", n)
   127  			}
   128  		}
   129  		require.Equal(1, cnt)
   130  	})
   131  
   132  	// child table
   133  	crec := app.CRecord(appdef.NewQName("main", "TablePlanItem"))
   134  	require.NotNil(crec)
   135  	require.Equal(appdef.TypeKind_CRecord, crec.Kind())
   136  	require.Equal(appdef.DataKind_int32, crec.Field("TableNo").DataKind())
   137  
   138  	crec = app.CRecord(appdef.NewQName("main", "NestedWithName"))
   139  	require.NotNil(crec)
   140  	require.True(crec.Abstract())
   141  	field := crec.Field("ItemName")
   142  	require.NotNil(field)
   143  	require.Equal("Field is added to any table inherited from NestedWithName\nThe current comment is also added to scheme for this field", field.Comment())
   144  
   145  	csingleton := app.CDoc(appdef.NewQName("main", "SubscriptionProfile"))
   146  	require.True(csingleton.Singleton())
   147  	require.Equal("CSingletones is a configration singleton.\nThese comments are included in the statement definition, but may be overridden with `WITH Comment=...`", csingleton.Comment())
   148  
   149  	wsingletone := app.WDoc(appdef.NewQName("main", "Transaction"))
   150  	require.True(wsingletone.Singleton())
   151  
   152  	cmd := app.Command(appdef.NewQName("main", "NewOrder"))
   153  	require.Equal("Commands can only be declared in workspaces\nCommand can have optional argument and/or unlogged argument\nCommand can return TYPE", cmd.Comment())
   154  
   155  	// type
   156  	obj := app.Object(appdef.NewQName("main", "SubscriptionEvent"))
   157  	require.Equal(appdef.TypeKind_Object, obj.Kind())
   158  	require.Equal(appdef.DataKind_string, obj.Field("Origin").DataKind())
   159  
   160  	// view
   161  	view := app.View(appdef.NewQName("main", "XZReports"))
   162  	require.NotNil(view)
   163  	require.Equal(appdef.TypeKind_ViewRecord, view.Kind())
   164  	require.Equal("VIEWs generated by the PROJECTOR.\nPrimary Key must be declared in View.", view.Comment())
   165  
   166  	require.Equal(2, view.Value().UserFieldCount())
   167  	require.Equal(1, view.Key().PartKey().FieldCount())
   168  	require.Equal(4, view.Key().ClustCols().FieldCount())
   169  
   170  	// workspace descriptor
   171  	descr := app.CDoc(appdef.NewQName("main", "MyWorkspaceDescriptor"))
   172  	require.NotNil(descr)
   173  	require.Equal(appdef.TypeKind_CDoc, descr.Kind())
   174  	require.Equal(appdef.DataKind_string, descr.Field("Name").DataKind())
   175  	require.Equal(appdef.DataKind_string, descr.Field("Country").DataKind())
   176  
   177  	// fieldsets
   178  	cdoc = app.CDoc(appdef.NewQName("main", "WsTable"))
   179  	require.Equal(appdef.DataKind_string, cdoc.Field("Name").DataKind())
   180  
   181  	crec = app.CRecord(appdef.NewQName("main", "Child"))
   182  	require.Equal(appdef.DataKind_int32, crec.Field("Kind").DataKind())
   183  
   184  	// QUERY
   185  	q1 := app.Query(appdef.NewQName("main", "Query11"))
   186  	require.NotNil(q1)
   187  	require.Equal(appdef.TypeKind_Query, q1.Kind())
   188  
   189  	// CUD Projector
   190  	proj := app.Projector(appdef.NewQName("main", "RecordsRegistryProjector"))
   191  	require.NotNil(proj)
   192  	eventsCount := 0
   193  	proj.Events().Enum(func(ie appdef.IProjectorEvent) {
   194  		eventsCount++
   195  		k, on := ie.Kind(), ie.On().QName()
   196  		require.Len(k, 3)
   197  		require.Contains(k, appdef.ProjectorEventKind_Insert)
   198  		require.Contains(k, appdef.ProjectorEventKind_Activate)
   199  		require.Contains(k, appdef.ProjectorEventKind_Deactivate)
   200  		switch eventsCount {
   201  		case 1:
   202  			require.Equal(istructs.QNameCRecord, on)
   203  		case 2:
   204  			require.Equal(istructs.QNameWRecord, on)
   205  		}
   206  	})
   207  	require.Equal(2, eventsCount)
   208  	require.Equal(eventsCount, proj.Events().Len())
   209  
   210  	// Execute Projector
   211  	proj = app.Projector(appdef.NewQName("main", "UpdateDashboard"))
   212  	require.NotNil(proj)
   213  	eventsCount = 0
   214  	proj.Events().Enum(func(ie appdef.IProjectorEvent) {
   215  		eventsCount++
   216  		if eventsCount == 1 {
   217  			require.Len(ie.Kind(), 1)
   218  			require.Equal(appdef.ProjectorEventKind_Execute, ie.Kind()[0])
   219  			require.Equal(appdef.NewQName("main", "NewOrder"), ie.On().QName())
   220  		} else if eventsCount == 2 {
   221  			require.Len(ie.Kind(), 1)
   222  			require.Equal(appdef.ProjectorEventKind_Execute, ie.Kind()[0])
   223  			require.Equal(appdef.NewQName("main", "NewOrder2"), ie.On().QName())
   224  		}
   225  	})
   226  	require.Equal(2, eventsCount)
   227  	require.Equal(eventsCount, proj.Events().Len())
   228  
   229  	stateCount := 0
   230  	proj.States().Enum(func(storage appdef.IStorage) {
   231  		stateCount++
   232  		if stateCount == 1 {
   233  			require.Equal(appdef.NewQName("sys", "AppSecret"), storage.Name())
   234  			require.Empty(storage.Names())
   235  		} else if stateCount == 2 {
   236  			require.Equal(appdef.NewQName("sys", "Http"), storage.Name())
   237  			require.Empty(storage.Names())
   238  		}
   239  	})
   240  	require.Equal(2, stateCount)
   241  	require.Equal(stateCount, proj.States().Len())
   242  
   243  	intentsCount := 0
   244  	proj.Intents().Enum(func(storage appdef.IStorage) {
   245  		intentsCount++
   246  		if intentsCount == 1 {
   247  			require.Equal(appdef.NewQName("sys", "View"), storage.Name())
   248  			require.Len(storage.Names(), 4)
   249  			require.Equal(appdef.NewQName("main", "ActiveTablePlansView"), storage.Names()[0])
   250  			require.Equal(appdef.NewQName("main", "DashboardView"), storage.Names()[1])
   251  			require.Equal(appdef.NewQName("main", "NotificationsHistory"), storage.Names()[2])
   252  			require.Equal(appdef.NewQName("main", "XZReports"), storage.Names()[3])
   253  		}
   254  	})
   255  	require.Equal(1, intentsCount)
   256  	require.Equal(intentsCount, proj.Intents().Len())
   257  
   258  	cmd = app.Command(appdef.NewQName("main", "NewOrder2"))
   259  	require.Equal(1, cmd.States().Len())
   260  	require.NotNil(cmd.States().Storage(appdef.NewQName("sys", "AppSecret")))
   261  	require.Equal(1, cmd.States().Len())
   262  	intent := cmd.Intents().Storage(appdef.NewQName("sys", "Record"))
   263  	require.NotNil(intent)
   264  	require.True(intent.Names().Contains(appdef.NewQName("main", "Transaction")))
   265  
   266  	localNames := app.PackageLocalNames()
   267  	require.Len(localNames, 4)
   268  	require.Contains(localNames, appdef.SysPackage)
   269  	require.Contains(localNames, "main")
   270  	require.Contains(localNames, "air")
   271  	require.Contains(localNames, "untill")
   272  
   273  	require.Equal(appdef.SysPackagePath, app.PackageFullPath(appdef.SysPackage))
   274  	require.Equal("github.com/untillpro/main", app.PackageFullPath("main"))
   275  	require.Equal("github.com/untillpro/airsbp", app.PackageFullPath("air"))
   276  	require.Equal("github.com/untillpro/untill", app.PackageFullPath("untill"))
   277  
   278  	require.Equal("main", app.PackageLocalName("github.com/untillpro/main"))
   279  	require.Equal("air", app.PackageLocalName("github.com/untillpro/airsbp"))
   280  	require.Equal("untill", app.PackageLocalName("github.com/untillpro/untill"))
   281  }
   282  
   283  type ParserAssertions struct {
   284  	*require.Assertions
   285  }
   286  
   287  func (require *ParserAssertions) AppSchemaError(sql string, expectErrors ...string) {
   288  	_, err := require.AppSchema(sql)
   289  	require.EqualError(err, strings.Join(expectErrors, "\n"))
   290  }
   291  
   292  func (require *ParserAssertions) NoAppSchemaError(sql string) {
   293  	_, err := require.AppSchema(sql)
   294  	require.NoError(err)
   295  }
   296  
   297  func (require *ParserAssertions) AppSchema(sql string) (*AppSchemaAST, error) {
   298  	ast, err := ParseFile("file.vsql", sql)
   299  	require.NoError(err)
   300  
   301  	pkg, err := BuildPackageSchema("github.com/company/pkg", []*FileSchemaAST{ast})
   302  	require.NoError(err)
   303  
   304  	schema, err := BuildAppSchema([]*PackageSchemaAST{
   305  		getSysPackageAST(),
   306  		pkg,
   307  	})
   308  
   309  	return schema, err
   310  }
   311  
   312  func assertions(t *testing.T) *ParserAssertions {
   313  	return &ParserAssertions{require.New(t)}
   314  }
   315  
   316  func Test_Refs_NestedTables(t *testing.T) {
   317  
   318  	require := require.New(t)
   319  
   320  	fs, err := ParseFile("file1.vsql", `APPLICATION test();
   321  	TABLE table1 INHERITS CDoc (
   322  		items TABLE inner1 (
   323  			table1 ref,
   324  			ref1 ref(table3),
   325  			urg_number int32
   326  		)
   327  	);
   328  	TABLE table2 INHERITS CRecord (
   329  	);
   330  	TABLE table3 INHERITS CDoc (
   331  		items table2
   332  	);
   333  	`)
   334  	require.NoError(err)
   335  	pkg, err := BuildPackageSchema("test/pkg1", []*FileSchemaAST{fs})
   336  	require.NoError(err)
   337  
   338  	packages, err := BuildAppSchema([]*PackageSchemaAST{
   339  		getSysPackageAST(),
   340  		pkg,
   341  	})
   342  	require.NoError(err)
   343  
   344  	adb := appdef.New()
   345  	require.NoError(BuildAppDefs(packages, adb))
   346  
   347  	app, err := adb.Build()
   348  	require.NoError(err)
   349  
   350  	inner1 := app.Type(appdef.NewQName("pkg1", "inner1"))
   351  	ref1 := inner1.(appdef.IFields).RefField("ref1")
   352  	require.EqualValues(appdef.QNames{appdef.NewQName("pkg1", "table3")}, ref1.Refs())
   353  }
   354  
   355  func Test_CircularReferencesTables(t *testing.T) {
   356  	require := require.New(t)
   357  	// Tables
   358  	fs, err := ParseFile("file1.vsql", `APPLICATION test();
   359  	ABSTRACT TABLE table2 INHERITS table2 ();
   360  	ABSTRACT TABLE table3 INHERITS table3 ();
   361  	ABSTRACT TABLE table4 INHERITS table5 ();
   362  	ABSTRACT TABLE table5 INHERITS table6 ();
   363  	ABSTRACT TABLE table6 INHERITS table4 ();
   364  	`)
   365  	require.NoError(err)
   366  	pkg, err := BuildPackageSchema("pkg/test", []*FileSchemaAST{fs})
   367  	require.NoError(err)
   368  
   369  	_, err = BuildAppSchema([]*PackageSchemaAST{
   370  		getSysPackageAST(),
   371  		pkg,
   372  	})
   373  	require.EqualError(err, strings.Join([]string{
   374  		"file1.vsql:2:2: circular reference in INHERITS",
   375  		"file1.vsql:3:2: circular reference in INHERITS",
   376  		"file1.vsql:4:2: circular reference in INHERITS",
   377  		"file1.vsql:5:2: circular reference in INHERITS",
   378  		"file1.vsql:6:2: circular reference in INHERITS",
   379  	}, "\n"))
   380  }
   381  
   382  func Test_CircularReferencesWorkspaces(t *testing.T) {
   383  	require := require.New(t)
   384  	// Workspaces
   385  	fs, err := ParseFile("file1.vsql", `APPLICATION test();
   386  	ABSTRACT WORKSPACE w1();
   387  		ABSTRACT WORKSPACE w2 INHERITS w1,w2(
   388  		TABLE table4 INHERITS CDoc();
   389  	);
   390  	ABSTRACT WORKSPACE w3 INHERITS w4();
   391  	ABSTRACT WORKSPACE w4 INHERITS w5();
   392  	ABSTRACT WORKSPACE w5 INHERITS w3();
   393  	`)
   394  	require.NoError(err)
   395  	pkg, err := BuildPackageSchema("pkg/test", []*FileSchemaAST{fs})
   396  	require.NoError(err)
   397  
   398  	_, err = BuildAppSchema([]*PackageSchemaAST{
   399  		getSysPackageAST(),
   400  		pkg,
   401  	})
   402  	require.EqualError(err, strings.Join([]string{
   403  		"file1.vsql:3:37: circular reference in INHERITS",
   404  		"file1.vsql:6:33: circular reference in INHERITS",
   405  		"file1.vsql:7:33: circular reference in INHERITS",
   406  		"file1.vsql:8:33: circular reference in INHERITS",
   407  	}, "\n"))
   408  }
   409  
   410  func Test_Workspace_Defs(t *testing.T) {
   411  
   412  	require := require.New(t)
   413  
   414  	fs1, err := ParseFile("file1.vsql", `APPLICATION test();
   415  		ABSTRACT WORKSPACE AWorkspace(
   416  			TABLE table1 INHERITS CDoc (
   417  				a ref,
   418  				items TABLE inner1 (
   419  					b ref
   420  				)
   421  			);
   422  		);
   423  	`)
   424  	require.NoError(err)
   425  	fs2, err := ParseFile("file2.vsql", `
   426  		ALTER WORKSPACE AWorkspace(
   427  			TABLE table2 INHERITS CDoc (
   428  				a ref,
   429  				items TABLE inner2 (
   430  					b ref
   431  				)
   432  			);
   433  		);
   434  		WORKSPACE MyWorkspace INHERITS AWorkspace();
   435  		WORKSPACE MyWorkspace2 INHERITS AWorkspace();
   436  		ALTER WORKSPACE sys.Profile(
   437  			USE WORKSPACE MyWorkspace;
   438  		);
   439  	`)
   440  	require.NoError(err)
   441  	pkg, err := BuildPackageSchema("test/pkg1", []*FileSchemaAST{fs1, fs2})
   442  	require.NoError(err)
   443  
   444  	packages, err := BuildAppSchema([]*PackageSchemaAST{
   445  		getSysPackageAST(),
   446  		pkg,
   447  	})
   448  	require.NoError(err)
   449  
   450  	builder := appdef.New()
   451  	require.NoError(BuildAppDefs(packages, builder))
   452  
   453  	app, err := builder.Build()
   454  	require.NoError(err)
   455  
   456  	ws := app.Workspace(appdef.NewQName("pkg1", "MyWorkspace"))
   457  
   458  	require.Equal(appdef.TypeKind_CDoc, ws.Type(appdef.NewQName("pkg1", "table1")).Kind())
   459  	require.Equal(appdef.TypeKind_CDoc, ws.Type(appdef.NewQName("pkg1", "table2")).Kind())
   460  	require.Equal(appdef.TypeKind_CRecord, ws.Type(appdef.NewQName("pkg1", "inner1")).Kind())
   461  	require.Equal(appdef.TypeKind_CRecord, ws.Type(appdef.NewQName("pkg1", "inner2")).Kind())
   462  	require.Equal(appdef.TypeKind_Command, ws.Type(appdef.NewQName("sys", "CreateLogin")).Kind())
   463  
   464  	wsProfile := app.Workspace(appdef.NewQName("sys", "Profile"))
   465  
   466  	require.Equal(appdef.TypeKind_Workspace, wsProfile.Type(appdef.NewQName("pkg1", "MyWorkspace")).Kind())
   467  	require.Nil(wsProfile.TypeByName(appdef.NewQName("pkg1", "MyWorkspace2")))
   468  }
   469  
   470  func Test_Workspace_Defs2(t *testing.T) {
   471  	require := require.New(t)
   472  	fs, err := ParseFile("file1.vsql", `IMPORT SCHEMA 'test/pkg2';
   473  		APPLICATION test(
   474  			USE pkg2;
   475  		);
   476  		WORKSPACE w(
   477  			USE TABLE pkg2.*;
   478  		);
   479  	`)
   480  	require.NoError(err)
   481  	pkg, err := BuildPackageSchema("test/pkg1", []*FileSchemaAST{fs})
   482  	require.NoError(err)
   483  
   484  	fs2, err := ParseFile("file2.vsql", `
   485  		TABLE order INHERITS ODoc (
   486  			order_item TABLE order_item (
   487  				b ref
   488  			)
   489  		);
   490  	`)
   491  	require.NoError(err)
   492  	pkg2, err := BuildPackageSchema("test/pkg2", []*FileSchemaAST{fs2})
   493  	require.NoError(err)
   494  
   495  	packages, err := BuildAppSchema([]*PackageSchemaAST{
   496  		getSysPackageAST(),
   497  		pkg,
   498  		pkg2,
   499  	})
   500  	require.NoError(err)
   501  
   502  	builder := appdef.New()
   503  	require.NoError(BuildAppDefs(packages, builder))
   504  
   505  	app, err := builder.Build()
   506  	require.NoError(err)
   507  
   508  	ws := app.Workspace(appdef.NewQName("pkg1", "w"))
   509  
   510  	require.Equal(appdef.TypeKind_ODoc, ws.Type(appdef.NewQName("pkg2", "order")).Kind())
   511  	require.Equal(appdef.TypeKind_ORecord, ws.Type(appdef.NewQName("pkg2", "order_item")).Kind())
   512  }
   513  
   514  func Test_Alter_Workspace(t *testing.T) {
   515  
   516  	require := require.New(t)
   517  
   518  	fs0, err := ParseFile("file0.vsql", `
   519  	IMPORT SCHEMA 'org/pkg1';
   520  	IMPORT SCHEMA 'org/pkg2';
   521  	APPLICATION test(
   522  		USE pkg1;
   523  		USE pkg2;
   524  	);
   525  	`)
   526  	require.NoError(err)
   527  	pkg0, err := BuildPackageSchema("org/main", []*FileSchemaAST{fs0})
   528  	require.NoError(err)
   529  
   530  	fs1, err := ParseFile("file1.vsql", `
   531  		ABSTRACT WORKSPACE AWorkspace(
   532  			TABLE table1 INHERITS CDoc (a ref);
   533  		);
   534  	`)
   535  	require.NoError(err)
   536  	pkg1, err := BuildPackageSchema("org/pkg1", []*FileSchemaAST{fs1})
   537  	require.NoError(err)
   538  
   539  	fs2, err := ParseFile("file2.vsql", `
   540  		IMPORT SCHEMA 'org/pkg1'
   541  		ALTER WORKSPACE pkg1.AWorkspace(
   542  			TABLE table2 INHERITS CDoc (a ref);
   543  		);
   544  	`)
   545  	require.NoError(err)
   546  	pkg2, err := BuildPackageSchema("org/pkg2", []*FileSchemaAST{fs2})
   547  	require.NoError(err)
   548  
   549  	_, err = BuildAppSchema([]*PackageSchemaAST{
   550  		getSysPackageAST(),
   551  		pkg0,
   552  		pkg1,
   553  		pkg2,
   554  	})
   555  	require.EqualError(err, strings.Join([]string{
   556  		"file2.vsql:3:19: workspace pkg1.AWorkspace is not alterable",
   557  	}, "\n"))
   558  }
   559  
   560  func Test_DupFieldsInTypes(t *testing.T) {
   561  	require := require.New(t)
   562  
   563  	fs, err := ParseFile("file1.vsql", `APPLICATION test();
   564  	TYPE RootType (
   565  		Id int32
   566  	);
   567  	TYPE BaseType(
   568  		RootType,
   569  		baseField int
   570  	);
   571  	TYPE BaseType2 (
   572  		someField int
   573  	);
   574  	TYPE MyType(
   575  		BaseType,
   576  		BaseType2,
   577  		field varchar,
   578  		field varchar,
   579  		baseField varchar,
   580  		someField int,
   581  		Id varchar
   582  	)
   583  	`)
   584  	require.NoError(err)
   585  	pkg, err := BuildPackageSchema("pkg/test", []*FileSchemaAST{fs})
   586  	require.NoError(err)
   587  
   588  	packages, err := BuildAppSchema([]*PackageSchemaAST{
   589  		getSysPackageAST(),
   590  		pkg,
   591  	})
   592  	require.NoError(err)
   593  
   594  	err = BuildAppDefs(packages, appdef.New())
   595  	require.EqualError(err, strings.Join([]string{
   596  		"file1.vsql:16:3: redefinition of field",
   597  		"file1.vsql:17:3: redefinition of baseField",
   598  		"file1.vsql:18:3: redefinition of someField",
   599  		"file1.vsql:19:3: redefinition of Id",
   600  	}, "\n"))
   601  
   602  }
   603  
   604  func Test_Varchar(t *testing.T) {
   605  	require := require.New(t)
   606  
   607  	fs, err := ParseFile("file1.vsql", fmt.Sprintf(`APPLICATION test();
   608  	TYPE RootType (
   609  		Oversize varchar(%d)
   610  	);
   611  	TYPE CDoc1 (
   612  		Oversize varchar(%d)
   613  	);
   614  	`, uint32(appdef.MaxFieldLength)+1, uint32(appdef.MaxFieldLength)+1))
   615  	require.NoError(err)
   616  	pkg, err := BuildPackageSchema("pkg/test", []*FileSchemaAST{fs})
   617  	require.NoError(err)
   618  
   619  	_, err = BuildAppSchema([]*PackageSchemaAST{
   620  		getSysPackageAST(),
   621  		pkg,
   622  	})
   623  	require.EqualError(err, strings.Join([]string{
   624  		fmt.Sprintf("file1.vsql:3:12: maximum field length is %d", appdef.MaxFieldLength),
   625  		fmt.Sprintf("file1.vsql:6:12: maximum field length is %d", appdef.MaxFieldLength),
   626  	}, "\n"))
   627  
   628  }
   629  
   630  func Test_DupFieldsInTables(t *testing.T) {
   631  	require := require.New(t)
   632  
   633  	fs, err := ParseFile("file1.vsql", `APPLICATION test();
   634  	TYPE RootType (
   635  		Kind int32
   636  	);
   637  	TYPE BaseType(
   638  		RootType,
   639  		baseField int
   640  	);
   641  	TYPE BaseType2 (
   642  		someField int
   643  	);
   644  	ABSTRACT TABLE ByBaseTable INHERITS CDoc (
   645  		Name varchar,
   646  		Code varchar
   647  	);
   648  	TABLE MyTable INHERITS ByBaseTable(
   649  		BaseType,
   650  		BaseType2,
   651  		newField varchar,
   652  		field varchar,
   653  		field varchar, 		-- duplicated in the this table
   654  		baseField varchar,		-- duplicated in the first OF
   655  		someField int,		-- duplicated in the second OF
   656  		Kind int,			-- duplicated in the first OF (2nd level)
   657  		Name int,			-- duplicated in the inherited table
   658  		ID varchar
   659  	)
   660  	`)
   661  	require.NoError(err)
   662  	pkg, err := BuildPackageSchema("pkg/test", []*FileSchemaAST{fs})
   663  	require.NoError(err)
   664  
   665  	packages, err := BuildAppSchema([]*PackageSchemaAST{
   666  		getSysPackageAST(),
   667  		pkg,
   668  	})
   669  	require.NoError(err)
   670  
   671  	err = BuildAppDefs(packages, appdef.New())
   672  	require.EqualError(err, strings.Join([]string{
   673  		"file1.vsql:21:3: redefinition of field",
   674  		"file1.vsql:22:3: redefinition of baseField",
   675  		"file1.vsql:23:3: redefinition of someField",
   676  		"file1.vsql:24:3: redefinition of Kind",
   677  		"file1.vsql:25:3: redefinition of Name",
   678  	}, "\n"))
   679  
   680  }
   681  
   682  func Test_AbstractTables(t *testing.T) {
   683  	require := require.New(t)
   684  
   685  	fs, err := ParseFile("file1.vsql", `APPLICATION test();
   686  	TABLE ByBaseTable INHERITS CDoc (
   687  		Name varchar
   688  	);
   689  	TABLE MyTable INHERITS ByBaseTable(		-- NOT ALLOWED (base table must be abstract)
   690  	);
   691  
   692  	TABLE My1 INHERITS CRecord(
   693  		f1 ref(AbstractTable)				-- NOT ALLOWED (reference to abstract table)
   694  	);
   695  
   696  	ABSTRACT TABLE AbstractTable INHERITS CDoc(
   697  	);
   698  
   699  	WORKSPACE MyWorkspace1(
   700  		EXTENSION ENGINE BUILTIN (
   701  
   702  			PROJECTOR proj1
   703              AFTER INSERT ON AbstractTable 	-- NOT ALLOWED (projector refers to abstract table)
   704              INTENTS(SendMail);
   705  
   706  			SYNC PROJECTOR proj2
   707              AFTER INSERT ON My1
   708              INTENTS(Record(AbstractTable));	-- NOT ALLOWED (projector refers to abstract table)
   709  
   710  			PROJECTOR proj3
   711              AFTER INSERT ON My1
   712  			STATE(Record(AbstractTable))		-- NOT ALLOWED (projector refers to abstract table)
   713              INTENTS(SendMail);
   714  		);
   715  		TABLE My2 INHERITS CRecord(
   716  			nested AbstractTable			-- NOT ALLOWED
   717  		);
   718  		USE TABLE AbstractTable;			-- NOT ALLOWED
   719  		TABLE My3 INHERITS CRecord(
   720  			f int,
   721  			items ABSTRACT TABLE Nested()	-- NOT ALLOWED
   722  		);
   723  	)
   724  	`)
   725  	require.NoError(err)
   726  	pkg, err := BuildPackageSchema("test/pkg1", []*FileSchemaAST{fs})
   727  	require.NoError(err)
   728  
   729  	_, err = BuildAppSchema([]*PackageSchemaAST{
   730  		getSysPackageAST(),
   731  		pkg,
   732  	})
   733  	require.EqualError(err, strings.Join([]string{
   734  		"file1.vsql:5:25: base table must be abstract",
   735  		"file1.vsql:19:29: projector refers to abstract table AbstractTable",
   736  		"file1.vsql:24:21: projector refers to abstract table AbstractTable",
   737  		"file1.vsql:28:10: projector refers to abstract table AbstractTable",
   738  		"file1.vsql:32:11: nested abstract table AbstractTable",
   739  		"file1.vsql:34:13: use of abstract table AbstractTable",
   740  		"file1.vsql:37:4: nested abstract table Nested",
   741  		"file1.vsql:9:10: reference to abstract table AbstractTable",
   742  	}, "\n"))
   743  
   744  }
   745  
   746  func Test_AbstractTables2(t *testing.T) {
   747  	require := require.New(t)
   748  
   749  	fs, err := ParseFile("file1.vsql", `APPLICATION test();
   750  	ABSTRACT TABLE AbstractTable INHERITS CDoc(
   751  	);
   752  
   753  	WORKSPACE MyWorkspace1(
   754  		TABLE My2 INHERITS CRecord(
   755  			nested AbstractTable			-- NOT ALLOWED
   756  		);
   757  	);
   758  	`)
   759  	require.NoError(err)
   760  	pkg, err := BuildPackageSchema("test/pkg", []*FileSchemaAST{fs})
   761  	require.NoError(err)
   762  
   763  	_, err = BuildAppSchema([]*PackageSchemaAST{
   764  		getSysPackageAST(),
   765  		pkg,
   766  	})
   767  	require.EqualError(err, strings.Join([]string{
   768  		"file1.vsql:7:11: nested abstract table AbstractTable",
   769  	}, "\n"))
   770  
   771  }
   772  
   773  func Test_WorkspaceDescriptors(t *testing.T) {
   774  	require := require.New(t)
   775  
   776  	fs, err := ParseFile("file1.vsql", `APPLICATION test();
   777  	ROLE R1;
   778  	WORKSPACE W1(
   779  		DESCRIPTOR(); -- gets name W1Descriptor
   780  	);
   781  	WORKSPACE W2(
   782  		DESCRIPTOR W2D(); -- gets name W2D
   783  	);
   784  	WORKSPACE W3(
   785  		DESCRIPTOR R1(); -- duplicated name
   786  	);
   787  	ROLE W2D; -- duplicated name
   788  	`)
   789  	require.NoError(err)
   790  	pkg, err := BuildPackageSchema("test/pkg", []*FileSchemaAST{fs})
   791  	require.EqualError(err, strings.Join([]string{
   792  		"file1.vsql:10:14: redefinition of R1",
   793  		"file1.vsql:12:2: redefinition of W2D",
   794  	}, "\n"))
   795  
   796  	require.Equal(Ident("W1Descriptor"), pkg.Ast.Statements[2].Workspace.Descriptor.Name)
   797  	require.Equal(Ident("W2D"), pkg.Ast.Statements[3].Workspace.Descriptor.Name)
   798  }
   799  func Test_PanicUnknownFieldType(t *testing.T) {
   800  	require := require.New(t)
   801  
   802  	fs, err := ParseFile("file1.vsql", `APPLICATION test();
   803  	TABLE MyTable INHERITS CDoc (
   804  		Name asdasd,
   805  		Code varchar
   806  	);
   807  	`)
   808  	require.NoError(err)
   809  	pkg, err := BuildPackageSchema("test/pkg", []*FileSchemaAST{fs})
   810  	require.NoError(err)
   811  
   812  	_, err = BuildAppSchema([]*PackageSchemaAST{
   813  		getSysPackageAST(),
   814  		pkg,
   815  	})
   816  	require.EqualError(err, strings.Join([]string{
   817  		"file1.vsql:3:8: undefined data type or table: asdasd",
   818  	}, "\n"))
   819  
   820  }
   821  
   822  func Test_Expressions(t *testing.T) {
   823  	require := require.New(t)
   824  
   825  	_, err := ParseFile("file1.vsql", `
   826  	TABLE MyTable(
   827  		Int1 varchar DEFAULT 1 CHECK(Int1 > Int2),
   828  		Int1 int DEFAULT 1 CHECK(Text != 'asd'),
   829  		Int1 int DEFAULT 1 CHECK(Int2 > -5),
   830  		Int1 int DEFAULT 1 CHECK(TextField > 'asd' AND (SomeFloat/3.2)*4 != 5.003),
   831  		Int1 int DEFAULT 1 CHECK(SomeFunc('a', TextField) AND BoolField=FALSE),
   832  
   833  		CHECK(MyRowValidator(this))
   834  	)
   835  	`)
   836  	require.NoError(err)
   837  
   838  }
   839  
   840  func Test_Duplicates(t *testing.T) {
   841  	require := require.New(t)
   842  
   843  	ast1, err := ParseFile("file1.vsql", `APPLICATION test();
   844  	EXTENSION ENGINE BUILTIN (
   845  		FUNCTION MyTableValidator() RETURNS void;
   846  		FUNCTION MyTableValidator(TableRow) RETURNS string;
   847  		FUNCTION MyFunc2() RETURNS void;
   848  	);
   849  	TABLE Rec1 INHERITS CRecord();
   850  	`)
   851  	require.NoError(err)
   852  
   853  	ast2, err := ParseFile("file2.vsql", `
   854  	WORKSPACE ChildWorkspace (
   855  		TAG MyFunc2; -- redeclared
   856  		EXTENSION ENGINE BUILTIN (
   857  			FUNCTION MyFunc3() RETURNS void;
   858  			FUNCTION MyFunc4() RETURNS void;
   859  		);
   860  		WORKSPACE InnerWorkspace (
   861  			ROLE MyFunc4; -- redeclared
   862  		);
   863  		TABLE Doc1 INHERITS ODoc(
   864  			nested1 Rec1,
   865  			nested2 TABLE Rec1() -- redeclared
   866  		)
   867  	)
   868  	`)
   869  	require.NoError(err)
   870  
   871  	_, err = BuildPackageSchema("test/pkg", []*FileSchemaAST{ast1, ast2})
   872  
   873  	require.EqualError(err, strings.Join([]string{
   874  		"file1.vsql:4:3: redefinition of MyTableValidator",
   875  		"file2.vsql:3:3: redefinition of MyFunc2",
   876  		"file2.vsql:9:4: redefinition of MyFunc4",
   877  		"file2.vsql:13:12: redefinition of Rec1",
   878  	}, "\n"))
   879  
   880  }
   881  
   882  func Test_DuplicatesInViews(t *testing.T) {
   883  	require := require.New(t)
   884  
   885  	ast, err := ParseFile("file2.vsql", `APPLICATION test();
   886  	WORKSPACE Workspace (
   887  		VIEW test(
   888  			field1 int,
   889  			field2 int,
   890  			field1 varchar,
   891  			PRIMARY KEY(field1),
   892  			PRIMARY KEY(field2)
   893  		) AS RESULT OF Proj1;
   894  
   895  		EXTENSION ENGINE BUILTIN (
   896  			PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
   897  			COMMAND Orders()
   898  		);
   899  	)
   900  	`)
   901  	require.NoError(err)
   902  
   903  	pkg, err := BuildPackageSchema("test/pkg", []*FileSchemaAST{ast})
   904  	require.NoError(err)
   905  
   906  	_, err = BuildAppSchema([]*PackageSchemaAST{
   907  		pkg,
   908  		getSysPackageAST(),
   909  	})
   910  
   911  	require.EqualError(err, strings.Join([]string{
   912  		"file2.vsql:6:4: redefinition of field1",
   913  		"file2.vsql:8:16: redefinition of primary key",
   914  	}, "\n"))
   915  
   916  }
   917  func Test_Views(t *testing.T) {
   918  	require := assertions(t)
   919  
   920  	require.AppSchemaError(`APPLICATION test(); WORKSPACE Workspace (
   921  			VIEW test(
   922  				field1 int,
   923  				PRIMARY KEY(field2)
   924  			) AS RESULT OF Proj1;
   925  			EXTENSION ENGINE BUILTIN (
   926  				PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
   927  				COMMAND Orders()
   928  			);
   929  			)
   930  	`, "file.vsql:4:17: undefined field field2")
   931  
   932  	require.AppSchemaError(`APPLICATION test(); WORKSPACE Workspace (
   933  			VIEW test(
   934  				field1 varchar,
   935  				PRIMARY KEY((field1))
   936  			) AS RESULT OF Proj1;
   937  			EXTENSION ENGINE BUILTIN (
   938  				PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
   939  				COMMAND Orders()
   940  			);
   941  			)
   942  	`, "file.vsql:4:18: varchar field field1 not supported in partition key")
   943  
   944  	require.AppSchemaError(`APPLICATION test(); WORKSPACE Workspace (
   945  		VIEW test(
   946  			field1 bytes,
   947  			PRIMARY KEY((field1))
   948  		) AS RESULT OF Proj1;
   949  		EXTENSION ENGINE BUILTIN (
   950  			PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
   951  			COMMAND Orders()
   952  		);
   953  	)
   954  	`, "file.vsql:4:17: bytes field field1 not supported in partition key")
   955  
   956  	require.AppSchemaError(`APPLICATION test(); WORKSPACE Workspace (
   957  		VIEW test(
   958  			field1 varchar,
   959  			field2 int,
   960  			PRIMARY KEY(field1, field2)
   961  		) AS RESULT OF Proj1;
   962  		EXTENSION ENGINE BUILTIN (
   963  			PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
   964  			COMMAND Orders()
   965  		);
   966  	)
   967  	`, "file.vsql:5:16: varchar field field1 can only be the last one in clustering key")
   968  
   969  	require.AppSchemaError(`APPLICATION test(); WORKSPACE Workspace (
   970  		VIEW test(
   971  			field1 bytes,
   972  			field2 int,
   973  			PRIMARY KEY(field1, field2)
   974  		) AS RESULT OF Proj1;
   975  		EXTENSION ENGINE BUILTIN (
   976  			PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
   977  			COMMAND Orders()
   978  		);
   979  	)
   980  	`, "file.vsql:5:16: bytes field field1 can only be the last one in clustering key")
   981  
   982  	require.AppSchemaError(`APPLICATION test(); WORKSPACE Workspace (
   983  		ABSTRACT TABLE abc INHERITS CDoc();
   984  		VIEW test(
   985  			field1 ref(abc),
   986  			field2 ref(unexisting),
   987  			PRIMARY KEY(field1, field2)
   988  		) AS RESULT OF Proj1;
   989  		EXTENSION ENGINE BUILTIN (
   990  			PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
   991  			COMMAND Orders()
   992  		);
   993  	)
   994  	`, "file.vsql:4:15: reference to abstract table abc", "file.vsql:5:15: undefined table: unexisting")
   995  
   996  	require.AppSchemaError(`APPLICATION test(); WORKSPACE Workspace (
   997  		VIEW test(
   998  			fld1 int32
   999  		) AS RESULT OF Proj1;
  1000  		EXTENSION ENGINE BUILTIN (
  1001  			PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
  1002  			COMMAND Orders()
  1003  		);
  1004  	)
  1005  	`, "file.vsql:2:3: primary key not defined")
  1006  }
  1007  
  1008  func Test_Views2(t *testing.T) {
  1009  	require := require.New(t)
  1010  
  1011  	{
  1012  		ast, err := ParseFile("file2.vsql", `APPLICATION test(); WORKSPACE Workspace (
  1013  			VIEW test(
  1014  				-- comment1
  1015  				field1 int,
  1016  				-- comment2
  1017  				field2 varchar(20),
  1018  				-- comment3
  1019  				field3 bytes(20),
  1020  				-- comment4
  1021  				field4 ref,
  1022  				PRIMARY KEY((field1,field4),field2)
  1023  			) AS RESULT OF Proj1;
  1024  			EXTENSION ENGINE BUILTIN (
  1025  				PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
  1026  				COMMAND Orders()
  1027  			);
  1028  		)
  1029  		`)
  1030  		require.NoError(err)
  1031  		pkg, err := BuildPackageSchema("test", []*FileSchemaAST{ast})
  1032  		require.NoError(err)
  1033  
  1034  		packages, err := BuildAppSchema([]*PackageSchemaAST{
  1035  			getSysPackageAST(),
  1036  			pkg,
  1037  		})
  1038  		require.NoError(err)
  1039  
  1040  		appBld := appdef.New()
  1041  		err = BuildAppDefs(packages, appBld)
  1042  		require.NoError(err)
  1043  
  1044  		app, err := appBld.Build()
  1045  		require.NoError(err)
  1046  
  1047  		v := app.View(appdef.NewQName("test", "test"))
  1048  		require.NotNil(v)
  1049  	}
  1050  	{
  1051  		ast, err := ParseFile("file2.vsql", `APPLICATION test(); WORKSPACE Workspace (
  1052  			VIEW test(
  1053  				-- comment1
  1054  				field1 int,
  1055  				-- comment2
  1056  				field3 bytes(20),
  1057  				-- comment4
  1058  				field4 ref,
  1059  				PRIMARY KEY((field1),field4,field3)
  1060  			) AS RESULT OF Proj1;
  1061  			EXTENSION ENGINE BUILTIN (
  1062  				PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
  1063  				COMMAND Orders()
  1064  			);
  1065  		)
  1066  		`)
  1067  		require.NoError(err)
  1068  		pkg, err := BuildPackageSchema("test", []*FileSchemaAST{ast})
  1069  		require.NoError(err)
  1070  
  1071  		packages, err := BuildAppSchema([]*PackageSchemaAST{
  1072  			getSysPackageAST(),
  1073  			pkg,
  1074  		})
  1075  		require.NoError(err)
  1076  
  1077  		appBld := appdef.New()
  1078  		err = BuildAppDefs(packages, appBld)
  1079  		require.NoError(err)
  1080  
  1081  		app, err := appBld.Build()
  1082  		require.NoError(err)
  1083  
  1084  		v := app.View(appdef.NewQName("test", "test"))
  1085  		require.NotNil(v)
  1086  	}
  1087  	{
  1088  		ast, err := ParseFile("file2.vsql", `APPLICATION test(); WORKSPACE Workspace (
  1089  			VIEW test(
  1090  				-- comment1
  1091  				field1 int,
  1092  				-- comment2
  1093  				field3 bytes(20),
  1094  				-- comment4
  1095  				field4 ref,
  1096  				PRIMARY KEY((field1),field4,field3)
  1097  			) AS RESULT OF Proj1;
  1098  			EXTENSION ENGINE BUILTIN (
  1099  				PROJECTOR Proj1 AFTER EXECUTE ON (Orders);
  1100  				COMMAND Orders()
  1101  			);
  1102  		)
  1103  		`)
  1104  		require.NoError(err)
  1105  		pkg, err := BuildPackageSchema("test", []*FileSchemaAST{ast})
  1106  		require.NoError(err)
  1107  
  1108  		_, err = BuildAppSchema([]*PackageSchemaAST{
  1109  			getSysPackageAST(),
  1110  			pkg,
  1111  		})
  1112  		require.Error(err, "file2.vsql:2:4: projector Proj1 does not declare intent for view test")
  1113  
  1114  	}
  1115  
  1116  }
  1117  func Test_Comments(t *testing.T) {
  1118  	require := require.New(t)
  1119  
  1120  	fs, err := ParseFile("example.vsql", `
  1121  	EXTENSION ENGINE BUILTIN (
  1122  
  1123  	-- My function
  1124  	-- line 2
  1125  	FUNCTION MyFunc() RETURNS void;
  1126  
  1127  	/* 	Multiline
  1128  		comment  */
  1129  	FUNCTION MyFunc1() RETURNS void;
  1130  	);
  1131  
  1132  	`)
  1133  	require.NoError(err)
  1134  
  1135  	ps, err := BuildPackageSchema("test", []*FileSchemaAST{fs})
  1136  	require.NoError(err)
  1137  
  1138  	require.NotNil(ps.Ast.Statements[0].ExtEngine.Statements[0].Function.Comments)
  1139  
  1140  	comments := ps.Ast.Statements[0].ExtEngine.Statements[0].Function.GetComments()
  1141  	require.Len(comments, 2)
  1142  	require.Equal("My function", comments[0])
  1143  	require.Equal("line 2", comments[1])
  1144  
  1145  	fn := ps.Ast.Statements[0].ExtEngine.Statements[1].Function
  1146  	comments = fn.GetComments()
  1147  	require.Len(comments, 2)
  1148  	require.Equal("Multiline", comments[0])
  1149  	require.Equal("comment", comments[1])
  1150  }
  1151  
  1152  func Test_Undefined(t *testing.T) {
  1153  	require := require.New(t)
  1154  
  1155  	fs, err := ParseFile("example.vsql", `APPLICATION test();
  1156  	WORKSPACE test (
  1157  		EXTENSION ENGINE WASM (
  1158  			COMMAND Orders() WITH Tags=(UndefinedTag);
  1159  			PROJECTOR ImProjector AFTER EXECUTE ON xyz.CreateUPProfile;
  1160  			COMMAND CmdFakeReturn() RETURNS text;
  1161  			COMMAND CmdNoReturn() RETURNS void;
  1162  			COMMAND CmdFakeArg(text);
  1163  			COMMAND CmdVoidArg(void);
  1164  			COMMAND CmdFakeUnloggedArg(UNLOGGED text);
  1165  		)
  1166  	)
  1167  	`)
  1168  	require.NoError(err)
  1169  
  1170  	pkg, err := BuildPackageSchema("test", []*FileSchemaAST{fs})
  1171  	require.NoError(err)
  1172  
  1173  	_, err = BuildAppSchema([]*PackageSchemaAST{pkg, getSysPackageAST()})
  1174  
  1175  	require.EqualError(err, strings.Join([]string{
  1176  		"example.vsql:4:32: undefined tag: UndefinedTag",
  1177  		"example.vsql:5:43: xyz undefined",
  1178  		"example.vsql:6:36: undefined type or table: text",
  1179  		"example.vsql:8:23: undefined type or table: text",
  1180  		"example.vsql:10:40: undefined type or table: text",
  1181  	}, "\n"))
  1182  }
  1183  
  1184  func Test_Projectors(t *testing.T) {
  1185  	require := require.New(t)
  1186  
  1187  	fs, err := ParseFile("example.vsql", `APPLICATION test();
  1188  	WORKSPACE test (
  1189  		TABLE Order INHERITS ODoc();
  1190  		EXTENSION ENGINE WASM (
  1191  			COMMAND Orders();
  1192  			PROJECTOR ImProjector1 AFTER EXECUTE ON test.CreateUPProfile; 			-- Undefined
  1193  			PROJECTOR ImProjector2 AFTER EXECUTE ON Order; 							-- Bad: Order is not a type or command
  1194  			PROJECTOR ImProjector3 AFTER UPDATE ON Order; 				-- Bad
  1195  			PROJECTOR ImProjector4 AFTER ACTIVATE ON Order; 			-- Bad
  1196  			PROJECTOR ImProjector5 AFTER DEACTIVATE ON Order; 			-- Bad
  1197  			PROJECTOR ImProjector6 AFTER INSERT ON Order OR AFTER EXECUTE ON Orders;	-- Good
  1198  			PROJECTOR ImProjector7 AFTER EXECUTE WITH PARAM ON Bill;	-- Bad: Type undefined
  1199  			PROJECTOR ImProjector8 AFTER EXECUTE WITH PARAM ON ODoc;	-- Good
  1200  			PROJECTOR ImProjector9 AFTER EXECUTE WITH PARAM ON ORecord;	-- Bad
  1201  		);
  1202  	)
  1203  	`)
  1204  	require.NoError(err)
  1205  
  1206  	pkg, err := BuildPackageSchema("test", []*FileSchemaAST{fs})
  1207  	require.NoError(err)
  1208  
  1209  	_, err = BuildAppSchema([]*PackageSchemaAST{pkg, getSysPackageAST()})
  1210  
  1211  	require.EqualError(err, strings.Join([]string{
  1212  		"example.vsql:6:44: undefined command: test.CreateUPProfile",
  1213  		"example.vsql:7:44: undefined command: Order",
  1214  		"example.vsql:8:43: only INSERT allowed for ODoc or ORecord",
  1215  		"example.vsql:9:45: only INSERT allowed for ODoc or ORecord",
  1216  		"example.vsql:10:47: only INSERT allowed for ODoc or ORecord",
  1217  		"example.vsql:12:55: undefined type or ODoc: Bill",
  1218  		"example.vsql:14:55: undefined type or ODoc: ORecord",
  1219  	}, "\n"))
  1220  }
  1221  
  1222  func Test_Imports(t *testing.T) {
  1223  	require := require.New(t)
  1224  
  1225  	fs, err := ParseFile("example.vsql", `
  1226  	IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg2';
  1227  	IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg3' AS air;
  1228  	APPLICATION test(
  1229  		USE pkg2;
  1230  		USE pkg3;
  1231  	);
  1232  	WORKSPACE test (
  1233  		EXTENSION ENGINE WASM (
  1234      		COMMAND Orders WITH Tags=(pkg2.SomeTag);
  1235      		QUERY Query2 RETURNS void WITH Tags=(air.SomePkg3Tag);
  1236      		QUERY Query3 RETURNS void WITH Tags=(air.UnknownTag); -- air.UnknownTag undefined
  1237      		PROJECTOR ImProjector AFTER EXECUTE ON Air.CreateUPProfil; -- Air undefined
  1238  		)
  1239  	)
  1240  	`)
  1241  	require.NoError(err)
  1242  	pkg1, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg1", []*FileSchemaAST{fs})
  1243  	require.NoError(err)
  1244  
  1245  	fs, err = ParseFile("example.vsql", `TAG SomeTag;`)
  1246  	require.NoError(err)
  1247  	pkg2, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg2", []*FileSchemaAST{fs})
  1248  	require.NoError(err)
  1249  
  1250  	fs, err = ParseFile("example.vsql", `TAG SomePkg3Tag;`)
  1251  	require.NoError(err)
  1252  	pkg3, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg3", []*FileSchemaAST{fs})
  1253  	require.NoError(err)
  1254  
  1255  	_, err = BuildAppSchema([]*PackageSchemaAST{getSysPackageAST(), pkg1, pkg2, pkg3})
  1256  	require.EqualError(err, strings.Join([]string{
  1257  		"example.vsql:12:44: undefined tag: air.UnknownTag",
  1258  		"example.vsql:13:46: Air undefined",
  1259  	}, "\n"))
  1260  
  1261  }
  1262  
  1263  func Test_AbstractWorkspace(t *testing.T) {
  1264  	require := require.New(t)
  1265  
  1266  	fs, err := ParseFile("example.vsql", `APPLICATION test();
  1267  	WORKSPACE ws1 ();
  1268  	ABSTRACT WORKSPACE ws2(
  1269  		DESCRIPTOR(					-- Incorrect
  1270  			a int
  1271  		);
  1272  	);
  1273  	WORKSPACE ws4 INHERITS ws2 ();
  1274  	WORKSPACE ws5 INHERITS ws1 ();  -- Incorrect
  1275  	`)
  1276  	require.NoError(err)
  1277  
  1278  	ps, err := BuildPackageSchema("test", []*FileSchemaAST{fs})
  1279  	require.NoError(err)
  1280  
  1281  	require.False(ps.Ast.Statements[1].Workspace.Abstract)
  1282  	require.True(ps.Ast.Statements[2].Workspace.Abstract)
  1283  	require.False(ps.Ast.Statements[3].Workspace.Abstract)
  1284  	require.Equal("ws2", ps.Ast.Statements[3].Workspace.Inherits[0].String())
  1285  
  1286  	_, err = BuildAppSchema([]*PackageSchemaAST{
  1287  		getSysPackageAST(),
  1288  		ps,
  1289  	})
  1290  	require.EqualError(err, strings.Join([]string{
  1291  		"example.vsql:4:13: abstract workspace cannot have a descriptor",
  1292  		"example.vsql:9:25: base workspace must be abstract",
  1293  	}, "\n"))
  1294  
  1295  }
  1296  
  1297  func Test_UniqueFields(t *testing.T) {
  1298  	require := require.New(t)
  1299  
  1300  	fs, err := ParseFile("example.vsql", `APPLICATION test();
  1301  	TABLE MyTable INHERITS CDoc (
  1302  		Int1 int32,
  1303  		Int2 int32 NOT NULL,
  1304  		UNIQUEFIELD Int1,
  1305  		UNIQUEFIELD Int2
  1306  	)
  1307  	`)
  1308  	require.NoError(err)
  1309  
  1310  	pkg, err := BuildPackageSchema("test", []*FileSchemaAST{fs})
  1311  	require.NoError(err)
  1312  
  1313  	packages, err := BuildAppSchema([]*PackageSchemaAST{
  1314  		getSysPackageAST(),
  1315  		pkg,
  1316  	})
  1317  	require.NoError(err)
  1318  
  1319  	appBld := appdef.New()
  1320  	err = BuildAppDefs(packages, appBld)
  1321  	require.NoError(err)
  1322  
  1323  	app, err := appBld.Build()
  1324  	require.NoError(err)
  1325  
  1326  	cdoc := app.CDoc(appdef.NewQName("test", "MyTable"))
  1327  	require.NotNil(cdoc)
  1328  
  1329  	fld := cdoc.UniqueField()
  1330  	require.NotNil(fld)
  1331  	require.Equal("Int2", fld.Name())
  1332  }
  1333  
  1334  func Test_NestedTables(t *testing.T) {
  1335  	require := require.New(t)
  1336  
  1337  	fs, err := ParseFile("example.vsql", `APPLICATION test();
  1338  	TABLE NestedTable INHERITS CRecord (
  1339  		ItemName varchar,
  1340  		DeepNested TABLE DeepNestedTable (
  1341  			ItemName varchar
  1342  		)
  1343  	);
  1344  	`)
  1345  	require.NoError(err)
  1346  
  1347  	pkg, err := BuildPackageSchema("test", []*FileSchemaAST{fs})
  1348  	require.NoError(err)
  1349  
  1350  	packages, err := BuildAppSchema([]*PackageSchemaAST{
  1351  		getSysPackageAST(),
  1352  		pkg,
  1353  	})
  1354  	require.NoError(err)
  1355  
  1356  	appBld := appdef.New()
  1357  	err = BuildAppDefs(packages, appBld)
  1358  	require.NoError(err)
  1359  
  1360  	app, err := appBld.Build()
  1361  	require.NoError(err)
  1362  
  1363  	require.NotNil(app.CRecord(appdef.NewQName("test", "NestedTable")))
  1364  	require.NotNil(app.CRecord(appdef.NewQName("test", "DeepNestedTable")))
  1365  }
  1366  
  1367  func Test_SemanticAnalysisForReferences(t *testing.T) {
  1368  	t.Run("Should return error because CDoc references to ODoc", func(t *testing.T) {
  1369  		require := require.New(t)
  1370  
  1371  		fs, err := ParseFile("example.vsql", `APPLICATION test();
  1372  		TABLE OTable INHERITS ODoc ();
  1373  		TABLE CTable INHERITS CDoc (
  1374  			OTableRef ref(OTable)
  1375  		);
  1376  		`)
  1377  		require.NoError(err)
  1378  
  1379  		pkg, err := BuildPackageSchema("test", []*FileSchemaAST{fs})
  1380  		require.NoError(err)
  1381  
  1382  		packages, err := BuildAppSchema([]*PackageSchemaAST{
  1383  			getSysPackageAST(),
  1384  			pkg,
  1385  		})
  1386  		require.NoError(err)
  1387  
  1388  		appBld := appdef.New()
  1389  		err = BuildAppDefs(packages, appBld)
  1390  
  1391  		require.Contains(err.Error(), "table test.CTable can not reference to table test.OTable")
  1392  	})
  1393  }
  1394  
  1395  func Test_1KStringField(t *testing.T) {
  1396  	require := require.New(t)
  1397  
  1398  	fs, err := ParseFile("example.vsql", `APPLICATION test();
  1399  	TABLE MyTable INHERITS CDoc (
  1400  		KB varchar(1024)
  1401  	)
  1402  	`)
  1403  	require.NoError(err)
  1404  
  1405  	pkg, err := BuildPackageSchema("test", []*FileSchemaAST{fs})
  1406  	require.NoError(err)
  1407  
  1408  	packages, err := BuildAppSchema([]*PackageSchemaAST{
  1409  		getSysPackageAST(),
  1410  		pkg,
  1411  	})
  1412  	require.NoError(err)
  1413  
  1414  	appBld := appdef.New()
  1415  	err = BuildAppDefs(packages, appBld)
  1416  	require.NoError(err)
  1417  
  1418  	app, err := appBld.Build()
  1419  	require.NoError(err)
  1420  
  1421  	cdoc := app.CDoc(appdef.NewQName("test", "MyTable"))
  1422  	require.NotNil(cdoc)
  1423  
  1424  	fld := cdoc.Field("KB")
  1425  	require.NotNil(fld)
  1426  
  1427  	cnt := 0
  1428  	for _, c := range fld.Constraints() {
  1429  		cnt++
  1430  		require.Equal(appdef.ConstraintKind_MaxLen, c.Kind())
  1431  		require.EqualValues(1024, c.Value())
  1432  	}
  1433  	require.Equal(1, cnt)
  1434  }
  1435  
  1436  func Test_ReferenceToNoTable(t *testing.T) {
  1437  	require := require.New(t)
  1438  
  1439  	fs, err := ParseFile("example.vsql", `APPLICATION test();
  1440  	ROLE Admin;
  1441  	TABLE CTable INHERITS CDoc (
  1442  		RefField ref(Admin)
  1443  	);
  1444  	`)
  1445  	require.NoError(err)
  1446  
  1447  	pkg, err := BuildPackageSchema("test", []*FileSchemaAST{fs})
  1448  	require.NoError(err)
  1449  
  1450  	_, err = BuildAppSchema([]*PackageSchemaAST{
  1451  		getSysPackageAST(),
  1452  		pkg,
  1453  	})
  1454  	require.Contains(err.Error(), "undefined table: Admin")
  1455  
  1456  }
  1457  
  1458  func Test_VRestaurantBasic(t *testing.T) {
  1459  
  1460  	require := require.New(t)
  1461  
  1462  	vRestaurantPkgAST, err := ParsePackageDir("github.com/untillpro/vrestaurant", fsvRestaurant, "sql_example_app/vrestaurant")
  1463  	require.NoError(err)
  1464  
  1465  	packages, err := BuildAppSchema([]*PackageSchemaAST{
  1466  		getSysPackageAST(),
  1467  		vRestaurantPkgAST,
  1468  	})
  1469  	require.NoError(err)
  1470  
  1471  	builder := appdef.New()
  1472  	err = BuildAppDefs(packages, builder)
  1473  	require.NoError(err)
  1474  
  1475  	app, err := builder.Build()
  1476  	require.NoError(err)
  1477  
  1478  	// table
  1479  	cdoc := app.Type(appdef.NewQName("vrestaurant", "TablePlan"))
  1480  	require.NotNil(cdoc)
  1481  	require.Equal(appdef.TypeKind_CDoc, cdoc.Kind())
  1482  	require.Equal(appdef.DataKind_RecordID, cdoc.(appdef.IFields).Field("Picture").DataKind())
  1483  
  1484  	cdoc = app.Type(appdef.NewQName("vrestaurant", "Client"))
  1485  	require.NotNil(cdoc)
  1486  
  1487  	cdoc = app.Type(appdef.NewQName("vrestaurant", "POSUser"))
  1488  	require.NotNil(cdoc)
  1489  
  1490  	cdoc = app.Type(appdef.NewQName("vrestaurant", "Department"))
  1491  	require.NotNil(cdoc)
  1492  
  1493  	cdoc = app.Type(appdef.NewQName("vrestaurant", "Article"))
  1494  	require.NotNil(cdoc)
  1495  
  1496  	// child table
  1497  	crec := app.Type(appdef.NewQName("vrestaurant", "TableItem"))
  1498  	require.NotNil(crec)
  1499  	require.Equal(appdef.TypeKind_CRecord, crec.Kind())
  1500  	require.Equal(appdef.DataKind_int32, crec.(appdef.IFields).Field("Tableno").DataKind())
  1501  
  1502  	// view
  1503  	view := app.View(appdef.NewQName("vrestaurant", "SalesPerDay"))
  1504  	require.NotNil(view)
  1505  	require.Equal(appdef.TypeKind_ViewRecord, view.Kind())
  1506  }
  1507  
  1508  func Test_AppSchema(t *testing.T) {
  1509  	require := require.New(t)
  1510  
  1511  	fs, err := ParseFile("example1.vsql", `
  1512  	IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg2' AS air1;
  1513  	IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg3' AS air2;
  1514  	APPLICATION test(
  1515  		USE air1;
  1516  		USE air2;
  1517  	);
  1518  	TABLE MyTable INHERITS CDoc ();
  1519  	`)
  1520  	require.NoError(err)
  1521  	pkg1, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg1", []*FileSchemaAST{fs})
  1522  	require.NoError(err)
  1523  
  1524  	fs, err = ParseFile("example2.vsql", `
  1525  	TABLE MyTable INHERITS CDoc ();
  1526  	`)
  1527  	require.NoError(err)
  1528  	pkg2, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg2", []*FileSchemaAST{fs})
  1529  	require.NoError(err)
  1530  
  1531  	fs, err = ParseFile("example3.vsql", `
  1532  	IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg2' AS air1;
  1533  	WORKSPACE myWorkspace (
  1534  		USE TABLE air1.MyTable;
  1535  	);
  1536  	`)
  1537  	require.NoError(err)
  1538  	pkg3, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg3", []*FileSchemaAST{fs})
  1539  	require.NoError(err)
  1540  
  1541  	appSchema, err := BuildAppSchema([]*PackageSchemaAST{getSysPackageAST(), pkg1, pkg2, pkg3})
  1542  	require.NoError(err)
  1543  
  1544  	builder := appdef.New()
  1545  	err = BuildAppDefs(appSchema, builder)
  1546  	require.NoError(err)
  1547  
  1548  	app, err := builder.Build()
  1549  	require.NoError(err)
  1550  
  1551  	cdoc := app.CDoc(appdef.NewQName("pkg1", "MyTable"))
  1552  	require.NotNil(cdoc)
  1553  
  1554  	cdoc = app.CDoc(appdef.NewQName("air1", "MyTable"))
  1555  	require.NotNil(cdoc)
  1556  
  1557  	ws := app.Workspace(appdef.NewQName("air2", "myWorkspace"))
  1558  	require.NotNil(ws)
  1559  	require.NotNil(ws.Type(appdef.NewQName("air1", "MyTable")))
  1560  }
  1561  
  1562  func Test_AppSchemaErrors(t *testing.T) {
  1563  	require := require.New(t)
  1564  	fs, err := ParseFile("example2.vsql", ``)
  1565  	require.NoError(err)
  1566  	pkg2, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg2", []*FileSchemaAST{fs})
  1567  	require.NoError(err)
  1568  
  1569  	fs, err = ParseFile("example3.vsql", ``)
  1570  	require.NoError(err)
  1571  	pkg3, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg3", []*FileSchemaAST{fs})
  1572  	require.NoError(err)
  1573  
  1574  	f := func(sql string, expectErrors ...string) {
  1575  		ast, err := ParseFile("file2.vsql", sql)
  1576  		require.NoError(err)
  1577  		pkg, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg4", []*FileSchemaAST{ast})
  1578  		require.NoError(err)
  1579  
  1580  		_, err = BuildAppSchema([]*PackageSchemaAST{
  1581  			pkg, pkg2, pkg3,
  1582  		})
  1583  		require.EqualError(err, strings.Join(expectErrors, "\n"))
  1584  	}
  1585  
  1586  	f(`IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg3';
  1587  	APPLICATION test(
  1588  		USE air1;
  1589  		USE pkg3;
  1590  		)`, "file2.vsql:3:3: air1 undefined",
  1591  		"application does not define use of package github.com/untillpro/airsbp3/pkg2. Check if the package is defined in IMPORT SCHEMA and parsed under the same name")
  1592  
  1593  	f(`IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg2' AS air1;
  1594  		IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg3';
  1595  		APPLICATION test(
  1596  			USE air1;
  1597  			USE pkg3;
  1598  			USE pkg3;
  1599  		)`, "file2.vsql:6:4: package with the same name already included in application")
  1600  
  1601  	f(`IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg2' AS air1;
  1602  		IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg3';
  1603  		APPLICATION test(
  1604  			USE air1;
  1605  			USE pkg3;
  1606  		);
  1607  		APPLICATION test(
  1608  			USE air1;
  1609  			USE pkg3;
  1610  		)`, "file2.vsql:7:3: redefinition of application")
  1611  
  1612  	f(`IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg2' AS air1;
  1613  		IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg3';
  1614  		`, "application not defined")
  1615  
  1616  	f(`IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkgX' AS air1;
  1617  		IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg3';
  1618  		APPLICATION test(
  1619  			USE pkg3;
  1620  			USE air1;
  1621  		)
  1622  		`, "file2.vsql:5:4: could not import github.com/untillpro/airsbp3/pkgX. Check if the package is parsed under exactly this name")
  1623  }
  1624  
  1625  func Test_AppIn2Schemas(t *testing.T) {
  1626  	require := require.New(t)
  1627  	fs, err := ParseFile("example2.vsql", `APPLICATION test1();`)
  1628  	require.NoError(err)
  1629  	pkg2, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg2", []*FileSchemaAST{fs})
  1630  	require.NoError(err)
  1631  
  1632  	fs, err = ParseFile("example3.vsql", `APPLICATION test2();`)
  1633  	require.NoError(err)
  1634  	pkg3, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg3", []*FileSchemaAST{fs})
  1635  	require.NoError(err)
  1636  
  1637  	_, err = BuildAppSchema([]*PackageSchemaAST{
  1638  		pkg2, pkg3,
  1639  	})
  1640  	require.ErrorContains(err, "redefinition of application")
  1641  }
  1642  
  1643  func Test_Scope(t *testing.T) {
  1644  	require := require.New(t)
  1645  
  1646  	// *****  main
  1647  	fs, err := ParseFile("example1.vsql", `
  1648  	IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg1' AS p1;
  1649  	IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg2';
  1650  	APPLICATION test(
  1651  		USE pkg1;
  1652  		USE pkg2;
  1653  	);
  1654  	`)
  1655  	require.NoError(err)
  1656  	main, err := BuildPackageSchema("github.com/untillpro/airsbp3/main", []*FileSchemaAST{fs})
  1657  	require.NoError(err)
  1658  
  1659  	// *****  pkg1
  1660  	fs, err = ParseFile("example2.vsql", `
  1661  	WORKSPACE myWorkspace1 (
  1662  		TABLE MyTable INHERITS CDoc ();
  1663  	);
  1664  	`)
  1665  	require.NoError(err)
  1666  	pkg1, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg1", []*FileSchemaAST{fs})
  1667  	require.NoError(err)
  1668  
  1669  	// *****  pkg2
  1670  	fs, err = ParseFile("example3.vsql", `
  1671  	IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg1' AS p1;
  1672  	WORKSPACE myWorkspace2 (
  1673  		USE TABLE p1.MyTable;
  1674  	);
  1675  	`)
  1676  	require.NoError(err)
  1677  	pkg2, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg2", []*FileSchemaAST{fs})
  1678  	require.NoError(err)
  1679  
  1680  	_, err = BuildAppSchema([]*PackageSchemaAST{getSysPackageAST(), main, pkg1, pkg2})
  1681  	require.EqualError(err, "example3.vsql:4:16: undefined table: p1.MyTable")
  1682  
  1683  }
  1684  
  1685  func Test_Scope_TableRefs(t *testing.T) {
  1686  	require := require.New(t)
  1687  
  1688  	// *****  main
  1689  	fs, err := ParseFile("example1.vsql", `
  1690  	IMPORT SCHEMA 'github.com/untillpro/airsbp3/pkg1';
  1691  	APPLICATION test(
  1692  		USE pkg1;
  1693  	);
  1694  	`)
  1695  	require.NoError(err)
  1696  	main, err := BuildPackageSchema("github.com/untillpro/airsbp3/main", []*FileSchemaAST{fs})
  1697  	require.NoError(err)
  1698  
  1699  	// *****  pkg1
  1700  	fs, err = ParseFile("example2.vsql", `
  1701  	TABLE PkgTable INHERITS CRecord();
  1702  	WORKSPACE myWorkspace1 (
  1703  		TABLE MyTable INHERITS CDoc (
  1704  			Items TABLE MyInnerTable()
  1705  		);
  1706  		TABLE MyTable2 INHERITS CDoc (
  1707  			r1 ref(MyTable),
  1708  			r2 ref(MyTable2),
  1709  			r3 ref(PkgTable),
  1710  			r4 ref(MyInnerTable)
  1711  		);
  1712  	);
  1713  	WORKSPACE myWorkspace2 (
  1714  		TABLE MyTable3 INHERITS CDoc (
  1715  			r1 ref(MyTable),
  1716  			r2 ref(MyTable2),
  1717  			r3 ref(PkgTable),
  1718  			r4 ref(MyInnerTable)
  1719  		);
  1720  	);
  1721  	`)
  1722  	require.NoError(err)
  1723  	pkg1, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg1", []*FileSchemaAST{fs})
  1724  	require.NoError(err)
  1725  	_, err = BuildAppSchema([]*PackageSchemaAST{getSysPackageAST(), main, pkg1})
  1726  	require.EqualError(err, strings.Join([]string{
  1727  		"example2.vsql:10:11: table PkgTable not included into workspace",
  1728  		"example2.vsql:16:11: undefined table: MyTable",
  1729  		"example2.vsql:17:11: undefined table: MyTable2",
  1730  		"example2.vsql:18:11: table PkgTable not included into workspace",
  1731  		"example2.vsql:19:11: undefined table: MyInnerTable",
  1732  	}, "\n"))
  1733  
  1734  }
  1735  
  1736  func Test_Alter_Workspace_In_Package(t *testing.T) {
  1737  
  1738  	require := require.New(t)
  1739  
  1740  	fs0, err := ParseFile("file0.vsql", `
  1741  	IMPORT SCHEMA 'org/pkg1';
  1742  	IMPORT SCHEMA 'org/pkg2';
  1743  	APPLICATION test(
  1744  		USE pkg1;
  1745  	);
  1746  	`)
  1747  	require.NoError(err)
  1748  	pkg0, err := BuildPackageSchema("org/main", []*FileSchemaAST{fs0})
  1749  	require.NoError(err)
  1750  
  1751  	fs1, err := ParseFile("file1.vsql", `
  1752  		ALTERABLE WORKSPACE Ws0(
  1753  			TABLE wst01 INHERITS CDoc();
  1754  		);
  1755  		ABSTRACT WORKSPACE AWs(
  1756  			TABLE awst1 INHERITS CDoc();
  1757  		);
  1758  		WORKSPACE Ws(
  1759  			TABLE wst1 INHERITS CDoc();
  1760  		);
  1761  	`)
  1762  	require.NoError(err)
  1763  	fs2, err := ParseFile("file2.vsql", `
  1764  		ALTER WORKSPACE Ws0(
  1765  			TABLE wst02 INHERITS CDoc();
  1766  		);
  1767  		ALTER WORKSPACE AWs(
  1768  			TABLE awst2 INHERITS CDoc();
  1769  		);
  1770  		ALTER WORKSPACE Ws(
  1771  			TABLE wst2 INHERITS CDoc();
  1772  		);
  1773  	`)
  1774  	require.NoError(err)
  1775  	pkg1, err := BuildPackageSchema("org/pkg1", []*FileSchemaAST{fs1, fs2})
  1776  	require.NoError(err)
  1777  
  1778  	_, err = BuildAppSchema([]*PackageSchemaAST{
  1779  		getSysPackageAST(),
  1780  		pkg0,
  1781  		pkg1,
  1782  	})
  1783  	require.NoError(err)
  1784  }
  1785  
  1786  func Test_UseTableErrors(t *testing.T) {
  1787  	require := require.New(t)
  1788  
  1789  	fs, err := ParseFile("main.vsql", `
  1790  	IMPORT SCHEMA 'org/pkg1';
  1791  	APPLICATION test(
  1792  		USE pkg1;
  1793  	);
  1794  	WORKSPACE Ws(
  1795  		USE TABLE pkg1.Pkg1Table3;  -- bad, declared in workspace
  1796  		USE TABLE pkg2.*;  			-- bad, package not found
  1797  		USE WORKSPACE ws1;			-- bad, workspace not found
  1798  	)
  1799  	`)
  1800  	require.NoError(err)
  1801  	pkg, err := BuildPackageSchema("test/main", []*FileSchemaAST{fs})
  1802  	require.NoError(err)
  1803  
  1804  	// pkg1
  1805  	fs1, err := ParseFile("file1.vsql", `
  1806  	WORKSPACE Ws(
  1807  		TABLE Pkg1Table3 INHERITS CDoc();
  1808  	)
  1809  	`)
  1810  	require.NoError(err)
  1811  	pkg1, err := BuildPackageSchema("org/pkg1", []*FileSchemaAST{fs1})
  1812  	require.NoError(err)
  1813  
  1814  	_, err = BuildAppSchema([]*PackageSchemaAST{
  1815  		getSysPackageAST(),
  1816  		pkg,
  1817  		pkg1,
  1818  	})
  1819  
  1820  	require.EqualError(err, strings.Join([]string{
  1821  		"main.vsql:7:18: undefined table: pkg1.Pkg1Table3",
  1822  		"main.vsql:8:13: pkg2 undefined",
  1823  		"main.vsql:9:17: undefined workspace: main.ws1",
  1824  	}, "\n"))
  1825  }
  1826  
  1827  func Test_UseTables(t *testing.T) {
  1828  	require := require.New(t)
  1829  
  1830  	fs, err := ParseFile("main.vsql", `
  1831  	IMPORT SCHEMA 'org/pkg1';
  1832  	IMPORT SCHEMA 'org/pkg2';
  1833  	APPLICATION test(
  1834  		USE pkg1;
  1835  		USE pkg2;
  1836  	);
  1837  	TABLE TestTable1 INHERITS CDoc();
  1838  	TABLE TestTable2 INHERITS CDoc();
  1839  
  1840  	WORKSPACE Ws(
  1841  		USE TABLE *;				-- good, import all tables declared on current package level
  1842  		USE TABLE pkg1.*;			-- good, import all tables from specified package
  1843  		USE TABLE pkg2.Pkg2Table1;	-- good, import specified table
  1844  	)
  1845  	`)
  1846  	require.NoError(err)
  1847  	pkg, err := BuildPackageSchema("test/main", []*FileSchemaAST{fs})
  1848  	require.NoError(err)
  1849  
  1850  	// pkg1
  1851  	fs1, err := ParseFile("file1.vsql", `
  1852  	TABLE Pkg1Table1 INHERITS CDoc();
  1853  	TABLE Pkg1Table2 INHERITS CDoc();
  1854  
  1855  	WORKSPACE Ws(
  1856  		TABLE Pkg1Table3 INHERITS CDoc();
  1857  	)
  1858  	`)
  1859  	require.NoError(err)
  1860  	pkg1, err := BuildPackageSchema("org/pkg1", []*FileSchemaAST{fs1})
  1861  	require.NoError(err)
  1862  
  1863  	// pkg2
  1864  	fs2, err := ParseFile("file2.vsql", `
  1865  	TABLE Pkg2Table1 INHERITS CDoc();
  1866  	TABLE Pkg2Table2 INHERITS CDoc();
  1867  
  1868  	WORKSPACE Ws(
  1869  		TABLE Pkg2Table3 INHERITS CDoc();
  1870  	)
  1871  	`)
  1872  	require.NoError(err)
  1873  	pkg2, err := BuildPackageSchema("org/pkg2", []*FileSchemaAST{fs2})
  1874  	require.NoError(err)
  1875  
  1876  	schema, err := BuildAppSchema([]*PackageSchemaAST{
  1877  		getSysPackageAST(),
  1878  		pkg,
  1879  		pkg1,
  1880  		pkg2,
  1881  	})
  1882  
  1883  	require.NoError(err)
  1884  
  1885  	builder := appdef.New()
  1886  	err = BuildAppDefs(schema, builder)
  1887  	require.NoError(err)
  1888  
  1889  	app, err := builder.Build()
  1890  	require.NoError(err)
  1891  
  1892  	ws := app.Workspace(appdef.NewQName("main", "Ws"))
  1893  	require.NotNil(ws)
  1894  
  1895  	require.NotEqual(appdef.TypeKind_null, ws.Type(appdef.NewQName("main", "TestTable1")).Kind())
  1896  	require.NotEqual(appdef.TypeKind_null, ws.Type(appdef.NewQName("main", "TestTable2")).Kind())
  1897  	require.NotEqual(appdef.TypeKind_null, ws.Type(appdef.NewQName("pkg1", "Pkg1Table1")).Kind())
  1898  	require.NotEqual(appdef.TypeKind_null, ws.Type(appdef.NewQName("pkg1", "Pkg1Table2")).Kind())
  1899  	require.Equal(appdef.TypeKind_null, ws.Type(appdef.NewQName("pkg1", "Pkg1Table3")).Kind())
  1900  	require.NotEqual(appdef.TypeKind_null, ws.Type(appdef.NewQName("pkg2", "Pkg2Table1")).Kind())
  1901  	require.Equal(appdef.TypeKind_null, ws.Type(appdef.NewQName("pkg2", "Pkg2Table2")).Kind())
  1902  	require.Equal(appdef.TypeKind_null, ws.Type(appdef.NewQName("pkg2", "Pkg2Table3")).Kind())
  1903  
  1904  	_, err = builder.Build()
  1905  	require.NoError(err)
  1906  
  1907  }
  1908  
  1909  func Test_Storages(t *testing.T) {
  1910  	require := require.New(t)
  1911  	fs, err := ParseFile("example2.vsql", `APPLICATION test1();
  1912  	EXTENSION ENGINE BUILTIN (
  1913  		STORAGE MyStorage(
  1914  			INSERT SCOPE(PROJECTORS)
  1915  		);
  1916  	)
  1917  	`)
  1918  	require.NoError(err)
  1919  	pkg2, err := BuildPackageSchema("github.com/untillpro/airsbp3/pkg2", []*FileSchemaAST{fs})
  1920  	require.NoError(err)
  1921  
  1922  	schema, err := BuildAppSchema([]*PackageSchemaAST{
  1923  		pkg2,
  1924  	})
  1925  	require.ErrorContains(err, "storages are only declared in sys package")
  1926  	require.Nil(schema)
  1927  }
  1928  
  1929  func buildPackage(sql string) *PackageSchemaAST {
  1930  	fs, err := ParseFile("source.vsql", sql)
  1931  	if err != nil {
  1932  		panic(err)
  1933  	}
  1934  	pkg, err := BuildPackageSchema("github.com/voedger/voedger/app1", []*FileSchemaAST{fs})
  1935  	if err != nil {
  1936  		panic(err)
  1937  	}
  1938  	return pkg
  1939  }
  1940  
  1941  func Test_OdocCmdArgs(t *testing.T) {
  1942  	require := require.New(t)
  1943  	pkgApp1 := buildPackage(`
  1944  
  1945  	APPLICATION registry(
  1946  	);
  1947  
  1948  	TABLE TableODoc INHERITS ODoc (
  1949  		orecord1 TABLE orecord1(
  1950  			orecord2 TABLE orecord2()
  1951  		)
  1952  	);
  1953  
  1954  	WORKSPACE Workspace1 (
  1955  		EXTENSION ENGINE BUILTIN (
  1956  			COMMAND CmdODoc1(TableODoc) RETURNS TableODoc;
  1957  		)
  1958  	);
  1959  
  1960  	`)
  1961  
  1962  	schema, err := BuildAppSchema([]*PackageSchemaAST{pkgApp1, getSysPackageAST()})
  1963  	require.NoError(err)
  1964  
  1965  	builder := appdef.New()
  1966  	err = BuildAppDefs(schema, builder)
  1967  	require.NoError(err)
  1968  
  1969  	app, err := builder.Build()
  1970  	require.NoError(err)
  1971  
  1972  	cmdOdoc := app.Command(appdef.NewQName("app1", "CmdODoc1"))
  1973  	require.NotNil(cmdOdoc)
  1974  	require.NotNil(cmdOdoc.Param())
  1975  
  1976  	odoc := cmdOdoc.Param().(appdef.IContainers)
  1977  	require.Equal(1, odoc.ContainerCount())
  1978  	require.Equal("orecord1", odoc.Container("orecord1").Name())
  1979  	container := odoc.Container("orecord1")
  1980  	require.Equal(appdef.Occurs(0), container.MinOccurs())
  1981  	require.Equal(appdef.Occurs(100), container.MaxOccurs())
  1982  
  1983  	orec := app.ORecord(appdef.NewQName("app1", "orecord1"))
  1984  	require.NotNil(orec)
  1985  	require.Equal(1, orec.ContainerCount())
  1986  	require.Equal("orecord2", orec.Container("orecord2").Name())
  1987  
  1988  }
  1989  
  1990  func Test_TypeContainers(t *testing.T) {
  1991  	require := require.New(t)
  1992  	pkgApp1 := buildPackage(`
  1993  
  1994  APPLICATION registry(
  1995  );
  1996  
  1997  TYPE Person (
  1998  	Name 	varchar,
  1999  	Age 	int32
  2000  );
  2001  
  2002  TYPE Item (
  2003  	Name 	varchar,
  2004  	Price 	currency
  2005  );
  2006  
  2007  TYPE Deal (
  2008  	side1 		Person NOT NULL,	-- collection 1..1
  2009  	side2 		Person				-- collection 0..1
  2010  --	items 		Item[] NOT NULL,	-- (not yet supported by kernel) collection 1..* (up to maxNestedTableContainerOccurrences = 100)
  2011  --	discounts 	Item[3]				-- (not yet supported by kernel) collection 0..3 (one-based numbering convention for arrays, similarly to PostgreSQL)
  2012  );
  2013  
  2014  WORKSPACE Workspace1 (
  2015  	EXTENSION ENGINE BUILTIN (
  2016  		COMMAND CmdDeal(Deal) RETURNS Deal;
  2017  	)
  2018  );
  2019  	`)
  2020  
  2021  	schema, err := BuildAppSchema([]*PackageSchemaAST{pkgApp1, getSysPackageAST()})
  2022  	require.NoError(err)
  2023  
  2024  	builder := appdef.New()
  2025  	err = BuildAppDefs(schema, builder)
  2026  	require.NoError(err)
  2027  
  2028  	validate := func(par appdef.IType) {
  2029  		o, ok := par.(appdef.IObject)
  2030  		require.True(ok, "expected %v supports IObject", par)
  2031  		require.Equal(2, o.ContainerCount())
  2032  		require.Equal(appdef.Occurs(1), o.Container("side1").MinOccurs())
  2033  		require.Equal(appdef.Occurs(1), o.Container("side1").MaxOccurs())
  2034  		require.Equal(appdef.Occurs(0), o.Container("side2").MinOccurs())
  2035  		require.Equal(appdef.Occurs(1), o.Container("side2").MaxOccurs())
  2036  
  2037  		/* TODO: uncomment when kernel supports it
  2038  		require.Equal(appdef.Occurs(1), o.Container("items").MinOccurs())
  2039  		require.Equal(appdef.Occurs(100), o.Container("items").MaxOccurs())
  2040  		require.Equal(appdef.Occurs(0), o.Container("discounts").MinOccurs())
  2041  		require.Equal(appdef.Occurs(3), o.Container("discounts").MaxOccurs())
  2042  		*/
  2043  	}
  2044  
  2045  	app, err := builder.Build()
  2046  	require.NoError(err)
  2047  
  2048  	cmd := app.Command(appdef.NewQName("app1", "CmdDeal"))
  2049  	validate(cmd.Param())
  2050  	validate(cmd.Result())
  2051  }
  2052  
  2053  func Test_EmptyType(t *testing.T) {
  2054  	require := require.New(t)
  2055  	pkgApp1 := buildPackage(`
  2056  
  2057  APPLICATION registry(
  2058  );
  2059  
  2060  TYPE EmptyType (
  2061  );
  2062  	`)
  2063  
  2064  	schema, err := BuildAppSchema([]*PackageSchemaAST{pkgApp1, getSysPackageAST()})
  2065  	require.NoError(err)
  2066  
  2067  	builder := appdef.New()
  2068  	err = BuildAppDefs(schema, builder)
  2069  	require.NoError(err)
  2070  
  2071  	app, err := builder.Build()
  2072  	require.NoError(err)
  2073  
  2074  	cdoc := app.Object(appdef.NewQName("app1", "EmptyType"))
  2075  	require.NotNil(cdoc)
  2076  }
  2077  
  2078  func Test_EmptyType1(t *testing.T) {
  2079  	require := require.New(t)
  2080  	pkgApp1 := buildPackage(`
  2081  
  2082  APPLICATION registry(
  2083  );
  2084  
  2085  TYPE SomeType (
  2086  	t int321
  2087  );
  2088  
  2089  TABLE SomeTable INHERITS CDoc (
  2090  	t int321
  2091  )
  2092  	`)
  2093  
  2094  	_, err := BuildAppSchema([]*PackageSchemaAST{pkgApp1, getSysPackageAST()})
  2095  	require.EqualError(err, strings.Join([]string{
  2096  		"source.vsql:7:4: undefined type: int321",
  2097  		"source.vsql:11:4: undefined data type or table: int321",
  2098  	}, "\n"))
  2099  
  2100  }
  2101  
  2102  func Test_ODocUnknown(t *testing.T) {
  2103  	require := require.New(t)
  2104  	pkgApp1 := buildPackage(`APPLICATION registry();
  2105  TABLE MyTable1 INHERITS ODocUnknown ( MyField ref(registry.Login) NOT NULL );
  2106  `)
  2107  
  2108  	_, err := BuildAppSchema([]*PackageSchemaAST{pkgApp1, getSysPackageAST()})
  2109  	require.EqualError(err, strings.Join([]string{
  2110  		"source.vsql:2:1: undefined table kind",
  2111  		"source.vsql:2:25: undefined table: ODocUnknown",
  2112  		"source.vsql:2:51: registry undefined",
  2113  	}, "\n"))
  2114  
  2115  }
  2116  
  2117  //go:embed package.vsql
  2118  var pkgSqlFS embed.FS
  2119  
  2120  func TestParseFilesFromFSRoot(t *testing.T) {
  2121  	t.Run("dot", func(t *testing.T) {
  2122  		_, err := ParsePackageDir("github.com/untillpro/main", pkgSqlFS, ".")
  2123  		require.NoError(t, err)
  2124  	})
  2125  }
  2126  
  2127  func Test_Constraints(t *testing.T) {
  2128  	require := assertions(t)
  2129  
  2130  	require.AppSchemaError(`
  2131  	APPLICATION app1();
  2132  	TABLE SomeTable INHERITS CDoc (
  2133  		t1 int32,
  2134  		t2 int32,
  2135  		CONSTRAINT c1 UNIQUE(t1),
  2136  		CONSTRAINT c1 UNIQUE(t2)
  2137  	)`, "file.vsql:7:3: redefinition of c1")
  2138  
  2139  	require.AppSchemaError(`
  2140  	APPLICATION app1();
  2141  	TABLE SomeTable INHERITS CDoc (
  2142  		UNIQUEFIELD UnknownField
  2143  	)`, "file.vsql:4:3: undefined field UnknownField")
  2144  
  2145  	require.AppSchemaError(`
  2146  	APPLICATION app1();
  2147  	TABLE SomeTable INHERITS CDoc (
  2148  		t1 int32,
  2149  		t2 int32,
  2150  		CONSTRAINT c1 UNIQUE(t1),
  2151  		CONSTRAINT c2 UNIQUE(t2, t1)
  2152  	)`, "file.vsql:7:3: field t1 already in unique constraint")
  2153  
  2154  }
  2155  
  2156  func Test_Grants(t *testing.T) {
  2157  	require := assertions(t)
  2158  
  2159  	require.AppSchemaError(`
  2160  	APPLICATION app1();
  2161  	ROLE role1;
  2162  	WORKSPACE ws1 (
  2163  		GRANT ALL ON TABLE Fake TO app1;
  2164  		GRANT INSERT ON COMMAND Fake TO role1;
  2165  		GRANT SELECT ON QUERY Fake TO role1;
  2166  		GRANT INSERT ON WORKSPACE Fake TO role1;
  2167  		TABLE Tbl INHERITS CDoc();
  2168  		GRANT ALL(FakeCol) ON TABLE Tbl TO role1;
  2169  		GRANT INSERT,UPDATE(FakeCol) ON TABLE Tbl TO role1;
  2170  		GRANT INSERT ON ALL COMMANDS WITH TAG x TO role1;
  2171  		TABLE Nested1 INHERITS CRecord();
  2172  		TABLE Tbl2 INHERITS CDoc(
  2173  			ref1 ref(Tbl),
  2174  			items TABLE Nested(),
  2175  			items2 Nested1
  2176  		);
  2177  		GRANT ALL(ref1) ON TABLE Tbl2 TO role1;
  2178  		GRANT ALL(items) ON TABLE Tbl2 TO role1;
  2179  		GRANT ALL(items2) ON TABLE Tbl2 TO role1;
  2180  	);
  2181  	`, "file.vsql:5:30: undefined role: app1",
  2182  		"file.vsql:5:22: undefined table: Fake",
  2183  		"file.vsql:6:27: undefined command: Fake",
  2184  		"file.vsql:7:25: undefined query: Fake",
  2185  		"file.vsql:8:29: undefined workspace: Fake",
  2186  		"file.vsql:10:13: undefined field FakeCol",
  2187  		"file.vsql:11:23: undefined field FakeCol",
  2188  		"file.vsql:12:41: undefined tag: x",
  2189  	)
  2190  }
  2191  
  2192  func Test_UndefinedType(t *testing.T) {
  2193  	require := assertions(t)
  2194  
  2195  	require.AppSchemaError(`APPLICATION app1();
  2196  TABLE MyTable2 INHERITS ODoc (
  2197  MyField int23 NOT NULL
  2198  );
  2199  	`, "file.vsql:3:9: undefined data type or table: int23",
  2200  	)
  2201  }
  2202  
  2203  func Test_DescriptorInProjector(t *testing.T) {
  2204  	require := assertions(t)
  2205  
  2206  	require.AppSchemaError(`APPLICATION app1();
  2207  	WORKSPACE w (
  2208  		EXTENSION ENGINE BUILTIN (
  2209  		  PROJECTOR x AFTER INSERT ON (unknown.z) STATE(Http);
  2210  		);
  2211  	  );
  2212  	`,
  2213  		"file.vsql:4:34: unknown undefined")
  2214  
  2215  	require.NoAppSchemaError(`APPLICATION app1();
  2216  	WORKSPACE RestaurantWS (
  2217  		DESCRIPTOR Restaurant ();
  2218  		EXTENSION ENGINE BUILTIN (
  2219  		  PROJECTOR NewRestaurantVat AFTER INSERT OR UPDATE ON (Restaurant) STATE(AppSecret, Http) INTENTS(SendMail);
  2220  		);
  2221  	  );
  2222  	`)
  2223  }
  2224  
  2225  type testVarResolver struct {
  2226  	resolved map[appdef.QName]bool
  2227  }
  2228  
  2229  func (t testVarResolver) AsInt32(name appdef.QName) (int32, bool) {
  2230  	t.resolved[name] = true
  2231  	return 1, true
  2232  }
  2233  
  2234  func Test_Variables(t *testing.T) {
  2235  	require := assertions(t)
  2236  
  2237  	require.AppSchemaError(`APPLICATION app1(); RATE AppDefaultRate variable PER HOUR;`, "file.vsql:1:41: variable undefined")
  2238  
  2239  	schema, err := require.AppSchema(`APPLICATION app1();
  2240  	DECLARE variable int32 DEFAULT 100;
  2241  	RATE AppDefaultRate variable PER HOUR;
  2242  	`)
  2243  	require.NoError(err)
  2244  
  2245  	resolver := testVarResolver{resolved: make(map[appdef.QName]bool)}
  2246  
  2247  	BuildAppDefs(schema, appdef.New(), WithVariableResolver(&resolver))
  2248  	require.True(resolver.resolved[appdef.NewQName("pkg", "variable")])
  2249  }
  2250  
  2251  func Test_RatesAndLimits(t *testing.T) {
  2252  	require := assertions(t)
  2253  
  2254  	require.AppSchemaError(`APPLICATION app1();
  2255  	WORKSPACE w (
  2256  		RATE r 1 PER HOUR;
  2257  		LIMIT l1 ON EVERYTHING WITH RATE x;
  2258  		LIMIT l2 ON COMMAND x WITH RATE r;
  2259  		LIMIT l3 ON QUERY y WITH RATE r;
  2260  		LIMIT l4 ON TAG z WITH RATE r;
  2261  		LIMIT l5 ON TABLE t WITH RATE r;
  2262  	);`,
  2263  		"file.vsql:4:36: undefined rate: x",
  2264  		"file.vsql:5:23: undefined command: x",
  2265  		"file.vsql:6:21: undefined query: y",
  2266  		"file.vsql:7:19: undefined tag: z",
  2267  		"file.vsql:8:21: undefined table: t")
  2268  }
  2269  
  2270  func Test_RefsFromInheritedWs(t *testing.T) {
  2271  	require := assertions(t)
  2272  
  2273  	require.NoAppSchemaError(`APPLICATION test();
  2274  	ABSTRACT WORKSPACE base (
  2275  		TABLE tab1 INHERITS WDoc (
  2276  			Fld1 int32
  2277  		);
  2278  	);
  2279  	WORKSPACE work INHERITS base (
  2280  		TABLE tab2 INHERITS WDoc (
  2281  			Fld2 ref(tab1)
  2282  		);
  2283  	);`)
  2284  }
  2285  
  2286  //go:embed test/pkg1.vsql
  2287  var pkg1FS embed.FS
  2288  
  2289  func Test_Panic1(t *testing.T) {
  2290  	ast, errs := ParsePackageDir(appdef.SysPackage, pkg1FS, "test")
  2291  	require.ErrorContains(t, errs, "no valid schema files")
  2292  	require.Nil(t, ast)
  2293  }
  2294  
  2295  func Test_Identifiers(t *testing.T) {
  2296  	require := assertions(t)
  2297  
  2298  	_, err := ParseFile("file1.vsql", `APPLICATION app1();
  2299  	WORKSPACE w (
  2300  		ROLE _role;
  2301  	);`)
  2302  	require.ErrorContains(err, "file1.vsql:3:8: invalid input text")
  2303  
  2304  	_, err = ParseFile("file1.vsql", `APPLICATION app1();
  2305  	WORKSPACE w (
  2306  		ROLE r234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890r23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456;
  2307  	);`)
  2308  	require.ErrorContains(err, "file1.vsql:3:263: unexpected token")
  2309  
  2310  	_, err = ParseFile("file1.vsql", `APPLICATION app1();
  2311  	WORKSPACE w (
  2312  		ROLE r世界;
  2313  	);`)
  2314  	require.ErrorContains(err, "file1.vsql:3:9: invalid input text")
  2315  }
  2316  
  2317  func Test_RefsWorkspaces(t *testing.T) {
  2318  	require := assertions(t)
  2319  
  2320  	require.AppSchemaError(`APPLICATION test();
  2321  	TABLE t1 INHERITS WDoc();
  2322  	WORKSPACE w2 (
  2323  		TABLE tab2 INHERITS WDoc(
  2324  			f ref(t1) -- error, t1 is not in the workspace
  2325  		);
  2326  		TYPE typ2(
  2327  			f ref(t1) -- error, t1 is not in the workspace
  2328  		);
  2329  		VIEW test(
  2330  			f ref(t1), -- error, t1 is not in the workspace
  2331  			PRIMARY KEY(f)
  2332  		) AS RESULT OF Proj1;
  2333  
  2334  		EXTENSION ENGINE BUILTIN (
  2335  			PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
  2336  			COMMAND Orders()
  2337  		);
  2338  
  2339  	);`,
  2340  		"file.vsql:5:10: table t1 not included into workspace",
  2341  		"file.vsql:8:10: table t1 not included into workspace",
  2342  		"file.vsql:11:10: table t1 not included into workspace")
  2343  
  2344  	require.NoAppSchemaError(`APPLICATION test();
  2345  	WORKSPACE w2 (
  2346  		TABLE t1 INHERITS WDoc(
  2347  			items TABLE t2(
  2348  				items TABLE t3()
  2349  			)
  2350  		);
  2351  		TABLE tab2 INHERITS WDoc(
  2352  			f1 ref(t2),
  2353  			f2 ref(t3)
  2354  		);
  2355  		TYPE typ2(
  2356  			f1 ref(t2),
  2357  			f2 ref(t3)
  2358  		);
  2359  		VIEW test(
  2360  			f1 ref(t2),
  2361  			f2 ref(t3),
  2362  			PRIMARY KEY(f1)
  2363  		) AS RESULT OF Proj1;
  2364  
  2365  		EXTENSION ENGINE BUILTIN (
  2366  			PROJECTOR Proj1 AFTER EXECUTE ON (Orders) INTENTS (View(test));
  2367  			COMMAND Orders()
  2368  		);
  2369  
  2370  	);`)
  2371  }
  2372  
  2373  func Test_ScheduledProjectors(t *testing.T) {
  2374  
  2375  	t.Run("bad workspace", func(t *testing.T) {
  2376  		require := assertions(t)
  2377  		require.AppSchemaError(`APPLICATION test();
  2378  			WORKSPACE w2 (
  2379  				EXTENSION ENGINE BUILTIN (
  2380  					PROJECTOR Proj1 CRON '1 0 * * *';
  2381  				);
  2382  			);`, "file.vsql:4:6: scheduled projector must be in app workspace")
  2383  	})
  2384  
  2385  	t.Run("bad cron and intents", func(t *testing.T) {
  2386  		require := assertions(t)
  2387  		require.AppSchemaError(`APPLICATION test();
  2388  			ALTER WORKSPACE AppWorkspaceWS (
  2389  				VIEW test(
  2390  					i int32,
  2391  					PRIMARY KEY(i)
  2392  				) AS RESULT OF Proj1;
  2393  
  2394  				EXTENSION ENGINE BUILTIN (
  2395  					PROJECTOR Proj1 CRON 'blah' INTENTS (View(test));
  2396  				);
  2397  			);`, "file.vsql:9:6: invalid cron schedule: blah", "file.vsql:9:6: scheduled projector cannot have intents")
  2398  	})
  2399  
  2400  	t.Run("good cron", func(t *testing.T) {
  2401  		require := assertions(t)
  2402  		require.NoAppSchemaError(`APPLICATION test();
  2403  ALTER WORKSPACE sys.AppWorkspaceWS (
  2404  	EXTENSION ENGINE BUILTIN (
  2405  		PROJECTOR ScheduledProjector CRON '1 0 * * *';
  2406  	);
  2407  );`)
  2408  	})
  2409  }
  2410  
  2411  func Test_DataTypes(t *testing.T) {
  2412  
  2413  	require := assertions(t)
  2414  	require.NoAppSchemaError(`APPLICATION test();
  2415  ALTER WORKSPACE sys.AppWorkspaceWS (
  2416  	TABLE t1 INHERITS WDoc(
  2417  		s1_1_1 character varying(10),
  2418  		s1_1_1 character varying,
  2419  		s1_2_1 varchar(10),
  2420  		s1_2_2 varchar,
  2421  		s1_3_1 text(10),
  2422  		s1_3_1 text,
  2423  
  2424  		s2_1_1 binary varying(10),
  2425  		s2_1_1 binary varying,
  2426  		s2_2_1 varbinary(10),
  2427  		s2_2_2 varbinary,
  2428  		s2_3_1 bytes(10),
  2429  		s2_3_1 bytes,
  2430  
  2431  		s3_1 bigint,
  2432  		s3_2 int64,
  2433  
  2434  		s4_1 integer,
  2435  		s4_2 int32,
  2436  		s4_3 int,
  2437  
  2438  		s5_1 real,
  2439  		s5_2 float,
  2440  		s5_3 float32,
  2441  
  2442  		s6_1 double precision,
  2443  		s6_2 float64,
  2444  
  2445  		s7_2 money,
  2446  		s7_3 currency,
  2447  
  2448  		s8_1 boolean,
  2449  		s8_2 bool,
  2450  
  2451  		s9_1 binary large object,
  2452  		s9_2 blob,
  2453  
  2454  		s10_1 qualified name,
  2455  		s10_2 qname,
  2456  
  2457  		s11_1 record
  2458  
  2459  	);
  2460  );`)
  2461  }
  2462  
  2463  func Test_UniquesFromFieldsets(t *testing.T) {
  2464  	require := assertions(t)
  2465  	schema, err := require.AppSchema(`APPLICATION test();
  2466  	TYPE fieldset (
  2467  		f1 int32
  2468  	);
  2469  	TABLE t1 INHERITS WDoc(
  2470  		fieldset,
  2471  		f2 int32,
  2472  		UNIQUE(f1)
  2473  	);
  2474  `)
  2475  	require.NoError(err)
  2476  	require.NoError(BuildAppDefs(schema, appdef.New()))
  2477  }
  2478  
  2479  func Test_CRecordInDescriptor(t *testing.T) {
  2480  	require := assertions(t)
  2481  	schema, err := require.AppSchema(`APPLICATION test();
  2482  	WORKSPACE w (
  2483  		DESCRIPTOR wd(
  2484  			items x
  2485  		);
  2486  		TABLE x INHERITS CRecord(
  2487  			f1 int32
  2488  		);
  2489  	);
  2490  `)
  2491  	require.NoError(err)
  2492  	require.NoError(BuildAppDefs(schema, appdef.New()))
  2493  }