AnnotatedSQL: schema + content provider

    Finally, we got around to describe the changes that occurred in the AnnotatedSQL library.

    Announcement:
    1. Changes in the plugin
    2. Changes in the schema annotations
    3. What is the content provider in my understanding
    4. Generate the content provider according to the scheme

    1. Plugin


    Plugin update site
    Now this is a full plug-in for Eclipse with its update site

    Build path-> Libraries-> Add Library
    Annotations now do not need to be put in the project, the plugin carries them with you. You just need to add AnnotatedSQL Libaray to the project in the project properties. And you will always have an API corresponding to the plugin.

    Templates for creating diagrams, tables, view
    Eclipse has such a great thing as code templates. The plugin adds its own templates for creating a diagram, table, view. and these templates get code completion, the same one that is shown by ctrl + space

    For example, write Tabl, press the treasured buttons and see Table - AnnotatedSQL , and select your template for the table.
    Do not forget: to jump to the next field editing the template, press the Tab key, and Enter will finish editing the template.

    2. Updates in the scheme


    Perhaps only one annotation has changed
    Join
    Renamed attributes:
    srcTable -> joinTable
    srcColumn -> joinColumn
    destTable -> onTableAlias
    destColumn -> onColumn
    I hope this will be clearer. But the main thing to remember is that onTableAlias is not a table name, but an alias on it.

    And several were added at once:

    Rawjoin
    If the ON condition is different from column1 = column2 then go here. You indicate the table that joins and write the condition with your hands.
    Attributes:
    joinTable - the name of the table to join
    onCondition - ON condition

    Ignorecolumns
    When we do not need to select a single column from the table, we mark it with such an annotation. Applicable for From , Join , RawJoin

    Rawquery
    Request with parameters anywhere. This thing was invented for the content provider and is due to the limited view in sql. The view is select + join, and where is then applied.
    But often it is necessary to fulfill a request where parameters must already be used in the ON condition of the join. But for this, it was invented, ala sql function. Where it is necessary to use parameters naturally we set ?
    The received sql query doesn’t go anywhere, it just lies constant and it can be pulled by the URI (I’ll tell you later)

    RawQuery can be formed like SimpleView using From , Join and RawJoin ,
    or you can use “raw sql” via SqlQuery annotation

    @RawQuery(ChatListQuery.QUERY_NAME)
    public static interface ChatListQuery{
        String QUERY_NAME = "chatListQuery";
        @SqlQuery
        String CHAT_LIST_QUERY = " some sql here"
    }
    


    3. What is the content provider in my understanding


    Based on the experience of developing for Android, the content provider should have additional properties. And additional parameters can be pushed through Uri, there is plenty of "free space" - fragment, parametrs everything is like in the url. So, here is what you usually need:

    no-notify
    When you insert a packet of data into a provider, there is no need to notify the UI after inserting each row, but it is better to notify after inserting.

    alternative notify uri
    Often there is a need for notifications and one uri to specify the dependent uri. For example, you have a UserView that you use to fill the list, and the insert goes to the User table and you need to notify uri from view, this is alternative uri.

    limit
    trivial limit on request

    4. Generation of Content Provider according to the scheme


    After I wrote the auto- generation scheme for annotations, I thought: I have everything to capture the world, generate a content provider and make my life easier. No sooner said than done. A couple of annotations and you have a full-fledged provider + some goodies. Well, it started!

    First, I must say that according to the scheme, we generate a content provider. The Provider annotation will help us with this.

    Provider

    name - the name of the class for the content provider
    authority - we need to know the provider’s authoritative content .
    schemaClass is the name of the schema class. Used when open helper is generated.
    openHelperClass - you can refuse to generate an internal open helper and force yours to be used.

    @Schema(className="FManagerSchema", dbName="fmanager.db", dbVersion=6)
    @Provider(authority="com.gdubina.fmanager.store.FManagerProvider", schemaClass="FManagerSchema", name="FManagerProvider", openHelperClass="CustomOpenHelper")
    public interface FManagerStore {
    


    So, we said that we want a content provider. What's next?
    I must say by what URI our entity will be available - we use the URI annotation of the same name

    URI
    we hang on a constant in table, view or query. I like something like URI_CONTENT.
    All attributes are optional here, but they are.
    type - uri type. As we know in the content provider, it is customary to determine that many records (dir) or one (item) are returned by URI. Remember this getType method ? here is the same thing.
    onlyQuery - access only for query execution, usable for view and query. Attempting to execute insert / delete / update will result in an exception
    column - the default is "_id". Actually, when you use a URI of the parh / # type, the content provider selects _a = uri.getLastPathSegment (). so here you can override which field do select
    altNotify- a list of uri that need to be ratified yet to be ratified

    A couple of examples:
    this is how we got the content provider to work with the championship table. Everything is available - select, insert, delete, update

    @Table(ChempTable.TABLE_NAME)
    public static interface ChempTable{
    	@URI
    	String CONTENT_PATH = "chemps";
    	String TABLE_NAME = "chemp_table";
    	@PrimaryKey
    	@Column(type = Type.INTEGER)
    	String ID = "_id";
    	@Column(type = Type.TEXT)
    	String TITLE = "title";
    	@Column(type = Type.TEXT)
    	String CHEMP_KEY = "CHEMP_KEY";
    }
    


    And here is a piece of the message table. As we can see, here I have two URIs
    1. for accessing the URI_CONTENT
    2. table itself; for fetching the messages of a specific user URI_MESSAGES_BY_USER, here column = Message.FROM_ID

    @Table(Message.TABLE_NAME)
    @PrimaryKey(columns = {Message.USER_ID, Message.ID})
    public static interface Message{
    	@URI(altNotify={MessageChatView.URI_CONTENT, ChatListQuery.URI_CONTENT, URI_RECALC_MESSAGE_PATH})
    	String URI_CONTENT = "message";
    	@URI(type=URI.Type.ITEM, altNotify={Message.URI_CONTENT, MessageChatView.URI_CONTENT, ChatListQuery.URI_CONTENT, URI_RECALC_MESSAGE_PATH}, column=Message.FROM_ID)
    	String URI_MESSAGES_BY_USER = "message_by_user";
    }
    


    This is enough to create a simple conetp provider. Just two annotations!

    But that’s not all, what to do if something needs to be done on the actions with the table? for example, they added a user - they went and uploaded an avatar. in big sql there is such a thing as triggers - they do something similar. So I called my annotation as Trigger itself . A protected method will be created in the provider, which you must override in the heirs of the autogenerated class

    Trigger
    hangs on uri, but the method is called when the name of the table matches
    name - the name of the trigger, used to generate the name of the
    when method - when to call the method before the action with the table or after.
    type - what actions to respond to - insert / delete / udapte or all at once

    The method name is generated according to this template
    	onInserted(ContentValues values){}
    	onDeleted(Uri uri, String selection, String[] selectionArgs){}
    	onUpdated(Uri uri, ContentValues values, String selection, String[] selectionArg){}
    


    If you need to hang several triggers, use the Triggers annotation and fill it with triggers.

    Example:
    @Table(User.TABLE_NAME)
    public static interface User{
    	@Trigger(type=Trigger.Type.INSERT, name="user", when=When.BEFORE)
    	@URI(altNotify={SuggestionView.URI_CONTENT, MessageChatView.URI_CONTENT, ChatListQuery.URI_CONTENT})
    	String URI_CONTENT = "user";
    


    and this is what the provider looks like in this case

    public class AppProvider extends AppAutoProvider {
    	@Override
    	protected void onUserBeforeInserted(ContentValues values) {
    		.................
    	}
    


    How to use notify correctly?

    If you want to pronote uri and all alternatives, you must use the static method notifyUri(ContentResolver cr, Uri uri)

    Pack statically method from provider

    getContentUri(String path)- on path we get URIs
    getContentUriGroupBy(String path, String groupBy)- on path we get URIs with grouping support
    getContentUri(String path, long id)- we get URIs path / #
    getContentUri(String path, String id)- we get URIs path / #

    getContentWithLimitUri(String path, int limit)- path + limit

    getNoNotifyContentUri(String path)- on paths we get URIs without notify
    getNoNotifyContentUri(String path, long id)- we get URI path / # without notifications

    P.S. the library has passed “combat” tests and has already been used in
    PSS production projects for grammar and spelling, please do not kick

    Also popular now: