forked from countable/json-crud
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.coffee
executable file
·152 lines (122 loc) · 4.91 KB
/
index.coffee
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
fs = require 'fs'
exec = require('child_process').exec
_ = require 'underscore'
async = require 'async'
debounce = require './lib/debounce'
path = require 'path'
# A JSON filesystem store allowing read-all and write-one ops.
# It should be concurrency safe WITHIN A SINGLE PROCESS.
module.exports = (db_name, options = {})->
collections = {}
dirty_collections = {} # Keep track of which collections need cleaned
db_name += '.db'
if options.db_location
db_name = path.join options.db_location, db_name
if options.url_path
url_path = options.url_path + 'data/'
else
url_path = '/data/'
exec 'mkdir -p '+db_name, (err,out,serr)->
if err then throw err
mark_dirty = (collection)->
dirty_collections[collection] = 1
commit()
flush = (done)->
async.map (Object.keys dirty_collections), (collection, callback)->
filename = db_name+"/"+collection+".json"
console.log 'writing', filename
fs.writeFile filename, JSON.stringify(collections[collection], null, 2), (err)->
throw err if err
callback()
, ->
dirty_collections = {}
done?()
# Flush to disk at most once per 100ms
commit = debounce flush, 200
api =
# Drop a collection
drop: (collection, done)->
# Ensure collections exists before we can delete it.
@collection collection, =>
# Clear memory cache of collection.
collections[collection] = null
# Clear collection dirty marker (preventing re-creation)
if dirty_collections[collection]
delete dirty_collections[collection]
# Delete the JSON DB file.
fs.unlink db_name+"/"+collection+".json", (err)->
if err then throw err
done()
collection: (collection, done)->
filename = db_name+"/"+collection+".json"
load_collection = ->
fs.readFile filename, (err, result)->
if err then throw err
if not collections[collection] # Check this again to protect against race conditions.
collections[collection] = JSON.parse result + ''
done err
if collections[collection]?
done null
else # Check if collection exists - if so, load from disk.
fs.exists filename, (exists)->
if exists
load_collection()
else
collections[collection] = []
mark_dirty collection
flush -> # Forced flush when a new collection's created.
done null
# Passes all records in the collection to a callback @param done()
all: (collection, done)->
@collection collection, =>
done null, collections[collection]
del: (collection, record, done)->
if typeof record isnt 'object'
record =
_id: record
@collection collection, =>
collections[collection] = _.filter collections[collection], (row)->
row._id isnt record._id
mark_dirty collection
done?()
put: (collection, record, done)->
# Ensure the collection is loaded before saving an item to it.
@collection collection, =>
if record._id
collections[collection] = _.filter collections[collection], (row)-> row._id isnt record._id
collections[collection].push record
mark_dirty collection
done?()
# Take an express app and expose a collection via a rest interface, defined as follows:
restify: (app)->
store = @
app.get url_path + ":collection/:id/del", (req, res)->
store.del req.params.collection, {_id: req.params.id}, (err)->
res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0')
res.send {success: not err, message: err or ''}
app.get url_path + ":collection", (req,res)->
store.all req.params.collection, (err, results)->
if err then throw err
res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0')
res.send results
counter = 0
post_json = (req,res)->
req.params.id ?= (new Date).valueOf() + '' + counter
counter += 1
obj = JSON.parse req.body.data
obj._id ?= req.params.id
store.put req.params.collection, obj, (err)->
res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0')
res.send {success: not err, message: err or ''}
app.post url_path + ":collection/:id", post_json
app.post url_path + ":collection", post_json
collections: (done)->
exec 'mkdir -p '+db_name, (err,out,serr)->
if err then throw err
fs.readdir db_name, (err, files)->
if err then throw err
async.map files, (file, callback)->
file = file.replace ".json", ""
api.collection file, callback
, ->
done collections