Skip to content

Instantly share code, notes, and snippets.

@RossRogers
Created August 3, 2016 15:04
Show Gist options
  • Save RossRogers/aa0f3489383575a3fe414c0749a26d2a to your computer and use it in GitHub Desktop.
Save RossRogers/aa0f3489383575a3fe414c0749a26d2a to your computer and use it in GitHub Desktop.
from django.core.management.base import BaseCommand, CommandError
from django.conf import settings
import rest_framework
from collections import namedtuple
import re,sys
INDENT = ' '*2
# TODO(rrogers) 2015.06.01 - allow canonical, global nested-objects and
# automatically swap them in?
#
# If a model is marked as globally_canonical, then 1 and only 1 version of that
# model exists
#
# * post_restore on such an object should register its `url` globally and
# anyone wishing to get a reference should look in the hash
#
# * should updates from the server be golden? or should local state take
# precedence?
#
# * fields referencing canonical objects have a property in the place of
# reference url fields in order to spoof out and obviate the need for
# manual field obj/url alias sync'ing.
#
class Command(BaseCommand):
help = 'Generates a js interface from the Rest Framework serializers'
def add_arguments(self, parser):
parser.add_argument('output_path', nargs='+', type=str)
parser.add_argument('base_factory_name', nargs='+', type=str)
parser.add_argument('server_base_url', nargs='+', type=str)
def handle(self, *args, **options):
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
from django.utils.termcolors import colorize
import os, sys
(output_path,base_factory_name) = args[:2]
server_base_url = args[2] if len(args) > 2 else '/rest'
server_base_url = server_base_url.rstrip('/')+'/'
from qc_srvr.urls import urlpatterns
serializer_2_class = {}
ClassDefn = namedtuple('ClassDefn',('url_name','fields','meta'))
FieldDefn = namedtuple('FieldDefn',('field_name','type','meta','instance_class_name'))
def traverse(url_patterns, prefix=''):
for p in url_patterns:
if isinstance(p, RegexURLPattern):
composed = '%s%s' % (prefix, p.regex.pattern)
#print '\t%s' % (composed), '==> '
#sys.stdout.write('%s.' % p.callback.__module__)
viewset = getattr(p.callback,'cls',None)
if not viewset:
continue
viewset = viewset() # create instance
if not isinstance(viewset,rest_framework.viewsets.ModelViewSet):
continue
serializer_class = getattr(viewset,'serializer_class',None)
if not serializer_class:
continue
serializer = serializer_class()
model = getattr(serializer.Meta,'model')
full_serializer_type = serializer.__module__+'.'+serializer.__class__.__name__
url = re.compile(r'^\^*((?:\w+/?)+)').search(composed).group(1)
url_name = url.strip('/').split('/')
class_defn = ClassDefn(url_name,[],{})
class_defn.meta['url'] = server_base_url + url
class_defn.meta['is_list_class'] = p.callback.suffix == 'List'
if class_defn.meta['is_list_class']:
class_defn.meta['instance_class_name'] = url_name[-1]
# class_defn.meta['instance_class_full_name'] = base_factory_name + '.' + '.'.join(url_name)
if p.callback.suffix == 'List':
url_name[-1] += p.callback.suffix
full_serializer_type += p.callback.suffix
if full_serializer_type in serializer_2_class:
pass
# if -1 != composed.find('PackingInstr/'):
# import rpdb2;rpdb2.start_embedded_debugger('foo')
# print 'WARNING: entry',full_serializer_type,'already exists in serializer_2_class. \n\told defn:',serializer_2_class[full_serializer_type],'\n\tnew defn:',class_defn
serializer_2_class[full_serializer_type] = class_defn
model_fields = {}
for field in sorted(model._meta.concrete_fields + model._meta.many_to_many + model._meta.virtual_fields):
model_fields[field.name] = field
if class_defn.meta['is_list_class']:
def a(f):
class_defn.fields.append(f)
#a(FieldDefn('count','number',{'is_integer':True},None))
#a(FieldDefn('next','string',{},None))
#a(FieldDefn('previous','string',{},None))
f = FieldDefn('results','Array< '+class_defn.meta['instance_class_name'] + ' >',{},class_defn.meta['instance_class_name'])
class_defn.fields.append(f)
else :
#DRF3.+for f_name,f in serializer.fields.fields.iteritems():
for f_name,f in serializer.fields.iteritems():
t = None
field_meta = {}
# DRF3.+if isinstance(f,rest_framework.relations.ManyRelatedField):
if isinstance(f,rest_framework.relations.RelatedField):
#import rpdb2;rpdb2.start_embedded_debugger('foo')
f = getattr(serializer_class,f_name,f)
# DRF3.+
# many = isinstance(f,rest_framework.serializers.ListSerializer) or isinstance(f,rest_framework.relations.ManyRelatedField)
# if isinstance(f,rest_framework.serializers.ListSerializer):
# f = getattr(f,'child',f)
# f.many = many
f.many = getattr(f,'many',False)
# if f_name == 'header_sample_requirements':
# import rpdb2;rpdb2.start_embedded_debugger('foo')
#print f_name
#if f_name.endswith('user_permissions'):
# import rpdb2;rpdb2.start_embedded_debugger('foo')
if isinstance(f,rest_framework.fields.BooleanField): t = 'boolean'
elif isinstance(f,rest_framework.fields.CharField): t = 'String'
elif isinstance(f,rest_framework.fields.URLField): t = 'String'
elif isinstance(f,rest_framework.fields.SlugField): t = 'String'
elif isinstance(f,rest_framework.fields.ChoiceField): t = 'String'
elif isinstance(f,rest_framework.fields.EmailField): t = 'String'
elif isinstance(f,rest_framework.fields.RegexField): t = 'String'
elif isinstance(f,rest_framework.fields.DateField):
t = 'Date'
field_meta['is_date_only_field'] = True
elif isinstance(f,rest_framework.fields.DateTimeField): t = 'Date'
elif isinstance(f,rest_framework.fields.TimeField):
t = 'Date'
field_meta.is_time_only_field
elif isinstance(f,rest_framework.fields.IntegerField):
t = 'number'
field_meta['is_integer'] = True
elif isinstance(f,rest_framework.fields.FloatField): t = 'number'
elif isinstance(f,rest_framework.fields.DecimalField): t = 'number'
elif isinstance(f,rest_framework.relations.HyperlinkedIdentityField): t = 'String'
elif isinstance(f,rest_framework.relations.HyperlinkedRelatedField):
t = 'String'
field_meta['is_url'] = True
elif isinstance(f,rest_framework.relations.PrimaryKeyRelatedField):
t = 'number'
field_meta['is_integer'] = True
elif isinstance(f,rest_framework.serializers.Serializer):
def getter(module_name,many):
def inner():
return ('Array< ' if many else '')+\
base_factory_name + '.' + \
'.'.join(serializer_2_class[module_name].url_name) +\
(' >' if many else '')
return inner
field_meta['field_is_delegate_serializer'] = True
if f.many:
field_meta['is_array'] = True
field_meta['inst_type'] = getter(f.__module__+'.'+f.__class__.__name__,False)
t = getter(f.__module__+'.'+f.__class__.__name__,f.many)
elif isinstance(f,rest_framework.serializers.Field): t = 'String'
else:
print >>sys.stderr, "ERROR: Couldn't figure out field",f_name,"for serializer",full_serializer_type
t = 'String'
if getattr(f,'many',False) and not isinstance(f,rest_framework.serializers.Serializer):
field_meta['is_array'] = True
field_meta['inst_type'] = t
t = 'Array< '+t +' >'
wo = getattr(serializer.Meta,'write_only_fields', None)
if wo and f_name in wo:
field_meta['is_write_only'] = True
if not t:
raise Exception()
# import rpdb2;rpdb2.start_embedded_debugger('foo')
class_defn.fields.append(FieldDefn(f_name,t,field_meta,None))
if isinstance(p, RegexURLResolver):
traverse(p.url_patterns, prefix=p.regex.pattern)
traverse(urlpatterns)
#import rpdb2;rpdb2.start_embedded_debugger('foo')
base_module = {}
print ''
for serializer_name, cls in serializer_2_class.iteritems():
module = base_module
for u in cls.url_name[:-1]:
module = module.setdefault(u,{})
module[cls.url_name[-1]] = cls
#print serializer_name, '.'.join(cls.url_name)
for f in cls.fields:
pass
#print ' ',f.field_name,':',(f.type() if callable(f.type) else f.type)
#print len(cls.fields)
out = open(output_path,'w') if len(args) > 0 else sys.stdout
def w(s):
out.write(s)
out.write('\n')
w("'use strict';")
w('// jshint newcap:false')
w('/*jshint -W040 */')
w('function pad2(num) {')
w(INDENT + "return ('0'+num).slice(-2);")
w('}')
w('var TIMEZONE_OFFSET = new Date().getTimezoneOffset();')
w('/* jshint ignore:start */')
w('var TIMEZONE_OFFSET_MS = TIMEZONE_OFFSET*60*1000;')
w('var TIMEZONE_OFFSET_MS_PADDED = (TIMEZONE_OFFSET+12*60)*60*1000;')
w('/* jshint ignore:end */')
w("var TIMEZONE_ISO_TIME = 'T' + pad2(TIMEZONE_OFFSET/60 + 12) +")
w(INDENT + "':' + pad2(TIMEZONE_OFFSET%60) + ':00.000Z';")
w('')
w('var '+base_factory_name+' = {};')
w('(function ('+base_factory_name+') {')
w('''
function gen_list_get(base_url,Cls,InstClass) {
return function(parameters, config, destination) {
var url = base_url;
if (parameters) { url += '?'+parameters; }
destination = destination || new Cls();
var post_restore_intercept = function(data) {
var d = data.data;
destination.count = parseInt(d.count);
destination.next = d.next;
destination.previous = d.previous;
destination.results = [];
var list_element_promises = [];
d.results.forEach(function(_,i) {
var element_promise = InstClass.post_restore(d.results[i]);
list_element_promises.push(element_promise);
destination.results.push(element_promise);
element_promise.then(function(el) { destination.results[i] = el; });
});
if (list_element_promises.length) {
return ''' + base_factory_name + '''.$q.all(list_element_promises).then(function(){ return destination; });
} else {
return destination;
}
};
config = config || {}
return ''' + base_factory_name + '''.$http.get(url,config).then(post_restore_intercept);
};
}
function gen_inst_save(url, Cls) {
return function() {
var req_defer = ''' + base_factory_name + '''.$q.defer();
var self = this;
this.pre_save().then(function(saver) {
var promise;
if ('url' in saver) {
promise = ''' + base_factory_name + '''.$http.put(saver.url, saver);
} else if ('id' in saver) {
promise = ''' + base_factory_name + '''.$http.put(self.base_url + saver.id + '/', saver);
} else {
promise = ''' + base_factory_name + '''.$http.post(url, saver);
}
promise = promise.then(function(data) {
return Cls.post_restore(data.data,self);
});
promise.catch('''+base_factory_name+'''.log_http_error);
req_defer.resolve(promise);
});
return req_defer.promise;
};
}
function gen_inst_get(base_url, Cls) {
return function(pk, destination) {
destination = destination || new Cls();
var post_restore_intercept = function(data) {
return Cls.post_restore(data.data, destination);
};
var url = /^\w+$/.test(pk) ? base_url + pk + '/' : pk;
var promise = ''' + base_factory_name + '''.$http.get(url)
.then(post_restore_intercept);
promise.catch(''' + base_factory_name + '''.log_http_error);
return promise;
};
}
function gen_inst_delete(url, Cls) {
return function() {
if (this.url) {
return ''' + base_factory_name + '''.$http.delete(this.url);
} else if (this.id) {
return ''' + base_factory_name + '''.$http.delete(this.base_url + this.id + '/');
} else {
return ''' + base_factory_name + '''.$q.when(null);
}
};
}
''')
def OutputClasses(module,module_names=[],indent=''):
def keep_list_close_to_inst_cmp(a,b):
a_stripped = a
a_is_list = a[-4:] == 'List'
if a_is_list:
a_stripped = a[:-4]
b_stripped = b
b_is_list = b[-4:] == 'List'
if b_is_list:
b_stripped = b[:-4]
if a_stripped == b_stripped:
return cmp(a,b)
return cmp(a_stripped,b_stripped)
keys = sorted(module.keys(),keep_list_close_to_inst_cmp)
factory_lines = []
indent_child = indent + INDENT
for mod_class_name in keys:
mod_class = module[mod_class_name]
if isinstance(mod_class,ClassDefn):
cls = mod_class
cls_name = mod_class_name
indent_g_child = indent_child + INDENT
indent_gg_child = indent_child + 2 * INDENT
indent_ggg_child = indent_child + 3 * INDENT
indent_gggg_child = indent_child + 4 * INDENT
indent_ggggg_child = indent_child + 5 * INDENT
indent_gggggg_child = indent_child + 6 * INDENT
encapsulating_module = module_names[-1]
w(indent_child + encapsulating_module +'.' + cls_name + ' = (function() {')
w('')
len_longest_field_name = reduce(lambda accum,f: max(accum,len(f.field_name)),cls.fields,0)
field_name_formatter = '%%-%ds'%len_longest_field_name
if cls.meta['is_list_class']:
w(indent_g_child + 'function '+cls_name+'() {')
# w(indent_gg_child + 'this.count = null')
# w(indent_gg_child + 'this.next = null')
# w(indent_gg_child + 'this.previous = null')
w(indent_gg_child + 'this.results = [];')
w(indent_g_child +'}')
w('')
w(indent_g_child + cls_name + '.get = gen_list_get(\'' + cls.meta['url'] +'\', ' + cls_name + ', ' + encapsulating_module+'.'+cls.meta['instance_class_name'] + ');')
# w(indent_g_child + cls_name + '.get = function(parameters, config, destination) {')
# w(indent_gg_child + "var url = '" + cls.meta['url'] + "';")
# w(indent_gg_child + "if (parameters) { url += '?'+parameters; }")
# w(indent_gg_child + 'destination = destination || new '+cls_name+'();')
# w(indent_gg_child + 'var post_restore_intercept = function(data) {')
# w(indent_ggg_child + 'var d = data.data;')
# w(indent_ggg_child + 'destination.count = parseInt(d.count);')
# w(indent_ggg_child + 'destination.next = d.next;')
# w(indent_ggg_child + 'destination.previous = d.previous;')
# w(indent_ggg_child + 'destination.results = [];')
# w(indent_ggg_child + 'var list_element_promises = [];')
# w(indent_ggg_child + 'd.results.forEach(function(_,i) {')
# w(indent_gggg_child + 'var element_promise = ' + encapsulating_module+'.'+cls.meta['instance_class_name'] + '.post_restore(d.results[i]);')
# w(indent_gggg_child + 'list_element_promises.push(element_promise);')
# w(indent_gggg_child + 'destination.results.push(element_promise);')
# w(indent_gggg_child + 'element_promise.then(function(el) { destination.results[i] = el; });')
# w(indent_ggg_child + '});')
# w(indent_ggg_child + 'if (list_element_promises.length) {')
# w(indent_gggg_child + 'return ' + base_factory_name + '.$q.all(list_element_promises).then(function(){ return destination; });')
# w(indent_ggg_child + '} else {')
# w(indent_gggg_child + 'return destination;')
# w(indent_ggg_child + '}')
# w(indent_gg_child + '};')
# w(indent_gg_child + "config = config || {};")
# w(indent_gg_child + 'return ' + base_factory_name + '.$http.get(url,config).then(post_restore_intercept);')
# w(indent_g_child + '};')
w(indent_g_child + cls_name + '.prototype.get = function(parameters, config) {')
w(indent_gg_child + 'return '+ cls_name + '.get(parameters, config, this);')
w(indent_g_child + '};')
else:
w(indent_g_child + 'function '+cls_name+'() {')
for f in cls.fields:
if 'is_array' in f.meta:
w(indent_gg_child + 'this.' + f.field_name + ' = [];')
else:
pass
# w(indent_gg_child + 'this.' + f.field_name + ' = null')
w(indent_g_child +'}')
w('')
w(indent_g_child + cls_name + ".prototype.base_url = '" + cls.meta['url'] + "';")
w('')
w(indent_g_child + cls_name+'.prototype.pre_save = function() {')
w(indent_gg_child + 'var self = this;')
w(indent_gg_child + 'return ' + base_factory_name + '.$q(function(resolve) {')
w(indent_ggg_child + 'var result = self;')
w(indent_ggg_child + 'var child_pre_save_promises = [];')
saving_a_clone = {'yup':False}
def ensure_cloned_result(indent=0):
if not saving_a_clone['yup']:
saving_a_clone['yup'] = True
w(indent_ggg_child + indent*INDENT + 'result = $.extend({},result);')
for f in cls.fields:
data_manipulation_func = None
if 'is_date_only_field' in f.meta:
ensure_cloned_result()
data_manipulation_func = lambda src, dest: 'if ('+src+' && '+src+'.toISOString) { ' + dest +' = '+ src + '.toISOString().slice(0,10);}'
elif 'field_is_delegate_serializer' in f.meta:
ensure_cloned_result()
def func(src, dest, extra_indent=''):
promise_name = 'p_' + str(next_inst_cnt.next())
return (
'if ('+src + ' && '+src+'.pre_save) {\n' +
extra_indent + indent_gggg_child + 'var ' + promise_name + ' = ' +dest + ' = ' + src + '.pre_save();\n' +
extra_indent + indent_gggg_child + 'child_pre_save_promises.push(' + promise_name + ');\n' +
extra_indent + indent_gggg_child + promise_name + '.then(function(promise_result){ ' + dest + '= promise_result; });\n' +
extra_indent + indent_ggg_child + '} else {\n' +
extra_indent + indent_gggg_child + dest + ' = ' + src + ';\n' + extra_indent + indent_gggg_child + '\n' +
extra_indent + indent_ggg_child + '}')
data_manipulation_func = func
if data_manipulation_func:
if 'is_array' in f.meta:
w(indent_ggg_child + 'result.'+f.field_name+' = [];')
w(indent_ggg_child + 'self.'+f.field_name + '.forEach( function(_,i) {')
w(indent_gggg_child + data_manipulation_func('self.'+f.field_name+'[i]','result.'+f.field_name+'[i]',INDENT))
w(indent_ggg_child + '});')
else:
w(indent_ggg_child + data_manipulation_func('result.'+f.field_name,'result.'+f.field_name))
w(indent_ggg_child + 'if (child_pre_save_promises.length) {')
w(indent_gggg_child + 'resolve(' + base_factory_name + '.$q.all(child_pre_save_promises).then(function() { return result;}));')
w(indent_ggg_child + '} else {')
w(indent_gggg_child + 'resolve(result);')
w(indent_ggg_child + '}')
w(indent_gg_child + '});')
w(indent_g_child + '};')
w('')
w(indent_g_child + cls_name+'.post_restore = function(json_obj, destination) {')
w(indent_gg_child + 'return ' + base_factory_name + '.$q( function(resolve) {')
w(indent_ggg_child + 'var result = destination || new ' + cls_name + '(); // jshint ignore:line')
w(indent_ggg_child + 'if (json_obj === null) {')
w(indent_gggg_child + 'result = json_obj;')
w(indent_gggg_child + 'resolve(result);')
w(indent_ggg_child + '}')
w(indent_ggg_child + "if (typeof(json_obj) === 'undefined') {")
w(indent_gggg_child + 'resolve(result);')
w(indent_ggg_child + '}')
w(indent_ggg_child + 'var child_post_resolve_promises = [];')
def next_inst_cnt():
inst_cnt = 0
for i in xrange(0,1<<20):
inst_cnt += 1
yield inst_cnt
next_inst_cnt = next_inst_cnt()
for f in cls.fields:
if 'is_write_only' in f.meta:
continue
t = f.type() if callable(f.type) else f.type
inst_type = t
if 'is_array' in f.meta:
inst_type = f.meta['inst_type']
if callable(inst_type):
inst_type = inst_type()
data_manipulation_func = None
if 'is_date_only_field' in f.meta:
data_manipulation_func = lambda src,dest: 'if ('+src+" && (typeof("+dest+") === 'undefined' || "+dest+" === null)) { "+ dest + ' = new Date('+src+'+TIMEZONE_ISO_TIME); }'
elif 'is_integer' in f.meta:
data_manipulation_func = lambda src,dest: "if ("+src+" !== null && (typeof("+dest+") === 'undefined' || "+dest+" === null)) { "+dest + " = parseInt(" + src + "); }"
elif 'field_is_delegate_serializer' in f.meta:
data_manipulation_func = lambda src,dest: "if ( " + src + ') {child_post_resolve_promises.push('+ inst_type + '.post_restore(' + src + ', '+dest+').then(function(sub_result) { ' + dest + '= sub_result;})); }'
elif t == 'Date':
data_manipulation_func = lambda src,dest: 'if ('+src+" && (typeof("+dest+") === 'undefined' || "+dest+" === null)) { "+dest + ' = new Date('+src+'); }'
elif t == 'number':
data_manipulation_func = lambda src,dest: "if ("+src+" !== null && (typeof("+dest+") === 'undefined' || "+dest+" === null)) { "+dest + ' = parseFloat('+src+'); }'
else:
#if 'is_url' in f.meta:
# def data_manipulation_func(src,dest,idx=None):
# dest_obj = dest +'__obj'
# result = [
# 'if ('+src+" && (typeof("+dest+") === 'undefined' || "+dest+" === null)) {",
# INDENT + dest + ' = ' + src + ';',
# if idx is not None:
# result.append( INDENT*2 + dest_obj + ' = ' + dest_obj + ' || []')
# result.extend([
# INDENT*2 + base_factory_name + ".$http.get('" + src +"')",
# INDENT*3 + ".success(function(data) {",
# INDENT*4 + dest + '__obj' + ('' if idx is None else '['+idx+']')+ ' = data',
# INDENT*3 + "})",
# INDENT + "}",
# '}'
# ])
# return result
#else:
data_manipulation_func = lambda src,dest:\
'if ('+src+" && (typeof("+dest+") === 'undefined' || "+dest+" === null)) { " + dest + ' = ' + src + '; }'
if data_manipulation_func:
if 'is_array' in f.meta:
w(indent_ggg_child + 'result.'+f.field_name + ' = ' + 'result.'+f.field_name + ' || [];')
w(indent_ggg_child + 'json_obj.'+f.field_name+'.forEach(function(_,i) {')
inst_class = f.meta['inst_type']
if callable(inst_class):
inst_class = inst_class()
inst_name = 'inst_' + str(next_inst_cnt.next())
w(indent_gggg_child + 'var ' + inst_name + ';')
w(indent_gggg_child + 'if (i < result.'+f.field_name+'.length) {')
w(indent_ggggg_child + inst_name + ' = result.'+f.field_name+'[i];')
w(indent_gggg_child + '} else {')
if inst_class == 'String':
w(indent_ggggg_child + 'result.'+f.field_name+'.push(null);')
else:
w(indent_ggggg_child + inst_name + ' = new '+inst_class+'(); // jshint ignore:line')
w(indent_ggggg_child + 'result.'+f.field_name+'.push('+inst_name+');')
w(indent_gggg_child + '}')
#if 'is_url' in f.meta:
# w(indent_gggg_child + ('\n'+indent_gggg_child).join(data_manipulation_func('json_obj.'+f.field_name,inst_name,'i')))
#else:
if 1:
w(indent_gggg_child + data_manipulation_func('json_obj.'+f.field_name+'[i]','result.'+f.field_name+'[i]'))
w(indent_ggg_child + '});')
else:
#if 'is_url' in f.meta:
# w(indent_ggg_child + ('\n'+indent_ggg_child).join(data_manipulation_func('json_obj.'+f.field_name,'result.'+f.field_name)))
#else:
w(indent_ggg_child + data_manipulation_func('json_obj.'+f.field_name,'result.'+f.field_name))
w(indent_ggg_child + 'if (child_post_resolve_promises.length) {')
w(indent_gggg_child + 'resolve(' + base_factory_name + '.$q.all(child_post_resolve_promises).then(function() { return result; }));')
w(indent_ggg_child + '} else {')
w(indent_gggg_child + 'resolve(result);')
w(indent_ggg_child + '}')
w(indent_gg_child + "});")
w(indent_g_child + '};')
w('')
w(indent_g_child + cls_name + '.prototype.save = gen_inst_save(\'' + cls.meta['url'] + '\', ' + cls_name + ');')
#w(indent_g_child + cls_name + '.prototype.save = function() {')
#w(indent_gg_child + 'var req_defer = ' + base_factory_name + '.$q.defer();')
#w(indent_gg_child + 'var self = this;')
#w(indent_gg_child + 'this.pre_save().then(function(saver) {')
#w(indent_ggg_child + "var promise;")
#w(indent_ggg_child + "if ('url' in saver) {")
#w(indent_gggg_child + 'promise = ' + base_factory_name + ".$http.put(saver.url, saver);")
#w(indent_ggg_child + "} else if ('id' in saver) {")
#w(indent_gggg_child + 'promise = ' + base_factory_name + ".$http.put(self.base_url + saver.id + '/', saver);")
#w(indent_ggg_child + '} else {')
#w(indent_gggg_child + "promise = " + base_factory_name + ".$http.post('"+cls.meta['url']+"', saver);")
#w(indent_ggg_child + '}')
#w(indent_ggg_child + '')
#w(indent_ggg_child + 'promise = promise.then(function(data) {')
#w(indent_gggg_child + 'return ' + cls_name + '.post_restore(data.data,self);')
#w(indent_ggg_child + '});')
#w(indent_ggg_child + 'promise.catch('+base_factory_name+'.log_http_error);')
#w(indent_ggg_child + 'req_defer.resolve(promise);')
#w(indent_gg_child + '});')
#w(indent_gg_child + 'return req_defer.promise;')
#w(indent_g_child + '};')
w('')
w(indent_g_child + cls_name + '.get = gen_inst_get(\'' + cls.meta['url'] + '\', ' + cls_name + ');')
# w(indent_g_child + cls_name + '.get = function(pk,destination) {')
# w(indent_gg_child + 'destination = destination || new ' + cls_name + '();')
# w(indent_gg_child + 'var post_restore_intercept = function(data) {')
# w(indent_ggg_child + 'return ' + cls_name + '.post_restore(data.data,destination);')
# w(indent_gg_child + '};')
# w(indent_gg_child + "var url = /^\w+$/.test(pk) ? '"+cls.meta['url'] + "'+pk+'/' : pk;")
# w(indent_gg_child + 'var promise = '+base_factory_name+".$http.get(url)")
# w(indent_ggg_child+ '.then(post_restore_intercept);')
# w(indent_gg_child + 'promise.catch('+base_factory_name+'.log_http_error);')
# w(indent_gg_child + 'return promise;')
# w(indent_g_child + '};')
w('')
w(indent_g_child + cls_name + '.prototype.delete = gen_inst_delete(\'' + cls.meta['url'] + '\', ' + cls_name + ');')
# w(indent_g_child + cls_name + '.prototype.delete = function() {')
# w(indent_gg_child + 'if (this.url) {')
# w(indent_ggg_child + 'return '+base_factory_name+'.$http.delete(this.url);')
# w(indent_gg_child + '} else if (this.id) {')
# w(indent_ggg_child + "return "+base_factory_name+".$http.delete(this.base_url + this.id + '/');")
# w(indent_gg_child + '} else {')
# w(indent_ggg_child + 'return '+base_factory_name+'.$q.when(null);')
# w(indent_gg_child + '}')
# w(indent_g_child + '};')
w('')
w(indent_g_child +'return ' + cls_name + ';')
w(indent_child + '})();')
w('')
else:
child_scope = module_names + [mod_class_name]
child_ref = '.'.join(child_scope[-2:])
w(indent_child + child_ref + '= {};')
w(indent_child + '(function ('+mod_class_name+') {')
OutputClasses(mod_class,module_names + [mod_class_name],indent_child)
w(indent_child + '})('+child_ref+');')
OutputClasses(base_module,[base_factory_name])
w('})('+base_factory_name+');')
w('')
w("angular.module('app').factory('"+base_factory_name+"',[")
w(" '$http', 'log_http_error', '$q',")
w(INDENT + 'function($http, log_http_error, $q) {')
def export_classes(module,print_func):
for mod_class_name,mod_class in module.iteritems():
if isinstance(mod_class,ClassDefn):
print_func(base_factory_name + '.' + '.'.join(mod_class.url_name))
else:
export_classes(mod_class,print_func)
w(INDENT*2 + base_factory_name + '.$http = $http;')
w(INDENT*2 + base_factory_name + '.log_http_error = log_http_error;')
w(INDENT*2 + base_factory_name + '.$q = $q;')
w(INDENT*2 + 'return ' + base_factory_name + ';')
w(INDENT + '}')
w(']);')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment