Home » Modeling » TMF (Xtext) » How to get content assist to work with table names from a database(Content Assist with Table Names)
| | | | | |
Re: How to get content assist to work with table names from a database [message #551308 is a reply to message #551085] |
Thu, 05 August 2010 21:08 |
Pam Messages: 12 Registered: July 2010 |
Junior Member |
|
|
The language I am trying to achieve is a rework of SQL
namespace PubArticle{
/* Gets the Articles and Videos for the Homepage for a specific website and LandingPageSection with Related Vehicle*/
Query PubArticle.Top.HomePageArticlesVideos.bySection{
[Description: Brings back available articles, images, and Videos for Homepage Sections]
[Filter: PubArticleLandingPageWebSiteId*, PubArticleLandingPageSectionName*]
[Return: PubArticleArticle.PubArticleDatePrintCover,
PubArticleArticle.PubArticleId,
PubArticleArticle.PubArticlePromoTeaser,
PubArticleArticle.PubArticlePromoTeaserLarge,
PubArticleArticle.PubArticlePromoTitle,
PubArticleArticle.PubArticleSlug,
PubArticleArticle.PubArticleSubtitle,
PubArticleArticle.PubArticleUrl,
VehicleStrongHoldVehicle.VehicleMake As VideoVehicleMake,
VehicleStrongHoldVehicle.VehicleModel As VideoVehicleModel,
VehicleStrongHoldVehicle.VehicleYear As VideoVehicleYear,
Video.VideoDescription,
Video.VideoId,
Video.VideoThumbnailUrl,
Video.VideoTitle,
LandingPageSectionVideoArticle.PubArticleLandingPageSectionArticleOrder,
VehicleMake.VehicleMake,
VehicleModel.VehicleModel,
PubArticleVehicleCache.VehicleYear,
PubArticleImageTypeSpecific.PromoSmallFileMasterId,
PubArticleImageTypeSpecific.PromoLargeFileMasterId,
PubArticleImageTypeSpecific.HomepageFileMasterId,
PubArticleImageTypeSpecific.HeaderFileMasterId
]
[From: LandingPageSectionVideoArticle
Inner Join PubArticleLandingPageSection On LandingPageSectionVideoArticle.PubArticleLandingPageSectionId=PubArticleLandingPageSection.PubArticleLandingPageSectionId
Inner Join PubArticleLandingPage On PubArticleLandingPageSection.PubArticleLandingPageId=PubArticleLandingPage.PubArticleLandingPageId
Left Join PubArticleArticle On LandingPageSectionVideoArticle.PubArticleId=PubArticleArticle.PubArticleId
Left Join Video On Video.VideoId=LandingPageSectionVideoArticle.VideoId
Left Join PubArticleImageTypeSpecific On PubArticleArticle.PubArticleId=PubArticleImageTypeSpecific.PubArticleId
Optional Left Join VideoVehicle On Video.VideoId=VideoVehicle.VideoId
Optional Left Join VehicleStrongHoldVehicle On VideoVehicle.PubArticleVehicleId=VehicleStrongHoldVehicle.PubArticleVehicleId
Optional Left Join PubArticleVehicleCache On PubArticleArticle.PubArticleId=PubArticleVehicleCache.PubArticleId
Optional Left Join VehicleMake On PubArticleVehicleCache.VehicleMakeCache=VehicleMake.VehicleMake
Optional Left Join VehicleModel On PubArticleVehicleCache.VehicleModelCache=VehicleModel.VehicleModel
]
[Where: PubArticleLandingPage.PubArticleLandingPageName='Homepage']
[Order: PubArticleLandingPageSectionArticleOrder]
}
/*For Gets Articles for a specific Category not on the homepage with images of specific sizes header', 'homepage', 'promo_large', 'promo_small given */
Query PubArticle.Top.ArticlesImages.byCategory{
[Description: Gets Articles for A Specific Category not already on the Homepage]
[Filter: SiteId*, PubArticleSiteCategoryCategory*]
[Return: PubArticleArticle.PubArticleUrl,
PubArticleArticle.PubArticleDatePrintCover,
PubArticleArticle.PubArticleId,
PubArticleArticle.PubArticlePromoTeaser,
PubArticleArticle.PubArticlePromoTeaserLarge,
PubArticleArticle.PubArticlePromoTitle,
PubArticleArticle.PubArticleSlug,
PubArticleArticle.PubArticleSubtitle,
PubArticleImageTypeSpecific.PromoSmallFileMasterId,
PubArticleImageTypeSpecific.PromoLargeFileMasterId,
PubArticleImageTypeSpecific.HomepageFileMasterId,
PubArticleImageTypeSpecific.HeaderFileMasterId
]
[From: PubArticleArticle
Inner Join PubArticleSiteCategoryCache On PubArticleArticle.PubArticleId=PubArticleSiteCategoryCache.PubArticleId
Left Join PubArticleImageTypeSpecific On PubArticleArticle.PubArticleId=PubArticleImageTypeSpecific.PubArticleId
Left Join LandingPageSectionVideoArticle On PubArticleArticle.PubArticleId=LandingPageSectionVideoArticle.PubArticleId
and PubArticleLandingPageName='Homepage'
]
[Where: LandingPageSectionVideoArticle.PubArticleId is null]
[Order: PubArticleDatePrintCover desc, PubArticlePromoTitle]
}
}
The grammar is not yet complete because of the multiple options that one can have for each section. This is what I have so far but it still needs to be refined quite a bit
grammar org.xtext.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "http://www.xtext.org/MyDsl"
Model:
(namespace+=NameSpace)*;
NameSpace:
'Namespace' name=ID "{"
(query+=Query)*
"}";
Query:
'Query' name=[NameSpace]("." ID)* "{"
("[" 'Description:' description=MYSTRING"]")
("[" 'Query:'queryName=QueryName"]")?
("[" 'Filter:' filter+=ColumnName'*'? (',' filter+=ColumnName'*'?)*"]")?
("[" 'Return:' return+=QualifiedTableReference 'As'? ID? (',' return+=QualifiedTableReference 'As'? ID?)* "]")?
("[" 'From:'(from+=TableName)
((innerjoinexpression+=InnerJoinExpression?)*)
((outerjoinexpression+=OuterJoinExpression?)*)
"]")?
("["(where=Where)?"]")?
//("[" 'Order:' order+=ColumnName " "|"desc"|"asc"(',' order+=ColumnName)" "|"desc"|"asc"*"]")?
"}";
Where:
'Where:' QualifiedTableReference(expression=WhereExpression);
QueryName:
Queryname=[NameSpace]("." ID);
InnerJoinExpression:
('Optional')? 'Inner Join' name=TableJoinName
"On" QualifiedTableReference"="QualifiedTableReference*
(("And" QualifiedTableReference"="QualifiedTableReference)?);
OuterJoinExpression:
('Optional')? 'Left Join' name=TableNameExtended
"On" QualifiedTableReference"="QualifiedTableReference*
(("And" QualifiedTableReference"="QualifiedTableReference)?)
(("And" QualifiedTableReference"="STRING)?);
WhereExpression:
("=" STRING|INT)| "is null"| "is not null"|">" INT|"<" INT|">="INT;
MYSTRING:
ID(" "ID)*;
ColumnName:
name=ID;
TableJoinName:
name=ID;
TableName:
name=ID;
TableNameExtended:
name=ID;
QualifiedTableReference:
ID'.'ID;
|
|
| |
Re: How to get content assist to work with table names from a database [message #551395 is a reply to message #551308] |
Fri, 06 August 2010 09:21 |
Alexander Nittka Messages: 1193 Registered: July 2009 |
Senior Member |
|
|
Hi,
the following is a first grammar suggestion for using cross references
on tables and columns (excuse if you have to adapt comments I made
within the grammar because of automatic formatting issues). This gives
you immediate code completion and validation for references. However,
you will have to adapt the scoping, e.g. in order to restrict visibility
of columns in a join to those from the involved tables and return
columns to thos reachable from the From statement.
You basically provide a separate file containing the tables with their
columns (I will provide an example).
Please do not expect *me* to provide much more help, e.g. on the scoping
(estimate the time I spent so far on your problems to be about one
working day and figure the fee you would have had to pay for a day of
professional consulting). There are several threads within this forum
dealing with scoping.
Here is the Grammar.
//we do not only allow queries, but also
//table definitions, so that we can easily refer to columns
Model: TableDefinitions|NameSpaces;
//make tables and columns available, it should be trivial to
//automatically produce this format
TableDefinitions:{TableDefinition}'tabledefinitions' tables+=Table*;
Table: name=ID'{'columns+=Column*'}';
Column: name=ID;
//the actual queries
NameSpaces:{NameSpaces}
(namespace+=NameSpace)*;
NameSpace:
'Namespace' name=ID "{"
(query+=Query)*
"}";
Query:
//question: is the order of the elements fixed (desc, query, ...)
//or can the order vary (in which case unordered groups could be used
//separate the namespace from the name of the query because
//when calculating the fully qualified name of Query, the
//container (NameSpace) is automatically added
'Query' namespace=[NameSpace] ("." name=QualifiedName) "{"
//a description is mandatory?
("[" 'Description:' description=MYSTRING"]")
//is this a reference to a different query or this query
//then use ("[" 'Query:'queryName=[Query|QualifiedName]"]")?
//or simply a name different than the one that would be calculated
//from the name definition above
("[" 'Query:'queryName=QueryName"]")?
("[" 'Filter:' filter+=Filter (',' filter+=Filter)*"]")?
//no return fragments yet
("[" 'Return:' return+=ReturnElement (',' return+=ReturnElement)* "]")?
("[" 'From:' from=[Table]
(innerjoinexpression+=InnerJoinExpression)*
(outerjoinexpression+=OuterJoinExpression)*
"]")?
("[" 'Where:' where=Where"]")?
//("[" 'Order:' order+=ColumnName " "|"desc"|"asc"(','
order+=ColumnName)" "|"desc"|"asc"*"]")?
"}";
//I would like to use cross references for the filter, but there would
be some
//work involved referring to them without specifying the table name as well
Filter: column=ID (multi?='*')?;
ReturnElement: ref=[Column|QualifiedTableReference] ('As' asname=ID)?;
Where: column=[Column|QualifiedTableReference] (expression=WhereExpression);
QueryName:
Queryname=[NameSpace]("." ID);
//metamodel inference, so that common parts of inner and outer join
//can be treated easier
JoinExpression: InnerJoinExpression|OuterJoinExpression;
//sorry for my shallow SQL knowledge, but your examples contain little hints
//on the full join syntax (are several Ands possible (in this case
replate ? by *)
InnerJoinExpression:
//store optional flag in the model, don't use keywords containing a space
//refer to the table
(optional?='Optional')? 'Inner' 'Join' jointablename=[Table]
"On" equals+=ColumnRefEqualsExpression
("And" equals+=ColumnRefEqualsExpression)?;
//can only an outer join have an comparison to a string
//if not, one could merge the two joins into one rule
//only differentiating them via 'Inner' and 'Left' (e.g. as a stored
enum value)
OuterJoinExpression:
('Optional')? 'Left' 'Join' jointablename=[Table]
"On" equals+=ColumnRefEqualsExpression
("And" equals+=ColumnRefEqualsExpression)?
//this will have to be adapted if you want to reference columns without
//the table name prefix
(("And" equals+=ColumnStringEqualsExpression)?);
ColumnRefEqualsExpression: left=[Column|QualifiedTableReference] '='
right=[Column|QualifiedTableReference];
ColumnStringEqualsExpression: left=[Column|QualifiedTableReference] '='
right=STRING;
WhereExpression:
IntCompareExpression|NullExpression|NotNullExpression|String EqualsExpression;
NullExpression: "is" "null"{NullExpression};
NotNullExpression: "is" "not" "null"{NotNullExpression};
IntCompareExpression: comparator=Comparator value=INT;
StringEqualsExpression: '=' value=STRING;
enum Comparator: equals = "="| greater=">"|less="<"|
lessequals="<="|greaterequals= ">=";
//you possibly have to add keywords to the list, otherwise a description
//cannot for example contain the word 'As'
MYSTRING hidden(): (ID|WS|INT|STRING|'not'|','|ANY_OTHER)*;
//don't allow spaces or comments whithin a qualified name
QualifiedName hidden():ID('.'ID)*;
QualifiedTableReference hidden():
ID'.'ID;
//END OF GRAMMAR
Here is the sample file containing column definitions which should make
the sample models you gave in your posts to work almost completely
tabledefinitions
PubArticleArticle{
PubArticleDatePrintCover
PubArticleId
PubArticlePromoTeaser
PubArticlePromoTeaserLarge
PubArticlePromoTitle
PubArticleSlug
PubArticleSubtitle
PubArticleUrl
PubArticleLandingPageName
}
VehicleStrongHoldVehicle{
VehicleMake
VehicleModel
VehicleYear
PubArticleVehicleId
}
Video{
VideoDescription
VideoId
VideoThumbnailUrl
VideoTitle
}
VideoVehicle{
VideoId
PubArticleVehicleId
}
LandingPageSectionVideoArticle{
PubArticleLandingPageSectionArticleOrder
PubArticleLandingPageSectionId
PubArticleId
VideoId
}
VehicleMake{
VehicleMake
}
VehicleModel{
VehicleModel
}
PubArticleVehicleCache{
VehicleYear
PubArticleId
VehicleMakeCache
VehicleModelCache
}
PubArticleImageTypeSpecific{
PromoSmallFileMasterId
PromoLargeFileMasterId
HomepageFileMasterId
HeaderFileMasterId
PubArticleId
}
PubArticleLandingPage{
PubArticleLandingPageId
PubArticleLandingPageName
}
PubArticleLandingPageSection{
PubArticleLandingPageId
PubArticleLandingPageSectionId
}
PubArticleSiteCategoryCache{
PubArticleId
}
PostalCodeRegionCountyCity{
CityId
CountyId
RegionId
PostalCode
}
City{
CityId
}
County{
CountyId
}
Region{
RegionId
}
//END OF TABLE DEFINITIONS
Alex
Need training, onsite consulting or any other kind of help for Xtext?
Go visit http://xtext.itemis.com or send a mail to xtext@itemis.de
|
|
| | |
Re: How to get content assist to work with table names from a database [message #551688 is a reply to message #551504] |
Mon, 09 August 2010 07:28 |
Alexander Nittka Messages: 1193 Registered: July 2009 |
Senior Member |
|
|
Hi,
> What is the purpose of the keyword hidden()?
The purpose of hidden tokens (the default use cases are white spaces and
comments) is that they can be written in the model file but that they
need not be specified in the grammar at each position where they are
allowed to appear. E.g. if you have the following in a rule
'Namespace' name=ID
you basically say: as the first element the keyword 'Namesapce' has to
appear and after that an ID. But you don't say explicitly: and in
between there can be an arbitrary number of white spaces and comments.
This is implicit as by default WS, SL_COMMENT and ML_COMMENT are hidden
(see the definition of the Terminals grammar you import at the beginning
of your grammar).
For
QualifiedName:ID('.'ID)*;
x/*stupid comment*/ .//another one
y
or
x . y
would be valid, as comments and white spaces are ignored.
By writing
QualifiedName hidden():ID('.'ID)*;
I require that no tokens should be hidden for that rule. Thereby I
disallow white spaces and comments within a qualified name. The above
would thus cause syntax errors while x.y is OK.
See also the Xtext documentation.
> What does it mean when you have the curly brackets with rule inside:
> NullExpression: "is" "null"{NullExpression};
My design choice for where-expressions was having objects of different
type for each possibility. That way I can use polymorphism when
generating something from the model or when working with the model in
general.
NullExpression: "is" "null"
is a datatype rule as there are no assignments. That is, this rule does
not create an object but a datatype. The curly braces represent an
unassigned action, causing the creation of an object of type NullExpression.
See also the Xtext documentation.
NullExpression: "is" "null"{NullExpression};
> 1: Order of Elements is not important. So unorderered groups could be
> used. Can you explain that a little bit for me.
<x> & <y> & <z>
basically requires that x,y and z appear *exactly* once in the file, but
the order of them is not specified. If you want one to appear *at most*
once, you simply make it optional using the question mark.
See also the Xtext documentation.
> 2. Description is Mandatory
See grammar below
> 3. The query referred to is a previously existing query not the current
> one.
To be achieved via scoping, excluding the current query, if you want
sophisticated validation and code completion
> 4. Yes Several Ands are possible
See grammar below
> 5. Only the Left Join would have the comparison string otherwise it
> would be in the where clause
See grammar below
Alex
Adapted grammar.
//we do not only allow queries, but also
//table definitions, so that we can easily refer to columns
Model: TableDefinitions|NameSpaces;
//make tables and columns available, it should be trivial to
//automatically produce this format
TableDefinitions:{TableDefinition}'tabledefinitions' tables+=Table*;
Table: name=ID'{'columns+=Column*'}';
Column: name=ID;
//the actual queries
NameSpaces:{NameSpaces}
(namespace+=NameSpace)*;
NameSpace:
'Namespace' name=ID "{"
(query+=Query)*
"}";
Query:
//question: is the order of the elements fixed (desc, query, filter,...)
//or can the order vary (in which case unordered groups could be used
//separate the namespace from the name of the query because
//when calculating the fully qualified name of Query, the
//container (NameSpace) is automatically added
'Query' namespace=[NameSpace] ("." name=QualifiedName) "{"
(
//a description is mandatory?
("[" 'Description:' description=MYSTRING"]")
&
("[" 'Query:'queryName=[Query|QualifiedName]"]")?
&
("[" 'Filter:' filter+=Filter (',' filter+=Filter)*"]")?
&
//no return fragments yet
("[" 'Return:' return+=ReturnElement (',' return+=ReturnElement)* "]")?
&
("[" 'From:' from=[Table]
joinespression+=JoinExpression*
"]")?
&
("[" 'Where:' where=Where"]")?
&
("[" 'Order:' order+=Order (',' order+=Order)*"]")?
)
"}";
//I would like to use cross references for the filter, but there would
be some
//work involved referring to them without specifying the table name as well
Filter: column=ID (multi?='*')?;
ReturnElement: ref=[Column|QualifiedTableReference] ('As' asname=ID)?;
Where: column=[Column|QualifiedTableReference] (expression=WhereExpression);
//rather use references, same issue as in Filter
Order: column=ID (direction=Direction)?;
//the first element is the default one used, when
//nothing is specified
enum Direction: ascending="asc"|descending="desc";
//assigned actions might be the better alternative to
//handle the joins
JoinExpression: InnerJoinExpression|OuterJoinExpression;
InnerJoinExpression:
(optional?='Optional')? 'Inner' 'Join' jointablename=[Table]
"On" equals+=ColumnRefEqualsExpression
("And" equals+=ColumnRefEqualsExpression)*;
OuterJoinExpression:
('Optional')? 'Left' 'Join' jointablename=[Table]
"On" equals+=ColumnRefEqualsExpression
("And" equals+=ColumnEqualsExpression)*;
ColumnEqualsExpression:ColumnRefEqualsExpression|ColumnStrin gEqualsExpression;
ColumnRefEqualsExpression: left=[Column|QualifiedTableReference] '='
right=[Column|QualifiedTableReference];
ColumnStringEqualsExpression: left=[Column|QualifiedTableReference] '='
right=STRING;
WhereExpression:
IntCompareExpression|NullExpression|NotNullExpression|String EqualsExpression;
NullExpression: "is" "null"{NullExpression};
NotNullExpression: "is" "not" "null"{NotNullExpression};
IntCompareExpression: comparator=Comparator value=INT;
StringEqualsExpression: '=' value=STRING;
enum Comparator: equals = "="| greater=">"|less="<"|
lessequals="<="|greaterequals= ">=";
//you possibly have to add keywords to the list, otherwise a description
//cannot for example contain the word 'As'
MYSTRING hidden(): (ID|WS|INT|STRING|'not'|','|ANY_OTHER)*;
QualifiedName hidden():ID('.'ID)*;
QualifiedTableReference hidden():ID'.'ID;
Need training, onsite consulting or any other kind of help for Xtext?
Go visit http://xtext.itemis.com or send a mail to xtext@itemis.de
|
|
| | |
Goto Forum:
Current Time: Thu Sep 26 10:38:54 GMT 2024
Powered by FUDForum. Page generated in 0.04835 seconds
|