-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdaybedLib.livecodescript
More file actions
2281 lines (2049 loc) · 73.6 KB
/
daybedLib.livecodescript
File metadata and controls
2281 lines (2049 loc) · 73.6 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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
--name: libDaybed
--vers: 3.0.1
--date: 2020-10-28
--full: Daybed - A Library for Apache CouchDB
on ___DaybedDB___
end ___DaybedDB___
/*
Daybed - A Library for Apache CouchDB
contact: pink @ mad.pink (aka Greg Miller)
This is a simple library that calls CouchDB's REST functions.
---FUNCTION PARAMETERS---
pFunk - (always required) Couch function being called
pURL - (always required) the URL of the CouchDB installation, including "http://", the port numer and a trailing slash
pDB - (required when acting on or retrieving from a database) - the name of the database being accessed
pDocID - (required for most get functions) the document "_id" being retrieved
pDoc - (required for most put and post functions) array containing the data being converted into a document for the database
pParams - an array with any OPTIONAL parameters, with the parameter as a key.
pOptions - (optional) header options, including user and pass (see "Authentication"), also used in "config" operations
Output format:
-include pOptions["format"] with "array", "rawjson" or "prettyjson" for the return format
-the stack can have a customProperty called "preferredFormat" which can be one of those three values,
-if pOptions["format"] is blank, then "preferredFormat" will be used, if it is not set, then "array" will be used
*/
local jsonLibName = "fastJSON" --valid values: fastJSON, mergJSON, easyJSON
on ___CouchDB_Main_Functions___
/*
Function Parameters
pFunk (required) - CouchDB function being called; the leading underscore can be omitted, for example "all_docs"
pURL (required) - the URL of the CouchDB installation, including "https://" and the port number if applicable
--With username/password: "http://admin:trustno1@192.168.23.42:5984/"
pDB (required with database, doc and design-doc actions) - the name of the database being accessed
pDocID (required when GETting, or DELETEing a document) (optional when creating a doc) the document "_id" being retrieved
--should be blank for system and database functions
--use the pDocID param to specify the name of a design document being called
pDoc (required for PUTting and POSTing documents) array containing the data being converted into a document for the database
--should be blank for system functions
--required for document and design document (also used in a db function)
pParams (optional) - an array with any OPTIONAL parameters, with the parameter as a key.
--These parameters are specified in the CouchDB API
--For example: to download documents when running the _all_docs function, and limit the list to only 10 records:
----put true into pParams["include\_docs"]
----put 10 into pParams["limit"]
--Example, to include the revision number for a document
----put "13-8j4f9438jf3498j98fy39d23d" into pParams["rev"]
pOptions (optional) - header options, including authentication, config values and return format
--For Design Documents, use the following options:
----pOptions["ddoc"]["func"] for the function being called (info, view, show, list, update)
----pOptions["ddoc"]["name"] for the name of the specific function programmed in the ddoc
----pOptions["ddoc"]["otherid"] and pOptions["ddoc"]["otherfunc"] for further extended URLs
--For Authentication, use the following options:
----pOptions["authtype"] for the type of authentication being used, valid values:
------"login" - default value if blank, must be in the format username:password
------"encoded" - base64 encoded version of username:password
------"cookie" - cookie-based login
----pOptions["authval"] with the login, encoded login or cookie value
--To set the return format:
----pOptions["format"] with a valid format value (array, rawjson, prettyjson)
--When setting _config values:
----pOptions["key"] with the key to be set
----pOptions["value"] with the value to set it to
--When PUTting an attachment (using the "attach" function): (If left blank, the script will attempt to fill in an applicable type)
----pOptions["attachname"] with the file name to be used in CouchDB
----pOptions["attachpath"] with the full path to the file being uploaded
----pOptions["attachmode"] with "bin" or "text", "bin" will be used if left blank
----pOptions["attachtype"] with the MIME content-type, for example "image/jpg" or "application/pdf"
--When PUTting an attachment (inline), Repeat for each file to be included
----pOptions["attachments"][filename]["path"] with the full file path of the file to be uploaded
----pOptions["attachments"][filename]["mime"] with the MIME content-type of the file
----pOptions["attachments"][filename]["mode"] with "bin" or "text", with "bin" used as default
--When GETting an attachment:
----pOptions["attachment"] with the file name in DB
----pOptions["destination"] with the destination location (include filename)
*/
end ___CouchDB_Main_Functions___
function couch.get pFunk pURL pDB pDocID pParams pOptions
-----
local tURL, tResult
-----
switch pFunk
case "db"
put empty into pDocID
put empty into pFunk
break
case "localdoc"
put "_local/" before pDocID
case "doc"
put empty into pFunk
break
case "slash"
put empty into pFunk
break
case "ddoc-view"
case "ddoc-list"
case "ddoc-show"
case "ddoc-update"
put char 6 to -1 of pFunk into pOptions["ddoc"]["func"]
case "design"
case "ddoc"
put couch.ddoc(pDocID,pOptions) into pDocID
put empty into pFunk
break
case "_config"
case "config"
if char 1 of pFunk is not "_" then put "_" before pFunk
put pOptions["section"] into pDocID
if pOptions["key"] is not empty then
put slash & pOptions["key"] after pDocID
end if
break
case "attach"
put empty into pFunk
put "/" & pOptions["attachment"] after pDocID
break
default
if char 1 of pFunk is not "_" then put "_" before pFunk
break
end switch
couch.setHeaders pOptions
put couch.DBURL(pURL,pDB,pParams,pFunk,pDocID) into tURL
if pOptions["destination"] is not empty then
libURLDownloadToFile tURL, pOptions["destination"]
return "Done"
else
put URL(tURL) into tResult
end if
return couch.returnFormat(tResult,pOptions["format"])
end couch.get
function couch.put pFunk pURL pDB pDoc pParams pOptions
-----
local tURL, tResult, tRaw, temp, tFunktion, tDocID, tPath, tJson
-----
put pFunk into tFunktion
switch pFunk
case "db"
put empty into pDoc
put empty into pFunk
break
case "localdoc"
put empty into pFunk
put "_local/" & pDoc["_id"] into tDocID
break
case "doc"
put empty into pFunk
put pDoc["_id"] into tDocID
break
case "attach"
put empty into pFunk
put pOptions["docid"] & "/" & pOptions["attachname"] into tDocID
break
case "ddoc-view"
case "ddoc-list"
case "ddoc-show"
case "ddoc-update"
put char 6 to -1 of pFunk into pOptions["ddoc"]["func"]
case "design"
case "ddoc"
put pDoc["_id"] into tDocID
put couch.ddoc(tDocID,pOptions) into tDocID
put empty into pFunk
break
case "_config"
case "config"
if char 1 of pFunk is not "_" then put "_" before pFunk
put pOptions["section"] into tDocID
if pOptions["key"] is not empty then
put slash & pOptions["key"] after tDocID
end if
break
case "users"
put "org.couchdb.user:" & pDoc["name"] into tDocID
put tDocID into pDoc["_id"]
put "_users" into pDB
put empty into pFunk
break
default
if char 1 of pFunk is not "_" then put "_" before pFunk
break
end switch
if pOptions["attachments"] is not empty then
put couch.attachments(pOptions["attachments"]) into pDoc["_attachments"]
end if
couch.setHeaders pOptions
put couch.DBURL(pURL,pDB,pParams,pFunk,tDocID) into tURL
switch tFunktion
case "db"
put empty into URL(tURL)
break
case "_config"
put quote & pOptions["value"] & quote into pDoc
put pDoc into URL(tURL)
break
case "_revs_limit"
put pDoc into URL(tURL)
break
case "attach"
put couch.aType(pOptions["attachmode"],pOptions["attachpath"]) into tPath
put URL(tPath) into URL(tURL)
break
default
put a2j(pDoc) into tJson
replace "[null]" with "[]" in tJson
put tJson into URL(tURL)
break
end switch
put the urlResponse into tResult
return couch.returnFormat(tResult,pOptions["format"])
end couch.put
function couch.post pFunk pURL pDB pDoc pParams pOptions
-----
local tURL, tResult, tJson, tDocID
-----
switch pFunk
case "db"
put empty into pFunk
break
case "changes"
put "_doc_ids" into pParams["filter"]
break
case "compactdesign"
put "_compact" into pFunk
put pDoc into tDocID
break
case "ddoc-view"
case "ddoc-list"
case "ddoc-show"
case "ddoc-update"
put char 6 to -1 of pFunk into pOptions["ddoc"]["func"]
case "design"
case "ddoc"
put pDoc["_id"] into tDocID
put couch.ddoc(tDocID,pOptions) into tDocID
put empty into pFunk
break
default
if char 1 of pFunk is not "_" then put "_" before pFunk
break
end switch
couch.setHeaders pOptions
put a2j(pDoc) into tJson
put couch.DBURL(pURL,pDB,pParams,pFunk,tDocID) into tURL
post tJson to URL(tURL)
put the urlResponse into tResult
switch pFunk
case "_session"
return couch.cookie(tResult)
break
default
return couch.returnFormat(tResult,pOptions["format"])
break
end switch
end couch.post
function couch.delete pFunk pURL pDB pDocID pParams pOptions
-----
local tURL, tResult
-----
switch pFunk
case "db"
put empty into pDocID
put empty into pFunk
break
case "attach"
put empty into pFunk
put "/" & pOptions["attachment"] after pDocID
break
case "doc"
put empty into pFunk
break
case "localdoc"
put empty into pFunk
put "_local/" before pDocID
break
default
if char 1 of pFunk is not "_" then put "_" before pFunk
break
end switch
couch.setHeaders
put couch.DBURL(pURL,pDB,pParams,pFunk,pDocID) into tURL
delete URL(tURL)
put the urlResponse into tResult
return couch.returnFormat(tResult,pOptions["format"])
end couch.delete
function couch.adduser pURL pUser pPass pOptions
/*
pURL - URL of the CouchDB instance
pUser - username of new user
pPass - password of new user
pOptions - additional options:
--pOptions["makedatabase"] contains info for creating a user specific database (NOTE: key cannot be blank if none of the options below
are being included, something must be filled in)
----pOptions["makedatabase"]["dbonly"] (boolean) creates only the database, does not create a new user
----pOptions["makedatabase"]["prefix"] (string) prefix to be used when creating the database, defaults to "user_"
--pOptions["format"] - return format of the response
--pOptions["roles"] - roles as defined in the CouchDB instance
--pOptions["userdata"] - additional user data
--pOptions["registration"] - optional registration information
*/
-----
local tResult, tReturnFormat, tUser, tDBName
-----
if pOptions["makedatabase"]["dbonly"] is not true then
put pOptions["format"] into tReturnFormat
put "json" into pOptions["format"]
put pUser into tUser["name"]
put pPass into tUser["password"]
put "user" into tUser["type"]
if pOptions["roles"] is not empty then
put pOptions["roles"] into tUser["roles"]
else
put empty into tUser["roles"][1]
end if
if pOptions["userdata"] is not empty then put pOptions["userdata"] into tUser["userdata"]
if pOptions["registration"] is not empty then put pOptions["registration"] into tUser["registration"]
put couch.put("users",pURL,,tUser,,pOptions) into tResult
end if
if pOptions["makedatabase"] is not empty then
put couch.userDB(pUser, pOptions["makedatabase"]["prefix"]) into tDBName
put couch.put("db", pURL, tDBName) into tResult
end if
-- TODO: combine these "results"
return couch.returnFormat(tResult,tReturnFormat)
end couch.adduser
function couch.securedb pFunk pURL pDB pOptions pAdminNames pAdminRoles pMemberNames pMemberRoles
/*
pFunk - "set" (replace current security), "add" adds user/roles to existing security, "delete" removes user/roles from existing
pAdminNames: sets the given names up with admin rights (read,write,delete all)
pAdminRoles: sets the given user roles up with admin rights (read,write,delete all)
pMemberNames: sets the given names up with member rights (read, write documents/read design documents)
pMemberRoles: sets the given user roles up with member rights (read, write documents/read design documents)
*/
-----
local returnFormat,tSecurity
local tResult
-----
put pOptions["format"] into returnFormat
put "json" into pOptions["format"]
switch pFunk
case "set"
case "replace"
put "_security" into tSecurity["_id"]
put c2a(pAdminNames) into tSecurity["admins"]["names"]
put c2a(pAdminRoles)into tSecurity["admins"]["roles"]
put c2a(pMemberNames) into tSecurity["members"]["names"]
put c2a(pMemberRoles) into tSecurity["members"]["roles"]
put couch.put("doc",pURL,pDB,tSecurity,,pOptions) into tResult
break
case "get"
put couch.get("doc",pURL,pDB,"_security",,pOptions) into tResult
break
case "add"
put "array" into pOptions["format"]
put couch.get("doc",pURL,pDB,"_security",,pOptions) into tSecurity
put "_security" into tSecurity["_id"]
put add2list(pAdminNames,tSecurity["admins"]["names"]) into tSecurity["admins"]["names"]
put add2list(pAdminRoles,tSecurity["admins"]["roles"]) into tSecurity["admins"]["roles"]
put add2list(pMemberNames,tSecurity["members"]["names"]) into tSecurity["members"]["names"]
put add2list(pMemberRoles,tSecurity["members"]["roles"]) into tSecurity["members"]["roles"]
put "json" into pOptions["format"]
put couch.put("doc",pURL,pDB,tSecurity,,pOptions) into tResult
break
case "remove"
case "delete"
put "array" into pOptions["format"]
put couch.get("doc",pURL,pDB,"_security",,pOptions) into tSecurity
put "_security" into tSecurity["_id"]
put delFromlist(pAdminNames,tSecurity["admins"]["names"]) into tSecurity["admins"]["names"]
put delFromlist(pAdminRoles,tSecurity["admins"]["roles"]) into tSecurity["admins"]["roles"]
put delFromlist(pMemberNames,tSecurity["members"]["names"]) into tSecurity["members"]["names"]
put delFromlist(pMemberRoles,tSecurity["members"]["roles"]) into tSecurity["members"]["roles"]
put "json" into pOptions["format"]
put couch.put("doc",pURL,pDB,tSecurity,,pOptions) into tResult
break
end switch
return couch.returnFormat(tResult,returnFormat)
end couch.securedb
function couch.dbdb pCouch
/*
This function does all of the above with an array instead of individual
parameters
pCouch["verb"]
pCouch["url"]
pCouch["funk"]
pCouch["options"]
pCouch["params"]
pCouch["doc"]
pCouch["docid"]
*/
-----
local tFormat, tResult
-----
put pCouch["options"]["format"] into tFormat
if pCouch["load"] is not empty then put dbdb.useSavedCouch(pCouch) into pCouch
put "json" into pCouch["options"]["format"]
switch pCouch["verb"]
case "get"
put couch.get(pCouch["funk"],pCouch["url"],pCouch["db"],pCouch["docid"],pCouch["params"],pCouch["options"]) into tResult
break
case "put"
put couch.put(pCouch["funk"],pCouch["url"],pCouch["db"],pCouch["doc"],pCouch["params"],pCouch["options"]) into tResult
break
case "post"
put couch.post(pCouch["funk"],pCouch["url"],pCouch["db"],pCouch["doc"],pCouch["params"],pCouch["options"]) into tResult
break
case "delete"
put couch.delete(pCouch["funk"],pCouch["url"],pCouch["db"],pCouch["docid"],pCouch["params"],pCouch["options"]) into tResult
break
case "adduser"
put couch.adduser(pCouch["url"],pCouch["user"],pCouch["pass"],pCouch["options"],pCouch["addDB"]) into tResult
break
case "securedb"
put couch.securedb(pCouch["funk"],pCouch["url"],pCouch["db"],pCouch["adminnames"],pCouch["adminroles"],pCouch["membernames"],pCouch["memberroles"]) into tResult
break
end switch
return couch.returnFormat(tResult,tFormat)
end couch.dbdb
/*
command couch.db.example
local tCouch, tResults
put "get" into tCouch["verb"]
put "192.168.23.42:5984" into tCouch["url"]
put "doc" into tCouch["funk"]
put "rec541" into tCouch["docid"]
put "admin" into tCouch["options"]["user"]
put "trustno1" into tCouch["options"]["pass"]
put couch.dbdb(tCouch) into tResults
end couch.db.example
*/
on ___Sofa_CouchDB_Quick_Functions___
/*
These are simplified functions that require less params.
The assumption here is that a single user, single URL and a single DB will be used all along
sofa.init is used to save this information into script local variables
if the database is a user's database, then the prefix including the "_" should be added (name will be generated)
pDatabase in the functions below is always optional, is used for a db other than the database set in sofa.init
*/
end ___Sofa_CouchDB_Quick_Functions___
local sCouchURL = "http://127.0.0.1:5984"
local sDatabase = "test"
local sAuthentication = ""
command sofa.init pDB pUser pPass pURL
if pURL is not empty then put pURL into sCouchURL
if pDB is not empty then
if char -1 of pDB is "_" then
put couch.userDB(pUser,pDB) into sDatabase
else
put pDB into sDatabase
end if
end if
if pUser is not empty then put base64encode(pUser & colon & pPass) into sAuthentication
end sofa.init
function sofa.getdoc pDocID pParams pDatabase
return couch.get("doc",sCouchURL,sofa.dbname(pDatabase),pDocID,sofa.auth(),pParams)
end sofa.getdoc
function sofa.putdoc pDoc pParams pDatabase
return couch.put("doc",sCouchURL,sofa.dbname(pDatabase),pDoc,sofa.auth(),pParams)
end sofa.putdoc
function sofa.alldocs pInclude pParams pDatabase
--if pInclude then put true into pCDB["params"]["include_docs"]
if pInclude then put true into pParams["include_docs"]
return couch.get("all_docs",sCouchURL,sofa.dbname(pDatabase),,pParams,sofa.auth())
end sofa.alldocs
function sofa.changes pLast pInclude pParams pDatabase
local tCDB
if pLast is not empty then put pLast into tCDB["params"]["since"]
if pInclude then put true into tCDB["params"]["include_docs"]
return couch.get("changes",sCouchURL,sofa.dbname(pDatabase),,sofa.auth(),pParams)
end sofa.changes
function sofa.ddoc pDdoc pType pName pInclude pParams pDatabase
local tCDB
if pInclude then put true into tCDB["params"]["include_docs"]
put pType into tCDB["options"]["ddoc"]["func"]
put pName into tCDB["options"]["ddoc"]["xtend"]
put couch.get("design",sCouchURL,sofa.dbname(pDatabase),pDdoc,sofa.auth(),pParams)
end sofa.ddoc
private function sofa.dbname pDB
if pDatabase is empty then
return sDatabase
else
return pDatabase
end if
end sofa.dbname
private function sofa.auth
local tOptions
put sAuthentication into tOptions["authval"]
put "encoded" into tOptions["authtype"]
return tOptions
end sofa.auth
on ___DaybedDB_LocalProp_Sync__
end ___DaybedDB_LocalProp_Sync__
function dbdb.local.newuser pURL pUser pPass pAuth pPrefix pOther pConflict pIDPrefix pApp pPurge pType
/*
pURL - full URL including port
pPrefix - prefix of the db name (e.g. "user", "mppb")
pUser - username
pPass - password
pOther - (optional) array of other data to be saved in _users
pConflict - (optional - defaults to server) local, server, duplicate
pAuth - (optional if "Admin party" is in effect) the admin authorization string
pIDPrefix - (optional) prefix for id numbers based on milliseconds
for userDB:
pApp - (optional for userdb) application name for searches
for appDB:
pApp - application db name
pPurge - (optional) how often to purge deleted docs */
-----
local tSettings
-----
set the customPropertySet of this stack to "daybedDB"
if pType is "appdb" then
put dbdb.appdb.createuser(pURL,pApp,pUser,pPass,pConflict,pAuth,pOther,pPurge) into tSettings
else
put dbdb.userdb.createuser(pURL,pPrefix,pUser,pPass,pConflict,pAuth,pOther,pIDPrefix,pApp,pPurge) into tSettings
end if
set the "_dbdbsettings" of this stack to tSettings["dbdb"]
return tSettings
end dbdb.local.newuser
command dbdb.local.addsetting pKey pVal
---
local tSettings
---
set the customPropertySet of this stack to "daybedDB"
put the _dbdbsettings of this stack into tSettings
put pVal into tSettings[pKey]
set the _dbdbsettings of this stack to tSettings
end dbdb.local.addsetting
command dbdb.local.sync
------
local currentData, revisedData, tResult
------
put the customProperties["daybedDB"] of this stack into currentData
if currentData["_dbdbsettings"] is empty then
put "Error: Not setup, run dbdb.newuser" into tResult["errorcode"]
put true into tResult["error"]
return tResult
end if
put dbdb.sync(currentData) into revisedData
if not revisedData["error"] then
set the customProperties["daybedDB"] of this stack to revisedData
put true into tResult["ok"]
return tResult
else
return revisedData
end if
end dbdb.local.sync
command dbdb.local.setdoc pDoc pDelete
-----
local tID, tSett
-----
put the daybedDB["_dbdbsettings"] of this stack into tSett
if pDoc["_id"] is empty then put dbdb.newdocid(tSett) into pDoc["_id"]
put pDoc["_id"] into tID
put the seconds into pDoc["dbdb"]["lastupdated"]
put tSett["appname"] into pDoc["dbdb"]["app"]
if pDoc["_rev"] is not empty then
put "update" into pDoc["dbdb"]["flag"]
else
put "new" into pDoc["dbdb"]["flag"]
put 0 into pDoc["dbdb"]["lastsync"]
end if
put tSett["idprefix"] & pDoc["dbdb"]["lastsync"] into pDoc["dbdb"]["syncid"]
set the daybedDB[tID] of this stack to pDoc
end dbdb.local.setdoc
command dbdb.local.deletedoc pDocID
-----
local tDoc
-----
put the daybedDB[pDocID] of this stack into tDoc
put "delete" into tDoc["dbdb"]["flag"]
put the seconds into tDoc["dbdb"]["lastupdated"]
set the daybedDB[pDocID] of this stack to tDoc
end dbdb.local.deletedoc
function dbdb.local.getdoc pDocID
return the daybedDB[pDocID] of this stack
end dbdb.local.getdoc
on ___DaybedDB_Local_Save_File___
/*
*/
end ___DaybedDB_Local_Save_File___
command dbdb.savedata pFileName pMainFolder pSubFolder pType pStackName
-----
local tData, tFileNamePath
-----
if pFileName is empty then put the short name of this stack & "_data" into pFileName
put getFilePath(pMainFolder,pSubFolder,pFileName) into tFileNamePath
put the customproperties["daybedDB"] of this stack into tData
switch pType
case "file"
put arrayEncode(tData) into URL("binfile:" & tFileNamePath)
break
case "json"
put a2j(tData,,true) into URL("file:" & tFileNamePath)
break
default --stack (pType is Property set name)
if pType is empty then put "daybedDB" into pType
if pStackName is empty then
set itemdel to period
put item 1 to -2 of pFileName into pStackName
end if
if pFileName is not among the lines of the mainStacks then
dbdb.loaddata pFileName, pMainFolder, pSubFolder, pType, pStackName
end if
put the customproperties["daybedDB"] of this stack into tData
set the customProperties[pType] of stack pStackName to tData
save stack pStackName as pFileName
break
end switch
end dbdb.savedata
command dbdb.loaddata pFileName pMainFolder pSubFolder pType pStackName
-----
local tData, tFileNamePath
-----
if pFileName is empty then put the short name of this stack & "_data" into pFileName
put getFilePath(pMainFolder,pSubFolder,pFileName) into tFileNamePath
put the customproperties["daybedDB"] of this stack into tData
switch pType
case "file"
if there is a file tPath then
put URL("binfile:" & pFileName) into tData
set the customproperties["daybedDB"] of this stack to arrayDecode(tData)
end if
break
case "json"
if there is a file pFileName then
put URL("file:" & pFileName) into tData
set the customproperties["daybedDB"] of this stack to j2a(tData)
end if
break
default --stack (pType is Property set name)
if pType is empty then put "daybedDB" into pType
if pStackName is empty then
set itemdel to period
put item 1 to -2 of pFileName into pStackName
end if
if pStackName is not among the lines of the mainStacks then
if there is no file pFileName then
create invisible stack pFileName
save stack pFileName as tFileNamePath
return true
else
open invisible stack tFileNamePath
put the customProperties[pType] of stack pFileName into tData
set the customproperties["daybedDB"] of this stack to tData
end if
end if
break
end switch
end dbdb.loaddata
on ___DaybedDB_User_Functions__
end ___DaybedDB_User_Functions__
function dbdb.appdb.createdb pURL pDB pAuth
-----
local tResult, tOptions, tSettings
-----
if pAuth is not empty then
put pAuth into tOptions["authval"]
put "encoded" into tOptions["authtype"]
end if
put couch.put("db",pURL,PDB,,,tOptions) into tResult["db"]
put couch.put("doc",pURL,tSettings["db"],dbdb.appdbdesigndoc(),,tOptions) into tResult["ddoc"]
return tResult
end dbdb.appdb.createdb
function dbdb.appdb.createuser pURL pDB pUser pPass pConflict pAuth pOther pPurge
------
local tOptions, tSettings, tUser, tResult, tOther
------
if pAuth is not empty then
put pAuth into tOptions["authval"]
put "encoded" into tOptions["authtype"]
end if
put urlencode(pUser) into pUser
---create Settings
put "appdb" into tSettings["type"]
put pURL into tSettings["url"]
put pDB into tSettings["db"]
put pAuth into tSettings["auth"]
put 0 into tSettings["lastsync"]
put czVal(pConflict,"server") into tSettings["conflict"]
put pUser into tSettings["idprefix"]
put czVal(pPurge,30) into tSettings["purge"]
put encodeUserPass(pUser,pPass) into tSettings["userauth"]
put "dbdbid_" & pUser into tSettings["userdoc"]
put pOther into tSettings["userdata"]
---create User Doc
put "dbdbid_" & pUser into tUser["_id"]
put the seconds into tUser["datestamp"]
put encodeUserPass(pUser,pPass,tUser["datestamp"]) into tUser["userauth"]
put pOther into tUser["userdata"]
put couch.put("doc",pURL,pDB,tUser,tOther) into tResult
if tResult["ok"] is not true and tResult["error"] is "conflict" then
put dbdb.appdb.login(tSettings) into tResult
if tResult["reason"] is "login_failed" then
put empty into tSettings
put true into tSettings ["error"]
put "user_exists" into tSettings["reason"]
else
put tResult["_rev"] into tSettings["userrev"]
end if
else
put tResult["rev"] into tSettings["userrev"]
end if
return tSettings
end dbdb.appdb.createuser
function dbdb.appdb.login pSett
---
local tResult, tOptions, tAuth
---
if tAuth is not empty then
put pSett["auth"] into tOptions["authval"]
put "encoded" into tOptions["authtype"]
end if
put couch.get("doc",pSett["url"],pSett["db"],pSett["userdoc"],tOptions) into tResult
if tResult["userauth"] is not pSett["userauth"] then
put empty into tResult
put true into tResult["error"]
put "login_failed" into tResult["reason"]
end if
return tResult
end dbdb.appdb.login
function dbdb.userdb.createuser pURL pPrefix pUser pPass pConflict pAuth pOther pIDPrefix pAppName pPurge
------
local tOptions, tSettings, tResult
------
if pAuth is not empty then
put pAuth into tOptions["authval"]
put "encoded" into tOptions["authtype"]
end if
put couch.authval(pUser,pPass) into tSettings["auth"]
get binarydecode("H*",pUser,tSettings["db"])
put czVal(pPrefix,"user") & "_" before tSettings["db"]
put pURL into tSettings["url"]
put 0 into tSettings["lastsync"]
put "userdb" into tSettings["type"]
put czVal(pConflict,"server") into tSettings["conflict"]
put czVal(pIDPrefix,"user") into tSettings["idprefix"]
put czVal(pAppName,tSettings["idprefix"]) into tSettings["appname"]
put czVal(pPurge,30) into tSettings["purge"]
put pOther into tSettings["userdata"]
put tSettings into tResult["dbdb"]
put pOther into tOptions["userdata"]
put couch.adduser(pURL,pUser,pPass,tOptions) into tResult["user"]
put couch.put("db",pURL,tSettings["db"],,,tOptions) into tResult["db"]
put couch.put("doc",pURL,tSettings["db"],dbdb.appdesigndoc(tSettings["appname"]),,tOptions) into tResult["ddoc"]
put couch.securedb("set",pURL,tSettings["db"],tOptions,pUser,,pUser) into tResult["security"]
return tResult
end dbdb.userdb.createuser
on ___DaybedDB_Sync_Functions__
end ___DaybedDB_Sync_Functions__
function dbdb.sync pArray pForceFull
/*
Settings are passed in pArray["_dbdbsettings"]
*/
--TODO: add audit trail with revision numbers and timestamps?
-----
local tKey, dbName, dbURL, dbDdoc, tOptions, tParams, syncTime, tNewID
local upList, upDocs, downList, downDocs
local tempID, tRevS, tRevL, tCnt
-----
put pArray["_dbdbsettings"]["lastsync"] into tParams["startkey"]
put the seconds into syncTime
put syncTime into pArray["_dbdbsettings"]["lastsync"]
put pArray["_dbdbsettings"]["db"] into dbName
put pArray["_dbdbsettings"]["url"] into dbURL
put pArray["_dbdbsettings"]["auth"] into tOptions["authval"]
put "encoded" into tOptions["authtype"]
--scan local data for flagged changes and copy into upDocs
repeat for each key tKey in pArray
if char 1 of tKey is "_" then next repeat
if pArray[tKey]["dbdb"]["flag"] is empty or pArray[tKey]["dbdb"]["flag"] is "synced" then next repeat
if pArray[tKey]["dbdb"]["flag"] is "delete" then put true into pArray[tKey]["dbdb"]["deleted"]
if pArray[tKey]["dbdb"]["deleted"] then put "delete" into pArray[tKey]["dbdb"]["flag"]
put pArray["_dbdbsettings"]["lastsync"] into pArray[tKey]["dbdb"]["lastsync"]
put empty into pArray[tKey]["dbdb"]["flag"]
put pArray[tKey] into upDocs["docs"][tKey]
if pArray[tKey]["_delete"] then delete variable pArray[tKey]
end repeat
--download list with ddoc using synctime as key filter
if pArray["_dbdbsettings"]["type"] is "appdb" then
put "daybedusers" into dbDdoc
else
put "daybed" & pArray["_dbdbsettings"]["appname"] into dbDdoc
end if
put "view" into tOptions["ddoc"]["func"]
put "app" into tOptions["ddoc"]["name"]
put couch.get("design",dbURL,dbName,dbDdoc,tParams,tOptions) into downList
--scan change log, record by record
repeat for each key tKey in downList["rows"]
put downList["rows"][tKey]["value"]["id"] into tempID
--for later, we'll double check that all documents are on server
put tempID & cr after downlist["idlist"]
--skip documents not related if applicable
if pArray["_dbdbsettings"]["idprefix"] is not empty and pArray["_dbdbsettings"]["idprefix"] is not "uuid" then
if not(tempID begins with pArray["_dbdbsettings"]["idprefix"]) then next repeat
end if
--delete documents locally that have been deleted on the server
if downList["rows"][tKey]["value"]["deleted"] then
delete variable pArray[tempID]
next repeat
end if
--if document doesn't exist locally, flag it for download
if pArray[tempID] is empty then
put tempID into downDocs["keys"][tKey]
next repeat
end if
--compare revision numbers
set itemdel to "-"
put item 1 of downList["rows"][tKey]["value"]["rev"] into tRevS
put item 1 of pArray[tempID]["_rev"] into tRevL
if tRevL = tRevS then next repeat
if tRevL > tRevS then
--This shouldn't happen
--This resets the revID and reuploads the doc
--Unless it is already flagged for upload, in which case rev is updated
if upDocs[tempID] is empty then
put pArray[tempID] into upDocs["docs"][tempID]
put downList["rows"][tKey]["value"]["rev"] into upDocs["docs"][tempID]["_rev"]
else if pArray[tempID] is not empty then
put downList["rows"][tKey]["value"]["rev"] into pArray[tempID]["_rev"]
end if
next repeat
end if
if tRevL < tRevS then
--If the local doc hasn't been updated, it will be updated
if upDocs["docs"][tempID] is empty then
put tempID into downDocs["keys"][tKey]
next repeat
end if
put "server" into pArray["_dbdbsettings"]["conflict"]
--if the local doc has been updated and the server doc has been updated:
switch pArray["_dbdbsettings"]["conflict"]
case "local"
put downList["rows"][tKey]["value"]["rev"] into upDocs["docs"][tempID]["_rev"]
break
case "server"
put tempID into downDocs["keys"][tKey]
break
case "duplicate"
put tempID into downDocs["keys"][tKey]
delete variable upDocs["docs"][tempID]
put dbdb.newdocid() into tNewID
put pArray[tempID] into upDocs["docs"][tNewID]
put pArray[tempID] into pArray[tNewID]
delete variable upDocs["docs"][tNewID]["_rev"]
break
end switch
end if
end repeat
--doublecheck that all local files are on server
repeat for each key tKey in pArray
if char 1 of tKey is "_" then next repeat
if tKey is among the lines of downList["idlist"] then next repeat
if pArray["_dbdbsettings"]["lastsync"] is not empty then next repeat
put pArray[tKey] into upDocs["docs"][tKey]
end repeat
--upload local docs that are new or have been modified
if upDocs["docs"] is not empty then
put jsonArrayMaker(upDocs["docs"]) into upDocs["docs"]
put couch.post("bulk_docs",dbURL,dbName,upDocs,tParams,tOptions) into upList
repeat for each key tKey in upList
put upList[tKey]["id"] into tempID
if pArray[tempID]["_deleted"] then
delete variable pArray[tempID]
else
put upList[tKey]["rev"] into pArray[tempID]["_rev"]
end if
end repeat
end if
--download server docs that are new or have been modified
if downDocs["keys"] is not empty then
put empty into tParams
put true into tParams["include_docs"]
put jsonArrayMaker(downDocs["keys"]) into downDocs["keys"]
put couch.post("all_docs",dbURL,dbName,downDocs,tParams,tOptions) into downList
repeat for each key tKey in downList["rows"]
put downList["rows"][tKey]["id"] into tempID
put downList["rows"][tKey]["doc"] into pArray[tempID]
end repeat
end if
delete variable pArray[empty]
repeat for each key tKey in pArray
if char 1 of tKey is "_" then next repeat
put "synced" into pArray[tKey]["dbdb"]["flag"]
end repeat
return pArray