7 Replies Latest reply on Dec 5, 2014 10:22 AM by Jon Tara

    Javascript ORM API: Handle model updates in different versions

    Ruben Ruben

      Hi,

       

      We are soon releasing a new version of one of our apps. This new version includes some model changes, and when testing update scenarios, it seems that unless we remove the previous version or do a complete DB reset (manually) the app won't work correctly.

       

      I remember that within the Ruby API it was possible to add model versions to the definition of the model itself, but I don't see the same functionality in the Javascript version. How should we handle this so no user intervention is required when updating the app?

       

      Thanks,

       

      Rubén Torrero

        • Re: Javascript ORM API: Handle model updates in different versions
          Kutir Mobility

          Hi Ruben,

          Have you tried 'set' method to define version?

               model.set("schema_version",'1.0')

           

          Visnupriya R

          Kutir Mobility

            • Re: Javascript ORM API: Handle model updates in different versions
              Ruben Ruben

              Hi Visnupriya,

               

              I tried it, but I'm not sure how I am supposed to implement the hook that triggers a database reset. However, if I have understood correctly, PropertyBag is the default in the Javascript ORM API, so in theory, it shouldn't be needed. However, the app won't work correctly until this is done.

               

              Any other suggestions? Am I missing some point?

                • Re: Re: Javascript ORM API: Handle model updates in different versions
                  Jon Tara

                  Not sure what you mean by "database reset".

                   

                  Any time the application is updated, your application.rb will receive an application notification of Rho::Application::APP_EVENT_DBMIGRATESOURCE for every model for which the model version has changed.

                   

                  It is up to you to catch this notification on application startup, and then perform any actions needed to update the table. For example, perhaps you have added a field, and you have some code that would fail now because it references a non-existent field. So, you will have to write some code to populate the database with that field. (Maybe it is OK just to set to to an empty string, etc. - it depends on what your code expects!)

                   

                  The model versions are just there to help you identify which tables have had their definitions changed. You are expected to increment the version if you have changed the table structure, and then you write code in the migration notification(s) to deal with it.

                   

                  You might have more complex changes needed, that involve multiple tables, maybe even ones that have't changed. (maybe you need to store a reference to an object in another table.) Again, it is up to your to write the code.

                   

                  I don't know how/if you can do this in Javacript.

                   

                  I use the modern, 4.x way of handling this. From my application.rb:

                   

                  Rho::Application.setApplicationNotify( lambda do |callback_data; event_type, event_data|

                    event_type = callback_data['applicationEvent']

                    # eventData is present only for APP_EVENT_CONFIGCONFLICT, and must be omitted from

                    # processApplicationEvent if not present

                    event_data = callback_data.include?('eventData') ? callback_data['eventData'] : nil

                    app_info "***** setApplicationNotify callback callback_data = #{callback_data.inspect} event_type = #{event_type.inspect}, event_data = #{event_data.inspect}"

                      case event_type

                      when Rho::Application::APP_EVENT_ACTIVATED        then on_activate_app

                      when Rho::Application::APP_EVENT_DEACTIVATED      then on_deactivate_app

                      when Rho::Application::APP_EVENT_UICREATED        then on_ui_created

                      when Rho::Application::APP_EVENT_UIDESTROYED      then on_ui_destroyed

                      when Rho::Application::APP_EVENT_SCREEN_OFF

                      when Rho::Application::APP_EVENT_SCREEN_ON

                      when Rho::Application::APP_EVENT_SYNCUSERCHANGED

                      when Rho::Application::APP_EVENT_CONFIGCONFLICT   then on_reinstall_config_update event_data

                      when Rho::Application::APP_EVENT_DBMIGRATESOURCE  then on_migrate_source

                      else  app_error "Unknown Application event: #    {event_type}"

                    end

                    if event_data

                      Rho::Application.processApplicationEvent event_type,event_data

                    else

                      Rho::Application.processApplicationEvent event_type

                    end

                    end  # lambda

                    )

                     super

                  end

                   

                  We don't currently do anything with this, as we've never done a migration. But we have a bit of skeletal code as a guide:

                   

                  def on_migrate_source(old_version, new_src)

                    # ... do something like alert user ...

                    app_info "Data Migration from #{old_version} to schema_version: #{new_src['schema_version']} name: #{new_src['name']} schema: #{new_src['schema']}"

                    model_object = Object.const_get(new_src['name']) # how to get from a string to the class by that name

                    model_object.on_migrate_source(old_version, new_src) # each of our classes should have this method

                    # TODO: how does this work with new callbacks? There is no return value!

                    true # does not create table

                  end

                    • Re: Re: Javascript ORM API: Handle model updates in different versions
                      Ruben Ruben

                      Hi Jon,

                       

                      I already had read about the APP_EVENT_DBMIGRATESOURCE, but according to Rho.Application API documentation:

                       

                          Constant: Rho.Application.APP_EVENT_DBMIGRATESOURCE (For Ruby use "::" instead of ".")

                          String:DBMigrateSource

                          This is available under Ruby Only.

                      So I wonder if there is another way to handle this in Javascript. What I don't understand either is why I need to do a full reset (that's what I meant by 'Database reset') through Android's application menu -> Application -> Remove all data for the application to work.

                      Supposedly, PropertyBag models don't require data migrations, and since PropertyBag are the default in Javascript's ORM API, I would assume I dont need data migrations. However, this has proven to be an incorrect assumption.

                • Re: Javascript ORM API: Handle model updates in different versions
                  Ruben Ruben

                  I figured it out: in the documentation for the Ruby API, there is at the end information about a rhoconfig.txt variable:

                       app_db_version

                   

                  When this is set to a value higher than the previous build, it will reset the database on the first start.

                    • Re: Javascript ORM API: Handle model updates in different versions
                      Jon Tara

                      I'd guess that "not available in Javascript" actually means "not available in Javascript!"

                       

                      Try a little Ruby! It's not that scary! A migration is a good place to start.

                       

                      And application.rb is also a good place to start, because there are many cool things you can do with it, that I don't think you can do with JS.

                       

                      For example, what if you want to send a user an email, and they can click on a link and it will open your app to a a specific item? ("Your order has been shipped! Click here to view details in our app..."). You can do that in application.rb.

                       

                      Migrations are NECESSARY if you use a fixed schema.

                       

                      Migrations are A CONVENIENCE if you use PropertyBag. It allows you to massage the database once so that you don't have to write a bunch of conditional code all over the place to deal with changes that have been made in the past.

                       

                      I think your app doesn't work correctly because of assumptions that some code in your application make about what will be found in the tables. Patch it up at the migration.

                       

                      I haven't done a migration in Rhodes, but have in Ruby on Rails. It's a common need.