parse-stack-next 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.bundle/config +2 -0
- data/.env.sample +112 -0
- data/.env.test +10 -0
- data/.github/workflows/ruby.yml +36 -0
- data/.gitignore +49 -0
- data/.ruby-version +1 -0
- data/.solargraph.yml +22 -0
- data/CHANGELOG.md +5816 -0
- data/Gemfile +30 -0
- data/Gemfile.lock +175 -0
- data/LICENSE.txt +23 -0
- data/Makefile +63 -0
- data/README.md +5655 -0
- data/Rakefile +573 -0
- data/bin/console +38 -0
- data/bin/parse-console +136 -0
- data/bin/server +17 -0
- data/bin/setup +7 -0
- data/config/parse-config.json +12 -0
- data/docs/TEST_SERVER.md +271 -0
- data/docs/_config.yml +1 -0
- data/docs/mcp_guide.md +3484 -0
- data/docs/mongodb_direct_guide.md +1348 -0
- data/docs/mongodb_index_optimization_guide.md +631 -0
- data/examples/transaction_example.rb +219 -0
- data/lib/parse/acl_scope.rb +728 -0
- data/lib/parse/agent/cancellation_token.rb +80 -0
- data/lib/parse/agent/constraint_translator.rb +480 -0
- data/lib/parse/agent/describe.rb +420 -0
- data/lib/parse/agent/errors.rb +133 -0
- data/lib/parse/agent/mcp_client.rb +557 -0
- data/lib/parse/agent/mcp_dispatcher.rb +1023 -0
- data/lib/parse/agent/mcp_rack_app.rb +1143 -0
- data/lib/parse/agent/mcp_server.rb +376 -0
- data/lib/parse/agent/metadata_audit.rb +259 -0
- data/lib/parse/agent/metadata_dsl.rb +733 -0
- data/lib/parse/agent/metadata_registry.rb +794 -0
- data/lib/parse/agent/pipeline_validator.rb +82 -0
- data/lib/parse/agent/prompts.rb +351 -0
- data/lib/parse/agent/rate_limiter.rb +158 -0
- data/lib/parse/agent/relation_graph.rb +162 -0
- data/lib/parse/agent/result_formatter.rb +453 -0
- data/lib/parse/agent/tools.rb +5489 -0
- data/lib/parse/agent.rb +3249 -0
- data/lib/parse/api/aggregate.rb +79 -0
- data/lib/parse/api/all.rb +26 -0
- data/lib/parse/api/analytics.rb +18 -0
- data/lib/parse/api/batch.rb +33 -0
- data/lib/parse/api/cloud_functions.rb +58 -0
- data/lib/parse/api/config.rb +125 -0
- data/lib/parse/api/files.rb +29 -0
- data/lib/parse/api/hooks.rb +117 -0
- data/lib/parse/api/objects.rb +146 -0
- data/lib/parse/api/path_segment.rb +75 -0
- data/lib/parse/api/push.rb +20 -0
- data/lib/parse/api/schema.rb +49 -0
- data/lib/parse/api/server.rb +50 -0
- data/lib/parse/api/sessions.rb +24 -0
- data/lib/parse/api/users.rb +250 -0
- data/lib/parse/atlas_search/index_manager.rb +353 -0
- data/lib/parse/atlas_search/result.rb +204 -0
- data/lib/parse/atlas_search/search_builder.rb +604 -0
- data/lib/parse/atlas_search/session.rb +253 -0
- data/lib/parse/atlas_search.rb +995 -0
- data/lib/parse/client/authentication.rb +97 -0
- data/lib/parse/client/batch.rb +234 -0
- data/lib/parse/client/body_builder.rb +240 -0
- data/lib/parse/client/caching.rb +203 -0
- data/lib/parse/client/logging.rb +293 -0
- data/lib/parse/client/profiling.rb +181 -0
- data/lib/parse/client/protocol.rb +91 -0
- data/lib/parse/client/request.rb +233 -0
- data/lib/parse/client/response.rb +208 -0
- data/lib/parse/client.rb +1104 -0
- data/lib/parse/clp_scope.rb +361 -0
- data/lib/parse/live_query/circuit_breaker.rb +256 -0
- data/lib/parse/live_query/client.rb +1001 -0
- data/lib/parse/live_query/configuration.rb +224 -0
- data/lib/parse/live_query/event.rb +115 -0
- data/lib/parse/live_query/event_queue.rb +272 -0
- data/lib/parse/live_query/health_monitor.rb +214 -0
- data/lib/parse/live_query/logging.rb +149 -0
- data/lib/parse/live_query/subscription.rb +294 -0
- data/lib/parse/live_query.rb +163 -0
- data/lib/parse/lookup_rewriter.rb +445 -0
- data/lib/parse/model/acl.rb +968 -0
- data/lib/parse/model/associations/belongs_to.rb +275 -0
- data/lib/parse/model/associations/collection_proxy.rb +435 -0
- data/lib/parse/model/associations/has_many.rb +597 -0
- data/lib/parse/model/associations/has_one.rb +158 -0
- data/lib/parse/model/associations/pointer_collection_proxy.rb +134 -0
- data/lib/parse/model/associations/relation_collection_proxy.rb +177 -0
- data/lib/parse/model/bytes.rb +62 -0
- data/lib/parse/model/classes/audience.rb +262 -0
- data/lib/parse/model/classes/installation.rb +363 -0
- data/lib/parse/model/classes/job_schedule.rb +153 -0
- data/lib/parse/model/classes/job_status.rb +264 -0
- data/lib/parse/model/classes/product.rb +75 -0
- data/lib/parse/model/classes/push_status.rb +263 -0
- data/lib/parse/model/classes/role.rb +751 -0
- data/lib/parse/model/classes/session.rb +201 -0
- data/lib/parse/model/classes/user.rb +943 -0
- data/lib/parse/model/clp.rb +544 -0
- data/lib/parse/model/core/actions.rb +1268 -0
- data/lib/parse/model/core/builder.rb +139 -0
- data/lib/parse/model/core/create_lock.rb +386 -0
- data/lib/parse/model/core/describe.rb +382 -0
- data/lib/parse/model/core/enhanced_change_tracking.rb +159 -0
- data/lib/parse/model/core/errors.rb +38 -0
- data/lib/parse/model/core/fetching.rb +566 -0
- data/lib/parse/model/core/field_guards.rb +220 -0
- data/lib/parse/model/core/indexing.rb +382 -0
- data/lib/parse/model/core/parse_reference.rb +407 -0
- data/lib/parse/model/core/properties.rb +809 -0
- data/lib/parse/model/core/querying.rb +491 -0
- data/lib/parse/model/core/schema.rb +202 -0
- data/lib/parse/model/core/search_indexing.rb +174 -0
- data/lib/parse/model/date.rb +88 -0
- data/lib/parse/model/email.rb +213 -0
- data/lib/parse/model/file.rb +527 -0
- data/lib/parse/model/geojson.rb +271 -0
- data/lib/parse/model/geopoint.rb +261 -0
- data/lib/parse/model/model.rb +260 -0
- data/lib/parse/model/object.rb +2068 -0
- data/lib/parse/model/phone.rb +520 -0
- data/lib/parse/model/pointer.rb +443 -0
- data/lib/parse/model/polygon.rb +406 -0
- data/lib/parse/model/push.rb +975 -0
- data/lib/parse/model/shortnames.rb +8 -0
- data/lib/parse/model/time_zone.rb +141 -0
- data/lib/parse/model/validations/uniqueness_validator.rb +97 -0
- data/lib/parse/model/validations.rb +96 -0
- data/lib/parse/mongodb.rb +2300 -0
- data/lib/parse/pipeline_security.rb +554 -0
- data/lib/parse/query/constraint.rb +198 -0
- data/lib/parse/query/constraints.rb +3279 -0
- data/lib/parse/query/cursor.rb +434 -0
- data/lib/parse/query/n_plus_one_detector.rb +445 -0
- data/lib/parse/query/operation.rb +104 -0
- data/lib/parse/query/ordering.rb +66 -0
- data/lib/parse/query.rb +7028 -0
- data/lib/parse/schema/index_migrator.rb +291 -0
- data/lib/parse/schema/search_index_migrator.rb +289 -0
- data/lib/parse/schema.rb +494 -0
- data/lib/parse/stack/generators/rails.rb +40 -0
- data/lib/parse/stack/generators/templates/model.erb +51 -0
- data/lib/parse/stack/generators/templates/model_installation.rb +4 -0
- data/lib/parse/stack/generators/templates/model_role.rb +4 -0
- data/lib/parse/stack/generators/templates/model_session.rb +4 -0
- data/lib/parse/stack/generators/templates/model_user.rb +11 -0
- data/lib/parse/stack/generators/templates/parse.rb +12 -0
- data/lib/parse/stack/generators/templates/webhooks.rb +10 -0
- data/lib/parse/stack/railtie.rb +18 -0
- data/lib/parse/stack/tasks.rb +563 -0
- data/lib/parse/stack/version.rb +11 -0
- data/lib/parse/stack.rb +455 -0
- data/lib/parse/two_factor_auth/user_extension.rb +449 -0
- data/lib/parse/two_factor_auth.rb +310 -0
- data/lib/parse/webhooks/payload.rb +360 -0
- data/lib/parse/webhooks/registration.rb +199 -0
- data/lib/parse/webhooks/replay_protection.rb +189 -0
- data/lib/parse/webhooks.rb +510 -0
- data/lib/parse-stack-next.rb +5 -0
- data/lib/parse-stack.rb +5 -0
- data/parse-stack-next.gemspec +82 -0
- data/parse-stack.png +0 -0
- data/scripts/debug-ips.js +35 -0
- data/scripts/docker/Dockerfile.parse +13 -0
- data/scripts/docker/atlas-init.js +284 -0
- data/scripts/docker/docker-compose.atlas.yml +76 -0
- data/scripts/docker/docker-compose.test.yml +106 -0
- data/scripts/docker/mongo-init.js +21 -0
- data/scripts/eval_mcp_with_lm_studio.rb +274 -0
- data/scripts/start-parse.sh +90 -0
- data/scripts/start_mcp_server.rb +78 -0
- data/scripts/test_server_connection.rb +82 -0
- metadata +377 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Note: Do not require "../object" here - this file is loaded from object.rb
|
|
5
|
+
# and adding that require would create a circular dependency.
|
|
6
|
+
|
|
7
|
+
module Parse
|
|
8
|
+
# This class represents the data and columns contained in the standard Parse
|
|
9
|
+
# `_JobSchedule` collection. Rows here define recurring runs for background
|
|
10
|
+
# jobs registered via +Parse.Cloud.job(...)+. The collection is populated by
|
|
11
|
+
# the Parse Dashboard's "Schedule a Job" UI and consumed by Parse Server's
|
|
12
|
+
# scheduler.
|
|
13
|
+
#
|
|
14
|
+
# The default schema for {JobSchedule} is as follows:
|
|
15
|
+
#
|
|
16
|
+
# class Parse::JobSchedule < Parse::Object
|
|
17
|
+
# # See Parse::Object for inherited properties...
|
|
18
|
+
#
|
|
19
|
+
# property :job_name
|
|
20
|
+
# property :description
|
|
21
|
+
# property :params # JSON-encoded string of params (server stores as String)
|
|
22
|
+
# property :start_after # ISO 8601 timestamp string for first run
|
|
23
|
+
# property :days_of_week, :array
|
|
24
|
+
# property :time_of_day # "HH:MM:SS"
|
|
25
|
+
# property :last_run, :integer # epoch seconds of the previous run
|
|
26
|
+
# property :repeat_minutes, :integer
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# *Defining and scheduling a job*
|
|
30
|
+
#
|
|
31
|
+
# The job itself is registered in Parse Server's Cloud Code (server-side
|
|
32
|
+
# JavaScript). See {Parse::JobStatus} for the +Parse.Cloud.job(...)+
|
|
33
|
+
# registration example.
|
|
34
|
+
#
|
|
35
|
+
# Schedules are normally created through the Parse Dashboard "Jobs" tab,
|
|
36
|
+
# which writes the `_JobSchedule` row for you. The dashboard exposes:
|
|
37
|
+
#
|
|
38
|
+
# - the registered job name to invoke
|
|
39
|
+
# - the parameters to pass (serialized to {#params} as JSON)
|
|
40
|
+
# - the start time ({#start_after}) and time-of-day ({#time_of_day})
|
|
41
|
+
# - the days of the week ({#days_of_week}) or repeat interval
|
|
42
|
+
# ({#repeat_minutes}) at which the run should fire
|
|
43
|
+
#
|
|
44
|
+
# `_JobSchedule` is a metadata collection: it stores schedule definitions
|
|
45
|
+
# but Parse Server itself does not auto-trigger jobs from these rows. The
|
|
46
|
+
# actual dispatch is performed by external tooling (e.g.
|
|
47
|
+
# +parse-server-scheduler+, dashboard-driven cron wrappers, or a sidecar
|
|
48
|
+
# process) which reads `_JobSchedule` and fires +POST /parse/jobs/<name>+
|
|
49
|
+
# at the appropriate times. Run status rows then appear in
|
|
50
|
+
# {Parse::JobStatus}.
|
|
51
|
+
#
|
|
52
|
+
# *Reading a schedule from Ruby*
|
|
53
|
+
#
|
|
54
|
+
# schedule = Parse::JobSchedule.for_job("nightlyCleanup").first
|
|
55
|
+
# schedule.parsed_params # => { "dryRun" => false } (decoded from `params`)
|
|
56
|
+
# schedule.time_of_day # => "03:00:00"
|
|
57
|
+
# schedule.days_of_week # => ["mon","tue","wed","thu","fri"]
|
|
58
|
+
#
|
|
59
|
+
# @note This collection is consumed by external scheduling tooling, not by
|
|
60
|
+
# Parse Server itself. {#params} is stored as a JSON string (not an
|
|
61
|
+
# Object) per the canonical Parse Server schema; use {#parsed_params} to
|
|
62
|
+
# decode. Master-key access is typically required.
|
|
63
|
+
# @see Parse::JobStatus
|
|
64
|
+
# @see Parse::Object
|
|
65
|
+
class JobSchedule < Parse::Object
|
|
66
|
+
parse_class Parse::Model::CLASS_JOB_SCHEDULE
|
|
67
|
+
|
|
68
|
+
# Note: This class is marked `agent_hidden` after
|
|
69
|
+
# `Parse::Agent::MetadataDSL` is mixed into `Parse::Object` (the mixin
|
|
70
|
+
# happens in `lib/parse/agent.rb`, which is required after this file
|
|
71
|
+
# via `lib/parse/stack.rb`, so calling `agent_hidden` here in the class
|
|
72
|
+
# body would raise NameError). The actual hide is performed by the
|
|
73
|
+
# `Parse::JobSchedule.agent_hidden` call at the bottom of
|
|
74
|
+
# `lib/parse/agent.rb`. `_JobSchedule` rows define recurring runs and
|
|
75
|
+
# can contain scheduler parameters or credentials in {#params}.
|
|
76
|
+
|
|
77
|
+
# @!attribute job_name
|
|
78
|
+
# The registered job name to invoke on each run.
|
|
79
|
+
# @return [String]
|
|
80
|
+
property :job_name
|
|
81
|
+
|
|
82
|
+
# @!attribute description
|
|
83
|
+
# Free-form description of this scheduled job, as entered in the
|
|
84
|
+
# dashboard.
|
|
85
|
+
# @return [String]
|
|
86
|
+
property :description
|
|
87
|
+
|
|
88
|
+
# @!attribute params
|
|
89
|
+
# JSON-encoded string of parameters to pass to the job. Stored as a String
|
|
90
|
+
# in the canonical Parse Server schema to avoid the nested-key character
|
|
91
|
+
# restrictions that apply to Object columns.
|
|
92
|
+
# @return [String]
|
|
93
|
+
property :params
|
|
94
|
+
|
|
95
|
+
# @!attribute start_after
|
|
96
|
+
# ISO 8601 timestamp string indicating the earliest time the first
|
|
97
|
+
# scheduled run may fire.
|
|
98
|
+
# @return [String]
|
|
99
|
+
property :start_after
|
|
100
|
+
|
|
101
|
+
# @!attribute days_of_week
|
|
102
|
+
# Array of day-of-week identifiers indicating which days the job is
|
|
103
|
+
# eligible to run. The exact token set (e.g. +"mon"+/+"tue"+/... vs.
|
|
104
|
+
# +0+..+6+) is determined by the scheduler tooling that writes the row;
|
|
105
|
+
# the Parse Server schema only requires that the column hold an array.
|
|
106
|
+
# @return [Array]
|
|
107
|
+
property :days_of_week, :array
|
|
108
|
+
|
|
109
|
+
# @!attribute time_of_day
|
|
110
|
+
# "HH:MM:SS" string indicating the time of day at which the job should
|
|
111
|
+
# run on each eligible day.
|
|
112
|
+
# @return [String]
|
|
113
|
+
property :time_of_day
|
|
114
|
+
|
|
115
|
+
# @!attribute last_run
|
|
116
|
+
# Raw `Number` timestamp recording the previous run. The unit is
|
|
117
|
+
# scheduler-defined — most external schedulers write +Date.now()+
|
|
118
|
+
# milliseconds, but the canonical Parse Server schema only declares
|
|
119
|
+
# +Number+ and does not pin a unit. Treat values written by one
|
|
120
|
+
# scheduler as opaque to others.
|
|
121
|
+
# @return [Integer]
|
|
122
|
+
property :last_run, :integer
|
|
123
|
+
|
|
124
|
+
# @!attribute repeat_minutes
|
|
125
|
+
# Interval in minutes between runs, when the schedule is interval-based
|
|
126
|
+
# rather than time-of-day-based.
|
|
127
|
+
# @return [Integer]
|
|
128
|
+
property :repeat_minutes, :integer
|
|
129
|
+
|
|
130
|
+
class << self
|
|
131
|
+
# Query scope for schedules belonging to a specific job by name.
|
|
132
|
+
# @param name [String, Symbol]
|
|
133
|
+
# @return [Parse::Query]
|
|
134
|
+
def for_job(name)
|
|
135
|
+
query(job_name: name.to_s)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Decoded form of {#params}, which is stored on the wire as a JSON
|
|
140
|
+
# string per the canonical Parse Server schema. Returns the parsed
|
|
141
|
+
# Hash, or `nil` if `params` is blank, or `nil` if the stored string is
|
|
142
|
+
# not valid JSON (Parse Dashboard occasionally writes a non-JSON
|
|
143
|
+
# description string here for ad-hoc schedules — we swallow the parse
|
|
144
|
+
# error rather than crash the caller).
|
|
145
|
+
# @return [Hash, nil]
|
|
146
|
+
def parsed_params
|
|
147
|
+
return nil if params.blank?
|
|
148
|
+
JSON.parse(params)
|
|
149
|
+
rescue JSON::ParserError
|
|
150
|
+
nil
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Note: Do not require "../object" here - this file is loaded from object.rb
|
|
5
|
+
# and adding that require would create a circular dependency.
|
|
6
|
+
|
|
7
|
+
module Parse
|
|
8
|
+
# This class represents the data and columns contained in the standard Parse
|
|
9
|
+
# `_JobStatus` collection. Parse Server writes a row here every time a
|
|
10
|
+
# background job (registered via +Parse.Cloud.job(...)+) runs, recording its
|
|
11
|
+
# outcome and any status/message updates emitted via +response.message(...)+.
|
|
12
|
+
#
|
|
13
|
+
# The default schema for {JobStatus} is as follows:
|
|
14
|
+
#
|
|
15
|
+
# class Parse::JobStatus < Parse::Object
|
|
16
|
+
# # See Parse::Object for inherited properties...
|
|
17
|
+
#
|
|
18
|
+
# property :job_name
|
|
19
|
+
# property :source # how the job was invoked
|
|
20
|
+
# property :status # "running", "succeeded", "failed"
|
|
21
|
+
# property :message # latest status message emitted by the job
|
|
22
|
+
# property :params, :object # parameters the job was invoked with
|
|
23
|
+
# property :finished_at, :date # when the job stopped running
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# *Defining a job*
|
|
27
|
+
#
|
|
28
|
+
# Jobs are registered in your Parse Server's Cloud Code (server-side
|
|
29
|
+
# JavaScript), not in this Ruby SDK. A minimal example:
|
|
30
|
+
#
|
|
31
|
+
# // cloud/main.js
|
|
32
|
+
# Parse.Cloud.job("nightlyCleanup", async (request) => {
|
|
33
|
+
# const { params, headers, log, message } = request;
|
|
34
|
+
# message("Starting cleanup...");
|
|
35
|
+
# const query = new Parse.Query("_Session");
|
|
36
|
+
# query.lessThan("expiresAt", new Date());
|
|
37
|
+
# const sessions = await query.find({ useMasterKey: true });
|
|
38
|
+
# await Parse.Object.destroyAll(sessions, { useMasterKey: true });
|
|
39
|
+
# message(`Deleted ${sessions.length} sessions`);
|
|
40
|
+
# return `ok`;
|
|
41
|
+
# });
|
|
42
|
+
#
|
|
43
|
+
# *Invoking a job*
|
|
44
|
+
#
|
|
45
|
+
# Once registered, a job can be triggered ad-hoc via REST (requires the
|
|
46
|
+
# master key):
|
|
47
|
+
#
|
|
48
|
+
# POST /parse/jobs/nightlyCleanup
|
|
49
|
+
# X-Parse-Application-Id: ...
|
|
50
|
+
# X-Parse-Master-Key: ...
|
|
51
|
+
# Content-Type: application/json
|
|
52
|
+
#
|
|
53
|
+
# { "someParam": "value" }
|
|
54
|
+
#
|
|
55
|
+
# The request returns immediately with a `_JobStatus` `objectId`; the job
|
|
56
|
+
# itself runs asynchronously, and the `_JobStatus` row is updated as it
|
|
57
|
+
# progresses. For *recurring* runs, configure a {Parse::JobSchedule} row
|
|
58
|
+
# via the Parse Dashboard's "Jobs" tab — Parse Server's scheduler will
|
|
59
|
+
# invoke the job at the configured times.
|
|
60
|
+
#
|
|
61
|
+
# *Reading job status from Ruby*
|
|
62
|
+
#
|
|
63
|
+
# # Has the nightly cleanup run today?
|
|
64
|
+
# latest = Parse::JobStatus.latest_for("nightlyCleanup")
|
|
65
|
+
# puts "Last run: #{latest.status} at #{latest.created_at}"
|
|
66
|
+
# puts "Duration: #{latest.duration}s" if latest.finished?
|
|
67
|
+
#
|
|
68
|
+
# # Find failed jobs in the last 24h
|
|
69
|
+
# yesterday = Time.now - 86_400
|
|
70
|
+
# Parse::JobStatus.failed.where(:created_at.gt => yesterday).all
|
|
71
|
+
#
|
|
72
|
+
# @note This collection is written by Parse Server itself and read access
|
|
73
|
+
# typically requires the master key. Parse Server does not garbage-collect
|
|
74
|
+
# `_JobStatus` rows — long-running deployments accumulate history and
|
|
75
|
+
# should implement their own retention policy.
|
|
76
|
+
# @see Parse::JobSchedule for the corresponding scheduled-run configuration.
|
|
77
|
+
# @see Parse::Object
|
|
78
|
+
class JobStatus < Parse::Object
|
|
79
|
+
parse_class Parse::Model::CLASS_JOB_STATUS
|
|
80
|
+
|
|
81
|
+
# Note: This class is marked `agent_hidden` after
|
|
82
|
+
# `Parse::Agent::MetadataDSL` is mixed into `Parse::Object` (the mixin
|
|
83
|
+
# happens in `lib/parse/agent.rb`, which is required after this file
|
|
84
|
+
# via `lib/parse/stack.rb`, so calling `agent_hidden` here in the class
|
|
85
|
+
# body would raise NameError). The actual hide is performed by the
|
|
86
|
+
# `Parse::JobStatus.agent_hidden` call at the bottom of
|
|
87
|
+
# `lib/parse/agent.rb`. `_JobStatus` carries operational signal
|
|
88
|
+
# (registered job names, status messages, error traces in {#message},
|
|
89
|
+
# scheduler parameters) that an agent surface should not enumerate by
|
|
90
|
+
# default.
|
|
91
|
+
|
|
92
|
+
# @!attribute job_name
|
|
93
|
+
# The name the job was registered under (the first argument to
|
|
94
|
+
# +Parse.Cloud.job+).
|
|
95
|
+
# @return [String]
|
|
96
|
+
property :job_name
|
|
97
|
+
|
|
98
|
+
# @!attribute source
|
|
99
|
+
# How the job was invoked. Parse Server itself hard-codes +"api"+ in
|
|
100
|
+
# +StatusHandler.js+ for runs triggered via +POST /parse/jobs/<name>+;
|
|
101
|
+
# external schedulers (parse-server-scheduler, dashboard cron tooling)
|
|
102
|
+
# may inject other values when they create the +_JobStatus+ row.
|
|
103
|
+
# @return [String]
|
|
104
|
+
property :source
|
|
105
|
+
|
|
106
|
+
# @!attribute status
|
|
107
|
+
# Current state of the job run. Common values are +"running"+,
|
|
108
|
+
# +"succeeded"+, and +"failed"+.
|
|
109
|
+
# @return [String]
|
|
110
|
+
property :status
|
|
111
|
+
|
|
112
|
+
# @!attribute message
|
|
113
|
+
# The most recent status message emitted by the job via
|
|
114
|
+
# +response.message(...)+.
|
|
115
|
+
# @return [String]
|
|
116
|
+
property :message
|
|
117
|
+
|
|
118
|
+
# @!attribute params
|
|
119
|
+
# The parameters the job was invoked with.
|
|
120
|
+
# @return [Hash]
|
|
121
|
+
property :params, :object
|
|
122
|
+
|
|
123
|
+
# @!attribute finished_at
|
|
124
|
+
# Timestamp when the job stopped running. Nil while the job is still
|
|
125
|
+
# in-flight.
|
|
126
|
+
# @return [Parse::Date]
|
|
127
|
+
property :finished_at, :date
|
|
128
|
+
|
|
129
|
+
# Parse Server's terminal status values, written by `setFinalStatus` in
|
|
130
|
+
# `StatusHandler.js`. Mirrored here so callers can compare against named
|
|
131
|
+
# constants instead of hard-coding strings.
|
|
132
|
+
STATUS_RUNNING = "running"
|
|
133
|
+
STATUS_SUCCEEDED = "succeeded"
|
|
134
|
+
STATUS_FAILED = "failed"
|
|
135
|
+
|
|
136
|
+
class << self
|
|
137
|
+
# Query for jobs currently in the running state.
|
|
138
|
+
# @return [Parse::Query]
|
|
139
|
+
def running
|
|
140
|
+
query(status: STATUS_RUNNING)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Query for jobs that completed successfully.
|
|
144
|
+
# @return [Parse::Query]
|
|
145
|
+
def succeeded
|
|
146
|
+
query(status: STATUS_SUCCEEDED)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Query for jobs that failed.
|
|
150
|
+
# @return [Parse::Query]
|
|
151
|
+
def failed
|
|
152
|
+
query(status: STATUS_FAILED)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Query for the most recent job status rows, newest first.
|
|
156
|
+
# @param limit [Integer] number of rows to return (default: 100)
|
|
157
|
+
# @return [Parse::Query]
|
|
158
|
+
def recent(limit: 100)
|
|
159
|
+
query.order(:created_at.desc).limit(limit)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Query scope for runs of a specific job by name.
|
|
163
|
+
# @param name [String, Symbol]
|
|
164
|
+
# @return [Parse::Query]
|
|
165
|
+
def for_job(name)
|
|
166
|
+
query(job_name: name.to_s)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# The most recently *started* run of the named job (any status),
|
|
170
|
+
# ordered by `created_at`. Useful for "did the nightly cleanup run
|
|
171
|
+
# yet?" introspection. Note that for a still-running job this may
|
|
172
|
+
# return the in-flight row even after subsequent attempts have
|
|
173
|
+
# finished — `created_at` is the start time, not the finish time.
|
|
174
|
+
# @param name [String, Symbol]
|
|
175
|
+
# @return [Parse::JobStatus, nil]
|
|
176
|
+
def latest_for(name)
|
|
177
|
+
for_job(name).order(:created_at.desc).first
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Query scope for `_JobStatus` rows older than the given threshold.
|
|
181
|
+
# @param days [Integer] number of days since the row's `created_at`
|
|
182
|
+
# (default: 30)
|
|
183
|
+
# @return [Parse::Query]
|
|
184
|
+
# @example
|
|
185
|
+
# stale = Parse::JobStatus.older_than(days: 90).all
|
|
186
|
+
def older_than(days: 30)
|
|
187
|
+
cutoff = Time.now - (days * 24 * 60 * 60)
|
|
188
|
+
query(:created_at.lt => cutoff)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Count `_JobStatus` rows older than the given threshold.
|
|
192
|
+
# @param days [Integer] number of days since `created_at` (default: 30)
|
|
193
|
+
# @return [Integer]
|
|
194
|
+
def older_than_count(days: 30)
|
|
195
|
+
older_than(days: days).count
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Delete `_JobStatus` rows older than the given threshold. Parse Server
|
|
199
|
+
# does not garbage-collect this collection on its own, so long-running
|
|
200
|
+
# deployments accumulate run history indefinitely. Mirrors
|
|
201
|
+
# {Parse::Installation.cleanup_stale_tokens!}.
|
|
202
|
+
#
|
|
203
|
+
# By default (`terminal_only: true`), only rows in a terminal state
|
|
204
|
+
# (`succeeded` or `failed`) are eligible — an orphaned
|
|
205
|
+
# `status == "running"` row from a crashed worker is preserved, as is
|
|
206
|
+
# any row with an external-scheduler-injected status the SDK doesn't
|
|
207
|
+
# recognize. Set `terminal_only: false` to drop the status guard and
|
|
208
|
+
# reap every row older than the cutoff regardless of state (use with
|
|
209
|
+
# care for orphan cleanup).
|
|
210
|
+
#
|
|
211
|
+
# Use with caution — permanently removes job-history records.
|
|
212
|
+
#
|
|
213
|
+
# @param days [Integer] number of days since `created_at` (default: 30).
|
|
214
|
+
# Negative values are accepted and produce a future cutoff (useful in
|
|
215
|
+
# tests for "delete everything older than now-plus-a-minute").
|
|
216
|
+
# @param terminal_only [Boolean] when true (default), restrict the
|
|
217
|
+
# destroy to rows whose status is `succeeded` or `failed`. When
|
|
218
|
+
# false, every row older than the cutoff is eligible.
|
|
219
|
+
# @return [Integer] the number of rows deleted
|
|
220
|
+
# @example
|
|
221
|
+
# deleted = Parse::JobStatus.cleanup_older_than!(days: 90)
|
|
222
|
+
def cleanup_older_than!(days: 30, terminal_only: true)
|
|
223
|
+
scope = older_than(days: days)
|
|
224
|
+
if terminal_only
|
|
225
|
+
scope = scope.where(:status.in => [STATUS_SUCCEEDED, STATUS_FAILED])
|
|
226
|
+
end
|
|
227
|
+
stale = scope.all
|
|
228
|
+
stale.each(&:destroy)
|
|
229
|
+
stale.count
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# @return [Boolean] true if this row is in the running state.
|
|
234
|
+
def running?
|
|
235
|
+
status == STATUS_RUNNING
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# @return [Boolean] true if this run completed successfully.
|
|
239
|
+
def succeeded?
|
|
240
|
+
status == STATUS_SUCCEEDED
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# @return [Boolean] true if this run failed.
|
|
244
|
+
def failed?
|
|
245
|
+
status == STATUS_FAILED
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# @return [Boolean] true if the run has reached a terminal state
|
|
249
|
+
# (succeeded or failed). Parse Server writes `finished_at` at the same
|
|
250
|
+
# time it transitions out of `running`, so either signal is acceptable;
|
|
251
|
+
# we check `finished_at` first because it's the more authoritative one.
|
|
252
|
+
def finished?
|
|
253
|
+
!finished_at.nil? || succeeded? || failed?
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Wall-clock duration of the run as a `Float` number of seconds, or `nil`
|
|
257
|
+
# while the job is still in-flight (or if either timestamp is missing).
|
|
258
|
+
# @return [Float, nil]
|
|
259
|
+
def duration
|
|
260
|
+
return nil if finished_at.nil? || created_at.nil?
|
|
261
|
+
finished_at.to_time - created_at.to_time
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
# Note: Do not require "../object" here - this file is loaded from object.rb
|
|
4
|
+
# and adding that require would create a circular dependency.
|
|
5
|
+
# user.rb is also loaded from object.rb before this file.
|
|
6
|
+
|
|
7
|
+
module Parse
|
|
8
|
+
# This class represents the data and columns contained in the standard Parse `_Product` collection.
|
|
9
|
+
# These records were used when implementing in-app purchases in mobile applications via the
|
|
10
|
+
# original Parse iOS SDK's `PFProduct` downloadable-content flow.
|
|
11
|
+
#
|
|
12
|
+
# @note This Parse feature is effectively deprecated. The `PFProduct` IAP integration was tied
|
|
13
|
+
# to hosted Parse and is not actively used by modern Parse Server deployments. Most apps now
|
|
14
|
+
# verify in-app purchase receipts directly against the Apple App Store or Google Play. The
|
|
15
|
+
# `_Product` collection and this class are retained for backwards compatibility with legacy
|
|
16
|
+
# applications that still read or write product metadata in this table.
|
|
17
|
+
#
|
|
18
|
+
# The default schema for {Product} is as follows:
|
|
19
|
+
#
|
|
20
|
+
# class Parse::Product < Parse::Object
|
|
21
|
+
# # See Parse::Object for inherited properties...
|
|
22
|
+
#
|
|
23
|
+
# property :download, :file
|
|
24
|
+
# property :icon, :file, required: true
|
|
25
|
+
# property :order, :integer, required: true
|
|
26
|
+
# property :subtitle, required: true
|
|
27
|
+
# property :title, required: true
|
|
28
|
+
# property :product_identifier, required: true
|
|
29
|
+
#
|
|
30
|
+
# end
|
|
31
|
+
# @see Parse::Object
|
|
32
|
+
class Product < Parse::Object
|
|
33
|
+
parse_class Parse::Model::CLASS_PRODUCT
|
|
34
|
+
|
|
35
|
+
# Note: This class is marked `agent_hidden` after `Parse::Agent::MetadataDSL`
|
|
36
|
+
# is mixed into `Parse::Object`. The mixin happens in `lib/parse/agent.rb`,
|
|
37
|
+
# which is required after this file via `lib/parse/stack.rb`, so calling
|
|
38
|
+
# `agent_hidden` here in the class body would raise NameError. See the
|
|
39
|
+
# corresponding `Parse::Product.agent_hidden` call at the bottom of
|
|
40
|
+
# `lib/parse/agent.rb`.
|
|
41
|
+
|
|
42
|
+
# @!attribute download
|
|
43
|
+
# @return [String] the file payload for this product download.
|
|
44
|
+
property :download, :file
|
|
45
|
+
|
|
46
|
+
# @!attribute download_name
|
|
47
|
+
# @return [String] the name of this download.
|
|
48
|
+
property :download_name
|
|
49
|
+
|
|
50
|
+
# @!attribute icon
|
|
51
|
+
# An icon file representing this download. This field is required by Parse.
|
|
52
|
+
# @return [String]
|
|
53
|
+
property :icon, :file, required: true
|
|
54
|
+
|
|
55
|
+
# @!attribute order
|
|
56
|
+
# The product order number. This field is required by Parse.
|
|
57
|
+
# @return [String]
|
|
58
|
+
property :order, :integer, required: true
|
|
59
|
+
|
|
60
|
+
# @!attribute product_identifier
|
|
61
|
+
# The product identifier. This field is required by Parse.
|
|
62
|
+
# @return [String]
|
|
63
|
+
property :product_identifier, required: true
|
|
64
|
+
|
|
65
|
+
# @!attribute subtitle
|
|
66
|
+
# The subtitle description for this product. This field is required by Parse.
|
|
67
|
+
# @return [String]
|
|
68
|
+
property :subtitle, required: true
|
|
69
|
+
|
|
70
|
+
# @!attribute title
|
|
71
|
+
# The title for this product. This field is required by Parse.
|
|
72
|
+
# @return [String] the title for this product.
|
|
73
|
+
property :title, required: true
|
|
74
|
+
end
|
|
75
|
+
end
|