Repository navigation
Expand file tree
/
Copy pathrelation.coffee
More file actions
133 lines (104 loc) · 3.22 KB
/
Copy pathrelation.coffee
File metadata and controls
133 lines (104 loc) · 3.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
Spine = @Spine or require('spine')
class Collection extends Spine.Module
constructor: (options = {}) ->
for key, value of options
@[key] = value
all: ->
@model.select (rec) => @associated(rec)
first: ->
@all()[0]
last: ->
values = @all()
values[values.length - 1]
count: ->
@all().length
find: (id, notFound = @model.notFound) ->
records = @select (rec) =>
"#{rec.id}" is "#{id}"
return records[0] or notFound?(id)
findAllByAttribute: (name, value) ->
@model.select (rec) =>
@associated(rec) and rec[name] is value
findByAttribute: (name, value) ->
@findAllByAttribute(name, value)[0]
select: (cb) ->
@model.select (rec) =>
@associated(rec) and cb(rec)
refresh: (values) ->
return this unless values?
for record in @all()
delete @model.irecords[record.id]
for match, i in @model.records when match.id is record.id
@model.records.splice(i, 1)
break
values = [values] unless Array.isArray(values)
for record in values
record.newRecord = false
record[@fkey] = @record.id
@model.refresh values
this
create: (record, options) ->
record[@fkey] = @record.id
@model.create(record, options)
add: (record, options) ->
record.updateAttribute @fkey, @record.id, options
remove: (record, options) ->
record.updateAttribute @fkey, null, options
# Private
associated: (record) ->
record[@fkey] is @record.id
class Instance extends Spine.Module
constructor: (options = {}) ->
for key, value of options
@[key] = value
find: ->
@model.find(@record[@fkey])
update: (value) ->
return this unless value?
value = @model.refresh(value)[0]
@record[@fkey] = value and value.id
this
class Singleton extends Spine.Module
constructor: (options = {}) ->
for key, value of options
@[key] = value
find: ->
@record.id and @model.findByAttribute(@fkey, @record.id)
update: (value) ->
return this unless value?
value[@fkey] = @record.id
@model.refresh(value)
this
singularize = (str) ->
str.replace(/s$/, '')
underscore = (str) ->
str.replace(/::/g, '/')
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
.replace(/([a-z\d])([A-Z])/g, '$1_$2')
.replace(/(-|\.)/g, '_')
.toLowerCase()
requireModel = (model) ->
if typeof model is 'string'
require?(model) or eval(model)
else
model
association = (name, model, record, fkey, Ctor) ->
model = requireModel(model) if typeof model is 'string'
new Ctor(name: name, model: model, record: record, fkey: fkey)
Spine.Model.extend
hasMany: (name, model, fkey) ->
fkey ?= "#{underscore(this.className)}_id"
@::[name] = (value) ->
association(name, model, @, fkey, Collection).refresh(value)
belongsTo: (name, model, fkey) ->
fkey ?= "#{underscore(singularize(name))}_id"
@::[name] = (value) ->
association(name, model, @, fkey, Instance).update(value).find()
@attributes.push(fkey)
hasOne: (name, model, fkey) ->
fkey ?= "#{underscore(@className)}_id"
@::[name] = (value) ->
association(name, model, @, fkey, Singleton).update(value).find()
Spine.Collection = Collection
Spine.Singleton = Singleton
Spine.Instance = Instance